xref: /freebsd-src/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DependencyTracker.h (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
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