13using namespace dwarf_linker;
14using namespace dwarf_linker::parallel;
29#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
36 while (!Worklist.
empty()) {
52 CU.getDIEInfo(Child.getDebugInfoEntry());
56 if (!ParentPlainDieIsKept && ChildPlainDieIsKept)
58 "Found invalid link in keep chain");
60 if (Child.getTag() == dwarf::DW_TAG_subprogram) {
62 &
CU, Child.getDebugInfoEntry()))) {
64 "Live subprogram is not marked as kept");
68 if (!ChildInfo.getODRAvailable()) {
69 assert(!ChildTypeDieIsKept);
73 if (!ParentTypeDieIsKept && ChildTypeDieIsKept)
75 "Found invalid link in keep chain");
77 if (CurrentInfo.getIsInAnonNamespaceScope() &&
80 "Found invalid placement marking for member "
81 "of anonymous namespace");
86 if (!BrokenLinks.
empty()) {
88 errs() <<
"\n=================================\n";
90 Link.Parent.getOffset(),
91 Link.Child.getOffset());
93 errs() <<
"\nParent:";
94 Link.Parent.dump(
errs(), 0, {});
96 CU.getDIEInfo(Link.Parent).dump();
99 Link.Child.dump(
errs(), 2, {});
101 CU.getDIEInfo(Link.Child).dump();
109 bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
116 std::nullopt,
false);
120 HasNewInterconnectedCUs);
125 std::optional<UnitEntryPairTy> ReferencedBy) {
135 const UnitEntryPairTy &Entry, std::optional<UnitEntryPairTy> ReferencedBy,
138 Entry.CU->getFirstChildEntry(Entry.DieEntry);
139 CurChild && CurChild->getAbbreviationDeclarationPtr();
140 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
144 bool IsLiveChild =
false;
146 switch (CurChild->getTag()) {
147 case dwarf::DW_TAG_label: {
152 if (IsLiveChild || (IsLiveParent && ChildInfo.getHasAnAddress())) {
158 case dwarf::DW_TAG_subprogram: {
166 (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
173 case dwarf::DW_TAG_constant:
174 case dwarf::DW_TAG_variable: {
183 (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
190 case dwarf::DW_TAG_base_type: {
196 case dwarf::DW_TAG_imported_module:
197 case dwarf::DW_TAG_imported_declaration:
198 case dwarf::DW_TAG_imported_unit: {
200 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_compile_unit) {
211 case dwarf::DW_TAG_type_unit:
212 case dwarf::DW_TAG_partial_unit:
213 case dwarf::DW_TAG_compile_unit: {
226 bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
235 HasNewInterconnectedCUs)) {
246 bool HasNewDependency =
false;
248 assert(Root.hasReferencedByOtherEntry() &&
249 "Root entry without dependency inside the dependencies list");
261 HasNewDependency =
true;
269 return HasNewDependency;
276 !
Info.getKeepTypeChildren())
280 Info.unsetKeepTypeChildren();
284 Entry.CU->getFirstChildEntry(Entry.DieEntry);
285 CurChild && CurChild->getAbbreviationDeclarationPtr();
286 CurChild = Entry.CU->getSiblingEntry(CurChild))
291 switch (Entry->getTag()) {
292 case dwarf::DW_TAG_compile_unit:
293 case dwarf::DW_TAG_module:
294 case dwarf::DW_TAG_namespace:
307 switch (NewPlacement) {
309 return Info.needToPlaceInTypeTable();
312 return Info.needToKeepInPlainDwarf();
315 return Info.needToPlaceInTypeTable() &&
Info.needToKeepInPlainDwarf();
326 return isAlreadyMarked(Entry.CU->getDIEInfo(Entry.DieEntry), NewPlacement);
331 if (Entry.DieEntry->getAbbreviationDeclarationPtr() ==
nullptr)
335 bool NeedKeepTypeChildren =
Info.needToPlaceInTypeTable();
336 bool NeedKeepPlainChildren =
Info.needToKeepInPlainDwarf();
338 bool AreTypeParentsDone = !NeedKeepTypeChildren;
339 bool ArePlainParentsDone = !NeedKeepPlainChildren;
342 std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx();
345 Entry.CU->getDebugInfoEntry(*ParentIdx);
348 if (!AreTypeParentsDone && NeedKeepTypeChildren) {
349 if (ParentInfo.getKeepTypeChildren())
350 AreTypeParentsDone =
true;
354 ParentInfo.setKeepTypeChildren();
363 if (!ArePlainParentsDone && NeedKeepPlainChildren) {
364 if (ParentInfo.getKeepPlainChildren())
365 ArePlainParentsDone =
true;
369 ParentInfo.setKeepPlainChildren();
378 if (AreTypeParentsDone && ArePlainParentsDone)
396 if (!EntryInfo.getODRAvailable())
399 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_variable) {
410 switch (EntryInfo.getPlacement()) {
431 std::atomic<bool> &HasNewInterconnectedCUs) {
432 if (Entry.DieEntry->getAbbreviationDeclarationPtr() ==
nullptr)
443 "Wrong kind of placement for ODR unavailable entry");
457 Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram ? Entry : RootEntry;
462 InterCUProcessingStarted,
463 HasNewInterconnectedCUs))
472 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram &&
473 Info.getODRAvailable()) {
484 Entry.CU->getFirstChildEntry(Entry.DieEntry);
485 CurChild && CurChild->getAbbreviationDeclarationPtr();
486 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
489 switch (CurChild->getTag()) {
490 case dwarf::DW_TAG_variable:
491 case dwarf::DW_TAG_constant:
492 case dwarf::DW_TAG_subprogram:
493 case dwarf::DW_TAG_label: {
494 if (ChildInfo.getHasAnAddress())
499 case dwarf::DW_TAG_lexical_block:
500 case dwarf::DW_TAG_friend:
501 case dwarf::DW_TAG_inheritance:
502 case dwarf::DW_TAG_formal_parameter:
503 case dwarf::DW_TAG_unspecified_parameters:
504 case dwarf::DW_TAG_template_type_parameter:
505 case dwarf::DW_TAG_template_value_parameter:
506 case dwarf::DW_TAG_GNU_template_parameter_pack:
507 case dwarf::DW_TAG_GNU_formal_parameter_pack:
508 case dwarf::DW_TAG_GNU_template_template_param:
509 case dwarf::DW_TAG_thrown_type: {
530 InterCUProcessingStarted, HasNewInterconnectedCUs))
539 Entry.CU->getFirstChildEntry(Entry.DieEntry);
540 CurChild && CurChild->getAbbreviationDeclarationPtr();
541 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
543 switch (CurChild->getTag()) {
544 case dwarf::DW_TAG_variable:
545 case dwarf::DW_TAG_constant:
546 case dwarf::DW_TAG_subprogram:
547 case dwarf::DW_TAG_label: {
548 if (ChildInfo.getHasAnAddress())
557 InterCUProcessingStarted, HasNewInterconnectedCUs))
570 case dwarf::DW_TAG_imported_module:
571 case dwarf::DW_TAG_imported_declaration:
572 case dwarf::DW_TAG_imported_unit:
573 case dwarf::DW_TAG_array_type:
574 case dwarf::DW_TAG_class_type:
575 case dwarf::DW_TAG_enumeration_type:
576 case dwarf::DW_TAG_pointer_type:
577 case dwarf::DW_TAG_reference_type:
578 case dwarf::DW_TAG_string_type:
579 case dwarf::DW_TAG_structure_type:
580 case dwarf::DW_TAG_subroutine_type:
581 case dwarf::DW_TAG_typedef:
582 case dwarf::DW_TAG_union_type:
583 case dwarf::DW_TAG_variant:
584 case dwarf::DW_TAG_module:
585 case dwarf::DW_TAG_ptr_to_member_type:
586 case dwarf::DW_TAG_set_type:
587 case dwarf::DW_TAG_subrange_type:
588 case dwarf::DW_TAG_base_type:
589 case dwarf::DW_TAG_const_type:
590 case dwarf::DW_TAG_enumerator:
591 case dwarf::DW_TAG_file_type:
592 case dwarf::DW_TAG_packed_type:
593 case dwarf::DW_TAG_thrown_type:
594 case dwarf::DW_TAG_volatile_type:
595 case dwarf::DW_TAG_dwarf_procedure:
596 case dwarf::DW_TAG_restrict_type:
597 case dwarf::DW_TAG_interface_type:
598 case dwarf::DW_TAG_namespace:
599 case dwarf::DW_TAG_unspecified_type:
600 case dwarf::DW_TAG_shared_type:
601 case dwarf::DW_TAG_rvalue_reference_type:
602 case dwarf::DW_TAG_coarray_type:
603 case dwarf::DW_TAG_dynamic_type:
604 case dwarf::DW_TAG_atomic_type:
605 case dwarf::DW_TAG_immutable_type:
606 case dwarf::DW_TAG_function_template:
607 case dwarf::DW_TAG_class_template:
615 std::atomic<bool> &HasNewInterconnectedCUs) {
616 const auto *Abbrev = Entry.DieEntry->getAbbreviationDeclarationPtr();
617 if (Abbrev ==
nullptr)
620 DWARFUnit &Unit = Entry.CU->getOrigUnit();
626 for (
const auto &AttrSpec : Abbrev->attributes()) {
629 AttrSpec.Attr == dwarf::DW_AT_sibling) {
631 Unit.getFormParams());
637 std::optional<UnitEntryPairTy> RefDie = Entry.CU->resolveDIEReference(
638 Val, InterCUProcessingStarted
642 Entry.CU->warn(
"cann't find referenced DIE", Entry.DieEntry);
646 if (!RefDie->DieEntry) {
648 RefDie->CU->setInterconnectedCU();
649 Entry.CU->setInterconnectedCU();
650 HasNewInterconnectedCUs =
true;
654 assert((Entry.CU->getUniqueID() == RefDie->CU->getUniqueID() ||
655 InterCUProcessingStarted) &&
656 "Inter-CU reference while inter-CU processing is not started");
659 if (!RefInfo.getODRAvailable())
661 else if (RefInfo.getODRAvailable() &&
672 if (AttrSpec.Attr == dwarf::DW_AT_import) {
698 switch (Entry.DieEntry->getTag()) {
699 case dwarf::DW_TAG_subprogram:
700 case dwarf::DW_TAG_label:
701 case dwarf::DW_TAG_variable:
702 case dwarf::DW_TAG_constant: {
711 std::optional<uint32_t> ParentIdx = Result.DieEntry->getParentIdx();
716 Result.CU->getDebugInfoEntry(*ParentIdx);
719 Result.DieEntry = ParentEntry;
730 if (
Info.getTrackLiveness()) {
731 const auto *Abbrev =
DIE.getAbbreviationDeclarationPtr();
733 if (!
Info.getIsInFunctionScope() &&
734 Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
742 std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
743 Entry.CU->getContaingFile().Addresses->getVariableRelocAdjustment(
744 DIE, Entry.CU->getGlobalData().getOptions().Verbose);
746 if (LocExprAddrAndRelocAdjustment.first)
747 Info.setHasAnAddress();
749 if (!LocExprAddrAndRelocAdjustment.second)
752 if (!IsLiveParent &&
Info.getIsInFunctionScope() &&
753 !Entry.CU->getGlobalData().getOptions().KeepFunctionForStatic)
757 Info.setHasAnAddress();
759 if (Entry.CU->getGlobalData().getOptions().Verbose) {
760 outs() <<
"Keeping variable DIE:";
763 DumpOpts.
Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
773 std::optional<DWARFFormValue> LowPCVal =
DIE.find(dwarf::DW_AT_low_pc);
775 std::optional<uint64_t> LowPc;
776 std::optional<uint64_t> HighPc;
777 std::optional<int64_t> RelocAdjustment;
778 if (
Info.getTrackLiveness()) {
783 Info.setHasAnAddress();
786 Entry.CU->getContaingFile().Addresses->getSubprogramRelocAdjustment(
787 DIE, Entry.CU->getGlobalData().getOptions().Verbose);
788 if (!RelocAdjustment)
791 if (
DIE.
getTag() == dwarf::DW_TAG_subprogram) {
794 HighPc =
DIE.getHighPC(*LowPc);
796 Entry.CU->warn(
"function without high_pc. Range will be discarded.",
801 if (*LowPc > *HighPc) {
802 Entry.CU->warn(
"low_pc greater than high_pc. Range will be discarded.",
806 }
else if (
DIE.
getTag() == dwarf::DW_TAG_label) {
807 if (Entry.CU->hasLabelAt(*LowPc))
819 Entry.CU->addLabelLowPc(*LowPc, *RelocAdjustment);
822 Info.setHasAnAddress();
824 if (Entry.CU->getGlobalData().getOptions().Verbose) {
825 outs() <<
"Keeping subprogram DIE:";
828 DumpOpts.
Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
832 if (!
Info.getTrackLiveness() ||
DIE.
getTag() == dwarf::DW_TAG_label)
835 Entry.CU->addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);
Analysis containing CSE Info
bool isAlreadyMarked(const CompileUnit::DIEInfo &Info, CompileUnit::DieOutputPlacement NewPlacement)
static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry)
static CompileUnit::DieOutputPlacement getFinalPlacementForEntry(const UnitEntryPairTy &Entry, CompileUnit::DieOutputPlacement Placement)
Branch Probability Basic Block Placement
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A pointer to another debug information entry.
A structured debug information entry.
dwarf::Tag getTag() const
DWARFDebugInfoEntry - A DIE with only the minimum required data.
std::optional< uint32_t > getParentIdx() const
Returns index of the parent die.
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
iterator_range< iterator > children() const
const DWARFDebugInfoEntry * getDebugInfoEntry() const
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static raw_ostream & error()
Convenience method for printing "error: " to stderr.
DieOutputPlacement
Kinds of placement for the output die.
@ Both
Corresponding DIE goes to type table and to plain dwarf.
@ TypeTable
Corresponding DIE goes to the type table only.
@ PlainDwarf
Corresponding DIE goes to the plain dwarf only.
Class keeping live worklist item data.
UnitEntryPairTy getRootEntry() const
LiveRootWorklistActionTy getAction() const
bool hasReferencedByOtherEntry() const
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)
bool markCollectedLiveRootsAsKept(bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Examine worklist and mark all 'root DIE's as kept and set "Placement" property.
bool maybeAddReferencedRoots(LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, const UnitEntryPairTy &Entry, bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Check referenced DIEs and add them into the worklist.
bool isLiveAction(LiveRootWorklistActionTy Action)
bool isChildrenAction(LiveRootWorklistActionTy Action)
bool isSingleAction(LiveRootWorklistActionTy Action)
bool isTypeAction(LiveRootWorklistActionTy Action)
bool markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, const UnitEntryPairTy &Entry, bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Mark whole DIE tree as kept recursively.
bool isTypeTableCandidate(const DWARFDebugInfoEntry *DIEEntry)
void setPlainDwarfPlacementRec(const UnitEntryPairTy &Entry)
Mark whole DIE tree as placed in "PlainDwarf".
RootEntriesListTy RootEntriesWorkList
List of entries which are 'root DIE's.
void addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry, std::optional< UnitEntryPairTy > ReferencedBy)
Add action item to the work list.
static bool isLiveSubprogramEntry(const UnitEntryPairTy &Entry)
Returns true if specified subprogram references live code section.
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.
@ MarkSingleTypeEntry
Mark current item as type entry.
@ MarkSingleLiveEntry
Mark current item as live entry.
@ 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.
void collectRootsToKeep(const UnitEntryPairTy &Entry, std::optional< UnitEntryPairTy > ReferencedBy, bool IsLiveParent)
This function navigates DIEs tree starting from specified Entry.
bool updateDependenciesCompleteness()
Check if dependencies have incompatible placement.
DIEInfo & getDIEInfo(unsigned Idx)
Idx index of the DIE.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
ArrayRef< dwarf::Attribute > getODRAttributes()
std::optional< uint64_t > toAddress(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an address.
This is an optimization pass for GlobalISel generic memory operations.
raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
auto reverse(ContainerTy &&C)
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
unsigned getULEB128Size(uint64_t Value)
Utility function to get the size of the ULEB128-encoded value.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
A broken link in the keep chain.
BrokenLink(DWARFDie Parent, DWARFDie Child, const char *Message)
A broken link in the keep chain.
Container for dump options that control which debug information will be dumped.
unsigned ChildRecurseDepth
Information gathered about a DIE in the object file.
Information gathered about source DIEs.
void setPlacement(DieOutputPlacement Placement)
Sets Placement kind for the corresponding die.
bool needToKeepInPlainDwarf() const
bool needToPlaceInTypeTable() const
This is a helper structure which keeps a debug info entry with it's containing compilation unit.
const DWARFDebugInfoEntry * DieEntry