1 //===- "DependencyTracker.h" ------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIB_DWARFLINKER_PARALLEL_DEPENDENCYTRACKER_H
10 #define LLVM_LIB_DWARFLINKER_PARALLEL_DEPENDENCYTRACKER_H
12 #include "DWARFLinkerCompileUnit.h"
13 #include "llvm/ADT/PointerIntPair.h"
14 #include "llvm/ADT/SmallVector.h"
17 class DWARFDebugInfoEntry
;
20 namespace dwarf_linker
{
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
{
28 DependencyTracker(CompileUnit
&CU
) : CU(CU
) {}
30 /// Recursively walk the \p DIE tree and look for DIEs to keep. Store that
31 /// information in \p CU's DIEInfo.
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).
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
);
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();
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();
60 enum class LiveRootWorklistActionTy
: uint8_t {
61 /// Mark current item as live entry.
62 MarkSingleLiveEntry
= 0,
64 /// Mark current item as type entry.
67 /// Mark current item and all its children as live entry.
70 /// Mark current item and all its children as type entry.
73 /// Mark all children of current item as live entry.
76 /// Mark all children of current item as type entry.
80 /// \returns true if the specified action is for the "PlainDwarf".
81 bool isLiveAction(LiveRootWorklistActionTy Action
) {
86 case LiveRootWorklistActionTy::MarkSingleLiveEntry
:
87 case LiveRootWorklistActionTy::MarkLiveEntryRec
:
88 case LiveRootWorklistActionTy::MarkLiveChildrenRec
:
93 /// \returns true if the specified action is for the "TypeTable".
94 bool isTypeAction(LiveRootWorklistActionTy Action
) {
99 case LiveRootWorklistActionTy::MarkSingleTypeEntry
:
100 case LiveRootWorklistActionTy::MarkTypeEntryRec
:
101 case LiveRootWorklistActionTy::MarkTypeChildrenRec
:
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
) {
113 case LiveRootWorklistActionTy::MarkSingleLiveEntry
:
114 case LiveRootWorklistActionTy::MarkSingleTypeEntry
:
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
) {
126 case LiveRootWorklistActionTy::MarkLiveChildrenRec
:
127 case LiveRootWorklistActionTy::MarkTypeChildrenRec
:
132 /// Class keeping live worklist item data.
133 class LiveRootWorklistItemTy
{
135 LiveRootWorklistItemTy() = default;
136 LiveRootWorklistItemTy(const LiveRootWorklistItemTy
&) = default;
137 LiveRootWorklistItemTy(LiveRootWorklistActionTy Action
,
138 UnitEntryPairTy RootEntry
) {
139 RootCU
.setInt(Action
);
140 RootCU
.setPointer(RootEntry
.CU
);
142 RootDieEntry
= RootEntry
.DieEntry
;
144 LiveRootWorklistItemTy(LiveRootWorklistActionTy Action
,
145 UnitEntryPairTy RootEntry
,
146 UnitEntryPairTy ReferencedBy
) {
147 RootCU
.setPointer(RootEntry
.CU
);
148 RootCU
.setInt(Action
);
149 RootDieEntry
= RootEntry
.DieEntry
;
151 ReferencedByCU
= ReferencedBy
.CU
;
152 ReferencedByDieEntry
= ReferencedBy
.DieEntry
;
155 UnitEntryPairTy
getRootEntry() const {
156 return UnitEntryPairTy
{RootCU
.getPointer(), RootDieEntry
};
159 CompileUnit::DieOutputPlacement
getPlacement() const {
160 return static_cast<CompileUnit::DieOutputPlacement
>(RootCU
.getInt());
163 bool hasReferencedByOtherEntry() const { return ReferencedByCU
!= nullptr; }
165 UnitEntryPairTy
getReferencedByEntry() const {
166 assert(ReferencedByCU
);
167 assert(ReferencedByDieEntry
);
168 return UnitEntryPairTy
{ReferencedByCU
, ReferencedByDieEntry
};
171 LiveRootWorklistActionTy
getAction() const {
172 return static_cast<LiveRootWorklistActionTy
>(RootCU
.getInt());
177 /// ASSUMPTION: 3 bits are used to store LiveRootWorklistActionTy value.
178 /// Thus LiveRootWorklistActionTy should have no more eight elements.
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
;
186 static constexpr int NumLowBitsAvailable
= 3;
188 alignof(CompileUnit
) >= (1 << NumLowBitsAvailable
),
189 "CompileUnit insufficiently aligned to have enough low bits.");
192 PointerIntPair
<CompileUnit
*, 3, LiveRootWorklistActionTy
,
193 CompileUnitPointerTraits
>
195 const DWARFDebugInfoEntry
*RootDieEntry
= nullptr;
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;
205 using RootEntriesListTy
= SmallVector
<LiveRootWorklistItemTy
>;
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
,
216 /// Returns true if specified variable references live code section.
217 static bool isLiveVariableEntry(const UnitEntryPairTy
&Entry
,
220 /// Returns true if specified subprogram references live code section.
221 static bool isLiveSubprogramEntry(const UnitEntryPairTy
&Entry
);
223 /// Examine worklist and mark all 'root DIE's as kept and set "Placement"
225 bool markCollectedLiveRootsAsKept(bool InterCUProcessingStarted
,
226 std::atomic
<bool> &HasNewInterconnectedCUs
);
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
);
235 /// Mark parents as keeping children.
236 void markParentsAsKeepingChildren(const UnitEntryPairTy
&Entry
);
238 /// Mark whole DIE tree as placed in "PlainDwarf".
239 void setPlainDwarfPlacementRec(const UnitEntryPairTy
&Entry
);
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
);
248 /// \returns true if \p DIEEntry can possibly be put into the artificial type
250 bool isTypeTableCandidate(const DWARFDebugInfoEntry
*DIEEntry
);
252 /// \returns root for the specified \p Entry.
253 UnitEntryPairTy
getRootForSpecifiedEntry(UnitEntryPairTy Entry
);
255 /// Add action item to the work list.
257 addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action
,
258 const UnitEntryPairTy
&Entry
,
259 std::optional
<UnitEntryPairTy
> ReferencedBy
);
263 /// List of entries which are 'root DIE's.
264 RootEntriesListTy RootEntriesWorkList
;
266 /// List of entries dependencies.
267 RootEntriesListTy Dependencies
;
270 } // end of namespace parallel
271 } // end of namespace dwarf_linker
272 } // end of namespace llvm
274 #endif // LLVM_LIB_DWARFLINKER_PARALLEL_DEPENDENCYTRACKER_H