LLVM 23.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
109 bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
110 RootEntriesWorkList.clear();
111
112 // Search for live root DIEs.
113 CompileUnit::DIEInfo &CUInfo = CU.getDIEInfo(CU.getDebugInfoEntry(0));
115 collectRootsToKeep(UnitEntryPairTy{&CU, CU.getDebugInfoEntry(0)},
116 std::nullopt, false);
117
118 // Mark live DIEs as kept.
119 return markCollectedLiveRootsAsKept(InterCUProcessingStarted,
120 HasNewInterconnectedCUs);
121}
122
124 LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry,
125 std::optional<UnitEntryPairTy> ReferencedBy) {
126 if (ReferencedBy) {
127 RootEntriesWorkList.emplace_back(Action, Entry, *ReferencedBy);
128 return;
129 }
130
131 RootEntriesWorkList.emplace_back(Action, Entry);
132}
133
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);
143
144 bool IsLiveChild = false;
145
146 switch (CurChild->getTag()) {
147 case dwarf::DW_TAG_label: {
148 IsLiveChild = isLiveSubprogramEntry(ChildEntry);
149
150 // Keep label referencing live address.
151 // Keep label which is child of live parent entry.
152 if (IsLiveChild || (IsLiveParent && ChildInfo.getHasAnAddress())) {
155 ReferencedBy);
156 }
157 } break;
158 case dwarf::DW_TAG_subprogram: {
159 IsLiveChild = isLiveSubprogramEntry(ChildEntry);
160
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
166 (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
169
170 addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
171 }
172 } break;
173 case dwarf::DW_TAG_constant:
174 case dwarf::DW_TAG_variable: {
175 IsLiveChild = isLiveVariableEntry(ChildEntry, IsLiveParent);
176
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
181
183 (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
186
187 addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
188 }
189 } break;
190 case dwarf::DW_TAG_base_type: {
191 // Always keep base types.
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) {
203 ReferencedBy);
204 break;
205 }
206
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;
219 }
220
221 collectRootsToKeep(ChildEntry, ReferencedBy, IsLiveChild || IsLiveParent);
222 }
223}
224
226 bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
227 bool Res = true;
228
229 // Mark roots as kept.
230 while (!RootEntriesWorkList.empty()) {
231 LiveRootWorklistItemTy Root = RootEntriesWorkList.pop_back_val();
232
234 Root.getRootEntry(), InterCUProcessingStarted,
235 HasNewInterconnectedCUs)) {
236 if (Root.hasReferencedByOtherEntry())
237 Dependencies.push_back(Root);
238 } else
239 Res = false;
240 }
241
242 return Res;
243}
244
246 bool HasNewDependency = false;
248 assert(Root.hasReferencedByOtherEntry() &&
249 "Root entry without dependency inside the dependencies list");
250
251 UnitEntryPairTy RootEntry = Root.getRootEntry();
252 CompileUnit::DIEInfo &RootInfo =
253 RootEntry.CU->getDIEInfo(RootEntry.DieEntry);
254
255 UnitEntryPairTy ReferencedByEntry = Root.getReferencedByEntry();
256 CompileUnit::DIEInfo &ReferencedByInfo =
257 ReferencedByEntry.CU->getDIEInfo(ReferencedByEntry.DieEntry);
258
259 if (!RootInfo.needToPlaceInTypeTable() &&
260 ReferencedByInfo.needToPlaceInTypeTable()) {
261 HasNewDependency = true;
262 setPlainDwarfPlacementRec(ReferencedByEntry);
263
264 // FIXME: we probably need to update getKeepTypeChildren status for
265 // parents of *Root.ReferencedBy.
266 }
267 }
268
269 return HasNewDependency;
270}
271
273 const UnitEntryPairTy &Entry) {
274 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
275 if (Info.getPlacement() == CompileUnit::PlainDwarf &&
276 !Info.getKeepTypeChildren())
277 return;
278
280 Info.unsetKeepTypeChildren();
282
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});
288}
289
290static 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;
296
297 default:
298 return false;
299 }
300}
301
303 CompileUnit::DieOutputPlacement NewPlacement) {
304 if (!Info.getKeep())
305 return false;
306
307 switch (NewPlacement) {
309 return Info.needToPlaceInTypeTable();
310
312 return Info.needToKeepInPlainDwarf();
313
315 return Info.needToPlaceInTypeTable() && Info.needToKeepInPlainDwarf();
316
318 llvm_unreachable("Unset placement type is specified.");
319 };
320
321 llvm_unreachable("Unknown CompileUnit::DieOutputPlacement enum");
322}
323
325 CompileUnit::DieOutputPlacement NewPlacement) {
326 return isAlreadyMarked(Entry.CU->getDIEInfo(Entry.DieEntry), NewPlacement);
327}
328
330 const UnitEntryPairTy &Entry) {
331 if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
332 return;
333
334 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
335 bool NeedKeepTypeChildren = Info.needToPlaceInTypeTable();
336 bool NeedKeepPlainChildren = Info.needToKeepInPlainDwarf();
337
338 bool AreTypeParentsDone = !NeedKeepTypeChildren;
339 bool ArePlainParentsDone = !NeedKeepPlainChildren;
340
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);
347
348 if (!AreTypeParentsDone && NeedKeepTypeChildren) {
349 if (ParentInfo.getKeepTypeChildren())
350 AreTypeParentsDone = true;
351 else {
352 bool AddToWorklist = !isAlreadyMarked(
354 ParentInfo.setKeepTypeChildren();
355 if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
358 UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
359 }
360 }
361 }
362
363 if (!ArePlainParentsDone && NeedKeepPlainChildren) {
364 if (ParentInfo.getKeepPlainChildren())
365 ArePlainParentsDone = true;
366 else {
367 bool AddToWorklist = !isAlreadyMarked(
369 ParentInfo.setKeepPlainChildren();
370 if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
373 UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
374 }
375 }
376 }
377
378 if (AreTypeParentsDone && ArePlainParentsDone)
379 break;
380
381 ParentIdx = ParentEntry->getParentIdx();
382 }
383}
384
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.
393 assert((Placement != CompileUnit::NotSet) && "Placement is not set");
394 CompileUnit::DIEInfo &EntryInfo = Entry.CU->getDIEInfo(Entry.DieEntry);
395
396 if (!EntryInfo.getODRAvailable())
398
399 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_variable) {
400 // In-class static member declarations (e.g. "static constexpr int x = 1;")
401 // are DW_TAG_variable children of a DW_TAG_class_type /
402 // DW_TAG_structure_type / DW_TAG_union_type with DW_AT_declaration set.
403 // They are part of the class type and belong in the TypeTable together with
404 // the class. Forcing them into PlainDwarf would also drag the parent class
405 // into PlainDwarf (via markParentsAsKeepingChildren), producing a duplicate
406 // empty class declaration DIE alongside the full class definition emitted
407 // in another CU.
408 bool IsDeclaration = dwarf::toUnsigned(
409 Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_declaration), 0);
410 bool ParentIsType = false;
411 if (IsDeclaration) {
412 if (std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx()) {
413 dwarf::Tag ParentTag =
414 Entry.CU->getDebugInfoEntry(*ParentIdx)->getTag();
415 ParentIsType = ParentTag == dwarf::DW_TAG_class_type ||
416 ParentTag == dwarf::DW_TAG_structure_type ||
417 ParentTag == dwarf::DW_TAG_union_type;
418 }
419 }
420 if (IsDeclaration && ParentIsType) {
421 // Pure declarations have no runtime address; they belong with the class
422 // type. Always place in TypeTable regardless of how they were reached.
424 }
425
426 // Do not put variable into the "TypeTable" and "PlainDwarf" at the same
427 // time.
428 if (EntryInfo.getPlacement() == CompileUnit::PlainDwarf ||
429 EntryInfo.getPlacement() == CompileUnit::Both)
431
434 }
435
436 switch (EntryInfo.getPlacement()) {
438 return Placement;
439
442
445
447 return CompileUnit::Both;
448 };
449
450 llvm_unreachable("Unknown placement type.");
451 return Placement;
452}
453
455 LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
456 const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
457 std::atomic<bool> &HasNewInterconnectedCUs) {
458 if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
459 return true;
460
461 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
462
463 // Calculate final placement placement.
465 Entry,
467 assert((Info.getODRAvailable() || isLiveAction(Action) ||
469 "Wrong kind of placement for ODR unavailable entry");
470
471 if (!isChildrenAction(Action))
472 if (isAlreadyMarked(Entry, Placement))
473 return true;
474
475 // Mark current DIE as kept.
476 Info.setKeep();
477 Info.setPlacement(Placement);
478
479 // Set keep children property for parents.
481
482 UnitEntryPairTy FinalRootEntry =
483 Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram ? Entry : RootEntry;
484
485 // Analyse referenced DIEs.
486 bool Res = true;
487 if (!maybeAddReferencedRoots(Action, FinalRootEntry, Entry,
488 InterCUProcessingStarted,
489 HasNewInterconnectedCUs))
490 Res = false;
491
492 // Return if we do not need to process children.
493 if (isSingleAction(Action))
494 return Res;
495
496 // Process children.
497 // Check for subprograms special case.
498 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram &&
499 Info.getODRAvailable()) {
500 // Subprograms is a special case. As it can be root for type DIEs
501 // and itself may be subject to move into the artificial type unit.
502 // a) Non removable children(like DW_TAG_formal_parameter) should always
503 // be cloned. They are placed into the "PlainDwarf" and into the
504 // "TypeTable".
505 // b) ODR deduplication candidates(type DIEs) children should not be put
506 // into the "PlainDwarf".
507 // c) Children keeping addresses and locations(like DW_TAG_call_site)
508 // should not be put into the "TypeTable".
509 for (const DWARFDebugInfoEntry *CurChild =
510 Entry.CU->getFirstChildEntry(Entry.DieEntry);
511 CurChild && CurChild->getAbbreviationDeclarationPtr();
512 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
513 CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
514
515 switch (CurChild->getTag()) {
516 case dwarf::DW_TAG_variable:
517 case dwarf::DW_TAG_constant:
518 case dwarf::DW_TAG_subprogram:
519 case dwarf::DW_TAG_label: {
520 if (ChildInfo.getHasAnAddress())
521 continue;
522 } break;
523
524 // Entries having following tags could not be removed from the subprogram.
525 case dwarf::DW_TAG_lexical_block:
526 case dwarf::DW_TAG_friend:
527 case dwarf::DW_TAG_inheritance:
528 case dwarf::DW_TAG_formal_parameter:
529 case dwarf::DW_TAG_unspecified_parameters:
530 case dwarf::DW_TAG_template_type_parameter:
531 case dwarf::DW_TAG_template_value_parameter:
532 case dwarf::DW_TAG_GNU_template_parameter_pack:
533 case dwarf::DW_TAG_GNU_formal_parameter_pack:
534 case dwarf::DW_TAG_GNU_template_template_param:
535 case dwarf::DW_TAG_thrown_type: {
536 // Go to the default child handling.
537 } break;
538
539 default: {
540 bool ChildIsTypeTableCandidate = isTypeTableCandidate(CurChild);
541
542 // Skip child marked to be copied into the artificial type unit.
543 if (isLiveAction(Action) && ChildIsTypeTableCandidate)
544 continue;
545
546 // Skip child marked to be copied into the plain unit.
547 if (isTypeAction(Action) && !ChildIsTypeTableCandidate)
548 continue;
549
550 // Go to the default child handling.
551 } break;
552 }
553
555 Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
556 InterCUProcessingStarted, HasNewInterconnectedCUs))
557 Res = false;
558 }
559
560 return Res;
561 }
562
563 // Recursively process children.
564 for (const DWARFDebugInfoEntry *CurChild =
565 Entry.CU->getFirstChildEntry(Entry.DieEntry);
566 CurChild && CurChild->getAbbreviationDeclarationPtr();
567 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
568 CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
569 switch (CurChild->getTag()) {
570 case dwarf::DW_TAG_variable:
571 case dwarf::DW_TAG_constant:
572 case dwarf::DW_TAG_subprogram:
573 case dwarf::DW_TAG_label: {
574 if (ChildInfo.getHasAnAddress())
575 continue;
576 } break;
577 default:
578 break; // Nothing to do.
579 };
580
582 Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
583 InterCUProcessingStarted, HasNewInterconnectedCUs))
584 Res = false;
585 }
586
587 return Res;
588}
589
592 switch (DIEEntry->getTag()) {
593 default:
594 return false;
595
596 case dwarf::DW_TAG_imported_module:
597 case dwarf::DW_TAG_imported_declaration:
598 case dwarf::DW_TAG_imported_unit:
599 case dwarf::DW_TAG_array_type:
600 case dwarf::DW_TAG_class_type:
601 case dwarf::DW_TAG_enumeration_type:
602 case dwarf::DW_TAG_pointer_type:
603 case dwarf::DW_TAG_reference_type:
604 case dwarf::DW_TAG_string_type:
605 case dwarf::DW_TAG_structure_type:
606 case dwarf::DW_TAG_subroutine_type:
607 case dwarf::DW_TAG_typedef:
608 case dwarf::DW_TAG_union_type:
609 case dwarf::DW_TAG_variant:
610 case dwarf::DW_TAG_module:
611 case dwarf::DW_TAG_ptr_to_member_type:
612 case dwarf::DW_TAG_set_type:
613 case dwarf::DW_TAG_subrange_type:
614 case dwarf::DW_TAG_base_type:
615 case dwarf::DW_TAG_const_type:
616 case dwarf::DW_TAG_enumerator:
617 case dwarf::DW_TAG_file_type:
618 case dwarf::DW_TAG_packed_type:
619 case dwarf::DW_TAG_thrown_type:
620 case dwarf::DW_TAG_volatile_type:
621 case dwarf::DW_TAG_dwarf_procedure:
622 case dwarf::DW_TAG_restrict_type:
623 case dwarf::DW_TAG_interface_type:
624 case dwarf::DW_TAG_namespace:
625 case dwarf::DW_TAG_unspecified_type:
626 case dwarf::DW_TAG_shared_type:
627 case dwarf::DW_TAG_rvalue_reference_type:
628 case dwarf::DW_TAG_coarray_type:
629 case dwarf::DW_TAG_dynamic_type:
630 case dwarf::DW_TAG_atomic_type:
631 case dwarf::DW_TAG_immutable_type:
632 case dwarf::DW_TAG_function_template:
633 case dwarf::DW_TAG_class_template:
634 return true;
635 }
636}
637
639 LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
640 const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
641 std::atomic<bool> &HasNewInterconnectedCUs) {
642 const auto *Abbrev = Entry.DieEntry->getAbbreviationDeclarationPtr();
643 if (Abbrev == nullptr)
644 return true;
645
646 DWARFUnit &Unit = Entry.CU->getOrigUnit();
647 DWARFDataExtractor Data = Unit.getDebugInfoExtractor();
649 Entry.DieEntry->getOffset() + getULEB128Size(Abbrev->getCode());
650
651 // For each DIE attribute...
652 for (const auto &AttrSpec : Abbrev->attributes()) {
653 DWARFFormValue Val(AttrSpec.Form);
655 AttrSpec.Attr == dwarf::DW_AT_sibling) {
656 DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
657 Unit.getFormParams());
658 continue;
659 }
660 Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);
661
662 // Resolve reference.
663 std::optional<UnitEntryPairTy> RefDie = Entry.CU->resolveDIEReference(
664 Val, InterCUProcessingStarted
667 if (!RefDie) {
668 Entry.CU->warn("could not find referenced DIE", Entry.DieEntry);
669 continue;
670 }
671
672 if (!RefDie->DieEntry) {
673 // Delay resolving reference.
674 RefDie->CU->setInterconnectedCU();
675 Entry.CU->setInterconnectedCU();
676 HasNewInterconnectedCUs = true;
677 return false;
678 }
679
680 assert((Entry.CU->getUniqueID() == RefDie->CU->getUniqueID() ||
681 InterCUProcessingStarted) &&
682 "Inter-CU reference while inter-CU processing is not started");
683
684 CompileUnit::DIEInfo &RefInfo = RefDie->CU->getDIEInfo(RefDie->DieEntry);
685 if (!RefInfo.getODRAvailable())
687 else if (RefInfo.getODRAvailable() &&
688 llvm::is_contained(getODRAttributes(), AttrSpec.Attr))
689 // Note: getODRAttributes does not include DW_AT_containing_type.
690 // It should be OK as we do getRootForSpecifiedEntry(). So any containing
691 // type would be found as the root for the entry.
693 else if (isLiveAction(Action))
695 else
697
698 if (AttrSpec.Attr == dwarf::DW_AT_import) {
699 if (isNamespaceLikeEntry(RefDie->DieEntry)) {
701 isTypeAction(Action)
704 *RefDie, RootEntry);
705 continue;
706 }
707
708 addActionToRootEntriesWorkList(Action, *RefDie, RootEntry);
709 continue;
710 }
711
712 UnitEntryPairTy RootForReferencedDie = getRootForSpecifiedEntry(*RefDie);
713 addActionToRootEntriesWorkList(Action, RootForReferencedDie, RootEntry);
714 }
715
716 return true;
717}
718
721 UnitEntryPairTy Result = Entry;
722
723 do {
724 switch (Entry.DieEntry->getTag()) {
725 case dwarf::DW_TAG_subprogram:
726 case dwarf::DW_TAG_label:
727 case dwarf::DW_TAG_variable:
728 case dwarf::DW_TAG_constant: {
729 return Result;
730 } break;
731
732 default: {
733 // Nothing to do.
734 }
735 }
736
737 std::optional<uint32_t> ParentIdx = Result.DieEntry->getParentIdx();
738 if (!ParentIdx)
739 return Result;
740
741 const DWARFDebugInfoEntry *ParentEntry =
742 Result.CU->getDebugInfoEntry(*ParentIdx);
743 if (isNamespaceLikeEntry(ParentEntry))
744 break;
745 Result.DieEntry = ParentEntry;
746 } while (true);
747
748 return Result;
749}
750
751static void dumpKeptDIE(const DWARFDie &DIE, StringRef Kind, bool Verbose) {
752 if (!Verbose)
753 return;
754 outs() << "Keeping " << Kind << " DIE:";
755 DIDumpOptions DumpOpts;
756 DumpOpts.ChildRecurseDepth = 0;
757 DumpOpts.Verbose = Verbose;
758 DIE.dump(outs(), /*Indent=*/8, DumpOpts);
759}
760
762 bool IsLiveParent) {
763 DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
764 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(DIE);
765
766 if (Info.getTrackLiveness()) {
767 const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
768
769 if (!Info.getIsInFunctionScope() &&
770 Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
771 // Global variables with constant value can always be kept.
772 } else {
773 // See if there is a relocation to a valid debug map entry inside this
774 // variable's location. The order is important here. We want to always
775 // check if the variable has a location expression address. However, we
776 // don't want a static variable in a function to force us to keep the
777 // enclosing function, unless requested explicitly.
778 std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
779 Entry.CU->getContaingFile().Addresses->getVariableRelocAdjustment(
780 DIE, Entry.CU->getGlobalData().getOptions().Verbose);
781
782 if (LocExprAddrAndRelocAdjustment.first)
783 Info.setHasAnAddress();
784
785 if (!LocExprAddrAndRelocAdjustment.second)
786 return false;
787
788 if (!IsLiveParent && Info.getIsInFunctionScope() &&
789 !Entry.CU->getGlobalData().getOptions().KeepFunctionForStatic)
790 return false;
791 }
792 }
793 Info.setHasAnAddress();
794
795 dumpKeptDIE(DIE, "variable", Entry.CU->getGlobalData().getOptions().Verbose);
796
797 return true;
798}
799
801 DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
802 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
803 std::optional<DWARFFormValue> LowPCVal = DIE.find(dwarf::DW_AT_low_pc);
804
805 const bool Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
806 std::optional<uint64_t> LowPc;
807 std::optional<uint64_t> HighPc;
808 std::optional<int64_t> RelocAdjustment;
809 if (Info.getTrackLiveness()) {
810 LowPc = dwarf::toAddress(LowPCVal);
811 if (!LowPc)
812 return false;
813
814 Info.setHasAnAddress();
815
816 RelocAdjustment =
817 Entry.CU->getContaingFile().Addresses->getSubprogramRelocAdjustment(
818 DIE, Verbose);
819 if (!RelocAdjustment)
820 return false;
821
822 if (DIE.getTag() == dwarf::DW_TAG_subprogram) {
823 // Validate subprogram address range.
824
825 HighPc = DIE.getHighPC(*LowPc);
826 if (!HighPc) {
827 Entry.CU->warn("function without high_pc. Range will be discarded.",
828 &DIE);
829 return false;
830 }
831
832 if (*LowPc > *HighPc) {
833 Entry.CU->warn("low_pc greater than high_pc. Range will be discarded.",
834 &DIE);
835 return false;
836 }
837 } else if (DIE.getTag() == dwarf::DW_TAG_label) {
838 if (Entry.CU->hasLabelAt(*LowPc))
839 return false;
840
841 // FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider
842 // labels that don't fall into the CU's aranges. This is wrong IMO. Debug
843 // info generation bugs aside, this is really wrong in the case of labels,
844 // where a label marking the end of a function will have a PC == CU's
845 // high_pc.
846 if (dwarf::toAddress(Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_high_pc))
847 .value_or(UINT64_MAX) <= LowPc)
848 return false;
849
850 // For assembly-language CUs there are typically no DW_TAG_subprogram
851 // DIEs, so labels are the only addresses we see. Fall back to the
852 // assembly-range lookup to recover a function range for the line-table
853 // filter; otherwise the output line table would be empty.
854 uint16_t Language = dwarf::toUnsigned(
855 Entry.CU->getOrigUnit().getUnitDIE().find(dwarf::DW_AT_language), 0);
856 if (Language == dwarf::DW_LANG_Mips_Assembler ||
857 Language == dwarf::DW_LANG_Assembly) {
858 if (auto Range = Entry.CU->getContaingFile()
859 .Addresses->getAssemblyRangeForAddress(*LowPc))
860 Entry.CU->addFunctionRange(Range->LowPC, Range->HighPC,
861 *RelocAdjustment);
862 }
863
864 Entry.CU->addLabelLowPc(*LowPc, *RelocAdjustment);
865 }
866 } else
867 Info.setHasAnAddress();
868
869 dumpKeptDIE(DIE, "subprogram", Verbose);
870
871 if (!Info.getTrackLiveness() || DIE.getTag() == dwarf::DW_TAG_label)
872 return true;
873
874 Entry.CU->addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);
875 return true;
876}
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 bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry)
static CompileUnit::DieOutputPlacement getFinalPlacementForEntry(const UnitEntryPairTy &Entry, CompileUnit::DieOutputPlacement Placement)
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:828
dwarf::Tag getTag() const
Definition DIE.h:864
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:406
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:83
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.
void verifyKeepChain()
Recursively walk the DIE tree and check "keepness" and "placement" information.
RootEntriesListTy Dependencies
List of entries dependencies.
void markParentsAsKeepingChildren(const UnitEntryPairTy &Entry)
Mark parents as keeping children.
UnitEntryPairTy getRootForSpecifiedEntry(UnitEntryPairTy Entry)
bool markCollectedLiveRootsAsKept(bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Examine worklist and mark all 'root DIE's as kept and set "Placement" property.
bool maybeAddReferencedRoots(LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, const UnitEntryPairTy &Entry, bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Check referenced DIEs and add them into the worklist.
bool isLiveAction(LiveRootWorklistActionTy Action)
bool isChildrenAction(LiveRootWorklistActionTy Action)
bool isTypeAction(LiveRootWorklistActionTy Action)
bool markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, const UnitEntryPairTy &Entry, bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Mark whole DIE tree as kept recursively.
bool isTypeTableCandidate(const DWARFDebugInfoEntry *DIEEntry)
void setPlainDwarfPlacementRec(const UnitEntryPairTy &Entry)
Mark whole DIE tree as placed in "PlainDwarf".
RootEntriesListTy RootEntriesWorkList
List of entries which are 'root DIE's.
void addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry, std::optional< UnitEntryPairTy > ReferencedBy)
Add action item to the work list.
static bool isLiveSubprogramEntry(const UnitEntryPairTy &Entry)
Returns true if specified subprogram references live code section.
bool resolveDependenciesAndMarkLiveness(bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Recursively walk the DIE tree and look for DIEs to keep.
static bool isLiveVariableEntry(const UnitEntryPairTy &Entry, bool IsLiveParent)
Returns true if specified variable references live code section.
@ MarkTypeEntryRec
Mark current item and all its children as type entry.
@ MarkLiveChildrenRec
Mark all children of current item as live entry.
@ MarkLiveEntryRec
Mark current item and all its children as live entry.
@ MarkTypeChildrenRec
Mark all children of current item as type entry.
void collectRootsToKeep(const UnitEntryPairTy &Entry, std::optional< UnitEntryPairTy > ReferencedBy, bool IsLiveParent)
This function navigates DIEs tree starting from specified Entry.
bool updateDependenciesCompleteness()
Check if dependencies have incompatible placement.
DIEInfo & getDIEInfo(unsigned Idx)
Idx index of the DIE.
#define 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.
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:557
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
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:221
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1946
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.