aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DependencyTracker.h
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DependencyTracker.h')
-rw-r--r--contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DependencyTracker.h274
1 files changed, 274 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DependencyTracker.h b/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DependencyTracker.h
new file mode 100644
index 000000000000..4a0d985c8aaa
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DependencyTracker.h
@@ -0,0 +1,274 @@
+//===- "DependencyTracker.h" ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_DWARFLINKER_PARALLEL_DEPENDENCYTRACKER_H
+#define LLVM_LIB_DWARFLINKER_PARALLEL_DEPENDENCYTRACKER_H
+
+#include "DWARFLinkerCompileUnit.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace llvm {
+class DWARFDebugInfoEntry;
+class DWARFDie;
+
+namespace dwarf_linker {
+namespace parallel {
+
+/// This class discovers DIEs dependencies: marks "live" DIEs, marks DIE
+/// locations (whether DIE should be cloned as regular DIE or it should be put
+/// into the artificial type unit).
+class DependencyTracker {
+public:
+ DependencyTracker(CompileUnit &CU) : CU(CU) {}
+
+ /// Recursively walk the \p DIE tree and look for DIEs to keep. Store that
+ /// information in \p CU's DIEInfo.
+ ///
+ /// This function is the entry point of the DIE selection algorithm. It is
+ /// expected to walk the DIE tree and(through the mediation of
+ /// Context.File.Addresses) ask for relocation adjustment value on each
+ /// DIE that might be a 'root DIE'(f.e. subprograms, variables).
+ ///
+ /// Returns true if all dependencies are correctly discovered. Inter-CU
+ /// dependencies cannot be discovered if referenced CU is not analyzed yet.
+ /// If that is the case this method returns false.
+ bool resolveDependenciesAndMarkLiveness(
+ bool InterCUProcessingStarted,
+ std::atomic<bool> &HasNewInterconnectedCUs);
+
+ /// Check if dependencies have incompatible placement.
+ /// If that is the case modify placement to be compatible.
+ /// \returns true if any placement was updated, otherwise returns false.
+ /// This method should be called as a followup processing after
+ /// resolveDependenciesAndMarkLiveness().
+ bool updateDependenciesCompleteness();
+
+ /// Recursively walk the \p DIE tree and check "keepness" and "placement"
+ /// information. It is an error if parent node does not have "keep" flag,
+ /// while child has one. It is an error if parent node has "TypeTable"
+ /// placement while child has "PlainDwarf" placement. This function dump error
+ /// at stderr in that case.
+ void verifyKeepChain();
+
+protected:
+ enum class LiveRootWorklistActionTy : uint8_t {
+ /// Mark current item as live entry.
+ MarkSingleLiveEntry = 0,
+
+ /// Mark current item as type entry.
+ MarkSingleTypeEntry,
+
+ /// Mark current item and all its children as live entry.
+ MarkLiveEntryRec,
+
+ /// Mark current item and all its children as type entry.
+ MarkTypeEntryRec,
+
+ /// Mark all children of current item as live entry.
+ MarkLiveChildrenRec,
+
+ /// Mark all children of current item as type entry.
+ MarkTypeChildrenRec,
+ };
+
+ /// \returns true if the specified action is for the "PlainDwarf".
+ bool isLiveAction(LiveRootWorklistActionTy Action) {
+ switch (Action) {
+ default:
+ return false;
+
+ case LiveRootWorklistActionTy::MarkSingleLiveEntry:
+ case LiveRootWorklistActionTy::MarkLiveEntryRec:
+ case LiveRootWorklistActionTy::MarkLiveChildrenRec:
+ return true;
+ }
+ }
+
+ /// \returns true if the specified action is for the "TypeTable".
+ bool isTypeAction(LiveRootWorklistActionTy Action) {
+ switch (Action) {
+ default:
+ return false;
+
+ case LiveRootWorklistActionTy::MarkSingleTypeEntry:
+ case LiveRootWorklistActionTy::MarkTypeEntryRec:
+ case LiveRootWorklistActionTy::MarkTypeChildrenRec:
+ return true;
+ }
+ }
+
+ /// \returns true if the specified action affects only Root entry
+ /// itself and does not affect it`s children.
+ bool isSingleAction(LiveRootWorklistActionTy Action) {
+ switch (Action) {
+ default:
+ return false;
+
+ case LiveRootWorklistActionTy::MarkSingleLiveEntry:
+ case LiveRootWorklistActionTy::MarkSingleTypeEntry:
+ return true;
+ }
+ }
+
+ /// \returns true if the specified action affects only Root entry
+ /// itself and does not affect it`s children.
+ bool isChildrenAction(LiveRootWorklistActionTy Action) {
+ switch (Action) {
+ default:
+ return false;
+
+ case LiveRootWorklistActionTy::MarkLiveChildrenRec:
+ case LiveRootWorklistActionTy::MarkTypeChildrenRec:
+ return true;
+ }
+ }
+
+ /// Class keeping live worklist item data.
+ class LiveRootWorklistItemTy {
+ public:
+ LiveRootWorklistItemTy() = default;
+ LiveRootWorklistItemTy(const LiveRootWorklistItemTy &) = default;
+ LiveRootWorklistItemTy(LiveRootWorklistActionTy Action,
+ UnitEntryPairTy RootEntry) {
+ RootCU.setInt(Action);
+ RootCU.setPointer(RootEntry.CU);
+
+ RootDieEntry = RootEntry.DieEntry;
+ }
+ LiveRootWorklistItemTy(LiveRootWorklistActionTy Action,
+ UnitEntryPairTy RootEntry,
+ UnitEntryPairTy ReferencedBy) {
+ RootCU.setPointer(RootEntry.CU);
+ RootCU.setInt(Action);
+ RootDieEntry = RootEntry.DieEntry;
+
+ ReferencedByCU = ReferencedBy.CU;
+ ReferencedByDieEntry = ReferencedBy.DieEntry;
+ }
+
+ UnitEntryPairTy getRootEntry() const {
+ return UnitEntryPairTy{RootCU.getPointer(), RootDieEntry};
+ }
+
+ CompileUnit::DieOutputPlacement getPlacement() const {
+ return static_cast<CompileUnit::DieOutputPlacement>(RootCU.getInt());
+ }
+
+ bool hasReferencedByOtherEntry() const { return ReferencedByCU != nullptr; }
+
+ UnitEntryPairTy getReferencedByEntry() const {
+ assert(ReferencedByCU);
+ assert(ReferencedByDieEntry);
+ return UnitEntryPairTy{ReferencedByCU, ReferencedByDieEntry};
+ }
+
+ LiveRootWorklistActionTy getAction() const {
+ return static_cast<LiveRootWorklistActionTy>(RootCU.getInt());
+ }
+
+ protected:
+ /// Root entry.
+ /// ASSUMPTION: 3 bits are used to store LiveRootWorklistActionTy value.
+ /// Thus LiveRootWorklistActionTy should have no more eight elements.
+
+ /// Pointer traits for CompileUnit.
+ struct CompileUnitPointerTraits {
+ static inline void *getAsVoidPointer(CompileUnit *P) { return P; }
+ static inline CompileUnit *getFromVoidPointer(void *P) {
+ return (CompileUnit *)P;
+ }
+ static constexpr int NumLowBitsAvailable = 3;
+ static_assert(
+ alignof(CompileUnit) >= (1 << NumLowBitsAvailable),
+ "CompileUnit insufficiently aligned to have enough low bits.");
+ };
+
+ PointerIntPair<CompileUnit *, 3, LiveRootWorklistActionTy,
+ CompileUnitPointerTraits>
+ RootCU;
+ const DWARFDebugInfoEntry *RootDieEntry = nullptr;
+
+ /// Another root entry which references this RootDieEntry.
+ /// ReferencedByDieEntry is kept to update placement.
+ /// if RootDieEntry has placement incompatible with placement
+ /// of ReferencedByDieEntry then it should be updated.
+ CompileUnit *ReferencedByCU = nullptr;
+ const DWARFDebugInfoEntry *ReferencedByDieEntry = nullptr;
+ };
+
+ using RootEntriesListTy = SmallVector<LiveRootWorklistItemTy>;
+
+ /// This function navigates DIEs tree starting from specified \p Entry.
+ /// It puts found 'root DIE' into the worklist. The \p CollectLiveEntries
+ /// instructs to collect either live roots(like subprograms having live
+ /// DW_AT_low_pc) or otherwise roots which is not live(they need to be
+ /// collected if they are imported f.e. by DW_TAG_imported_module).
+ void collectRootsToKeep(const UnitEntryPairTy &Entry,
+ std::optional<UnitEntryPairTy> ReferencedBy,
+ bool IsLiveParent);
+
+ /// Returns true if specified variable references live code section.
+ static bool isLiveVariableEntry(const UnitEntryPairTy &Entry,
+ bool IsLiveParent);
+
+ /// Returns true if specified subprogram references live code section.
+ static bool isLiveSubprogramEntry(const UnitEntryPairTy &Entry);
+
+ /// Examine worklist and mark all 'root DIE's as kept and set "Placement"
+ /// property.
+ bool markCollectedLiveRootsAsKept(bool InterCUProcessingStarted,
+ std::atomic<bool> &HasNewInterconnectedCUs);
+
+ /// Mark whole DIE tree as kept recursively.
+ bool markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action,
+ const UnitEntryPairTy &RootEntry,
+ const UnitEntryPairTy &Entry,
+ bool InterCUProcessingStarted,
+ std::atomic<bool> &HasNewInterconnectedCUs);
+
+ /// Mark parents as keeping children.
+ void markParentsAsKeepingChildren(const UnitEntryPairTy &Entry);
+
+ /// Mark whole DIE tree as placed in "PlainDwarf".
+ void setPlainDwarfPlacementRec(const UnitEntryPairTy &Entry);
+
+ /// Check referenced DIEs and add them into the worklist.
+ bool maybeAddReferencedRoots(LiveRootWorklistActionTy Action,
+ const UnitEntryPairTy &RootEntry,
+ const UnitEntryPairTy &Entry,
+ bool InterCUProcessingStarted,
+ std::atomic<bool> &HasNewInterconnectedCUs);
+
+ /// \returns true if \p DIEEntry can possibly be put into the artificial type
+ /// unit.
+ bool isTypeTableCandidate(const DWARFDebugInfoEntry *DIEEntry);
+
+ /// \returns root for the specified \p Entry.
+ UnitEntryPairTy getRootForSpecifiedEntry(UnitEntryPairTy Entry);
+
+ /// Add action item to the work list.
+ void
+ addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action,
+ const UnitEntryPairTy &Entry,
+ std::optional<UnitEntryPairTy> ReferencedBy);
+
+ CompileUnit &CU;
+
+ /// List of entries which are 'root DIE's.
+ RootEntriesListTy RootEntriesWorkList;
+
+ /// List of entries dependencies.
+ RootEntriesListTy Dependencies;
+};
+
+} // end of namespace parallel
+} // end of namespace dwarf_linker
+} // end of namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKER_PARALLEL_DEPENDENCYTRACKER_H