1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
|
//===- "DependencyTracker.h" ------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_DWARFLINKER_PARALLEL_DEPENDENCYTRACKER_H
#define LLVM_LIB_DWARFLINKER_PARALLEL_DEPENDENCYTRACKER_H
#include "DWARFLinkerCompileUnit.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallVector.h"
namespace llvm {
class DWARFDebugInfoEntry;
class DWARFDie;
namespace dwarf_linker {
namespace parallel {
/// This class discovers DIEs dependencies: marks "live" DIEs, marks DIE
/// locations (whether DIE should be cloned as regular DIE or it should be put
/// into the artificial type unit).
class DependencyTracker {
public:
DependencyTracker(CompileUnit &CU) : CU(CU) {}
/// Recursively walk the \p DIE tree and look for DIEs to keep. Store that
/// information in \p CU's DIEInfo.
///
/// This function is the entry point of the DIE selection algorithm. It is
/// expected to walk the DIE tree and(through the mediation of
/// Context.File.Addresses) ask for relocation adjustment value on each
/// DIE that might be a 'root DIE'(f.e. subprograms, variables).
///
/// Returns true if all dependencies are correctly discovered. Inter-CU
/// dependencies cannot be discovered if referenced CU is not analyzed yet.
/// If that is the case this method returns false.
bool resolveDependenciesAndMarkLiveness(
bool InterCUProcessingStarted,
std::atomic<bool> &HasNewInterconnectedCUs);
/// Check if dependencies have incompatible placement.
/// If that is the case modify placement to be compatible.
/// \returns true if any placement was updated, otherwise returns false.
/// This method should be called as a followup processing after
/// resolveDependenciesAndMarkLiveness().
bool updateDependenciesCompleteness();
/// Recursively walk the \p DIE tree and check "keepness" and "placement"
/// information. It is an error if parent node does not have "keep" flag,
/// while child has one. It is an error if parent node has "TypeTable"
/// placement while child has "PlainDwarf" placement. This function dump error
/// at stderr in that case.
void verifyKeepChain();
protected:
enum class LiveRootWorklistActionTy : uint8_t {
/// Mark current item as live entry.
MarkSingleLiveEntry = 0,
/// Mark current item as type entry.
MarkSingleTypeEntry,
/// Mark current item and all its children as live entry.
MarkLiveEntryRec,
/// Mark current item and all its children as type entry.
MarkTypeEntryRec,
/// Mark all children of current item as live entry.
MarkLiveChildrenRec,
/// Mark all children of current item as type entry.
MarkTypeChildrenRec,
};
/// \returns true if the specified action is for the "PlainDwarf".
bool isLiveAction(LiveRootWorklistActionTy Action) {
switch (Action) {
default:
return false;
case LiveRootWorklistActionTy::MarkSingleLiveEntry:
case LiveRootWorklistActionTy::MarkLiveEntryRec:
case LiveRootWorklistActionTy::MarkLiveChildrenRec:
return true;
}
}
/// \returns true if the specified action is for the "TypeTable".
bool isTypeAction(LiveRootWorklistActionTy Action) {
switch (Action) {
default:
return false;
case LiveRootWorklistActionTy::MarkSingleTypeEntry:
case LiveRootWorklistActionTy::MarkTypeEntryRec:
case LiveRootWorklistActionTy::MarkTypeChildrenRec:
return true;
}
}
/// \returns true if the specified action affects only Root entry
/// itself and does not affect it`s children.
bool isSingleAction(LiveRootWorklistActionTy Action) {
switch (Action) {
default:
return false;
case LiveRootWorklistActionTy::MarkSingleLiveEntry:
case LiveRootWorklistActionTy::MarkSingleTypeEntry:
return true;
}
}
/// \returns true if the specified action affects only Root entry
/// itself and does not affect it`s children.
bool isChildrenAction(LiveRootWorklistActionTy Action) {
switch (Action) {
default:
return false;
case LiveRootWorklistActionTy::MarkLiveChildrenRec:
case LiveRootWorklistActionTy::MarkTypeChildrenRec:
return true;
}
}
/// Class keeping live worklist item data.
class LiveRootWorklistItemTy {
public:
LiveRootWorklistItemTy() = default;
LiveRootWorklistItemTy(const LiveRootWorklistItemTy &) = default;
LiveRootWorklistItemTy(LiveRootWorklistActionTy Action,
UnitEntryPairTy RootEntry) {
RootCU.setInt(Action);
RootCU.setPointer(RootEntry.CU);
RootDieEntry = RootEntry.DieEntry;
}
LiveRootWorklistItemTy(LiveRootWorklistActionTy Action,
UnitEntryPairTy RootEntry,
UnitEntryPairTy ReferencedBy) {
RootCU.setPointer(RootEntry.CU);
RootCU.setInt(Action);
RootDieEntry = RootEntry.DieEntry;
ReferencedByCU = ReferencedBy.CU;
ReferencedByDieEntry = ReferencedBy.DieEntry;
}
UnitEntryPairTy getRootEntry() const {
return UnitEntryPairTy{RootCU.getPointer(), RootDieEntry};
}
CompileUnit::DieOutputPlacement getPlacement() const {
return static_cast<CompileUnit::DieOutputPlacement>(RootCU.getInt());
}
bool hasReferencedByOtherEntry() const { return ReferencedByCU != nullptr; }
UnitEntryPairTy getReferencedByEntry() const {
assert(ReferencedByCU);
assert(ReferencedByDieEntry);
return UnitEntryPairTy{ReferencedByCU, ReferencedByDieEntry};
}
LiveRootWorklistActionTy getAction() const {
return static_cast<LiveRootWorklistActionTy>(RootCU.getInt());
}
protected:
/// Root entry.
/// ASSUMPTION: 3 bits are used to store LiveRootWorklistActionTy value.
/// Thus LiveRootWorklistActionTy should have no more eight elements.
/// Pointer traits for CompileUnit.
struct CompileUnitPointerTraits {
static inline void *getAsVoidPointer(CompileUnit *P) { return P; }
static inline CompileUnit *getFromVoidPointer(void *P) {
return (CompileUnit *)P;
}
static constexpr int NumLowBitsAvailable = 3;
static_assert(
alignof(CompileUnit) >= (1 << NumLowBitsAvailable),
"CompileUnit insufficiently aligned to have enough low bits.");
};
PointerIntPair<CompileUnit *, 3, LiveRootWorklistActionTy,
CompileUnitPointerTraits>
RootCU;
const DWARFDebugInfoEntry *RootDieEntry = nullptr;
/// Another root entry which references this RootDieEntry.
/// ReferencedByDieEntry is kept to update placement.
/// if RootDieEntry has placement incompatible with placement
/// of ReferencedByDieEntry then it should be updated.
CompileUnit *ReferencedByCU = nullptr;
const DWARFDebugInfoEntry *ReferencedByDieEntry = nullptr;
};
using RootEntriesListTy = SmallVector<LiveRootWorklistItemTy>;
/// This function navigates DIEs tree starting from specified \p Entry.
/// It puts found 'root DIE' into the worklist. The \p CollectLiveEntries
/// instructs to collect either live roots(like subprograms having live
/// DW_AT_low_pc) or otherwise roots which is not live(they need to be
/// collected if they are imported f.e. by DW_TAG_imported_module).
void collectRootsToKeep(const UnitEntryPairTy &Entry,
std::optional<UnitEntryPairTy> ReferencedBy,
bool IsLiveParent);
/// Returns true if specified variable references live code section.
static bool isLiveVariableEntry(const UnitEntryPairTy &Entry,
bool IsLiveParent);
/// Returns true if specified subprogram references live code section.
static bool isLiveSubprogramEntry(const UnitEntryPairTy &Entry);
/// Examine worklist and mark all 'root DIE's as kept and set "Placement"
/// property.
bool markCollectedLiveRootsAsKept(bool InterCUProcessingStarted,
std::atomic<bool> &HasNewInterconnectedCUs);
/// Mark whole DIE tree as kept recursively.
bool markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action,
const UnitEntryPairTy &RootEntry,
const UnitEntryPairTy &Entry,
bool InterCUProcessingStarted,
std::atomic<bool> &HasNewInterconnectedCUs);
/// Mark parents as keeping children.
void markParentsAsKeepingChildren(const UnitEntryPairTy &Entry);
/// Mark whole DIE tree as placed in "PlainDwarf".
void setPlainDwarfPlacementRec(const UnitEntryPairTy &Entry);
/// Check referenced DIEs and add them into the worklist.
bool maybeAddReferencedRoots(LiveRootWorklistActionTy Action,
const UnitEntryPairTy &RootEntry,
const UnitEntryPairTy &Entry,
bool InterCUProcessingStarted,
std::atomic<bool> &HasNewInterconnectedCUs);
/// \returns true if \p DIEEntry can possibly be put into the artificial type
/// unit.
bool isTypeTableCandidate(const DWARFDebugInfoEntry *DIEEntry);
/// \returns root for the specified \p Entry.
UnitEntryPairTy getRootForSpecifiedEntry(UnitEntryPairTy Entry);
/// Add action item to the work list.
void
addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action,
const UnitEntryPairTy &Entry,
std::optional<UnitEntryPairTy> ReferencedBy);
CompileUnit &CU;
/// List of entries which are 'root DIE's.
RootEntriesListTy RootEntriesWorkList;
/// List of entries dependencies.
RootEntriesListTy Dependencies;
};
} // end of namespace parallel
} // end of namespace dwarf_linker
} // end of namespace llvm
#endif // LLVM_LIB_DWARFLINKER_PARALLEL_DEPENDENCYTRACKER_H
|