LLVM 24.0.0git
DependencyTracker.cpp
Go to the documentation of this file.
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//===----------------------------------------------------------------------===//
8
9#include "DependencyTracker.h"
11
12using namespace llvm;
13using namespace dwarf_linker;
14using namespace dwarf_linker::parallel;
15
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.
25
26/// Verify the keep chain by looking for DIEs that are kept but who's parent
27/// isn't.
29#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
30 SmallVector<DWARFDie> Worklist;
31 Worklist.push_back(CU.getOrigUnit().getUnitDIE());
32
33 // List of broken links.
34 SmallVector<BrokenLink> BrokenLinks;
35
36 while (!Worklist.empty()) {
37 const DWARFDie Current = Worklist.back();
38 Worklist.pop_back();
39
40 if (!Current.isValid())
41 continue;
42
43 CompileUnit::DIEInfo &CurrentInfo =
44 CU.getDIEInfo(Current.getDebugInfoEntry());
45 const bool ParentPlainDieIsKept = CurrentInfo.needToKeepInPlainDwarf();
46 const bool ParentTypeDieIsKept = CurrentInfo.needToPlaceInTypeTable();
47
48 for (DWARFDie Child : reverse(Current.children())) {
49 Worklist.push_back(Child);
50
51 CompileUnit::DIEInfo &ChildInfo =
52 CU.getDIEInfo(Child.getDebugInfoEntry());
53 const bool ChildPlainDieIsKept = ChildInfo.needToKeepInPlainDwarf();
54 const bool ChildTypeDieIsKept = ChildInfo.needToPlaceInTypeTable();
55
56 if (!ParentPlainDieIsKept && ChildPlainDieIsKept)
57 BrokenLinks.emplace_back(Current, Child,
58 "Found invalid link in keep chain");
59
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");
65 }
66 }
67
68 if (!ChildInfo.getODRAvailable()) {
69 assert(!ChildTypeDieIsKept);
70 continue;
71 }
72
73 if (!ParentTypeDieIsKept && ChildTypeDieIsKept)
74 BrokenLinks.emplace_back(Current, Child,
75 "Found invalid link in keep chain");
76
77 if (CurrentInfo.getIsInAnonNamespaceScope() &&
78 ChildInfo.needToPlaceInTypeTable()) {
79 BrokenLinks.emplace_back(Current, Child,
80 "Found invalid placement marking for member "
81 "of anonymous namespace");
82 }
83 }
84 }
85
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());
92
93 errs() << "\nParent:";
94 Link.Parent.dump(errs(), 0, {});
95 errs() << "\n";
96 CU.getDIEInfo(Link.Parent).dump();
97
98 errs() << "\nChild:";
99 Link.Child.dump(errs(), 2, {});
100 errs() << "\n";
101 CU.getDIEInfo(Link.Child).dump();
102 }
103 report_fatal_error("invalid keep chain");
104 }
105#endif
106}
107
108static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry) {
109 switch (Entry->getTag()) {
110 case dwarf::DW_TAG_compile_unit:
111 case dwarf::DW_TAG_module:
112 case dwarf::DW_TAG_namespace:
113 return true;
114
115 default:
116 return false;
117 }
118}
119
121 bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
122 RootEntriesWorkList.clear();
123
124 // Search for live root DIEs.
125 CompileUnit::DIEInfo &CUInfo = CU.getDIEInfo(CU.getDebugInfoEntry(0));
127 collectRootsToKeep(UnitEntryPairTy{&CU, CU.getDebugInfoEntry(0)},
128 std::nullopt, false);
129
130 // Mark live DIEs as kept.
131 return markCollectedLiveRootsAsKept(InterCUProcessingStarted,
132 HasNewInterconnectedCUs);
133}
134
136 LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry,
137 std::optional<UnitEntryPairTy> ReferencedBy,
138 const DWARFDebugInfoEntry *ReferencedTypeDieEntry) {
139 if (ReferencedBy) {
140 RootEntriesWorkList.emplace_back(Action, Entry, *ReferencedBy,
141 ReferencedTypeDieEntry);
142 return;
143 }
144
145 RootEntriesWorkList.emplace_back(Action, Entry);
146}
147
149 const UnitEntryPairTy &Entry, std::optional<UnitEntryPairTy> ReferencedBy,
150 bool IsLiveParent) {
151 for (const DWARFDebugInfoEntry *CurChild =
152 Entry.CU->getFirstChildEntry(Entry.DieEntry);
153 CurChild && CurChild->getAbbreviationDeclarationPtr();
154 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
155 UnitEntryPairTy ChildEntry(Entry.CU, CurChild);
156 CompileUnit::DIEInfo &ChildInfo = Entry.CU->getDIEInfo(CurChild);
157
158 bool IsLiveChild = false;
159
160 switch (CurChild->getTag()) {
161 case dwarf::DW_TAG_label: {
162 IsLiveChild = isLiveSubprogramEntry(ChildEntry);
163
164 // Keep label referencing live address.
165 // Keep label which is child of live parent entry.
166 if (IsLiveChild || (IsLiveParent && ChildInfo.getHasAnAddress())) {
169 ReferencedBy);
170 }
171 } break;
172 case dwarf::DW_TAG_subprogram: {
173 IsLiveChild = isLiveSubprogramEntry(ChildEntry);
174
175 // Keep subprogram referencing live address.
176 if (IsLiveChild) {
177 // If subprogram is in module scope and this module allows ODR
178 // deduplication set "TypeTable" placement, otherwise set "" placement
180 (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
183
184 addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
185 }
186 } break;
187 case dwarf::DW_TAG_constant:
188 case dwarf::DW_TAG_variable: {
189 IsLiveChild = isLiveVariableEntry(ChildEntry, IsLiveParent);
190
191 // Keep variable referencing live address.
192 if (IsLiveChild) {
193 // If variable is in module scope and this module allows ODR
194 // deduplication set "TypeTable" placement, otherwise set "" placement
195
197 (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
200
201 addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
202 }
203 } break;
204 case dwarf::DW_TAG_base_type: {
205 // Always keep base types.
208 ReferencedBy);
209 } break;
210 case dwarf::DW_TAG_imported_module:
211 case dwarf::DW_TAG_imported_declaration:
212 case dwarf::DW_TAG_imported_unit: {
213 // Always keep DIEs having DW_AT_import attribute.
214 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_compile_unit) {
217 ReferencedBy);
218 break;
219 }
220
223 ReferencedBy);
224 } break;
225 case dwarf::DW_TAG_type_unit:
226 case dwarf::DW_TAG_partial_unit:
227 case dwarf::DW_TAG_compile_unit: {
228 llvm_unreachable("Called for incorrect DIE");
229 } break;
230 default:
231 // A module compile unit has no relocations, so liveness analysis never
232 // reaches a type definition that nothing else in the unit references. The
233 // module owns the only copy of those definitions, so keep them.
234 if (Entry.CU->isClangModule() && isNamespaceLikeEntry(Entry.DieEntry) &&
235 dwarf::isType(CurChild->getTag())) {
238 ReferencedBy);
239 break;
240 }
241
242 // An importing unit emits a skeleton of the module it imports, so a
243 // forward-declared type nested in a DW_TAG_module there is the module's
244 // record that the name exists, even when no full definition has been
245 // emitted. Route it through the type pool: when another CU emits a
246 // real definition for the same synthetic name, the existing
247 // decl-vs-def race resolution in allocateTypeDie + getFinalDie keeps
248 // the definition and drops this declaration at emission time. For
249 // non-ODR languages getFinalPlacementForEntry forces PlainDwarf,
250 // so the forward decl is kept in place under its module.
251 if (!Entry.CU->isClangModule() &&
252 Entry.DieEntry->getTag() == dwarf::DW_TAG_module &&
253 dwarf::isType(CurChild->getTag()) &&
254 dwarf::toUnsigned(Entry.CU->find(CurChild, dwarf::DW_AT_declaration),
255 0)) {
258 ReferencedBy);
259 }
260 break;
261 }
262
263 collectRootsToKeep(ChildEntry, ReferencedBy, IsLiveChild || IsLiveParent);
264 }
265}
266
268 bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
269 bool Res = true;
270
271 // Mark roots as kept.
272 while (!RootEntriesWorkList.empty()) {
273 LiveRootWorklistItemTy Root = RootEntriesWorkList.pop_back_val();
274
276 Root.getRootEntry(), InterCUProcessingStarted,
277 HasNewInterconnectedCUs)) {
278 if (Root.hasReferencedByOtherEntry())
279 Dependencies.push_back(Root);
280 } else
281 Res = false;
282 }
283
284 return Res;
285}
286
288 bool HasNewDependency = false;
290 assert(Root.hasReferencedByOtherEntry() &&
291 "Root entry without dependency inside the dependencies list");
292
293 UnitEntryPairTy RootEntry = Root.getRootEntry();
294
295 // Completeness must be checked against the actual referenced DIE, not its
296 // enclosing root. A nested type can be demoted to plain DWARF while its
297 // root stays in the type table, and a type-table DIE may only reference
298 // DIEs that are themselves in the type table. Checking the root instead
299 // leaves such a DIE in the type table, later tripping the type-unit
300 // reference assertion in DIEAttributeCloner::cloneDieRefAttr.
301 const DWARFDebugInfoEntry *ReferencedDieEntry =
302 Root.getReferencedTypeDieEntry() ? Root.getReferencedTypeDieEntry()
303 : RootEntry.DieEntry;
304 CompileUnit::DIEInfo &RootInfo =
305 RootEntry.CU->getDIEInfo(ReferencedDieEntry);
306
307 UnitEntryPairTy ReferencedByEntry = Root.getReferencedByEntry();
308 CompileUnit::DIEInfo &ReferencedByInfo =
309 ReferencedByEntry.CU->getDIEInfo(ReferencedByEntry.DieEntry);
310
311 if (!RootInfo.needToPlaceInTypeTable() &&
312 ReferencedByInfo.needToPlaceInTypeTable()) {
313 HasNewDependency = true;
314 setPlainDwarfPlacementRec(ReferencedByEntry);
315
316 // FIXME: we probably need to update getKeepTypeChildren status for
317 // parents of *Root.ReferencedBy.
318 }
319 }
320
321 return HasNewDependency;
322}
323
325 const UnitEntryPairTy &Entry) {
326 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
327 if (Info.getPlacement() == CompileUnit::PlainDwarf &&
328 !Info.getKeepTypeChildren())
329 return;
330
332 Info.unsetKeepTypeChildren();
334
335 for (const DWARFDebugInfoEntry *CurChild =
336 Entry.CU->getFirstChildEntry(Entry.DieEntry);
337 CurChild && CurChild->getAbbreviationDeclarationPtr();
338 CurChild = Entry.CU->getSiblingEntry(CurChild))
339 setPlainDwarfPlacementRec(UnitEntryPairTy{Entry.CU, CurChild});
340}
341
343 CompileUnit::DieOutputPlacement NewPlacement) {
344 if (!Info.getKeep())
345 return false;
346
347 switch (NewPlacement) {
349 return Info.needToPlaceInTypeTable();
350
352 return Info.needToKeepInPlainDwarf();
353
355 return Info.needToPlaceInTypeTable() && Info.needToKeepInPlainDwarf();
356
358 llvm_unreachable("Unset placement type is specified.");
359 };
360
361 llvm_unreachable("Unknown CompileUnit::DieOutputPlacement enum");
362}
363
365 CompileUnit::DieOutputPlacement NewPlacement) {
366 return isAlreadyMarked(Entry.CU->getDIEInfo(Entry.DieEntry), NewPlacement);
367}
368
370 const UnitEntryPairTy &Entry) {
371 if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
372 return;
373
374 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
375 bool NeedKeepTypeChildren = Info.needToPlaceInTypeTable();
376 bool NeedKeepPlainChildren = Info.needToKeepInPlainDwarf();
377
378 bool AreTypeParentsDone = !NeedKeepTypeChildren;
379 bool ArePlainParentsDone = !NeedKeepPlainChildren;
380
381 // Mark parents as 'Keep*Children'.
382 std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx();
383 while (ParentIdx) {
384 const DWARFDebugInfoEntry *ParentEntry =
385 Entry.CU->getDebugInfoEntry(*ParentIdx);
386 CompileUnit::DIEInfo &ParentInfo = Entry.CU->getDIEInfo(*ParentIdx);
387
388 if (!AreTypeParentsDone && NeedKeepTypeChildren) {
389 if (ParentInfo.getKeepTypeChildren())
390 AreTypeParentsDone = true;
391 else {
392 bool AddToWorklist = !isAlreadyMarked(
394 ParentInfo.setKeepTypeChildren();
395 if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
398 UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
399 }
400 }
401 }
402
403 if (!ArePlainParentsDone && NeedKeepPlainChildren) {
404 if (ParentInfo.getKeepPlainChildren())
405 ArePlainParentsDone = true;
406 else {
407 bool AddToWorklist = !isAlreadyMarked(
409 ParentInfo.setKeepPlainChildren();
410 if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
413 UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
414 }
415 }
416 }
417
418 if (AreTypeParentsDone && ArePlainParentsDone)
419 break;
420
421 ParentIdx = ParentEntry->getParentIdx();
422 }
423}
424
425namespace {
426struct FinalPlacement {
428
429 /// How Placement combines with the DIE's current placement when applied.
430 enum ApplyMode {
431 /// Overwrite the current placement. Used for entries whose placement is
432 /// fully determined regardless of how they were reached, so every mark
433 /// agrees on the value (ODR-unavailable entries and static data member
434 /// declarations).
435 Overwrite,
436 /// OR-join into the current placement (the common monotone-lattice case):
437 /// a DIE reached by both a live and a type mark ends up in Both.
438 Join,
439 /// Join for a DW_TAG_variable, which cannot occupy the type table and plain
440 /// DWARF at once: PlainDwarf is absorbing so the variable never lands in
441 /// Both.
442 JoinVariable,
443 } Mode;
444};
445} // namespace
446
447// Computes the placement to apply to \p Entry for a mark requesting \p
448// Placement (PlainDwarf for a live action, TypeTable for a type action), along
449// with how it combines with the DIE's current placement. Most entries join, so
450// a DIE reached by both actions ends up in Both. Entries whose placement is
451// fully determined regardless of how they were reached instead overwrite with
452// an exact placement: ODR-unavailable entries cannot be deduplicated into the
453// type table, and a DW_TAG_variable cannot occupy the type table and plain
454// DWARF at once.
455static FinalPlacement
458 assert((Placement != CompileUnit::NotSet) && "Placement is not set");
459 CompileUnit::DIEInfo &EntryInfo = Entry.CU->getDIEInfo(Entry.DieEntry);
460
461 if (!EntryInfo.getODRAvailable())
462 return {CompileUnit::PlainDwarf, FinalPlacement::Overwrite};
463
464 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_variable) {
465 // In-class static member declarations (e.g. "static constexpr int x = 1;")
466 // are DW_TAG_variable children of a DW_TAG_class_type /
467 // DW_TAG_structure_type / DW_TAG_union_type with DW_AT_declaration set.
468 // They are part of the class type and belong in the TypeTable together with
469 // the class. Forcing them into PlainDwarf would also drag the parent class
470 // into PlainDwarf (via markParentsAsKeepingChildren), producing a duplicate
471 // empty class declaration DIE alongside the full class definition emitted
472 // in another CU.
473 bool IsDeclaration = dwarf::toUnsigned(
474 Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_declaration), 0);
475 bool ParentIsType = false;
476 if (IsDeclaration) {
477 if (std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx()) {
478 dwarf::Tag ParentTag =
479 Entry.CU->getDebugInfoEntry(*ParentIdx)->getTag();
480 ParentIsType = ParentTag == dwarf::DW_TAG_class_type ||
481 ParentTag == dwarf::DW_TAG_structure_type ||
482 ParentTag == dwarf::DW_TAG_union_type;
483 }
484 }
485 if (IsDeclaration && ParentIsType) {
486 // Pure declarations have no runtime address; they belong with the class
487 // type. Always place in TypeTable regardless of how they were reached.
488 return {CompileUnit::TypeTable, FinalPlacement::Overwrite};
489 }
490
491 // A live (PlainDwarf) mark pins the variable to plain DWARF.
493 return {CompileUnit::PlainDwarf, FinalPlacement::Overwrite};
494
495 // Only a type-table mark reaches here. The variable join keeps a PlainDwarf
496 // mark racing this one from turning the variable into Both.
497 return {Placement, FinalPlacement::JoinVariable};
498 }
499
500 return {Placement, FinalPlacement::Join};
501}
502
504 LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
505 const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
506 std::atomic<bool> &HasNewInterconnectedCUs, bool RecordDepsOnly) {
507 if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
508 return true;
509
510 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
511
512 // Calculate final placement.
513 FinalPlacement Final = getFinalPlacementForEntry(
514 Entry,
517 assert((Info.getODRAvailable() || isLiveAction(Action) ||
519 "Wrong kind of placement for ODR unavailable entry");
520
521 if (!RecordDepsOnly && !isChildrenAction(Action) &&
522 isAlreadyMarked(Entry, Placement)) {
523 // Entry (and its subtree) were already marked, possibly by a racing CU or
524 // another referencing root, and which one wins is non-deterministic. Skip
525 // the redundant marking, but re-walk the subtree in record-deps-only mode
526 // so this referencing root still contributes its outgoing completeness
527 // dependencies. Otherwise the recorded dependency set depends on thread
528 // interleaving, the demotion fixpoint misses demotions, and whole type
529 // subtrees are left in the artificial type unit non-deterministically.
530 // Recording extra dependencies is harmless: a dependency only triggers a
531 // demotion when the referenced type is actually placed in plain DWARF.
532 return markDIEEntryAsKeptRec(Action, RootEntry, Entry,
533 InterCUProcessingStarted,
534 HasNewInterconnectedCUs,
535 /*RecordDepsOnly=*/true);
536 }
537
538 if (!RecordDepsOnly) {
539 // Mark current DIE as kept.
540 Info.setKeep();
541 // Marks compose monotonically so no interleaving loses an update: a general
542 // mark only raises the placement in the lattice, and a forced placement is
543 // a value every mark agrees on.
544 switch (Final.Mode) {
545 case FinalPlacement::Overwrite:
546 Info.setPlacement(Placement);
547 break;
548 case FinalPlacement::Join:
549 Info.joinPlacement(Placement);
550 break;
551 case FinalPlacement::JoinVariable:
552 Info.joinVariablePlacement(Placement);
553 break;
554 }
555
556 // Set keep children property for parents.
558 }
559
560 UnitEntryPairTy FinalRootEntry =
561 Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram ? Entry : RootEntry;
562
563 // Analyse referenced DIEs.
564 bool Res = true;
565 if (!maybeAddReferencedRoots(Action, FinalRootEntry, Entry,
566 InterCUProcessingStarted,
567 HasNewInterconnectedCUs, RecordDepsOnly))
568 Res = false;
569
570 // Return if we do not need to process children.
571 if (isSingleAction(Action))
572 return Res;
573
574 // Process children.
575 // Check for subprograms special case.
576 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram &&
577 Info.getODRAvailable()) {
578 // Subprograms is a special case. As it can be root for type DIEs
579 // and itself may be subject to move into the artificial type unit.
580 // a) Non removable children(like DW_TAG_formal_parameter) should always
581 // be cloned. They are placed into the "PlainDwarf" and into the
582 // "TypeTable".
583 // b) ODR deduplication candidates(type DIEs) children should not be put
584 // into the "PlainDwarf".
585 // c) Children keeping addresses and locations(like DW_TAG_call_site)
586 // should not be put into the "TypeTable".
587 for (const DWARFDebugInfoEntry *CurChild =
588 Entry.CU->getFirstChildEntry(Entry.DieEntry);
589 CurChild && CurChild->getAbbreviationDeclarationPtr();
590 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
591 CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
592
593 switch (CurChild->getTag()) {
594 case dwarf::DW_TAG_variable:
595 case dwarf::DW_TAG_constant:
596 case dwarf::DW_TAG_subprogram:
597 case dwarf::DW_TAG_label: {
598 if (ChildInfo.getHasAnAddress())
599 continue;
600 } break;
601
602 // Entries having following tags could not be removed from the subprogram.
603 case dwarf::DW_TAG_lexical_block:
604 case dwarf::DW_TAG_friend:
605 case dwarf::DW_TAG_inheritance:
606 case dwarf::DW_TAG_formal_parameter:
607 case dwarf::DW_TAG_unspecified_parameters:
608 case dwarf::DW_TAG_template_type_parameter:
609 case dwarf::DW_TAG_template_value_parameter:
610 case dwarf::DW_TAG_GNU_template_parameter_pack:
611 case dwarf::DW_TAG_GNU_formal_parameter_pack:
612 case dwarf::DW_TAG_GNU_template_template_param:
613 case dwarf::DW_TAG_thrown_type: {
614 // Go to the default child handling.
615 } break;
616
617 default: {
618 bool ChildIsTypeTableCandidate = isTypeTableCandidate(CurChild);
619
620 // Skip child marked to be copied into the artificial type unit.
621 if (isLiveAction(Action) && ChildIsTypeTableCandidate)
622 continue;
623
624 // Skip child marked to be copied into the plain unit.
625 if (isTypeAction(Action) && !ChildIsTypeTableCandidate)
626 continue;
627
628 // Go to the default child handling.
629 } break;
630 }
631
632 if (!markDIEEntryAsKeptRec(Action, FinalRootEntry,
633 UnitEntryPairTy{Entry.CU, CurChild},
634 InterCUProcessingStarted,
635 HasNewInterconnectedCUs, RecordDepsOnly))
636 Res = false;
637 }
638
639 return Res;
640 }
641
642 // Recursively process children.
643 for (const DWARFDebugInfoEntry *CurChild =
644 Entry.CU->getFirstChildEntry(Entry.DieEntry);
645 CurChild && CurChild->getAbbreviationDeclarationPtr();
646 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
647 CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
648 switch (CurChild->getTag()) {
649 case dwarf::DW_TAG_variable:
650 case dwarf::DW_TAG_constant:
651 case dwarf::DW_TAG_subprogram:
652 case dwarf::DW_TAG_label: {
653 if (ChildInfo.getHasAnAddress())
654 continue;
655 } break;
656 default:
657 break; // Nothing to do.
658 };
659
661 Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
662 InterCUProcessingStarted, HasNewInterconnectedCUs, RecordDepsOnly))
663 Res = false;
664 }
665
666 return Res;
667}
668
671 switch (DIEEntry->getTag()) {
672 default:
673 return false;
674
675 case dwarf::DW_TAG_imported_module:
676 case dwarf::DW_TAG_imported_declaration:
677 case dwarf::DW_TAG_imported_unit:
678 case dwarf::DW_TAG_array_type:
679 case dwarf::DW_TAG_class_type:
680 case dwarf::DW_TAG_enumeration_type:
681 case dwarf::DW_TAG_pointer_type:
682 case dwarf::DW_TAG_reference_type:
683 case dwarf::DW_TAG_string_type:
684 case dwarf::DW_TAG_structure_type:
685 case dwarf::DW_TAG_subroutine_type:
686 case dwarf::DW_TAG_typedef:
687 case dwarf::DW_TAG_union_type:
688 case dwarf::DW_TAG_variant:
689 case dwarf::DW_TAG_module:
690 case dwarf::DW_TAG_ptr_to_member_type:
691 case dwarf::DW_TAG_set_type:
692 case dwarf::DW_TAG_subrange_type:
693 case dwarf::DW_TAG_base_type:
694 case dwarf::DW_TAG_const_type:
695 case dwarf::DW_TAG_enumerator:
696 case dwarf::DW_TAG_file_type:
697 case dwarf::DW_TAG_packed_type:
698 case dwarf::DW_TAG_thrown_type:
699 case dwarf::DW_TAG_volatile_type:
700 case dwarf::DW_TAG_dwarf_procedure:
701 case dwarf::DW_TAG_restrict_type:
702 case dwarf::DW_TAG_interface_type:
703 case dwarf::DW_TAG_namespace:
704 case dwarf::DW_TAG_unspecified_type:
705 case dwarf::DW_TAG_shared_type:
706 case dwarf::DW_TAG_rvalue_reference_type:
707 case dwarf::DW_TAG_coarray_type:
708 case dwarf::DW_TAG_dynamic_type:
709 case dwarf::DW_TAG_atomic_type:
710 case dwarf::DW_TAG_immutable_type:
711 case dwarf::DW_TAG_function_template:
712 case dwarf::DW_TAG_class_template:
713 return true;
714 }
715}
716
718 LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
719 const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
720 std::atomic<bool> &HasNewInterconnectedCUs, bool RecordDepsOnly) {
721 const auto *Abbrev = Entry.DieEntry->getAbbreviationDeclarationPtr();
722 if (Abbrev == nullptr)
723 return true;
724
725 // In record-deps-only mode the referenced root is not scheduled for marking.
726 // The completeness dependency is appended directly so it participates in the
727 // demotion fixpoint without triggering any reference-following recursion.
728 auto AddRoot = [&](LiveRootWorklistActionTy RootAction,
729 const UnitEntryPairTy &Root,
730 const DWARFDebugInfoEntry *ReferencedTypeDieEntry) {
731 if (RecordDepsOnly) {
732 Dependencies.emplace_back(RootAction, Root, RootEntry,
733 ReferencedTypeDieEntry);
734 return;
735 }
736 addActionToRootEntriesWorkList(RootAction, Root, RootEntry,
737 ReferencedTypeDieEntry);
738 };
739
740 DWARFUnit &Unit = Entry.CU->getOrigUnit();
741 DWARFDataExtractor Data = Unit.getDebugInfoExtractor();
743 Entry.DieEntry->getOffset() + getULEB128Size(Abbrev->getCode());
744
745 // For each DIE attribute...
746 for (const auto &AttrSpec : Abbrev->attributes()) {
747 DWARFFormValue Val(AttrSpec.Form);
749 AttrSpec.Attr == dwarf::DW_AT_sibling) {
750 DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
751 Unit.getFormParams());
752 continue;
753 }
754 Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);
755
756 // Resolve reference.
757 std::optional<UnitEntryPairTy> RefDie = Entry.CU->resolveDIEReference(
758 Val, InterCUProcessingStarted
761 if (!RefDie) {
762 Entry.CU->warn("could not find referenced DIE", Entry.DieEntry);
763 continue;
764 }
765
766 if (!RefDie->DieEntry) {
767 // The reference could not be resolved yet. Recording dependencies
768 // happens only after marking has fully resolved interconnections, so skip
769 // it here. The scheduling path below handles the delayed-resolution case.
770 if (RecordDepsOnly)
771 continue;
772
773 // Delay resolving reference.
774 RefDie->CU->setInterconnectedCU();
775 Entry.CU->setInterconnectedCU();
776 HasNewInterconnectedCUs = true;
777 return false;
778 }
779
780 assert((Entry.CU->getUniqueID() == RefDie->CU->getUniqueID() ||
781 InterCUProcessingStarted) &&
782 "Inter-CU reference while inter-CU processing is not started");
783
784 CompileUnit::DIEInfo &RefInfo = RefDie->CU->getDIEInfo(RefDie->DieEntry);
785 if (!RefInfo.getODRAvailable())
787 else if (RefInfo.getODRAvailable() &&
788 llvm::is_contained(getODRAttributes(), AttrSpec.Attr))
789 // Note: getODRAttributes does not include DW_AT_containing_type.
790 // It should be OK as we do getRootForSpecifiedEntry(). So any containing
791 // type would be found as the root for the entry.
793 else if (isLiveAction(Action))
795 else
797
798 if (AttrSpec.Attr == dwarf::DW_AT_import) {
799 if (isNamespaceLikeEntry(RefDie->DieEntry)) {
800 AddRoot(isTypeAction(Action)
803 *RefDie, nullptr);
804 continue;
805 }
806
807 AddRoot(Action, *RefDie, nullptr);
808 continue;
809 }
810
811 // Mark the enclosing root type as kept, but also record the actual
812 // referenced DIE: a nested type can be demoted to plain DWARF independently
813 // of its root, in which case ReferencedBy must be demoted too (see
814 // updateDependenciesCompleteness).
815 UnitEntryPairTy RootForReferencedDie = getRootForSpecifiedEntry(*RefDie);
816 AddRoot(Action, RootForReferencedDie, RefDie->DieEntry);
817 }
818
819 return true;
820}
821
824 UnitEntryPairTy Result = Entry;
825
826 do {
827 switch (Entry.DieEntry->getTag()) {
828 case dwarf::DW_TAG_subprogram:
829 case dwarf::DW_TAG_label:
830 case dwarf::DW_TAG_variable:
831 case dwarf::DW_TAG_constant: {
832 return Result;
833 } break;
834
835 default: {
836 // Nothing to do.
837 }
838 }
839
840 std::optional<uint32_t> ParentIdx = Result.DieEntry->getParentIdx();
841 if (!ParentIdx)
842 return Result;
843
844 const DWARFDebugInfoEntry *ParentEntry =
845 Result.CU->getDebugInfoEntry(*ParentIdx);
846 if (isNamespaceLikeEntry(ParentEntry))
847 break;
848 Result.DieEntry = ParentEntry;
849 } while (true);
850
851 return Result;
852}
853
854static void dumpKeptDIE(const DWARFDie &DIE, StringRef Kind, bool Verbose) {
855 if (!Verbose)
856 return;
857 outs() << "Keeping " << Kind << " DIE:";
858 DIDumpOptions DumpOpts;
859 DumpOpts.ChildRecurseDepth = 0;
860 DumpOpts.Verbose = Verbose;
861 DIE.dump(outs(), /*Indent=*/8, DumpOpts);
862}
863
865 bool IsLiveParent) {
866 DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
867 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(DIE);
868
869 if (Info.getTrackLiveness()) {
870 const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
871
872 if (!Info.getIsInFunctionScope() &&
873 Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
874 // Global variables with constant value can always be kept.
875 } else {
876 // See if there is a relocation to a valid debug map entry inside this
877 // variable's location. The order is important here. We want to always
878 // check if the variable has a location expression address. However, we
879 // don't want a static variable in a function to force us to keep the
880 // enclosing function, unless requested explicitly.
881 std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
882 Entry.CU->getContaingFile().Addresses->getVariableRelocAdjustment(
883 DIE, Entry.CU->getGlobalData().getOptions().Verbose);
884
885 if (LocExprAddrAndRelocAdjustment.first)
886 Info.setHasAnAddress();
887
888 if (!LocExprAddrAndRelocAdjustment.second)
889 return false;
890
891 if (!IsLiveParent && Info.getIsInFunctionScope() &&
892 !Entry.CU->getGlobalData().getOptions().KeepFunctionForStatic)
893 return false;
894 }
895 }
896 Info.setHasAnAddress();
897
898 dumpKeptDIE(DIE, "variable", Entry.CU->getGlobalData().getOptions().Verbose);
899
900 return true;
901}
902
904 DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
905 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
906 std::optional<DWARFFormValue> LowPCVal = DIE.find(dwarf::DW_AT_low_pc);
907
908 const bool Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
909 std::optional<uint64_t> LowPc;
910 std::optional<uint64_t> HighPc;
911 std::optional<int64_t> RelocAdjustment;
912 if (Info.getTrackLiveness()) {
913 LowPc = dwarf::toAddress(LowPCVal);
914 if (!LowPc)
915 return false;
916
917 Info.setHasAnAddress();
918
919 RelocAdjustment =
920 Entry.CU->getContaingFile().Addresses->getSubprogramRelocAdjustment(
921 DIE, Verbose);
922 if (!RelocAdjustment)
923 return false;
924
925 if (DIE.getTag() == dwarf::DW_TAG_subprogram) {
926 // Validate subprogram address range.
927
928 HighPc = DIE.getHighPC(*LowPc);
929 if (!HighPc) {
930 Entry.CU->warn("function without high_pc. Range will be discarded.",
931 &DIE);
932 return false;
933 }
934
935 if (*LowPc > *HighPc) {
936 Entry.CU->warn("low_pc greater than high_pc. Range will be discarded.",
937 &DIE);
938 return false;
939 }
940 } else if (DIE.getTag() == dwarf::DW_TAG_label) {
941 if (Entry.CU->hasLabelAt(*LowPc))
942 return false;
943
944 // FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider
945 // labels that don't fall into the CU's aranges. This is wrong IMO. Debug
946 // info generation bugs aside, this is really wrong in the case of labels,
947 // where a label marking the end of a function will have a PC == CU's
948 // high_pc.
949 if (dwarf::toAddress(Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_high_pc))
950 .value_or(UINT64_MAX) <= LowPc)
951 return false;
952
953 // For assembly-language CUs there are typically no DW_TAG_subprogram
954 // DIEs, so labels are the only addresses we see. Fall back to the
955 // symbol-range lookup to recover a function range for the line-table
956 // filter; otherwise the output line table would be empty.
957 uint16_t Language = dwarf::toUnsigned(
958 Entry.CU->getOrigUnit().getUnitDIE().find(dwarf::DW_AT_language), 0);
959 if (Language == dwarf::DW_LANG_Mips_Assembler ||
960 Language == dwarf::DW_LANG_Assembly) {
961 if (auto Range =
962 Entry.CU->getContaingFile().Addresses->getSymbolRangeForAddress(
963 *LowPc))
964 Entry.CU->addFunctionRange(Range->LowPC, Range->HighPC,
965 *RelocAdjustment);
966 }
967
968 Entry.CU->addLabelLowPc(*LowPc, *RelocAdjustment);
969 }
970 } else
971 Info.setHasAnAddress();
972
973 dumpKeptDIE(DIE, "subprogram", Verbose);
974
975 if (!Info.getTrackLiveness() || DIE.getTag() == dwarf::DW_TAG_label)
976 return true;
977
978 Entry.CU->addFunctionRange(
979 *LowPc,
980 Entry.CU->getContaingFile().Addresses->constrainCodeRangeHighPC(
981 *LowPc, *HighPc, *RelocAdjustment),
982 *RelocAdjustment);
983 return true;
984}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
bool isAlreadyMarked(const CompileUnit::DIEInfo &Info, CompileUnit::DieOutputPlacement NewPlacement)
static void dumpKeptDIE(const DWARFDie &DIE, StringRef Kind, bool Verbose)
static FinalPlacement getFinalPlacementForEntry(const UnitEntryPairTy &Entry, CompileUnit::DieOutputPlacement Placement)
static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry)
Branch Probability Basic Block Placement
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
A pointer to another debug information entry.
Definition DIE.h:325
A structured debug information entry.
Definition DIE.h:840
dwarf::Tag getTag() const
Definition DIE.h:876
LLVM_ABI void dump() const
Definition DIE.cpp:261
A DWARFDataExtractor (typically for an in-memory copy of an object-file section) plus a relocation ma...
DWARFDebugInfoEntry - A DIE with only the minimum required data.
std::optional< uint32_t > getParentIdx() const
Returns index of the parent die.
const DWARFAbbreviationDeclaration * getAbbreviationDeclarationPtr() const
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
Definition DWARFDie.h:43
iterator_range< iterator > children() const
Definition DWARFDie.h:407
const DWARFDebugInfoEntry * getDebugInfoEntry() const
Definition DWARFDie.h:54
bool isValid() const
Definition DWARFDie.h:52
LLVM_ABI bool isFormClass(FormClass FC) const
LLVM_ABI bool extractValue(const DWARFDataExtractor &Data, uint64_t *OffsetPtr, dwarf::FormParams FormParams, const DWARFContext *Context=nullptr, const DWARFUnit *Unit=nullptr)
Extracts a value in Data at offset *OffsetPtr.
bool skipValue(DataExtractor DebugInfoData, uint64_t *OffsetPtr, const dwarf::FormParams Params) const
Skip a form's value in DebugInfoData at the offset specified by OffsetPtr.
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.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
static LLVM_ABI raw_ostream & error()
Convenience method for printing "error: " to stderr.
Definition WithColor.cpp:84
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.
bool markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, const UnitEntryPairTy &Entry, bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs, bool RecordDepsOnly=false)
Mark whole DIE tree as kept recursively.
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 isLiveAction(LiveRootWorklistActionTy Action)
bool isChildrenAction(LiveRootWorklistActionTy Action)
bool isTypeAction(LiveRootWorklistActionTy Action)
void addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry, std::optional< UnitEntryPairTy > ReferencedBy, const DWARFDebugInfoEntry *ReferencedTypeDieEntry=nullptr)
Add action item to the work list.
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.
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.
@ 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.
bool maybeAddReferencedRoots(LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, const UnitEntryPairTy &Entry, bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs, bool RecordDepsOnly=false)
Check referenced DIEs and add them into the worklist.
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 UINT64_MAX
Definition DataTypes.h:77
#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.
bool isType(Tag T)
Definition Dwarf.h:113
std::optional< uint64_t > toUnsigned(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an unsigned constant.
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:578
LLVM_ABI 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)
Definition STLExtras.h:407
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
LLVM_ABI unsigned getULEB128Size(uint64_t Value)
Utility function to get the size of the ULEB128-encoded value.
Definition LEB128.cpp:19
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
Container for dump options that control which debug information will be dumped.
Definition DIContext.h:196
unsigned ChildRecurseDepth
Definition DIContext.h:198
Information gathered about a DIE in the object file.
void setPlacement(DieOutputPlacement Placement)
Sets Placement kind for the corresponding die.
This is a helper structure which keeps a debug info entry with it's containing compilation unit.