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