LLVM 24.0.0git
DependencyTracker.h
Go to the documentation of this file.
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
13#include "llvm/ADT/DenseMap.h"
16
17namespace llvm {
19class DWARFDie;
20
21namespace dwarf_linker {
22namespace parallel {
23
24/// This class discovers DIEs dependencies: marks "live" DIEs, marks DIE
25/// locations (whether DIE should be cloned as regular DIE or it should be put
26/// into the artificial type unit).
28public:
30
31 /// Recursively walk the \p DIE tree and look for DIEs to keep. Store that
32 /// information in \p CU's DIEInfo.
33 ///
34 /// This function is the entry point of the DIE selection algorithm. It is
35 /// expected to walk the DIE tree and(through the mediation of
36 /// Context.File.Addresses) ask for relocation adjustment value on each
37 /// DIE that might be a 'root DIE'(f.e. subprograms, variables).
38 ///
39 /// Returns true if all dependencies are correctly discovered. Inter-CU
40 /// dependencies cannot be discovered if referenced CU is not analyzed yet.
41 /// If that is the case this method returns false.
43 bool InterCUProcessingStarted,
44 std::atomic<bool> &HasNewInterconnectedCUs);
45
46 /// Check if dependencies have incompatible placement.
47 /// If that is the case modify placement to be compatible.
48 /// \returns true if any placement was updated, otherwise returns false.
49 /// This method should be called as a followup processing after
50 /// resolveDependenciesAndMarkLiveness().
52
53 /// Recursively walk the \p DIE tree and check "keepness" and "placement"
54 /// information. It is an error if parent node does not have "keep" flag,
55 /// while child has one. It is an error if parent node has "TypeTable"
56 /// placement while child has "PlainDwarf" placement. This function dump error
57 /// at stderr in that case.
58 void verifyKeepChain();
59
60protected:
62 /// Mark current item as live entry.
64
65 /// Mark current item as type entry.
67
68 /// Mark current item and all its children as live entry.
70
71 /// Mark current item and all its children as type entry.
73
74 /// Mark all children of current item as live entry.
76
77 /// Mark all children of current item as type entry.
79 };
80
81 /// \returns true if the specified action is for the "PlainDwarf".
83 switch (Action) {
84 default:
85 return false;
86
90 return true;
91 }
92 }
93
94 /// \returns true if the specified action is for the "TypeTable".
96 switch (Action) {
97 default:
98 return false;
99
103 return true;
104 }
105 }
106
107 /// \returns true if the specified action affects only Root entry
108 /// itself and does not affect it`s children.
109 bool isSingleAction(LiveRootWorklistActionTy Action) {
110 switch (Action) {
111 default:
112 return false;
113
116 return true;
117 }
118 }
119
120 /// \returns true if the specified action affects only Root entry
121 /// itself and does not affect it`s children.
123 switch (Action) {
124 default:
125 return false;
126
129 return true;
130 }
131 }
132
133 /// What a tree walk does, and for a walk that only records dependencies,
134 /// which root the dependencies it finds are recorded under. Only a
135 /// DW_TAG_subprogram re-anchors that root, so the distinction cannot be
136 /// recovered by comparing root entries: a walk of a subprogram subtree starts
137 /// out anchored to the subprogram itself.
138 enum class TreeWalkKindTy : uint8_t {
139 /// Mark the tree as kept and schedule the roots it references.
141
142 /// Do not mark. Record the dependencies as belonging to whichever root
143 /// references the walked subtree.
145
146 /// Do not mark. Record the dependencies as belonging to a subprogram inside
147 /// the walked subtree, which makes them the same for every referencing
148 /// root.
150 };
151
152 /// \returns true if the specified walk records dependencies instead of
153 /// marking the tree.
154 static bool recordsDepsOnly(TreeWalkKindTy Kind) {
155 return Kind != TreeWalkKindTy::MarkTree;
156 }
157
158 /// Class keeping live worklist item data.
160 public:
164 UnitEntryPairTy RootEntry) {
165 RootCU.setInt(Action);
166 RootCU.setPointer(RootEntry.CU);
167
168 RootDieEntry = RootEntry.DieEntry;
169 }
172 UnitEntryPairTy ReferencedBy,
174 RootCU.setPointer(RootEntry.CU);
175 RootCU.setInt(Action);
176 RootDieEntry = RootEntry.DieEntry;
177
178 ReferencedByCU = ReferencedBy.CU;
179 ReferencedByDieEntry = ReferencedBy.DieEntry;
180
182 }
183
185 return UnitEntryPairTy{RootCU.getPointer(), RootDieEntry};
186 }
187
189 return static_cast<CompileUnit::DieOutputPlacement>(RootCU.getInt());
190 }
191
192 bool hasReferencedByOtherEntry() const { return ReferencedByCU != nullptr; }
193
199
200 /// \returns the DIE actually referenced by ReferencedByDieEntry, whose
201 /// placement (rather than the enclosing RootDieEntry's) determines whether
202 /// ReferencedByDieEntry may remain in the type table. Null when the
203 /// referenced DIE is RootDieEntry itself, in which case RootDieEntry's
204 /// placement is used instead.
208
210 return static_cast<LiveRootWorklistActionTy>(RootCU.getInt());
211 }
212
213 protected:
214 /// Root entry.
215 /// ASSUMPTION: 3 bits are used to store LiveRootWorklistActionTy value.
216 /// Thus LiveRootWorklistActionTy should have no more eight elements.
217
218 /// Pointer traits for CompileUnit.
220 static inline void *getAsVoidPointer(CompileUnit *P) { return P; }
221 static inline CompileUnit *getFromVoidPointer(void *P) {
222 return (CompileUnit *)P;
223 }
224 static constexpr int NumLowBitsAvailable = 3;
225 static_assert(
226 alignof(CompileUnit) >= (1 << NumLowBitsAvailable),
227 "CompileUnit insufficiently aligned to have enough low bits.");
228 };
229
234
235 /// Another root entry which references this RootDieEntry.
236 /// ReferencedByDieEntry is kept to update placement.
237 /// if RootDieEntry has placement incompatible with placement
238 /// of ReferencedByDieEntry then it should be updated.
241
242 /// The DIE actually referenced by ReferencedByDieEntry. It lives in the
243 /// same CU as RootDieEntry, but its placement can differ: RootDieEntry is
244 /// the enclosing root that is marked as kept, whereas this DIE may be a
245 /// nested type demoted independently. That placement, not RootDieEntry's,
246 /// determines whether ReferencedByDieEntry may remain in the type table.
247 /// Null when RootDieEntry is the referenced DIE itself.
249 };
250
252
253 /// A completeness dependency of a subtree that belongs to whichever root
254 /// references the subtree, which is not known while the subtree is walked.
260
262
263 /// A subtree paired with the action it is walked with, which selects both the
264 /// visited children and the action recorded for a reference.
266 std::tuple<CompileUnit *, const DWARFDebugInfoEntry *,
268
269 /// A root referencing an already-marked subtree, standing in for all of that
270 /// subtree's dependencies. The subtree is walked when completeness is
271 /// checked, once per subtree rather than once per referencing root, which is
272 /// what keeps recording linear in the number of shared subtrees.
273 ///
274 /// Deferring the walk out of marking also keeps it off the state marking is
275 /// still mutating. A walk that only records dependencies reads a DIE's ODR
276 /// availability and whether it has an address, both settled before marking
277 /// begins, and never the keep and placement bits that sibling units raise as
278 /// they mark. Walking during marking would consult those bits through
279 /// isAlreadyMarked and yield a result that depends on how the units
280 /// interleave.
286
287 /// This function navigates DIEs tree starting from specified \p Entry.
288 /// It puts found 'root DIE' into the worklist. The \p CollectLiveEntries
289 /// instructs to collect either live roots(like subprograms having live
290 /// DW_AT_low_pc) or otherwise roots which is not live(they need to be
291 /// collected if they are imported f.e. by DW_TAG_imported_module).
292 void collectRootsToKeep(const UnitEntryPairTy &Entry,
293 std::optional<UnitEntryPairTy> ReferencedBy,
294 bool IsLiveParent);
295
296 /// Returns true if specified variable references live code section.
297 static bool isLiveVariableEntry(const UnitEntryPairTy &Entry,
298 bool IsLiveParent);
299
300 /// Returns true if specified subprogram references live code section.
301 static bool isLiveSubprogramEntry(const UnitEntryPairTy &Entry);
302
303 /// Examine worklist and mark all 'root DIE's as kept and set "Placement"
304 /// property.
305 bool markCollectedLiveRootsAsKept(bool InterCUProcessingStarted,
306 std::atomic<bool> &HasNewInterconnectedCUs);
307
308 /// Mark whole DIE tree as kept recursively. A walk that only records
309 /// dependencies (see \p Kind) does not mark the tree. Instead its
310 /// completeness dependencies are collected (see maybeAddReferencedRoots) so
311 /// they can be applied to every root referencing the tree.
312 /// \see materializeSubtreeSummaries.
314 const UnitEntryPairTy &RootEntry,
315 const UnitEntryPairTy &Entry,
316 bool InterCUProcessingStarted,
317 std::atomic<bool> &HasNewInterconnectedCUs,
319
320 /// Record that \p RootEntry references the already-marked subtree \p Entry,
321 /// and therefore carries the completeness dependencies of that subtree. The
322 /// subtree itself is walked later, by materializeSubtreeSummaries().
324 const UnitEntryPairTy &RootEntry,
325 const UnitEntryPairTy &Entry);
326
327 /// Walk every subtree that a recorded reference stands for, once per subtree
328 /// and action, and summarize the dependencies it contributes. Called when
329 /// completeness is checked, so that liveness marking and inter-unit reference
330 /// resolution have settled and the summary no longer depends on the order the
331 /// units were processed in.
333
334 /// Apply each summarized subtree's dependencies to every root recorded as
335 /// referencing it.
336 /// \returns true if any placement was updated.
338
339 /// Demote \p ReferencedBy to plain DWARF if it may not stay in the type table
340 /// while the DIE it references through \p Root is not placed there.
341 /// \returns true if the placement was updated.
342 bool demoteIfIncomplete(const UnitEntryPairTy &Root,
343 const DWARFDebugInfoEntry *ReferencedTypeDieEntry,
344 const UnitEntryPairTy &ReferencedBy);
345
346 /// Mark parents as keeping children.
348
349 /// Mark whole DIE tree as placed in "PlainDwarf".
351
352 /// Check referenced DIEs and add them into the worklist. A walk that only
353 /// records dependencies (see \p Kind) schedules nothing, so it triggers no
354 /// reference-following recursion. Each dependency it finds is instead
355 /// collected for the root that carries it, which is either whichever root
356 /// references the walked subtree or a subprogram nested inside it. This is
357 /// used when \p Entry was already marked by a racing CU/root: the marking and
358 /// subtree are handled elsewhere, but the referencing root's dependencies
359 /// must still be recorded so the completeness fixpoint sees a complete,
360 /// order-independent dependency set.
362 const UnitEntryPairTy &RootEntry,
363 const UnitEntryPairTy &Entry,
364 bool InterCUProcessingStarted,
365 std::atomic<bool> &HasNewInterconnectedCUs,
367
368 /// \returns true if \p DIEEntry can possibly be put into the artificial type
369 /// unit.
371
372 /// \returns root for the specified \p Entry.
374
375 /// Add action item to the work list.
377 LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry,
378 std::optional<UnitEntryPairTy> ReferencedBy,
379 const DWARFDebugInfoEntry *ReferencedTypeDieEntry = nullptr);
380
382
383 /// List of entries which are 'root DIE's.
385
386 /// List of entries dependencies.
388
389 /// Dependency summaries of already-marked subtrees, keyed by subtree and
390 /// action. Filled once, when completeness is first checked.
392
393 /// Roots referencing an already-marked subtree.
395
396 /// Number of leading SubtreeDependencyRefs whose subtree is summarized.
398
399 /// Where the walk in progress collects the dependencies that belong to the
400 /// root referencing the walked subtree, or null when no such walk is in
401 /// progress. Scoped by materializeSubtreeSummaries().
403
404 /// Whether inter-unit references could be resolved during marking. Reused
405 /// when the recorded subtrees are walked, which happens outside of marking.
407};
408
409} // end of namespace parallel
410} // end of namespace dwarf_linker
411} // end of namespace llvm
412
413#endif // LLVM_LIB_DWARFLINKER_PARALLEL_DEPENDENCYTRACKER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the DenseMap class.
#define P(N)
This file defines the PointerIntPair class.
This file defines the SmallVector class.
A pointer to another debug information entry.
Definition DIE.h:325
DWARFDebugInfoEntry - A DIE with only the minimum required data.
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
Definition DWARFDie.h:43
PointerIntPair - This class implements a pair of a pointer and small integer.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Stores all information related to a compile unit, be it in its original instance of the object file o...
DieOutputPlacement
Kinds of placement for the output die.
LiveRootWorklistItemTy(LiveRootWorklistActionTy Action, UnitEntryPairTy RootEntry, UnitEntryPairTy ReferencedBy, const DWARFDebugInfoEntry *ReferencedTypeDieEntry=nullptr)
LiveRootWorklistItemTy(LiveRootWorklistActionTy Action, UnitEntryPairTy RootEntry)
PointerIntPair< CompileUnit *, 3, LiveRootWorklistActionTy, CompileUnitPointerTraits > RootCU
const DWARFDebugInfoEntry * ReferencedTypeDieEntry
The DIE actually referenced by ReferencedByDieEntry.
CompileUnit * ReferencedByCU
Another root entry which references this RootDieEntry.
bool markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, const UnitEntryPairTy &Entry, bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs, TreeWalkKindTy Kind=TreeWalkKindTy::MarkTree)
Mark whole DIE tree as kept recursively.
void verifyKeepChain()
Recursively walk the DIE tree and check "keepness" and "placement" information.
RootEntriesListTy Dependencies
List of entries dependencies.
void markParentsAsKeepingChildren(const UnitEntryPairTy &Entry)
Mark parents as keeping children.
UnitEntryPairTy getRootForSpecifiedEntry(UnitEntryPairTy Entry)
static bool recordsDepsOnly(TreeWalkKindTy Kind)
bool demoteIfIncomplete(const UnitEntryPairTy &Root, const DWARFDebugInfoEntry *ReferencedTypeDieEntry, const UnitEntryPairTy &ReferencedBy)
Demote ReferencedBy to plain DWARF if it may not stay in the type table while the DIE it references t...
bool markCollectedLiveRootsAsKept(bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Examine worklist and mark all 'root DIE's as kept and set "Placement" property.
bool InterCUProcessingWasStarted
Whether inter-unit references could be resolved during marking.
bool applySubtreeSummaries()
Apply each summarized subtree's dependencies to every root recorded as referencing it.
bool isLiveAction(LiveRootWorklistActionTy Action)
bool isChildrenAction(LiveRootWorklistActionTy Action)
TreeWalkKindTy
What a tree walk does, and for a walk that only records dependencies, which root the dependencies it ...
@ MarkTree
Mark the tree as kept and schedule the roots it references.
bool isTypeAction(LiveRootWorklistActionTy Action)
void addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry, std::optional< UnitEntryPairTy > ReferencedBy, const DWARFDebugInfoEntry *ReferencedTypeDieEntry=nullptr)
Add action item to the work list.
DenseMap< SubtreeDependenciesKeyTy, SubtreeDependenciesTy > SubtreeSummaries
Dependency summaries of already-marked subtrees, keyed by subtree and action.
SubtreeDependenciesTy * CollectedSubtreeDeps
Where the walk in progress collects the dependencies that belong to the root referencing the walked s...
bool isTypeTableCandidate(const DWARFDebugInfoEntry *DIEEntry)
size_t MaterializedRefs
Number of leading SubtreeDependencyRefs whose subtree is summarized.
SmallVector< LiveRootWorklistItemTy > RootEntriesListTy
void setPlainDwarfPlacementRec(const UnitEntryPairTy &Entry)
Mark whole DIE tree as placed in "PlainDwarf".
RootEntriesListTy RootEntriesWorkList
List of entries which are 'root DIE's.
SmallVector< SubtreeDependencyTy > SubtreeDependenciesTy
static bool isLiveSubprogramEntry(const UnitEntryPairTy &Entry)
Returns true if specified subprogram references live code section.
std::tuple< CompileUnit *, const DWARFDebugInfoEntry *, LiveRootWorklistActionTy > SubtreeDependenciesKeyTy
A subtree paired with the action it is walked with, which selects both the visited children and the a...
void recordSubtreeDependencies(LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, const UnitEntryPairTy &Entry)
Record that RootEntry references the already-marked subtree Entry, and therefore carries the complete...
bool resolveDependenciesAndMarkLiveness(bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Recursively walk the DIE tree and look for DIEs to keep.
static bool isLiveVariableEntry(const UnitEntryPairTy &Entry, bool IsLiveParent)
Returns true if specified variable references live code section.
@ MarkTypeEntryRec
Mark current item and all its children as type entry.
@ MarkLiveChildrenRec
Mark all children of current item as live entry.
@ MarkLiveEntryRec
Mark current item and all its children as live entry.
@ MarkTypeChildrenRec
Mark all children of current item as type entry.
SmallVector< SubtreeDependencyRefTy > SubtreeDependencyRefs
Roots referencing an already-marked subtree.
void collectRootsToKeep(const UnitEntryPairTy &Entry, std::optional< UnitEntryPairTy > ReferencedBy, bool IsLiveParent)
This function navigates DIEs tree starting from specified Entry.
bool maybeAddReferencedRoots(LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, const UnitEntryPairTy &Entry, bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs, TreeWalkKindTy Kind=TreeWalkKindTy::MarkTree)
Check referenced DIEs and add them into the worklist.
bool updateDependenciesCompleteness()
Check if dependencies have incompatible placement.
void materializeSubtreeSummaries()
Walk every subtree that a recorded reference stands for, once per subtree and action,...
This is an optimization pass for GlobalISel generic memory operations.
A root referencing an already-marked subtree, standing in for all of that subtree's dependencies.
A completeness dependency of a subtree that belongs to whichever root references the subtree,...
This is a helper structure which keeps a debug info entry with it's containing compilation unit.