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