[TableGen] Fix validateOperandClass for non Phyical Reg (#118146)
[llvm-project.git] / llvm / lib / DWARFLinker / Parallel / DependencyTracker.cpp
blob5e30d9a8b6690e152cd66e9ff8c750e8d63c0320
1 //=== DependencyTracker.cpp -----------------------------------------------===//
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 //===----------------------------------------------------------------------===//
9 #include "DependencyTracker.h"
10 #include "llvm/Support/FormatVariadic.h"
12 using namespace llvm;
13 using namespace dwarf_linker;
14 using namespace dwarf_linker::parallel;
16 /// A broken link in the keep chain. By recording both the parent and the child
17 /// we can show only broken links for DIEs with multiple children.
18 struct BrokenLink {
19 BrokenLink(DWARFDie Parent, DWARFDie Child, const char *Message)
20 : Parent(Parent), Child(Child), Message(Message) {}
21 DWARFDie Parent;
22 DWARFDie Child;
23 std::string Message;
26 /// Verify the keep chain by looking for DIEs that are kept but who's parent
27 /// isn't.
28 void DependencyTracker::verifyKeepChain() {
29 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
30 SmallVector<DWARFDie> Worklist;
31 Worklist.push_back(CU.getOrigUnit().getUnitDIE());
33 // List of broken links.
34 SmallVector<BrokenLink> BrokenLinks;
36 while (!Worklist.empty()) {
37 const DWARFDie Current = Worklist.back();
38 Worklist.pop_back();
40 if (!Current.isValid())
41 continue;
43 CompileUnit::DIEInfo &CurrentInfo =
44 CU.getDIEInfo(Current.getDebugInfoEntry());
45 const bool ParentPlainDieIsKept = CurrentInfo.needToKeepInPlainDwarf();
46 const bool ParentTypeDieIsKept = CurrentInfo.needToPlaceInTypeTable();
48 for (DWARFDie Child : reverse(Current.children())) {
49 Worklist.push_back(Child);
51 CompileUnit::DIEInfo &ChildInfo =
52 CU.getDIEInfo(Child.getDebugInfoEntry());
53 const bool ChildPlainDieIsKept = ChildInfo.needToKeepInPlainDwarf();
54 const bool ChildTypeDieIsKept = ChildInfo.needToPlaceInTypeTable();
56 if (!ParentPlainDieIsKept && ChildPlainDieIsKept)
57 BrokenLinks.emplace_back(Current, Child,
58 "Found invalid link in keep chain");
60 if (Child.getTag() == dwarf::DW_TAG_subprogram) {
61 if (!ChildInfo.getKeep() && isLiveSubprogramEntry(UnitEntryPairTy(
62 &CU, Child.getDebugInfoEntry()))) {
63 BrokenLinks.emplace_back(Current, Child,
64 "Live subprogram is not marked as kept");
68 if (!ChildInfo.getODRAvailable()) {
69 assert(!ChildTypeDieIsKept);
70 continue;
73 if (!ParentTypeDieIsKept && ChildTypeDieIsKept)
74 BrokenLinks.emplace_back(Current, Child,
75 "Found invalid link in keep chain");
77 if (CurrentInfo.getIsInAnonNamespaceScope() &&
78 ChildInfo.needToPlaceInTypeTable()) {
79 BrokenLinks.emplace_back(Current, Child,
80 "Found invalid placement marking for member "
81 "of anonymous namespace");
86 if (!BrokenLinks.empty()) {
87 for (BrokenLink Link : BrokenLinks) {
88 errs() << "\n=================================\n";
89 WithColor::error() << formatv("{0} between {1:x} and {2:x}", Link.Message,
90 Link.Parent.getOffset(),
91 Link.Child.getOffset());
93 errs() << "\nParent:";
94 Link.Parent.dump(errs(), 0, {});
95 errs() << "\n";
96 CU.getDIEInfo(Link.Parent).dump();
98 errs() << "\nChild:";
99 Link.Child.dump(errs(), 2, {});
100 errs() << "\n";
101 CU.getDIEInfo(Link.Child).dump();
103 report_fatal_error("invalid keep chain");
105 #endif
108 bool DependencyTracker::resolveDependenciesAndMarkLiveness(
109 bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
110 RootEntriesWorkList.clear();
112 // Search for live root DIEs.
113 CompileUnit::DIEInfo &CUInfo = CU.getDIEInfo(CU.getDebugInfoEntry(0));
114 CUInfo.setPlacement(CompileUnit::PlainDwarf);
115 collectRootsToKeep(UnitEntryPairTy{&CU, CU.getDebugInfoEntry(0)},
116 std::nullopt, false);
118 // Mark live DIEs as kept.
119 return markCollectedLiveRootsAsKept(InterCUProcessingStarted,
120 HasNewInterconnectedCUs);
123 void DependencyTracker::addActionToRootEntriesWorkList(
124 LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry,
125 std::optional<UnitEntryPairTy> ReferencedBy) {
126 if (ReferencedBy) {
127 RootEntriesWorkList.emplace_back(Action, Entry, *ReferencedBy);
128 return;
131 RootEntriesWorkList.emplace_back(Action, Entry);
134 void DependencyTracker::collectRootsToKeep(
135 const UnitEntryPairTy &Entry, std::optional<UnitEntryPairTy> ReferencedBy,
136 bool IsLiveParent) {
137 for (const DWARFDebugInfoEntry *CurChild =
138 Entry.CU->getFirstChildEntry(Entry.DieEntry);
139 CurChild && CurChild->getAbbreviationDeclarationPtr();
140 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
141 UnitEntryPairTy ChildEntry(Entry.CU, CurChild);
142 CompileUnit::DIEInfo &ChildInfo = Entry.CU->getDIEInfo(CurChild);
144 bool IsLiveChild = false;
146 switch (CurChild->getTag()) {
147 case dwarf::DW_TAG_label: {
148 IsLiveChild = isLiveSubprogramEntry(ChildEntry);
150 // Keep label referencing live address.
151 // Keep label which is child of live parent entry.
152 if (IsLiveChild || (IsLiveParent && ChildInfo.getHasAnAddress())) {
153 addActionToRootEntriesWorkList(
154 LiveRootWorklistActionTy::MarkLiveEntryRec, ChildEntry,
155 ReferencedBy);
157 } break;
158 case dwarf::DW_TAG_subprogram: {
159 IsLiveChild = isLiveSubprogramEntry(ChildEntry);
161 // Keep subprogram referencing live address.
162 if (IsLiveChild) {
163 // If subprogram is in module scope and this module allows ODR
164 // deduplication set "TypeTable" placement, otherwise set "" placement
165 LiveRootWorklistActionTy Action =
166 (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
167 ? LiveRootWorklistActionTy::MarkTypeEntryRec
168 : LiveRootWorklistActionTy::MarkLiveEntryRec;
170 addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
172 } break;
173 case dwarf::DW_TAG_constant:
174 case dwarf::DW_TAG_variable: {
175 IsLiveChild = isLiveVariableEntry(ChildEntry, IsLiveParent);
177 // Keep variable referencing live address.
178 if (IsLiveChild) {
179 // If variable is in module scope and this module allows ODR
180 // deduplication set "TypeTable" placement, otherwise set "" placement
182 LiveRootWorklistActionTy Action =
183 (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
184 ? LiveRootWorklistActionTy::MarkTypeEntryRec
185 : LiveRootWorklistActionTy::MarkLiveEntryRec;
187 addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
189 } break;
190 case dwarf::DW_TAG_base_type: {
191 // Always keep base types.
192 addActionToRootEntriesWorkList(
193 LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,
194 ReferencedBy);
195 } break;
196 case dwarf::DW_TAG_imported_module:
197 case dwarf::DW_TAG_imported_declaration:
198 case dwarf::DW_TAG_imported_unit: {
199 // Always keep DIEs having DW_AT_import attribute.
200 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_compile_unit) {
201 addActionToRootEntriesWorkList(
202 LiveRootWorklistActionTy::MarkSingleLiveEntry, ChildEntry,
203 ReferencedBy);
204 break;
207 addActionToRootEntriesWorkList(
208 LiveRootWorklistActionTy::MarkSingleTypeEntry, ChildEntry,
209 ReferencedBy);
210 } break;
211 case dwarf::DW_TAG_type_unit:
212 case dwarf::DW_TAG_partial_unit:
213 case dwarf::DW_TAG_compile_unit: {
214 llvm_unreachable("Called for incorrect DIE");
215 } break;
216 default:
217 // Nothing to do.
218 break;
221 collectRootsToKeep(ChildEntry, ReferencedBy, IsLiveChild || IsLiveParent);
225 bool DependencyTracker::markCollectedLiveRootsAsKept(
226 bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
227 bool Res = true;
229 // Mark roots as kept.
230 while (!RootEntriesWorkList.empty()) {
231 LiveRootWorklistItemTy Root = RootEntriesWorkList.pop_back_val();
233 if (markDIEEntryAsKeptRec(Root.getAction(), Root.getRootEntry(),
234 Root.getRootEntry(), InterCUProcessingStarted,
235 HasNewInterconnectedCUs)) {
236 if (Root.hasReferencedByOtherEntry())
237 Dependencies.push_back(Root);
238 } else
239 Res = false;
242 return Res;
245 bool DependencyTracker::updateDependenciesCompleteness() {
246 bool HasNewDependency = false;
247 for (LiveRootWorklistItemTy &Root : Dependencies) {
248 assert(Root.hasReferencedByOtherEntry() &&
249 "Root entry without dependency inside the dependencies list");
251 UnitEntryPairTy RootEntry = Root.getRootEntry();
252 CompileUnit::DIEInfo &RootInfo =
253 RootEntry.CU->getDIEInfo(RootEntry.DieEntry);
255 UnitEntryPairTy ReferencedByEntry = Root.getReferencedByEntry();
256 CompileUnit::DIEInfo &ReferencedByInfo =
257 ReferencedByEntry.CU->getDIEInfo(ReferencedByEntry.DieEntry);
259 if (!RootInfo.needToPlaceInTypeTable() &&
260 ReferencedByInfo.needToPlaceInTypeTable()) {
261 HasNewDependency = true;
262 setPlainDwarfPlacementRec(ReferencedByEntry);
264 // FIXME: we probably need to update getKeepTypeChildren status for
265 // parents of *Root.ReferencedBy.
269 return HasNewDependency;
272 void DependencyTracker::setPlainDwarfPlacementRec(
273 const UnitEntryPairTy &Entry) {
274 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
275 if (Info.getPlacement() == CompileUnit::PlainDwarf &&
276 !Info.getKeepTypeChildren())
277 return;
279 Info.setPlacement(CompileUnit::PlainDwarf);
280 Info.unsetKeepTypeChildren();
281 markParentsAsKeepingChildren(Entry);
283 for (const DWARFDebugInfoEntry *CurChild =
284 Entry.CU->getFirstChildEntry(Entry.DieEntry);
285 CurChild && CurChild->getAbbreviationDeclarationPtr();
286 CurChild = Entry.CU->getSiblingEntry(CurChild))
287 setPlainDwarfPlacementRec(UnitEntryPairTy{Entry.CU, CurChild});
290 static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry) {
291 switch (Entry->getTag()) {
292 case dwarf::DW_TAG_compile_unit:
293 case dwarf::DW_TAG_module:
294 case dwarf::DW_TAG_namespace:
295 return true;
297 default:
298 return false;
302 bool isAlreadyMarked(const CompileUnit::DIEInfo &Info,
303 CompileUnit::DieOutputPlacement NewPlacement) {
304 if (!Info.getKeep())
305 return false;
307 switch (NewPlacement) {
308 case CompileUnit::TypeTable:
309 return Info.needToPlaceInTypeTable();
311 case CompileUnit::PlainDwarf:
312 return Info.needToKeepInPlainDwarf();
314 case CompileUnit::Both:
315 return Info.needToPlaceInTypeTable() && Info.needToKeepInPlainDwarf();
317 case CompileUnit::NotSet:
318 llvm_unreachable("Unset placement type is specified.");
321 llvm_unreachable("Unknown CompileUnit::DieOutputPlacement enum");
324 bool isAlreadyMarked(const UnitEntryPairTy &Entry,
325 CompileUnit::DieOutputPlacement NewPlacement) {
326 return isAlreadyMarked(Entry.CU->getDIEInfo(Entry.DieEntry), NewPlacement);
329 void DependencyTracker::markParentsAsKeepingChildren(
330 const UnitEntryPairTy &Entry) {
331 if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
332 return;
334 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
335 bool NeedKeepTypeChildren = Info.needToPlaceInTypeTable();
336 bool NeedKeepPlainChildren = Info.needToKeepInPlainDwarf();
338 bool AreTypeParentsDone = !NeedKeepTypeChildren;
339 bool ArePlainParentsDone = !NeedKeepPlainChildren;
341 // Mark parents as 'Keep*Children'.
342 std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx();
343 while (ParentIdx) {
344 const DWARFDebugInfoEntry *ParentEntry =
345 Entry.CU->getDebugInfoEntry(*ParentIdx);
346 CompileUnit::DIEInfo &ParentInfo = Entry.CU->getDIEInfo(*ParentIdx);
348 if (!AreTypeParentsDone && NeedKeepTypeChildren) {
349 if (ParentInfo.getKeepTypeChildren())
350 AreTypeParentsDone = true;
351 else {
352 bool AddToWorklist = !isAlreadyMarked(
353 ParentInfo, CompileUnit::DieOutputPlacement::TypeTable);
354 ParentInfo.setKeepTypeChildren();
355 if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
356 addActionToRootEntriesWorkList(
357 LiveRootWorklistActionTy::MarkTypeChildrenRec,
358 UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
363 if (!ArePlainParentsDone && NeedKeepPlainChildren) {
364 if (ParentInfo.getKeepPlainChildren())
365 ArePlainParentsDone = true;
366 else {
367 bool AddToWorklist = !isAlreadyMarked(
368 ParentInfo, CompileUnit::DieOutputPlacement::PlainDwarf);
369 ParentInfo.setKeepPlainChildren();
370 if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
371 addActionToRootEntriesWorkList(
372 LiveRootWorklistActionTy::MarkLiveChildrenRec,
373 UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
378 if (AreTypeParentsDone && ArePlainParentsDone)
379 break;
381 ParentIdx = ParentEntry->getParentIdx();
385 // This function tries to set specified \p Placement for the \p Entry.
386 // Depending on the concrete entry, the placement could be:
387 // a) changed to another.
388 // b) joined with current entry placement.
389 // c) set as requested.
390 static CompileUnit::DieOutputPlacement
391 getFinalPlacementForEntry(const UnitEntryPairTy &Entry,
392 CompileUnit::DieOutputPlacement Placement) {
393 assert((Placement != CompileUnit::NotSet) && "Placement is not set");
394 CompileUnit::DIEInfo &EntryInfo = Entry.CU->getDIEInfo(Entry.DieEntry);
396 if (!EntryInfo.getODRAvailable())
397 return CompileUnit::PlainDwarf;
399 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_variable) {
400 // Do not put variable into the "TypeTable" and "PlainDwarf" at the same
401 // time.
402 if (EntryInfo.getPlacement() == CompileUnit::PlainDwarf ||
403 EntryInfo.getPlacement() == CompileUnit::Both)
404 return CompileUnit::PlainDwarf;
406 if (Placement == CompileUnit::PlainDwarf || Placement == CompileUnit::Both)
407 return CompileUnit::PlainDwarf;
410 switch (EntryInfo.getPlacement()) {
411 case CompileUnit::NotSet:
412 return Placement;
414 case CompileUnit::TypeTable:
415 return Placement == CompileUnit::PlainDwarf ? CompileUnit::Both : Placement;
417 case CompileUnit::PlainDwarf:
418 return Placement == CompileUnit::TypeTable ? CompileUnit::Both : Placement;
420 case CompileUnit::Both:
421 return CompileUnit::Both;
424 llvm_unreachable("Unknown placement type.");
425 return Placement;
428 bool DependencyTracker::markDIEEntryAsKeptRec(
429 LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
430 const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
431 std::atomic<bool> &HasNewInterconnectedCUs) {
432 if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
433 return true;
435 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
437 // Calculate final placement placement.
438 CompileUnit::DieOutputPlacement Placement = getFinalPlacementForEntry(
439 Entry,
440 isLiveAction(Action) ? CompileUnit::PlainDwarf : CompileUnit::TypeTable);
441 assert((Info.getODRAvailable() || isLiveAction(Action) ||
442 Placement == CompileUnit::PlainDwarf) &&
443 "Wrong kind of placement for ODR unavailable entry");
445 if (!isChildrenAction(Action))
446 if (isAlreadyMarked(Entry, Placement))
447 return true;
449 // Mark current DIE as kept.
450 Info.setKeep();
451 Info.setPlacement(Placement);
453 // Set keep children property for parents.
454 markParentsAsKeepingChildren(Entry);
456 UnitEntryPairTy FinalRootEntry =
457 Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram ? Entry : RootEntry;
459 // Analyse referenced DIEs.
460 bool Res = true;
461 if (!maybeAddReferencedRoots(Action, FinalRootEntry, Entry,
462 InterCUProcessingStarted,
463 HasNewInterconnectedCUs))
464 Res = false;
466 // Return if we do not need to process children.
467 if (isSingleAction(Action))
468 return Res;
470 // Process children.
471 // Check for subprograms special case.
472 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram &&
473 Info.getODRAvailable()) {
474 // Subprograms is a special case. As it can be root for type DIEs
475 // and itself may be subject to move into the artificial type unit.
476 // a) Non removable children(like DW_TAG_formal_parameter) should always
477 // be cloned. They are placed into the "PlainDwarf" and into the
478 // "TypeTable".
479 // b) ODR deduplication candidates(type DIEs) children should not be put
480 // into the "PlainDwarf".
481 // c) Children keeping addresses and locations(like DW_TAG_call_site)
482 // should not be put into the "TypeTable".
483 for (const DWARFDebugInfoEntry *CurChild =
484 Entry.CU->getFirstChildEntry(Entry.DieEntry);
485 CurChild && CurChild->getAbbreviationDeclarationPtr();
486 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
487 CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(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())
495 continue;
496 } break;
498 // Entries having following tags could not be removed from the subprogram.
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: {
510 // Go to the default child handling.
511 } break;
513 default: {
514 bool ChildIsTypeTableCandidate = isTypeTableCandidate(CurChild);
516 // Skip child marked to be copied into the artificial type unit.
517 if (isLiveAction(Action) && ChildIsTypeTableCandidate)
518 continue;
520 // Skip child marked to be copied into the plain unit.
521 if (isTypeAction(Action) && !ChildIsTypeTableCandidate)
522 continue;
524 // Go to the default child handling.
525 } break;
528 if (!markDIEEntryAsKeptRec(
529 Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
530 InterCUProcessingStarted, HasNewInterconnectedCUs))
531 Res = false;
534 return Res;
537 // Recursively process children.
538 for (const DWARFDebugInfoEntry *CurChild =
539 Entry.CU->getFirstChildEntry(Entry.DieEntry);
540 CurChild && CurChild->getAbbreviationDeclarationPtr();
541 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
542 CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(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())
549 continue;
550 } break;
551 default:
552 break; // Nothing to do.
555 if (!markDIEEntryAsKeptRec(
556 Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
557 InterCUProcessingStarted, HasNewInterconnectedCUs))
558 Res = false;
561 return Res;
564 bool DependencyTracker::isTypeTableCandidate(
565 const DWARFDebugInfoEntry *DIEEntry) {
566 switch (DIEEntry->getTag()) {
567 default:
568 return false;
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:
608 return true;
612 bool DependencyTracker::maybeAddReferencedRoots(
613 LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
614 const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
615 std::atomic<bool> &HasNewInterconnectedCUs) {
616 const auto *Abbrev = Entry.DieEntry->getAbbreviationDeclarationPtr();
617 if (Abbrev == nullptr)
618 return true;
620 DWARFUnit &Unit = Entry.CU->getOrigUnit();
621 DWARFDataExtractor Data = Unit.getDebugInfoExtractor();
622 uint64_t Offset =
623 Entry.DieEntry->getOffset() + getULEB128Size(Abbrev->getCode());
625 // For each DIE attribute...
626 for (const auto &AttrSpec : Abbrev->attributes()) {
627 DWARFFormValue Val(AttrSpec.Form);
628 if (!Val.isFormClass(DWARFFormValue::FC_Reference) ||
629 AttrSpec.Attr == dwarf::DW_AT_sibling) {
630 DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
631 Unit.getFormParams());
632 continue;
634 Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);
636 // Resolve reference.
637 std::optional<UnitEntryPairTy> RefDie = Entry.CU->resolveDIEReference(
638 Val, InterCUProcessingStarted
639 ? ResolveInterCUReferencesMode::Resolve
640 : ResolveInterCUReferencesMode::AvoidResolving);
641 if (!RefDie) {
642 Entry.CU->warn("cann't find referenced DIE", Entry.DieEntry);
643 continue;
646 if (!RefDie->DieEntry) {
647 // Delay resolving reference.
648 RefDie->CU->setInterconnectedCU();
649 Entry.CU->setInterconnectedCU();
650 HasNewInterconnectedCUs = true;
651 return false;
654 assert((Entry.CU->getUniqueID() == RefDie->CU->getUniqueID() ||
655 InterCUProcessingStarted) &&
656 "Inter-CU reference while inter-CU processing is not started");
658 CompileUnit::DIEInfo &RefInfo = RefDie->CU->getDIEInfo(RefDie->DieEntry);
659 if (!RefInfo.getODRAvailable())
660 Action = LiveRootWorklistActionTy::MarkLiveEntryRec;
661 else if (RefInfo.getODRAvailable() &&
662 llvm::is_contained(getODRAttributes(), AttrSpec.Attr))
663 // Note: getODRAttributes does not include DW_AT_containing_type.
664 // It should be OK as we do getRootForSpecifiedEntry(). So any containing
665 // type would be found as the root for the entry.
666 Action = LiveRootWorklistActionTy::MarkTypeEntryRec;
667 else if (isLiveAction(Action))
668 Action = LiveRootWorklistActionTy::MarkLiveEntryRec;
669 else
670 Action = LiveRootWorklistActionTy::MarkTypeEntryRec;
672 if (AttrSpec.Attr == dwarf::DW_AT_import) {
673 if (isNamespaceLikeEntry(RefDie->DieEntry)) {
674 addActionToRootEntriesWorkList(
675 isTypeAction(Action)
676 ? LiveRootWorklistActionTy::MarkSingleTypeEntry
677 : LiveRootWorklistActionTy::MarkSingleLiveEntry,
678 *RefDie, RootEntry);
679 continue;
682 addActionToRootEntriesWorkList(Action, *RefDie, RootEntry);
683 continue;
686 UnitEntryPairTy RootForReferencedDie = getRootForSpecifiedEntry(*RefDie);
687 addActionToRootEntriesWorkList(Action, RootForReferencedDie, RootEntry);
690 return true;
693 UnitEntryPairTy
694 DependencyTracker::getRootForSpecifiedEntry(UnitEntryPairTy Entry) {
695 UnitEntryPairTy Result = Entry;
697 do {
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: {
703 return Result;
704 } break;
706 default: {
707 // Nothing to do.
711 std::optional<uint32_t> ParentIdx = Result.DieEntry->getParentIdx();
712 if (!ParentIdx)
713 return Result;
715 const DWARFDebugInfoEntry *ParentEntry =
716 Result.CU->getDebugInfoEntry(*ParentIdx);
717 if (isNamespaceLikeEntry(ParentEntry))
718 break;
719 Result.DieEntry = ParentEntry;
720 } while (true);
722 return Result;
725 bool DependencyTracker::isLiveVariableEntry(const UnitEntryPairTy &Entry,
726 bool IsLiveParent) {
727 DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
728 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(DIE);
730 if (Info.getTrackLiveness()) {
731 const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
733 if (!Info.getIsInFunctionScope() &&
734 Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
735 // Global variables with constant value can always be kept.
736 } else {
737 // See if there is a relocation to a valid debug map entry inside this
738 // variable's location. The order is important here. We want to always
739 // check if the variable has a location expression address. However, we
740 // don't want a static variable in a function to force us to keep the
741 // enclosing function, unless requested explicitly.
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)
750 return false;
752 if (!IsLiveParent && Info.getIsInFunctionScope() &&
753 !Entry.CU->getGlobalData().getOptions().KeepFunctionForStatic)
754 return false;
757 Info.setHasAnAddress();
759 if (Entry.CU->getGlobalData().getOptions().Verbose) {
760 outs() << "Keeping variable DIE:";
761 DIDumpOptions DumpOpts;
762 DumpOpts.ChildRecurseDepth = 0;
763 DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
764 DIE.dump(outs(), 8 /* Indent */, DumpOpts);
767 return true;
770 bool DependencyTracker::isLiveSubprogramEntry(const UnitEntryPairTy &Entry) {
771 DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
772 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
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()) {
779 LowPc = dwarf::toAddress(LowPCVal);
780 if (!LowPc)
781 return false;
783 Info.setHasAnAddress();
785 RelocAdjustment =
786 Entry.CU->getContaingFile().Addresses->getSubprogramRelocAdjustment(
787 DIE, Entry.CU->getGlobalData().getOptions().Verbose);
788 if (!RelocAdjustment)
789 return false;
791 if (DIE.getTag() == dwarf::DW_TAG_subprogram) {
792 // Validate subprogram address range.
794 HighPc = DIE.getHighPC(*LowPc);
795 if (!HighPc) {
796 Entry.CU->warn("function without high_pc. Range will be discarded.",
797 &DIE);
798 return false;
801 if (*LowPc > *HighPc) {
802 Entry.CU->warn("low_pc greater than high_pc. Range will be discarded.",
803 &DIE);
804 return false;
806 } else if (DIE.getTag() == dwarf::DW_TAG_label) {
807 if (Entry.CU->hasLabelAt(*LowPc))
808 return false;
810 // FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider
811 // labels that don't fall into the CU's aranges. This is wrong IMO. Debug
812 // info generation bugs aside, this is really wrong in the case of labels,
813 // where a label marking the end of a function will have a PC == CU's
814 // high_pc.
815 if (dwarf::toAddress(Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_high_pc))
816 .value_or(UINT64_MAX) <= LowPc)
817 return false;
819 Entry.CU->addLabelLowPc(*LowPc, *RelocAdjustment);
821 } else
822 Info.setHasAnAddress();
824 if (Entry.CU->getGlobalData().getOptions().Verbose) {
825 outs() << "Keeping subprogram DIE:";
826 DIDumpOptions DumpOpts;
827 DumpOpts.ChildRecurseDepth = 0;
828 DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
829 DIE.dump(outs(), 8 /* Indent */, DumpOpts);
832 if (!Info.getTrackLiveness() || DIE.getTag() == dwarf::DW_TAG_label)
833 return true;
835 Entry.CU->addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);
836 return true;