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 | |