xref: /freebsd-src/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/DependencyTracker.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
11db9f3b2SDimitry Andric //=== DependencyTracker.cpp -----------------------------------------------===//
21db9f3b2SDimitry Andric //
31db9f3b2SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41db9f3b2SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
51db9f3b2SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61db9f3b2SDimitry Andric //
71db9f3b2SDimitry Andric //===----------------------------------------------------------------------===//
81db9f3b2SDimitry Andric 
91db9f3b2SDimitry Andric #include "DependencyTracker.h"
101db9f3b2SDimitry Andric #include "llvm/Support/FormatVariadic.h"
111db9f3b2SDimitry Andric 
121db9f3b2SDimitry Andric using namespace llvm;
131db9f3b2SDimitry Andric using namespace dwarf_linker;
141db9f3b2SDimitry Andric using namespace dwarf_linker::parallel;
151db9f3b2SDimitry Andric 
161db9f3b2SDimitry Andric /// A broken link in the keep chain. By recording both the parent and the child
171db9f3b2SDimitry Andric /// we can show only broken links for DIEs with multiple children.
181db9f3b2SDimitry Andric struct BrokenLink {
BrokenLinkBrokenLink191db9f3b2SDimitry Andric   BrokenLink(DWARFDie Parent, DWARFDie Child, const char *Message)
201db9f3b2SDimitry Andric       : Parent(Parent), Child(Child), Message(Message) {}
211db9f3b2SDimitry Andric   DWARFDie Parent;
221db9f3b2SDimitry Andric   DWARFDie Child;
231db9f3b2SDimitry Andric   std::string Message;
241db9f3b2SDimitry Andric };
251db9f3b2SDimitry Andric 
261db9f3b2SDimitry Andric /// Verify the keep chain by looking for DIEs that are kept but who's parent
271db9f3b2SDimitry Andric /// isn't.
verifyKeepChain()281db9f3b2SDimitry Andric void DependencyTracker::verifyKeepChain() {
291db9f3b2SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
301db9f3b2SDimitry Andric   SmallVector<DWARFDie> Worklist;
311db9f3b2SDimitry Andric   Worklist.push_back(CU.getOrigUnit().getUnitDIE());
321db9f3b2SDimitry Andric 
331db9f3b2SDimitry Andric   // List of broken links.
341db9f3b2SDimitry Andric   SmallVector<BrokenLink> BrokenLinks;
351db9f3b2SDimitry Andric 
361db9f3b2SDimitry Andric   while (!Worklist.empty()) {
371db9f3b2SDimitry Andric     const DWARFDie Current = Worklist.back();
381db9f3b2SDimitry Andric     Worklist.pop_back();
391db9f3b2SDimitry Andric 
401db9f3b2SDimitry Andric     if (!Current.isValid())
411db9f3b2SDimitry Andric       continue;
421db9f3b2SDimitry Andric 
431db9f3b2SDimitry Andric     CompileUnit::DIEInfo &CurrentInfo =
441db9f3b2SDimitry Andric         CU.getDIEInfo(Current.getDebugInfoEntry());
451db9f3b2SDimitry Andric     const bool ParentPlainDieIsKept = CurrentInfo.needToKeepInPlainDwarf();
461db9f3b2SDimitry Andric     const bool ParentTypeDieIsKept = CurrentInfo.needToPlaceInTypeTable();
471db9f3b2SDimitry Andric 
481db9f3b2SDimitry Andric     for (DWARFDie Child : reverse(Current.children())) {
491db9f3b2SDimitry Andric       Worklist.push_back(Child);
501db9f3b2SDimitry Andric 
511db9f3b2SDimitry Andric       CompileUnit::DIEInfo &ChildInfo =
521db9f3b2SDimitry Andric           CU.getDIEInfo(Child.getDebugInfoEntry());
531db9f3b2SDimitry Andric       const bool ChildPlainDieIsKept = ChildInfo.needToKeepInPlainDwarf();
541db9f3b2SDimitry Andric       const bool ChildTypeDieIsKept = ChildInfo.needToPlaceInTypeTable();
551db9f3b2SDimitry Andric 
561db9f3b2SDimitry Andric       if (!ParentPlainDieIsKept && ChildPlainDieIsKept)
571db9f3b2SDimitry Andric         BrokenLinks.emplace_back(Current, Child,
581db9f3b2SDimitry Andric                                  "Found invalid link in keep chain");
591db9f3b2SDimitry Andric 
601db9f3b2SDimitry Andric       if (Child.getTag() == dwarf::DW_TAG_subprogram) {
611db9f3b2SDimitry Andric         if (!ChildInfo.getKeep() && isLiveSubprogramEntry(UnitEntryPairTy(
621db9f3b2SDimitry Andric                                         &CU, Child.getDebugInfoEntry()))) {
631db9f3b2SDimitry Andric           BrokenLinks.emplace_back(Current, Child,
641db9f3b2SDimitry Andric                                    "Live subprogram is not marked as kept");
651db9f3b2SDimitry Andric         }
661db9f3b2SDimitry Andric       }
671db9f3b2SDimitry Andric 
681db9f3b2SDimitry Andric       if (!ChildInfo.getODRAvailable()) {
691db9f3b2SDimitry Andric         assert(!ChildTypeDieIsKept);
701db9f3b2SDimitry Andric         continue;
711db9f3b2SDimitry Andric       }
721db9f3b2SDimitry Andric 
731db9f3b2SDimitry Andric       if (!ParentTypeDieIsKept && ChildTypeDieIsKept)
741db9f3b2SDimitry Andric         BrokenLinks.emplace_back(Current, Child,
751db9f3b2SDimitry Andric                                  "Found invalid link in keep chain");
761db9f3b2SDimitry Andric 
771db9f3b2SDimitry Andric       if (CurrentInfo.getIsInAnonNamespaceScope() &&
781db9f3b2SDimitry Andric           ChildInfo.needToPlaceInTypeTable()) {
791db9f3b2SDimitry Andric         BrokenLinks.emplace_back(Current, Child,
801db9f3b2SDimitry Andric                                  "Found invalid placement marking for member "
811db9f3b2SDimitry Andric                                  "of anonymous namespace");
821db9f3b2SDimitry Andric       }
831db9f3b2SDimitry Andric     }
841db9f3b2SDimitry Andric   }
851db9f3b2SDimitry Andric 
861db9f3b2SDimitry Andric   if (!BrokenLinks.empty()) {
871db9f3b2SDimitry Andric     for (BrokenLink Link : BrokenLinks) {
881db9f3b2SDimitry Andric       errs() << "\n=================================\n";
891db9f3b2SDimitry Andric       WithColor::error() << formatv("{0} between {1:x} and {2:x}", Link.Message,
901db9f3b2SDimitry Andric                                     Link.Parent.getOffset(),
911db9f3b2SDimitry Andric                                     Link.Child.getOffset());
921db9f3b2SDimitry Andric 
931db9f3b2SDimitry Andric       errs() << "\nParent:";
941db9f3b2SDimitry Andric       Link.Parent.dump(errs(), 0, {});
951db9f3b2SDimitry Andric       errs() << "\n";
961db9f3b2SDimitry Andric       CU.getDIEInfo(Link.Parent).dump();
971db9f3b2SDimitry Andric 
981db9f3b2SDimitry Andric       errs() << "\nChild:";
991db9f3b2SDimitry Andric       Link.Child.dump(errs(), 2, {});
1001db9f3b2SDimitry Andric       errs() << "\n";
1011db9f3b2SDimitry Andric       CU.getDIEInfo(Link.Child).dump();
1021db9f3b2SDimitry Andric     }
1031db9f3b2SDimitry Andric     report_fatal_error("invalid keep chain");
1041db9f3b2SDimitry Andric   }
1051db9f3b2SDimitry Andric #endif
1061db9f3b2SDimitry Andric }
1071db9f3b2SDimitry Andric 
resolveDependenciesAndMarkLiveness(bool InterCUProcessingStarted,std::atomic<bool> & HasNewInterconnectedCUs)1081db9f3b2SDimitry Andric bool DependencyTracker::resolveDependenciesAndMarkLiveness(
1091db9f3b2SDimitry Andric     bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
1101db9f3b2SDimitry Andric   RootEntriesWorkList.clear();
1111db9f3b2SDimitry Andric 
1121db9f3b2SDimitry Andric   // Search for live root DIEs.
1131db9f3b2SDimitry Andric   CompileUnit::DIEInfo &CUInfo = CU.getDIEInfo(CU.getDebugInfoEntry(0));
1141db9f3b2SDimitry Andric   CUInfo.setPlacement(CompileUnit::PlainDwarf);
1151db9f3b2SDimitry Andric   collectRootsToKeep(UnitEntryPairTy{&CU, CU.getDebugInfoEntry(0)},
1161db9f3b2SDimitry Andric                      std::nullopt, false);
1171db9f3b2SDimitry Andric 
1181db9f3b2SDimitry Andric   // Mark live DIEs as kept.
1191db9f3b2SDimitry Andric   return markCollectedLiveRootsAsKept(InterCUProcessingStarted,
1201db9f3b2SDimitry Andric                                       HasNewInterconnectedCUs);
1211db9f3b2SDimitry Andric }
1221db9f3b2SDimitry Andric 
addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action,const UnitEntryPairTy & Entry,std::optional<UnitEntryPairTy> ReferencedBy)1231db9f3b2SDimitry Andric void DependencyTracker::addActionToRootEntriesWorkList(
1241db9f3b2SDimitry Andric     LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry,
1251db9f3b2SDimitry Andric     std::optional<UnitEntryPairTy> ReferencedBy) {
1261db9f3b2SDimitry Andric   if (ReferencedBy) {
1271db9f3b2SDimitry Andric     RootEntriesWorkList.emplace_back(Action, Entry, *ReferencedBy);
1281db9f3b2SDimitry Andric     return;
1291db9f3b2SDimitry Andric   }
1301db9f3b2SDimitry Andric 
1311db9f3b2SDimitry Andric   RootEntriesWorkList.emplace_back(Action, Entry);
1321db9f3b2SDimitry Andric }
1331db9f3b2SDimitry Andric 
collectRootsToKeep(const UnitEntryPairTy & Entry,std::optional<UnitEntryPairTy> ReferencedBy,bool IsLiveParent)1341db9f3b2SDimitry Andric void DependencyTracker::collectRootsToKeep(
1351db9f3b2SDimitry Andric     const UnitEntryPairTy &Entry, std::optional<UnitEntryPairTy> ReferencedBy,
1361db9f3b2SDimitry Andric     bool IsLiveParent) {
1371db9f3b2SDimitry Andric   for (const DWARFDebugInfoEntry *CurChild =
1381db9f3b2SDimitry Andric            Entry.CU->getFirstChildEntry(Entry.DieEntry);
1391db9f3b2SDimitry Andric        CurChild && CurChild->getAbbreviationDeclarationPtr();
1401db9f3b2SDimitry Andric        CurChild = Entry.CU->getSiblingEntry(CurChild)) {
1411db9f3b2SDimitry Andric     UnitEntryPairTy ChildEntry(Entry.CU, CurChild);
1421db9f3b2SDimitry Andric     CompileUnit::DIEInfo &ChildInfo = Entry.CU->getDIEInfo(CurChild);
1431db9f3b2SDimitry Andric 
1441db9f3b2SDimitry Andric     bool IsLiveChild = false;
1451db9f3b2SDimitry Andric 
1461db9f3b2SDimitry Andric     switch (CurChild->getTag()) {
1471db9f3b2SDimitry Andric     case dwarf::DW_TAG_label: {
1481db9f3b2SDimitry Andric       IsLiveChild = isLiveSubprogramEntry(ChildEntry);
1491db9f3b2SDimitry Andric 
1501db9f3b2SDimitry Andric       // Keep label referencing live address.
1511db9f3b2SDimitry Andric       // Keep label which is child of live parent entry.
1521db9f3b2SDimitry Andric       if (IsLiveChild || (IsLiveParent && ChildInfo.getHasAnAddress())) {
1531db9f3b2SDimitry Andric         addActionToRootEntriesWorkList(
1541db9f3b2SDimitry Andric             LiveRootWorklistActionTy::MarkLiveEntryRec, ChildEntry,
1551db9f3b2SDimitry Andric             ReferencedBy);
1561db9f3b2SDimitry Andric       }
1571db9f3b2SDimitry Andric     } break;
1581db9f3b2SDimitry Andric     case dwarf::DW_TAG_subprogram: {
1591db9f3b2SDimitry Andric       IsLiveChild = isLiveSubprogramEntry(ChildEntry);
1601db9f3b2SDimitry Andric 
1611db9f3b2SDimitry Andric       // Keep subprogram referencing live address.
1621db9f3b2SDimitry Andric       if (IsLiveChild) {
1631db9f3b2SDimitry Andric         // If subprogram is in module scope and this module allows ODR
1641db9f3b2SDimitry Andric         // deduplication set "TypeTable" placement, otherwise set "" placement
1651db9f3b2SDimitry Andric         LiveRootWorklistActionTy Action =
1661db9f3b2SDimitry Andric             (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
1671db9f3b2SDimitry Andric                 ? LiveRootWorklistActionTy::MarkTypeEntryRec
1681db9f3b2SDimitry Andric                 : LiveRootWorklistActionTy::MarkLiveEntryRec;
1691db9f3b2SDimitry Andric 
1701db9f3b2SDimitry Andric         addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
1711db9f3b2SDimitry Andric       }
1721db9f3b2SDimitry Andric     } break;
1731db9f3b2SDimitry Andric     case dwarf::DW_TAG_constant:
1741db9f3b2SDimitry Andric     case dwarf::DW_TAG_variable: {
1751db9f3b2SDimitry Andric       IsLiveChild = isLiveVariableEntry(ChildEntry, IsLiveParent);
1761db9f3b2SDimitry Andric 
1771db9f3b2SDimitry Andric       // Keep variable referencing live address.
1781db9f3b2SDimitry Andric       if (IsLiveChild) {
1791db9f3b2SDimitry Andric         // If variable is in module scope and this module allows ODR
1801db9f3b2SDimitry Andric         // deduplication set "TypeTable" placement, otherwise set "" placement
1811db9f3b2SDimitry Andric 
1821db9f3b2SDimitry Andric         LiveRootWorklistActionTy Action =
1831db9f3b2SDimitry Andric             (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
1841db9f3b2SDimitry Andric                 ? LiveRootWorklistActionTy::MarkTypeEntryRec
1851db9f3b2SDimitry Andric                 : LiveRootWorklistActionTy::MarkLiveEntryRec;
1861db9f3b2SDimitry Andric 
1871db9f3b2SDimitry Andric         addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
1881db9f3b2SDimitry Andric       }
1891db9f3b2SDimitry Andric     } break;
1901db9f3b2SDimitry Andric     case dwarf::DW_TAG_base_type: {
1911db9f3b2SDimitry Andric       // Always keep base types.
1921db9f3b2SDimitry Andric       addActionToRootEntriesWorkList(
1931db9f3b2SDimitry Andric           LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,
1941db9f3b2SDimitry Andric           ReferencedBy);
1951db9f3b2SDimitry Andric     } break;
1961db9f3b2SDimitry Andric     case dwarf::DW_TAG_imported_module:
1971db9f3b2SDimitry Andric     case dwarf::DW_TAG_imported_declaration:
1981db9f3b2SDimitry Andric     case dwarf::DW_TAG_imported_unit: {
1991db9f3b2SDimitry Andric       // Always keep DIEs having DW_AT_import attribute.
2001db9f3b2SDimitry Andric       if (Entry.DieEntry->getTag() == dwarf::DW_TAG_compile_unit) {
2011db9f3b2SDimitry Andric         addActionToRootEntriesWorkList(
2021db9f3b2SDimitry Andric             LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,
2031db9f3b2SDimitry Andric             ReferencedBy);
2041db9f3b2SDimitry Andric         break;
2051db9f3b2SDimitry Andric       }
2061db9f3b2SDimitry Andric 
2071db9f3b2SDimitry Andric       addActionToRootEntriesWorkList(
2081db9f3b2SDimitry Andric           LiveRootWorklistActionTy::MarkSingleTypeEntry, ChildEntry,
2091db9f3b2SDimitry Andric           ReferencedBy);
2101db9f3b2SDimitry Andric     } break;
2111db9f3b2SDimitry Andric     case dwarf::DW_TAG_type_unit:
2121db9f3b2SDimitry Andric     case dwarf::DW_TAG_partial_unit:
2131db9f3b2SDimitry Andric     case dwarf::DW_TAG_compile_unit: {
2141db9f3b2SDimitry Andric       llvm_unreachable("Called for incorrect DIE");
2151db9f3b2SDimitry Andric     } break;
2161db9f3b2SDimitry Andric     default:
2171db9f3b2SDimitry Andric       // Nothing to do.
2181db9f3b2SDimitry Andric       break;
2191db9f3b2SDimitry Andric     }
2201db9f3b2SDimitry Andric 
2211db9f3b2SDimitry Andric     collectRootsToKeep(ChildEntry, ReferencedBy, IsLiveChild || IsLiveParent);
2221db9f3b2SDimitry Andric   }
2231db9f3b2SDimitry Andric }
2241db9f3b2SDimitry Andric 
markCollectedLiveRootsAsKept(bool InterCUProcessingStarted,std::atomic<bool> & HasNewInterconnectedCUs)2251db9f3b2SDimitry Andric bool DependencyTracker::markCollectedLiveRootsAsKept(
2261db9f3b2SDimitry Andric     bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
2271db9f3b2SDimitry Andric   bool Res = true;
2281db9f3b2SDimitry Andric 
2291db9f3b2SDimitry Andric   // Mark roots as kept.
2301db9f3b2SDimitry Andric   while (!RootEntriesWorkList.empty()) {
2311db9f3b2SDimitry Andric     LiveRootWorklistItemTy Root = RootEntriesWorkList.pop_back_val();
2321db9f3b2SDimitry Andric 
2331db9f3b2SDimitry Andric     if (markDIEEntryAsKeptRec(Root.getAction(), Root.getRootEntry(),
2341db9f3b2SDimitry Andric                               Root.getRootEntry(), InterCUProcessingStarted,
2351db9f3b2SDimitry Andric                               HasNewInterconnectedCUs)) {
2361db9f3b2SDimitry Andric       if (Root.hasReferencedByOtherEntry())
2371db9f3b2SDimitry Andric         Dependencies.push_back(Root);
2381db9f3b2SDimitry Andric     } else
2391db9f3b2SDimitry Andric       Res = false;
2401db9f3b2SDimitry Andric   }
2411db9f3b2SDimitry Andric 
2421db9f3b2SDimitry Andric   return Res;
2431db9f3b2SDimitry Andric }
2441db9f3b2SDimitry Andric 
updateDependenciesCompleteness()2451db9f3b2SDimitry Andric bool DependencyTracker::updateDependenciesCompleteness() {
2461db9f3b2SDimitry Andric   bool HasNewDependency = false;
2471db9f3b2SDimitry Andric   for (LiveRootWorklistItemTy &Root : Dependencies) {
2481db9f3b2SDimitry Andric     assert(Root.hasReferencedByOtherEntry() &&
2491db9f3b2SDimitry Andric            "Root entry without dependency inside the dependencies list");
2501db9f3b2SDimitry Andric 
2511db9f3b2SDimitry Andric     UnitEntryPairTy RootEntry = Root.getRootEntry();
2521db9f3b2SDimitry Andric     CompileUnit::DIEInfo &RootInfo =
2531db9f3b2SDimitry Andric         RootEntry.CU->getDIEInfo(RootEntry.DieEntry);
2541db9f3b2SDimitry Andric 
2551db9f3b2SDimitry Andric     UnitEntryPairTy ReferencedByEntry = Root.getReferencedByEntry();
2561db9f3b2SDimitry Andric     CompileUnit::DIEInfo &ReferencedByInfo =
2571db9f3b2SDimitry Andric         ReferencedByEntry.CU->getDIEInfo(ReferencedByEntry.DieEntry);
2581db9f3b2SDimitry Andric 
2591db9f3b2SDimitry Andric     if (!RootInfo.needToPlaceInTypeTable() &&
2601db9f3b2SDimitry Andric         ReferencedByInfo.needToPlaceInTypeTable()) {
2611db9f3b2SDimitry Andric       HasNewDependency = true;
2621db9f3b2SDimitry Andric       setPlainDwarfPlacementRec(ReferencedByEntry);
2631db9f3b2SDimitry Andric 
2641db9f3b2SDimitry Andric       // FIXME: we probably need to update getKeepTypeChildren status for
2651db9f3b2SDimitry Andric       // parents of *Root.ReferencedBy.
2661db9f3b2SDimitry Andric     }
2671db9f3b2SDimitry Andric   }
2681db9f3b2SDimitry Andric 
2691db9f3b2SDimitry Andric   return HasNewDependency;
2701db9f3b2SDimitry Andric }
2711db9f3b2SDimitry Andric 
setPlainDwarfPlacementRec(const UnitEntryPairTy & Entry)2721db9f3b2SDimitry Andric void DependencyTracker::setPlainDwarfPlacementRec(
2731db9f3b2SDimitry Andric     const UnitEntryPairTy &Entry) {
2741db9f3b2SDimitry Andric   CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
2751db9f3b2SDimitry Andric   if (Info.getPlacement() == CompileUnit::PlainDwarf &&
2761db9f3b2SDimitry Andric       !Info.getKeepTypeChildren())
2771db9f3b2SDimitry Andric     return;
2781db9f3b2SDimitry Andric 
2791db9f3b2SDimitry Andric   Info.setPlacement(CompileUnit::PlainDwarf);
2801db9f3b2SDimitry Andric   Info.unsetKeepTypeChildren();
2811db9f3b2SDimitry Andric   markParentsAsKeepingChildren(Entry);
2821db9f3b2SDimitry Andric 
2831db9f3b2SDimitry Andric   for (const DWARFDebugInfoEntry *CurChild =
2841db9f3b2SDimitry Andric            Entry.CU->getFirstChildEntry(Entry.DieEntry);
2851db9f3b2SDimitry Andric        CurChild && CurChild->getAbbreviationDeclarationPtr();
2861db9f3b2SDimitry Andric        CurChild = Entry.CU->getSiblingEntry(CurChild))
2871db9f3b2SDimitry Andric     setPlainDwarfPlacementRec(UnitEntryPairTy{Entry.CU, CurChild});
2881db9f3b2SDimitry Andric }
2891db9f3b2SDimitry Andric 
isNamespaceLikeEntry(const DWARFDebugInfoEntry * Entry)2901db9f3b2SDimitry Andric static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry) {
2911db9f3b2SDimitry Andric   switch (Entry->getTag()) {
2921db9f3b2SDimitry Andric   case dwarf::DW_TAG_compile_unit:
2931db9f3b2SDimitry Andric   case dwarf::DW_TAG_module:
2941db9f3b2SDimitry Andric   case dwarf::DW_TAG_namespace:
2951db9f3b2SDimitry Andric     return true;
2961db9f3b2SDimitry Andric 
2971db9f3b2SDimitry Andric   default:
2981db9f3b2SDimitry Andric     return false;
2991db9f3b2SDimitry Andric   }
3001db9f3b2SDimitry Andric }
3011db9f3b2SDimitry Andric 
isAlreadyMarked(const CompileUnit::DIEInfo & Info,CompileUnit::DieOutputPlacement NewPlacement)3021db9f3b2SDimitry Andric bool isAlreadyMarked(const CompileUnit::DIEInfo &Info,
3031db9f3b2SDimitry Andric                      CompileUnit::DieOutputPlacement NewPlacement) {
3041db9f3b2SDimitry Andric   if (!Info.getKeep())
3051db9f3b2SDimitry Andric     return false;
3061db9f3b2SDimitry Andric 
3071db9f3b2SDimitry Andric   switch (NewPlacement) {
3081db9f3b2SDimitry Andric   case CompileUnit::TypeTable:
3091db9f3b2SDimitry Andric     return Info.needToPlaceInTypeTable();
3101db9f3b2SDimitry Andric 
3111db9f3b2SDimitry Andric   case CompileUnit::PlainDwarf:
3121db9f3b2SDimitry Andric     return Info.needToKeepInPlainDwarf();
3131db9f3b2SDimitry Andric 
3141db9f3b2SDimitry Andric   case CompileUnit::Both:
3151db9f3b2SDimitry Andric     return Info.needToPlaceInTypeTable() && Info.needToKeepInPlainDwarf();
3161db9f3b2SDimitry Andric 
3171db9f3b2SDimitry Andric   case CompileUnit::NotSet:
3181db9f3b2SDimitry Andric     llvm_unreachable("Unset placement type is specified.");
3191db9f3b2SDimitry Andric   };
3201db9f3b2SDimitry Andric 
3211db9f3b2SDimitry Andric   llvm_unreachable("Unknown CompileUnit::DieOutputPlacement enum");
3221db9f3b2SDimitry Andric }
3231db9f3b2SDimitry Andric 
isAlreadyMarked(const UnitEntryPairTy & Entry,CompileUnit::DieOutputPlacement NewPlacement)3241db9f3b2SDimitry Andric bool isAlreadyMarked(const UnitEntryPairTy &Entry,
3251db9f3b2SDimitry Andric                      CompileUnit::DieOutputPlacement NewPlacement) {
3261db9f3b2SDimitry Andric   return isAlreadyMarked(Entry.CU->getDIEInfo(Entry.DieEntry), NewPlacement);
3271db9f3b2SDimitry Andric }
3281db9f3b2SDimitry Andric 
markParentsAsKeepingChildren(const UnitEntryPairTy & Entry)3291db9f3b2SDimitry Andric void DependencyTracker::markParentsAsKeepingChildren(
3301db9f3b2SDimitry Andric     const UnitEntryPairTy &Entry) {
3311db9f3b2SDimitry Andric   if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
3321db9f3b2SDimitry Andric     return;
3331db9f3b2SDimitry Andric 
3341db9f3b2SDimitry Andric   CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
3351db9f3b2SDimitry Andric   bool NeedKeepTypeChildren = Info.needToPlaceInTypeTable();
3361db9f3b2SDimitry Andric   bool NeedKeepPlainChildren = Info.needToKeepInPlainDwarf();
3371db9f3b2SDimitry Andric 
3381db9f3b2SDimitry Andric   bool AreTypeParentsDone = !NeedKeepTypeChildren;
3391db9f3b2SDimitry Andric   bool ArePlainParentsDone = !NeedKeepPlainChildren;
3401db9f3b2SDimitry Andric 
3411db9f3b2SDimitry Andric   // Mark parents as 'Keep*Children'.
3421db9f3b2SDimitry Andric   std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx();
3431db9f3b2SDimitry Andric   while (ParentIdx) {
3441db9f3b2SDimitry Andric     const DWARFDebugInfoEntry *ParentEntry =
3451db9f3b2SDimitry Andric         Entry.CU->getDebugInfoEntry(*ParentIdx);
3461db9f3b2SDimitry Andric     CompileUnit::DIEInfo &ParentInfo = Entry.CU->getDIEInfo(*ParentIdx);
3471db9f3b2SDimitry Andric 
3481db9f3b2SDimitry Andric     if (!AreTypeParentsDone && NeedKeepTypeChildren) {
3491db9f3b2SDimitry Andric       if (ParentInfo.getKeepTypeChildren())
3501db9f3b2SDimitry Andric         AreTypeParentsDone = true;
3511db9f3b2SDimitry Andric       else {
3521db9f3b2SDimitry Andric         bool AddToWorklist = !isAlreadyMarked(
3531db9f3b2SDimitry Andric             ParentInfo, CompileUnit::DieOutputPlacement::TypeTable);
3541db9f3b2SDimitry Andric         ParentInfo.setKeepTypeChildren();
3551db9f3b2SDimitry Andric         if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
3561db9f3b2SDimitry Andric           addActionToRootEntriesWorkList(
3571db9f3b2SDimitry Andric               LiveRootWorklistActionTy::MarkTypeChildrenRec,
3581db9f3b2SDimitry Andric               UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
3591db9f3b2SDimitry Andric         }
3601db9f3b2SDimitry Andric       }
3611db9f3b2SDimitry Andric     }
3621db9f3b2SDimitry Andric 
3631db9f3b2SDimitry Andric     if (!ArePlainParentsDone && NeedKeepPlainChildren) {
3641db9f3b2SDimitry Andric       if (ParentInfo.getKeepPlainChildren())
3651db9f3b2SDimitry Andric         ArePlainParentsDone = true;
3661db9f3b2SDimitry Andric       else {
3671db9f3b2SDimitry Andric         bool AddToWorklist = !isAlreadyMarked(
3681db9f3b2SDimitry Andric             ParentInfo, CompileUnit::DieOutputPlacement::PlainDwarf);
3691db9f3b2SDimitry Andric         ParentInfo.setKeepPlainChildren();
3701db9f3b2SDimitry Andric         if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
3711db9f3b2SDimitry Andric           addActionToRootEntriesWorkList(
3721db9f3b2SDimitry Andric               LiveRootWorklistActionTy::MarkLiveChildrenRec,
3731db9f3b2SDimitry Andric               UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
3741db9f3b2SDimitry Andric         }
3751db9f3b2SDimitry Andric       }
3761db9f3b2SDimitry Andric     }
3771db9f3b2SDimitry Andric 
3781db9f3b2SDimitry Andric     if (AreTypeParentsDone && ArePlainParentsDone)
3791db9f3b2SDimitry Andric       break;
3801db9f3b2SDimitry Andric 
3811db9f3b2SDimitry Andric     ParentIdx = ParentEntry->getParentIdx();
3821db9f3b2SDimitry Andric   }
3831db9f3b2SDimitry Andric }
3841db9f3b2SDimitry Andric 
3851db9f3b2SDimitry Andric // This function tries to set specified \p Placement for the \p Entry.
3861db9f3b2SDimitry Andric // Depending on the concrete entry, the placement could be:
3871db9f3b2SDimitry Andric //  a) changed to another.
3881db9f3b2SDimitry Andric //  b) joined with current entry placement.
3891db9f3b2SDimitry Andric //  c) set as requested.
3901db9f3b2SDimitry Andric static CompileUnit::DieOutputPlacement
getFinalPlacementForEntry(const UnitEntryPairTy & Entry,CompileUnit::DieOutputPlacement Placement)3911db9f3b2SDimitry Andric getFinalPlacementForEntry(const UnitEntryPairTy &Entry,
3921db9f3b2SDimitry Andric                           CompileUnit::DieOutputPlacement Placement) {
3931db9f3b2SDimitry Andric   assert((Placement != CompileUnit::NotSet) && "Placement is not set");
3941db9f3b2SDimitry Andric   CompileUnit::DIEInfo &EntryInfo = Entry.CU->getDIEInfo(Entry.DieEntry);
3951db9f3b2SDimitry Andric 
3961db9f3b2SDimitry Andric   if (!EntryInfo.getODRAvailable())
3971db9f3b2SDimitry Andric     return CompileUnit::PlainDwarf;
3981db9f3b2SDimitry Andric 
3991db9f3b2SDimitry Andric   if (Entry.DieEntry->getTag() == dwarf::DW_TAG_variable) {
4001db9f3b2SDimitry Andric     // Do not put variable into the "TypeTable" and "PlainDwarf" at the same
4011db9f3b2SDimitry Andric     // time.
4021db9f3b2SDimitry Andric     if (EntryInfo.getPlacement() == CompileUnit::PlainDwarf ||
4031db9f3b2SDimitry Andric         EntryInfo.getPlacement() == CompileUnit::Both)
4041db9f3b2SDimitry Andric       return CompileUnit::PlainDwarf;
4051db9f3b2SDimitry Andric 
4061db9f3b2SDimitry Andric     if (Placement == CompileUnit::PlainDwarf || Placement == CompileUnit::Both)
4071db9f3b2SDimitry Andric       return CompileUnit::PlainDwarf;
4081db9f3b2SDimitry Andric   }
4091db9f3b2SDimitry Andric 
4101db9f3b2SDimitry Andric   switch (EntryInfo.getPlacement()) {
4111db9f3b2SDimitry Andric   case CompileUnit::NotSet:
4121db9f3b2SDimitry Andric     return Placement;
4131db9f3b2SDimitry Andric 
4141db9f3b2SDimitry Andric   case CompileUnit::TypeTable:
4151db9f3b2SDimitry Andric     return Placement == CompileUnit::PlainDwarf ? CompileUnit::Both : Placement;
4161db9f3b2SDimitry Andric 
4171db9f3b2SDimitry Andric   case CompileUnit::PlainDwarf:
4181db9f3b2SDimitry Andric     return Placement == CompileUnit::TypeTable ? CompileUnit::Both : Placement;
4191db9f3b2SDimitry Andric 
4201db9f3b2SDimitry Andric   case CompileUnit::Both:
4211db9f3b2SDimitry Andric     return CompileUnit::Both;
4221db9f3b2SDimitry Andric   };
4231db9f3b2SDimitry Andric 
4241db9f3b2SDimitry Andric   llvm_unreachable("Unknown placement type.");
4251db9f3b2SDimitry Andric   return Placement;
4261db9f3b2SDimitry Andric }
4271db9f3b2SDimitry Andric 
markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action,const UnitEntryPairTy & RootEntry,const UnitEntryPairTy & Entry,bool InterCUProcessingStarted,std::atomic<bool> & HasNewInterconnectedCUs)4281db9f3b2SDimitry Andric bool DependencyTracker::markDIEEntryAsKeptRec(
4291db9f3b2SDimitry Andric     LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
4301db9f3b2SDimitry Andric     const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
4311db9f3b2SDimitry Andric     std::atomic<bool> &HasNewInterconnectedCUs) {
4321db9f3b2SDimitry Andric   if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
4331db9f3b2SDimitry Andric     return true;
4341db9f3b2SDimitry Andric 
4351db9f3b2SDimitry Andric   CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
4361db9f3b2SDimitry Andric 
4371db9f3b2SDimitry Andric   // Calculate final placement placement.
4381db9f3b2SDimitry Andric   CompileUnit::DieOutputPlacement Placement = getFinalPlacementForEntry(
4391db9f3b2SDimitry Andric       Entry,
4401db9f3b2SDimitry Andric       isLiveAction(Action) ? CompileUnit::PlainDwarf : CompileUnit::TypeTable);
4411db9f3b2SDimitry Andric   assert((Info.getODRAvailable() || isLiveAction(Action) ||
4421db9f3b2SDimitry Andric           Placement == CompileUnit::PlainDwarf) &&
4431db9f3b2SDimitry Andric          "Wrong kind of placement for ODR unavailable entry");
4441db9f3b2SDimitry Andric 
4451db9f3b2SDimitry Andric   if (!isChildrenAction(Action))
4461db9f3b2SDimitry Andric     if (isAlreadyMarked(Entry, Placement))
4471db9f3b2SDimitry Andric       return true;
4481db9f3b2SDimitry Andric 
4491db9f3b2SDimitry Andric   // Mark current DIE as kept.
4501db9f3b2SDimitry Andric   Info.setKeep();
4511db9f3b2SDimitry Andric   Info.setPlacement(Placement);
4521db9f3b2SDimitry Andric 
4531db9f3b2SDimitry Andric   // Set keep children property for parents.
4541db9f3b2SDimitry Andric   markParentsAsKeepingChildren(Entry);
4551db9f3b2SDimitry Andric 
4561db9f3b2SDimitry Andric   UnitEntryPairTy FinalRootEntry =
4571db9f3b2SDimitry Andric       Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram ? Entry : RootEntry;
4581db9f3b2SDimitry Andric 
4591db9f3b2SDimitry Andric   // Analyse referenced DIEs.
4601db9f3b2SDimitry Andric   bool Res = true;
4611db9f3b2SDimitry Andric   if (!maybeAddReferencedRoots(Action, FinalRootEntry, Entry,
4621db9f3b2SDimitry Andric                                InterCUProcessingStarted,
4631db9f3b2SDimitry Andric                                HasNewInterconnectedCUs))
4641db9f3b2SDimitry Andric     Res = false;
4651db9f3b2SDimitry Andric 
4661db9f3b2SDimitry Andric   // Return if we do not need to process children.
4671db9f3b2SDimitry Andric   if (isSingleAction(Action))
4681db9f3b2SDimitry Andric     return Res;
4691db9f3b2SDimitry Andric 
4701db9f3b2SDimitry Andric   // Process children.
4711db9f3b2SDimitry Andric   // Check for subprograms special case.
4721db9f3b2SDimitry Andric   if (Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram &&
4731db9f3b2SDimitry Andric       Info.getODRAvailable()) {
4741db9f3b2SDimitry Andric     // Subprograms is a special case. As it can be root for type DIEs
4751db9f3b2SDimitry Andric     // and itself may be subject to move into the artificial type unit.
4761db9f3b2SDimitry Andric     //  a) Non removable children(like DW_TAG_formal_parameter) should always
4771db9f3b2SDimitry Andric     //     be cloned. They are placed into the "PlainDwarf" and into the
4781db9f3b2SDimitry Andric     //     "TypeTable".
4791db9f3b2SDimitry Andric     //  b) ODR deduplication candidates(type DIEs) children should not be put
4801db9f3b2SDimitry Andric     //  into the "PlainDwarf".
4811db9f3b2SDimitry Andric     //  c) Children keeping addresses and locations(like DW_TAG_call_site)
4821db9f3b2SDimitry Andric     //  should not be put into the "TypeTable".
4831db9f3b2SDimitry Andric     for (const DWARFDebugInfoEntry *CurChild =
4841db9f3b2SDimitry Andric              Entry.CU->getFirstChildEntry(Entry.DieEntry);
4851db9f3b2SDimitry Andric          CurChild && CurChild->getAbbreviationDeclarationPtr();
4861db9f3b2SDimitry Andric          CurChild = Entry.CU->getSiblingEntry(CurChild)) {
4871db9f3b2SDimitry Andric       CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
4881db9f3b2SDimitry Andric 
4891db9f3b2SDimitry Andric       switch (CurChild->getTag()) {
4901db9f3b2SDimitry Andric       case dwarf::DW_TAG_variable:
4911db9f3b2SDimitry Andric       case dwarf::DW_TAG_constant:
4921db9f3b2SDimitry Andric       case dwarf::DW_TAG_subprogram:
4931db9f3b2SDimitry Andric       case dwarf::DW_TAG_label: {
4941db9f3b2SDimitry Andric         if (ChildInfo.getHasAnAddress())
4951db9f3b2SDimitry Andric           continue;
4961db9f3b2SDimitry Andric       } break;
4971db9f3b2SDimitry Andric 
4981db9f3b2SDimitry Andric       // Entries having following tags could not be removed from the subprogram.
4991db9f3b2SDimitry Andric       case dwarf::DW_TAG_lexical_block:
5001db9f3b2SDimitry Andric       case dwarf::DW_TAG_friend:
5011db9f3b2SDimitry Andric       case dwarf::DW_TAG_inheritance:
5021db9f3b2SDimitry Andric       case dwarf::DW_TAG_formal_parameter:
5031db9f3b2SDimitry Andric       case dwarf::DW_TAG_unspecified_parameters:
5041db9f3b2SDimitry Andric       case dwarf::DW_TAG_template_type_parameter:
5051db9f3b2SDimitry Andric       case dwarf::DW_TAG_template_value_parameter:
5061db9f3b2SDimitry Andric       case dwarf::DW_TAG_GNU_template_parameter_pack:
5071db9f3b2SDimitry Andric       case dwarf::DW_TAG_GNU_formal_parameter_pack:
5081db9f3b2SDimitry Andric       case dwarf::DW_TAG_GNU_template_template_param:
5091db9f3b2SDimitry Andric       case dwarf::DW_TAG_thrown_type: {
5101db9f3b2SDimitry Andric         // Go to the default child handling.
5111db9f3b2SDimitry Andric       } break;
5121db9f3b2SDimitry Andric 
5131db9f3b2SDimitry Andric       default: {
5141db9f3b2SDimitry Andric         bool ChildIsTypeTableCandidate = isTypeTableCandidate(CurChild);
5151db9f3b2SDimitry Andric 
5161db9f3b2SDimitry Andric         // Skip child marked to be copied into the artificial type unit.
5171db9f3b2SDimitry Andric         if (isLiveAction(Action) && ChildIsTypeTableCandidate)
5181db9f3b2SDimitry Andric           continue;
5191db9f3b2SDimitry Andric 
5201db9f3b2SDimitry Andric         // Skip child marked to be copied into the plain unit.
5211db9f3b2SDimitry Andric         if (isTypeAction(Action) && !ChildIsTypeTableCandidate)
5221db9f3b2SDimitry Andric           continue;
5231db9f3b2SDimitry Andric 
5241db9f3b2SDimitry Andric         // Go to the default child handling.
5251db9f3b2SDimitry Andric       } break;
5261db9f3b2SDimitry Andric       }
5271db9f3b2SDimitry Andric 
5281db9f3b2SDimitry Andric       if (!markDIEEntryAsKeptRec(
5291db9f3b2SDimitry Andric               Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
5301db9f3b2SDimitry Andric               InterCUProcessingStarted, HasNewInterconnectedCUs))
5311db9f3b2SDimitry Andric         Res = false;
5321db9f3b2SDimitry Andric     }
5331db9f3b2SDimitry Andric 
5341db9f3b2SDimitry Andric     return Res;
5351db9f3b2SDimitry Andric   }
5361db9f3b2SDimitry Andric 
5371db9f3b2SDimitry Andric   // Recursively process children.
5381db9f3b2SDimitry Andric   for (const DWARFDebugInfoEntry *CurChild =
5391db9f3b2SDimitry Andric            Entry.CU->getFirstChildEntry(Entry.DieEntry);
5401db9f3b2SDimitry Andric        CurChild && CurChild->getAbbreviationDeclarationPtr();
5411db9f3b2SDimitry Andric        CurChild = Entry.CU->getSiblingEntry(CurChild)) {
5421db9f3b2SDimitry Andric     CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
5431db9f3b2SDimitry Andric     switch (CurChild->getTag()) {
5441db9f3b2SDimitry Andric     case dwarf::DW_TAG_variable:
5451db9f3b2SDimitry Andric     case dwarf::DW_TAG_constant:
5461db9f3b2SDimitry Andric     case dwarf::DW_TAG_subprogram:
5471db9f3b2SDimitry Andric     case dwarf::DW_TAG_label: {
5481db9f3b2SDimitry Andric       if (ChildInfo.getHasAnAddress())
5491db9f3b2SDimitry Andric         continue;
5501db9f3b2SDimitry Andric     } break;
5511db9f3b2SDimitry Andric     default:
5521db9f3b2SDimitry Andric       break; // Nothing to do.
5531db9f3b2SDimitry Andric     };
5541db9f3b2SDimitry Andric 
5551db9f3b2SDimitry Andric     if (!markDIEEntryAsKeptRec(
5561db9f3b2SDimitry Andric             Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
5571db9f3b2SDimitry Andric             InterCUProcessingStarted, HasNewInterconnectedCUs))
5581db9f3b2SDimitry Andric       Res = false;
5591db9f3b2SDimitry Andric   }
5601db9f3b2SDimitry Andric 
5611db9f3b2SDimitry Andric   return Res;
5621db9f3b2SDimitry Andric }
5631db9f3b2SDimitry Andric 
isTypeTableCandidate(const DWARFDebugInfoEntry * DIEEntry)5641db9f3b2SDimitry Andric bool DependencyTracker::isTypeTableCandidate(
5651db9f3b2SDimitry Andric     const DWARFDebugInfoEntry *DIEEntry) {
5661db9f3b2SDimitry Andric   switch (DIEEntry->getTag()) {
5671db9f3b2SDimitry Andric   default:
5681db9f3b2SDimitry Andric     return false;
5691db9f3b2SDimitry Andric 
5701db9f3b2SDimitry Andric   case dwarf::DW_TAG_imported_module:
5711db9f3b2SDimitry Andric   case dwarf::DW_TAG_imported_declaration:
5721db9f3b2SDimitry Andric   case dwarf::DW_TAG_imported_unit:
5731db9f3b2SDimitry Andric   case dwarf::DW_TAG_array_type:
5741db9f3b2SDimitry Andric   case dwarf::DW_TAG_class_type:
5751db9f3b2SDimitry Andric   case dwarf::DW_TAG_enumeration_type:
5761db9f3b2SDimitry Andric   case dwarf::DW_TAG_pointer_type:
5771db9f3b2SDimitry Andric   case dwarf::DW_TAG_reference_type:
5781db9f3b2SDimitry Andric   case dwarf::DW_TAG_string_type:
5791db9f3b2SDimitry Andric   case dwarf::DW_TAG_structure_type:
5801db9f3b2SDimitry Andric   case dwarf::DW_TAG_subroutine_type:
5811db9f3b2SDimitry Andric   case dwarf::DW_TAG_typedef:
5821db9f3b2SDimitry Andric   case dwarf::DW_TAG_union_type:
5831db9f3b2SDimitry Andric   case dwarf::DW_TAG_variant:
5841db9f3b2SDimitry Andric   case dwarf::DW_TAG_module:
5851db9f3b2SDimitry Andric   case dwarf::DW_TAG_ptr_to_member_type:
5861db9f3b2SDimitry Andric   case dwarf::DW_TAG_set_type:
5871db9f3b2SDimitry Andric   case dwarf::DW_TAG_subrange_type:
5881db9f3b2SDimitry Andric   case dwarf::DW_TAG_base_type:
5891db9f3b2SDimitry Andric   case dwarf::DW_TAG_const_type:
5901db9f3b2SDimitry Andric   case dwarf::DW_TAG_enumerator:
5911db9f3b2SDimitry Andric   case dwarf::DW_TAG_file_type:
5921db9f3b2SDimitry Andric   case dwarf::DW_TAG_packed_type:
5931db9f3b2SDimitry Andric   case dwarf::DW_TAG_thrown_type:
5941db9f3b2SDimitry Andric   case dwarf::DW_TAG_volatile_type:
5951db9f3b2SDimitry Andric   case dwarf::DW_TAG_dwarf_procedure:
5961db9f3b2SDimitry Andric   case dwarf::DW_TAG_restrict_type:
5971db9f3b2SDimitry Andric   case dwarf::DW_TAG_interface_type:
5981db9f3b2SDimitry Andric   case dwarf::DW_TAG_namespace:
5991db9f3b2SDimitry Andric   case dwarf::DW_TAG_unspecified_type:
6001db9f3b2SDimitry Andric   case dwarf::DW_TAG_shared_type:
6011db9f3b2SDimitry Andric   case dwarf::DW_TAG_rvalue_reference_type:
6021db9f3b2SDimitry Andric   case dwarf::DW_TAG_coarray_type:
6031db9f3b2SDimitry Andric   case dwarf::DW_TAG_dynamic_type:
6041db9f3b2SDimitry Andric   case dwarf::DW_TAG_atomic_type:
6051db9f3b2SDimitry Andric   case dwarf::DW_TAG_immutable_type:
6061db9f3b2SDimitry Andric   case dwarf::DW_TAG_function_template:
6071db9f3b2SDimitry Andric   case dwarf::DW_TAG_class_template:
6081db9f3b2SDimitry Andric     return true;
6091db9f3b2SDimitry Andric   }
6101db9f3b2SDimitry Andric }
6111db9f3b2SDimitry Andric 
maybeAddReferencedRoots(LiveRootWorklistActionTy Action,const UnitEntryPairTy & RootEntry,const UnitEntryPairTy & Entry,bool InterCUProcessingStarted,std::atomic<bool> & HasNewInterconnectedCUs)6121db9f3b2SDimitry Andric bool DependencyTracker::maybeAddReferencedRoots(
6131db9f3b2SDimitry Andric     LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
6141db9f3b2SDimitry Andric     const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
6151db9f3b2SDimitry Andric     std::atomic<bool> &HasNewInterconnectedCUs) {
6161db9f3b2SDimitry Andric   const auto *Abbrev = Entry.DieEntry->getAbbreviationDeclarationPtr();
6171db9f3b2SDimitry Andric   if (Abbrev == nullptr)
6181db9f3b2SDimitry Andric     return true;
6191db9f3b2SDimitry Andric 
6201db9f3b2SDimitry Andric   DWARFUnit &Unit = Entry.CU->getOrigUnit();
6211db9f3b2SDimitry Andric   DWARFDataExtractor Data = Unit.getDebugInfoExtractor();
6221db9f3b2SDimitry Andric   uint64_t Offset =
6231db9f3b2SDimitry Andric       Entry.DieEntry->getOffset() + getULEB128Size(Abbrev->getCode());
6241db9f3b2SDimitry Andric 
6251db9f3b2SDimitry Andric   // For each DIE attribute...
6261db9f3b2SDimitry Andric   for (const auto &AttrSpec : Abbrev->attributes()) {
6271db9f3b2SDimitry Andric     DWARFFormValue Val(AttrSpec.Form);
6281db9f3b2SDimitry Andric     if (!Val.isFormClass(DWARFFormValue::FC_Reference) ||
6291db9f3b2SDimitry Andric         AttrSpec.Attr == dwarf::DW_AT_sibling) {
6301db9f3b2SDimitry Andric       DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
6311db9f3b2SDimitry Andric                                 Unit.getFormParams());
6321db9f3b2SDimitry Andric       continue;
6331db9f3b2SDimitry Andric     }
6341db9f3b2SDimitry Andric     Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);
6351db9f3b2SDimitry Andric 
6361db9f3b2SDimitry Andric     // Resolve reference.
6371db9f3b2SDimitry Andric     std::optional<UnitEntryPairTy> RefDie = Entry.CU->resolveDIEReference(
6381db9f3b2SDimitry Andric         Val, InterCUProcessingStarted
6391db9f3b2SDimitry Andric                  ? ResolveInterCUReferencesMode::Resolve
6401db9f3b2SDimitry Andric                  : ResolveInterCUReferencesMode::AvoidResolving);
6411db9f3b2SDimitry Andric     if (!RefDie) {
6421db9f3b2SDimitry Andric       Entry.CU->warn("cann't find referenced DIE", Entry.DieEntry);
6431db9f3b2SDimitry Andric       continue;
6441db9f3b2SDimitry Andric     }
6451db9f3b2SDimitry Andric 
6461db9f3b2SDimitry Andric     if (!RefDie->DieEntry) {
6471db9f3b2SDimitry Andric       // Delay resolving reference.
6481db9f3b2SDimitry Andric       RefDie->CU->setInterconnectedCU();
6491db9f3b2SDimitry Andric       Entry.CU->setInterconnectedCU();
6501db9f3b2SDimitry Andric       HasNewInterconnectedCUs = true;
6511db9f3b2SDimitry Andric       return false;
6521db9f3b2SDimitry Andric     }
6531db9f3b2SDimitry Andric 
6541db9f3b2SDimitry Andric     assert((Entry.CU->getUniqueID() == RefDie->CU->getUniqueID() ||
6551db9f3b2SDimitry Andric             InterCUProcessingStarted) &&
6561db9f3b2SDimitry Andric            "Inter-CU reference while inter-CU processing is not started");
6571db9f3b2SDimitry Andric 
6581db9f3b2SDimitry Andric     CompileUnit::DIEInfo &RefInfo = RefDie->CU->getDIEInfo(RefDie->DieEntry);
6591db9f3b2SDimitry Andric     if (!RefInfo.getODRAvailable())
6601db9f3b2SDimitry Andric       Action = LiveRootWorklistActionTy::MarkLiveEntryRec;
6611db9f3b2SDimitry Andric     else if (RefInfo.getODRAvailable() &&
6621db9f3b2SDimitry Andric              llvm::is_contained(getODRAttributes(), AttrSpec.Attr))
6631db9f3b2SDimitry Andric       // Note: getODRAttributes does not include DW_AT_containing_type.
6641db9f3b2SDimitry Andric       // It should be OK as we do getRootForSpecifiedEntry(). So any containing
6651db9f3b2SDimitry Andric       // type would be found as the root for the entry.
6661db9f3b2SDimitry Andric       Action = LiveRootWorklistActionTy::MarkTypeEntryRec;
6671db9f3b2SDimitry Andric     else if (isLiveAction(Action))
6681db9f3b2SDimitry Andric       Action = LiveRootWorklistActionTy::MarkLiveEntryRec;
6691db9f3b2SDimitry Andric     else
6701db9f3b2SDimitry Andric       Action = LiveRootWorklistActionTy::MarkTypeEntryRec;
6711db9f3b2SDimitry Andric 
6721db9f3b2SDimitry Andric     if (AttrSpec.Attr == dwarf::DW_AT_import) {
6731db9f3b2SDimitry Andric       if (isNamespaceLikeEntry(RefDie->DieEntry)) {
6741db9f3b2SDimitry Andric         addActionToRootEntriesWorkList(
6751db9f3b2SDimitry Andric             isTypeAction(Action)
6761db9f3b2SDimitry Andric                 ? LiveRootWorklistActionTy::MarkSingleTypeEntry
6771db9f3b2SDimitry Andric                 : LiveRootWorklistActionTy::MarkSingleLiveEntry,
6781db9f3b2SDimitry Andric             *RefDie, RootEntry);
6791db9f3b2SDimitry Andric         continue;
6801db9f3b2SDimitry Andric       }
6811db9f3b2SDimitry Andric 
6821db9f3b2SDimitry Andric       addActionToRootEntriesWorkList(Action, *RefDie, RootEntry);
6831db9f3b2SDimitry Andric       continue;
6841db9f3b2SDimitry Andric     }
6851db9f3b2SDimitry Andric 
6861db9f3b2SDimitry Andric     UnitEntryPairTy RootForReferencedDie = getRootForSpecifiedEntry(*RefDie);
6871db9f3b2SDimitry Andric     addActionToRootEntriesWorkList(Action, RootForReferencedDie, RootEntry);
6881db9f3b2SDimitry Andric   }
6891db9f3b2SDimitry Andric 
6901db9f3b2SDimitry Andric   return true;
6911db9f3b2SDimitry Andric }
6921db9f3b2SDimitry Andric 
6931db9f3b2SDimitry Andric UnitEntryPairTy
getRootForSpecifiedEntry(UnitEntryPairTy Entry)6941db9f3b2SDimitry Andric DependencyTracker::getRootForSpecifiedEntry(UnitEntryPairTy Entry) {
6951db9f3b2SDimitry Andric   UnitEntryPairTy Result = Entry;
6961db9f3b2SDimitry Andric 
6971db9f3b2SDimitry Andric   do {
6981db9f3b2SDimitry Andric     switch (Entry.DieEntry->getTag()) {
6991db9f3b2SDimitry Andric     case dwarf::DW_TAG_subprogram:
7001db9f3b2SDimitry Andric     case dwarf::DW_TAG_label:
7011db9f3b2SDimitry Andric     case dwarf::DW_TAG_variable:
7021db9f3b2SDimitry Andric     case dwarf::DW_TAG_constant: {
7031db9f3b2SDimitry Andric       return Result;
7041db9f3b2SDimitry Andric     } break;
7051db9f3b2SDimitry Andric 
7061db9f3b2SDimitry Andric     default: {
7071db9f3b2SDimitry Andric       // Nothing to do.
7081db9f3b2SDimitry Andric     }
7091db9f3b2SDimitry Andric     }
7101db9f3b2SDimitry Andric 
7111db9f3b2SDimitry Andric     std::optional<uint32_t> ParentIdx = Result.DieEntry->getParentIdx();
7121db9f3b2SDimitry Andric     if (!ParentIdx)
7131db9f3b2SDimitry Andric       return Result;
7141db9f3b2SDimitry Andric 
7151db9f3b2SDimitry Andric     const DWARFDebugInfoEntry *ParentEntry =
7161db9f3b2SDimitry Andric         Result.CU->getDebugInfoEntry(*ParentIdx);
7171db9f3b2SDimitry Andric     if (isNamespaceLikeEntry(ParentEntry))
7181db9f3b2SDimitry Andric       break;
7191db9f3b2SDimitry Andric     Result.DieEntry = ParentEntry;
7201db9f3b2SDimitry Andric   } while (true);
7211db9f3b2SDimitry Andric 
7221db9f3b2SDimitry Andric   return Result;
7231db9f3b2SDimitry Andric }
7241db9f3b2SDimitry Andric 
isLiveVariableEntry(const UnitEntryPairTy & Entry,bool IsLiveParent)7251db9f3b2SDimitry Andric bool DependencyTracker::isLiveVariableEntry(const UnitEntryPairTy &Entry,
7261db9f3b2SDimitry Andric                                             bool IsLiveParent) {
7271db9f3b2SDimitry Andric   DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
7281db9f3b2SDimitry Andric   CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(DIE);
7291db9f3b2SDimitry Andric 
7301db9f3b2SDimitry Andric   if (Info.getTrackLiveness()) {
7311db9f3b2SDimitry Andric     const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
7321db9f3b2SDimitry Andric 
7331db9f3b2SDimitry Andric     if (!Info.getIsInFunctionScope() &&
7341db9f3b2SDimitry Andric         Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
7351db9f3b2SDimitry Andric       // Global variables with constant value can always be kept.
7361db9f3b2SDimitry Andric     } else {
7371db9f3b2SDimitry Andric       // See if there is a relocation to a valid debug map entry inside this
7381db9f3b2SDimitry Andric       // variable's location. The order is important here. We want to always
7391db9f3b2SDimitry Andric       // check if the variable has a location expression address. However, we
7401db9f3b2SDimitry Andric       // don't want a static variable in a function to force us to keep the
7411db9f3b2SDimitry Andric       // enclosing function, unless requested explicitly.
7421db9f3b2SDimitry Andric       std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
7431db9f3b2SDimitry Andric           Entry.CU->getContaingFile().Addresses->getVariableRelocAdjustment(
744*7a6dacacSDimitry Andric               DIE, Entry.CU->getGlobalData().getOptions().Verbose);
7451db9f3b2SDimitry Andric 
7461db9f3b2SDimitry Andric       if (LocExprAddrAndRelocAdjustment.first)
7471db9f3b2SDimitry Andric         Info.setHasAnAddress();
7481db9f3b2SDimitry Andric 
7491db9f3b2SDimitry Andric       if (!LocExprAddrAndRelocAdjustment.second)
7501db9f3b2SDimitry Andric         return false;
7511db9f3b2SDimitry Andric 
7521db9f3b2SDimitry Andric       if (!IsLiveParent && Info.getIsInFunctionScope() &&
7531db9f3b2SDimitry Andric           !Entry.CU->getGlobalData().getOptions().KeepFunctionForStatic)
7541db9f3b2SDimitry Andric         return false;
7551db9f3b2SDimitry Andric     }
7561db9f3b2SDimitry Andric   }
7571db9f3b2SDimitry Andric   Info.setHasAnAddress();
7581db9f3b2SDimitry Andric 
7591db9f3b2SDimitry Andric   if (Entry.CU->getGlobalData().getOptions().Verbose) {
7601db9f3b2SDimitry Andric     outs() << "Keeping variable DIE:";
7611db9f3b2SDimitry Andric     DIDumpOptions DumpOpts;
7621db9f3b2SDimitry Andric     DumpOpts.ChildRecurseDepth = 0;
7631db9f3b2SDimitry Andric     DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
7641db9f3b2SDimitry Andric     DIE.dump(outs(), 8 /* Indent */, DumpOpts);
7651db9f3b2SDimitry Andric   }
7661db9f3b2SDimitry Andric 
7671db9f3b2SDimitry Andric   return true;
7681db9f3b2SDimitry Andric }
7691db9f3b2SDimitry Andric 
isLiveSubprogramEntry(const UnitEntryPairTy & Entry)7701db9f3b2SDimitry Andric bool DependencyTracker::isLiveSubprogramEntry(const UnitEntryPairTy &Entry) {
7711db9f3b2SDimitry Andric   DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
7721db9f3b2SDimitry Andric   CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
7731db9f3b2SDimitry Andric   std::optional<DWARFFormValue> LowPCVal = DIE.find(dwarf::DW_AT_low_pc);
7741db9f3b2SDimitry Andric 
7751db9f3b2SDimitry Andric   std::optional<uint64_t> LowPc;
7761db9f3b2SDimitry Andric   std::optional<uint64_t> HighPc;
7771db9f3b2SDimitry Andric   std::optional<int64_t> RelocAdjustment;
7781db9f3b2SDimitry Andric   if (Info.getTrackLiveness()) {
7791db9f3b2SDimitry Andric     LowPc = dwarf::toAddress(LowPCVal);
7801db9f3b2SDimitry Andric     if (!LowPc)
7811db9f3b2SDimitry Andric       return false;
7821db9f3b2SDimitry Andric 
7831db9f3b2SDimitry Andric     Info.setHasAnAddress();
7841db9f3b2SDimitry Andric 
7851db9f3b2SDimitry Andric     RelocAdjustment =
7861db9f3b2SDimitry Andric         Entry.CU->getContaingFile().Addresses->getSubprogramRelocAdjustment(
787*7a6dacacSDimitry Andric             DIE, Entry.CU->getGlobalData().getOptions().Verbose);
7881db9f3b2SDimitry Andric     if (!RelocAdjustment)
7891db9f3b2SDimitry Andric       return false;
7901db9f3b2SDimitry Andric 
7911db9f3b2SDimitry Andric     if (DIE.getTag() == dwarf::DW_TAG_subprogram) {
7921db9f3b2SDimitry Andric       // Validate subprogram address range.
7931db9f3b2SDimitry Andric 
7941db9f3b2SDimitry Andric       HighPc = DIE.getHighPC(*LowPc);
7951db9f3b2SDimitry Andric       if (!HighPc) {
7961db9f3b2SDimitry Andric         Entry.CU->warn("function without high_pc. Range will be discarded.",
7971db9f3b2SDimitry Andric                        &DIE);
7981db9f3b2SDimitry Andric         return false;
7991db9f3b2SDimitry Andric       }
8001db9f3b2SDimitry Andric 
8011db9f3b2SDimitry Andric       if (*LowPc > *HighPc) {
8021db9f3b2SDimitry Andric         Entry.CU->warn("low_pc greater than high_pc. Range will be discarded.",
8031db9f3b2SDimitry Andric                        &DIE);
8041db9f3b2SDimitry Andric         return false;
8051db9f3b2SDimitry Andric       }
8061db9f3b2SDimitry Andric     } else if (DIE.getTag() == dwarf::DW_TAG_label) {
8071db9f3b2SDimitry Andric       if (Entry.CU->hasLabelAt(*LowPc))
8081db9f3b2SDimitry Andric         return false;
8091db9f3b2SDimitry Andric 
8101db9f3b2SDimitry Andric       // FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider
8111db9f3b2SDimitry Andric       // labels that don't fall into the CU's aranges. This is wrong IMO. Debug
8121db9f3b2SDimitry Andric       // info generation bugs aside, this is really wrong in the case of labels,
8131db9f3b2SDimitry Andric       // where a label marking the end of a function will have a PC == CU's
8141db9f3b2SDimitry Andric       // high_pc.
8151db9f3b2SDimitry Andric       if (dwarf::toAddress(Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_high_pc))
8161db9f3b2SDimitry Andric               .value_or(UINT64_MAX) <= LowPc)
8171db9f3b2SDimitry Andric         return false;
8181db9f3b2SDimitry Andric 
8191db9f3b2SDimitry Andric       Entry.CU->addLabelLowPc(*LowPc, *RelocAdjustment);
8201db9f3b2SDimitry Andric     }
8211db9f3b2SDimitry Andric   } else
8221db9f3b2SDimitry Andric     Info.setHasAnAddress();
8231db9f3b2SDimitry Andric 
8241db9f3b2SDimitry Andric   if (Entry.CU->getGlobalData().getOptions().Verbose) {
8251db9f3b2SDimitry Andric     outs() << "Keeping subprogram DIE:";
8261db9f3b2SDimitry Andric     DIDumpOptions DumpOpts;
8271db9f3b2SDimitry Andric     DumpOpts.ChildRecurseDepth = 0;
8281db9f3b2SDimitry Andric     DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
8291db9f3b2SDimitry Andric     DIE.dump(outs(), 8 /* Indent */, DumpOpts);
8301db9f3b2SDimitry Andric   }
8311db9f3b2SDimitry Andric 
8321db9f3b2SDimitry Andric   if (!Info.getTrackLiveness() || DIE.getTag() == dwarf::DW_TAG_label)
8331db9f3b2SDimitry Andric     return true;
8341db9f3b2SDimitry Andric 
8351db9f3b2SDimitry Andric   Entry.CU->addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);
8361db9f3b2SDimitry Andric   return true;
8371db9f3b2SDimitry Andric }
838