LLVM 18.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
12namespace llvm {
13namespace dwarflinker_parallel {
14
15/// A broken link in the keep chain. By recording both the parent and the child
16/// we can show only broken links for DIEs with multiple children.
17struct BrokenLink {
22 std::string Message;
23};
24
25/// Verify the keep chain by looking for DIEs that are kept but who's parent
26/// isn't.
28#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
29 SmallVector<DWARFDie> Worklist;
30 Worklist.push_back(CU.getOrigUnit().getUnitDIE());
31
32 // List of broken links.
33 SmallVector<BrokenLink> BrokenLinks;
34
35 while (!Worklist.empty()) {
36 const DWARFDie Current = Worklist.back();
37 Worklist.pop_back();
38
39 if (!Current.isValid())
40 continue;
41
42 CompileUnit::DIEInfo &CurrentInfo =
43 CU.getDIEInfo(Current.getDebugInfoEntry());
44 const bool ParentPlainDieIsKept = CurrentInfo.needToKeepInPlainDwarf();
45 const bool ParentTypeDieIsKept = CurrentInfo.needToPlaceInTypeTable();
46
47 for (DWARFDie Child : reverse(Current.children())) {
48 Worklist.push_back(Child);
49
50 CompileUnit::DIEInfo &ChildInfo =
51 CU.getDIEInfo(Child.getDebugInfoEntry());
52 const bool ChildPlainDieIsKept = ChildInfo.needToKeepInPlainDwarf();
53 const bool ChildTypeDieIsKept = ChildInfo.needToPlaceInTypeTable();
54
55 if (!ParentPlainDieIsKept && ChildPlainDieIsKept)
56 BrokenLinks.emplace_back(Current, Child,
57 "Found invalid link in keep chain");
58
59 if (Child.getTag() == dwarf::DW_TAG_subprogram) {
60 if (!ChildInfo.getKeep() && isLiveSubprogramEntry(UnitEntryPairTy(
61 &CU, Child.getDebugInfoEntry()))) {
62 BrokenLinks.emplace_back(Current, Child,
63 "Live subprogram is not marked as kept");
64 }
65 }
66
67 if (!ChildInfo.getODRAvailable()) {
68 assert(!ChildTypeDieIsKept);
69 continue;
70 }
71
72 if (!ParentTypeDieIsKept && ChildTypeDieIsKept)
73 BrokenLinks.emplace_back(Current, Child,
74 "Found invalid link in keep chain");
75
76 if (CurrentInfo.getIsInAnonNamespaceScope() &&
77 ChildInfo.needToPlaceInTypeTable()) {
78 BrokenLinks.emplace_back(Current, Child,
79 "Found invalid placement marking for member "
80 "of anonymous namespace");
81 }
82 }
83 }
84
85 if (!BrokenLinks.empty()) {
86 for (BrokenLink Link : BrokenLinks) {
87 errs() << "\n=================================\n";
88 WithColor::error() << formatv("{0} between {1:x} and {2:x}", Link.Message,
89 Link.Parent.getOffset(),
90 Link.Child.getOffset());
91
92 errs() << "\nParent:";
93 Link.Parent.dump(errs(), 0, {});
94 errs() << "\n";
95 CU.getDIEInfo(Link.Parent).dump();
96
97 errs() << "\nChild:";
98 Link.Child.dump(errs(), 2, {});
99 errs() << "\n";
100 CU.getDIEInfo(Link.Child).dump();
101 }
102 report_fatal_error("invalid keep chain");
103 }
104#endif
105}
106
108 bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
110
111 // Search for live root DIEs.
112 CompileUnit::DIEInfo &CUInfo = CU.getDIEInfo(CU.getDebugInfoEntry(0));
114 collectRootsToKeep(UnitEntryPairTy{&CU, CU.getDebugInfoEntry(0)},
115 std::nullopt, false);
116
117 // Mark live DIEs as kept.
118 return markCollectedLiveRootsAsKept(InterCUProcessingStarted,
119 HasNewInterconnectedCUs);
120}
121
123 LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry,
124 std::optional<UnitEntryPairTy> ReferencedBy) {
125 if (ReferencedBy) {
126 RootEntriesWorkList.emplace_back(Action, Entry, *ReferencedBy);
127 return;
128 }
129
130 RootEntriesWorkList.emplace_back(Action, Entry);
131}
132
134 const UnitEntryPairTy &Entry, std::optional<UnitEntryPairTy> ReferencedBy,
135 bool IsLiveParent) {
136 for (const DWARFDebugInfoEntry *CurChild =
137 Entry.CU->getFirstChildEntry(Entry.DieEntry);
138 CurChild && CurChild->getAbbreviationDeclarationPtr();
139 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
140 UnitEntryPairTy ChildEntry(Entry.CU, CurChild);
141 CompileUnit::DIEInfo &ChildInfo = Entry.CU->getDIEInfo(CurChild);
142
143 bool IsLiveChild = false;
144
145 switch (CurChild->getTag()) {
146 case dwarf::DW_TAG_label: {
147 IsLiveChild = isLiveSubprogramEntry(ChildEntry);
148
149 // Keep label referencing live address.
150 // Keep label which is child of live parent entry.
151 if (IsLiveChild || (IsLiveParent && ChildInfo.getHasAnAddress())) {
154 ReferencedBy);
155 }
156 } break;
157 case dwarf::DW_TAG_subprogram: {
158 IsLiveChild = isLiveSubprogramEntry(ChildEntry);
159
160 // Keep subprogram referencing live address.
161 if (IsLiveChild) {
162 // If subprogram is in module scope and this module allows ODR
163 // deduplication set "TypeTable" placement, otherwise set "" placement
165 (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
168
169 addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
170 }
171 } break;
172 case dwarf::DW_TAG_constant:
173 case dwarf::DW_TAG_variable: {
174 IsLiveChild = isLiveVariableEntry(ChildEntry, IsLiveParent);
175
176 // Keep variable referencing live address.
177 if (IsLiveChild) {
178 // If variable is in module scope and this module allows ODR
179 // deduplication set "TypeTable" placement, otherwise set "" placement
180
182 (ChildInfo.getIsInMouduleScope() && ChildInfo.getODRAvailable())
185
186 addActionToRootEntriesWorkList(Action, ChildEntry, ReferencedBy);
187 }
188 } break;
189 case dwarf::DW_TAG_base_type: {
190 // Always keep base types.
193 ReferencedBy);
194 } break;
195 case dwarf::DW_TAG_imported_module:
196 case dwarf::DW_TAG_imported_declaration:
197 case dwarf::DW_TAG_imported_unit: {
198 // Always keep DIEs having DW_AT_import attribute.
199 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_compile_unit) {
202 ReferencedBy);
203 break;
204 }
205
208 ReferencedBy);
209 } break;
210 case dwarf::DW_TAG_type_unit:
211 case dwarf::DW_TAG_partial_unit:
212 case dwarf::DW_TAG_compile_unit: {
213 llvm_unreachable("Called for incorrect DIE");
214 } break;
215 default:
216 // Nothing to do.
217 break;
218 }
219
220 collectRootsToKeep(ChildEntry, ReferencedBy, IsLiveChild || IsLiveParent);
221 }
222}
223
225 bool InterCUProcessingStarted, std::atomic<bool> &HasNewInterconnectedCUs) {
226 bool Res = true;
227
228 // Mark roots as kept.
229 while (!RootEntriesWorkList.empty()) {
231
233 Root.getRootEntry(), InterCUProcessingStarted,
234 HasNewInterconnectedCUs)) {
235 if (Root.hasReferencedByOtherEntry())
237 } else
238 Res = false;
239 }
240
241 return Res;
242}
243
245 bool HasNewDependency = false;
247 assert(Root.hasReferencedByOtherEntry() &&
248 "Root entry without dependency inside the dependencies list");
249
250 UnitEntryPairTy RootEntry = Root.getRootEntry();
251 CompileUnit::DIEInfo &RootInfo =
252 RootEntry.CU->getDIEInfo(RootEntry.DieEntry);
253
254 UnitEntryPairTy ReferencedByEntry = Root.getReferencedByEntry();
255 CompileUnit::DIEInfo &ReferencedByInfo =
256 ReferencedByEntry.CU->getDIEInfo(ReferencedByEntry.DieEntry);
257
258 if (!RootInfo.needToPlaceInTypeTable() &&
259 ReferencedByInfo.needToPlaceInTypeTable()) {
260 HasNewDependency = true;
261 setPlainDwarfPlacementRec(ReferencedByEntry);
262
263 // FIXME: we probably need to update getKeepTypeChildren status for
264 // parents of *Root.ReferencedBy.
265 }
266 }
267
268 return HasNewDependency;
269}
270
272 const UnitEntryPairTy &Entry) {
273 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
274 if (Info.getPlacement() == CompileUnit::PlainDwarf &&
275 !Info.getKeepTypeChildren())
276 return;
277
278 Info.setPlacement(CompileUnit::PlainDwarf);
279 Info.unsetKeepTypeChildren();
281
282 for (const DWARFDebugInfoEntry *CurChild =
283 Entry.CU->getFirstChildEntry(Entry.DieEntry);
284 CurChild && CurChild->getAbbreviationDeclarationPtr();
285 CurChild = Entry.CU->getSiblingEntry(CurChild))
286 setPlainDwarfPlacementRec(UnitEntryPairTy{Entry.CU, CurChild});
287}
288
289static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry) {
290 switch (Entry->getTag()) {
291 case dwarf::DW_TAG_compile_unit:
292 case dwarf::DW_TAG_module:
293 case dwarf::DW_TAG_namespace:
294 return true;
295
296 default:
297 return false;
298 }
299}
300
302 CompileUnit::DieOutputPlacement NewPlacement) {
303 if (!Info.getKeep())
304 return false;
305
306 switch (NewPlacement) {
308 return Info.needToPlaceInTypeTable();
309
311 return Info.needToKeepInPlainDwarf();
312
314 return Info.needToPlaceInTypeTable() && Info.needToKeepInPlainDwarf();
315
317 llvm_unreachable("Unset placement type is specified.");
318 };
319
320 llvm_unreachable("Unknown CompileUnit::DieOutputPlacement enum");
321}
322
324 CompileUnit::DieOutputPlacement NewPlacement) {
325 return isAlreadyMarked(Entry.CU->getDIEInfo(Entry.DieEntry), NewPlacement);
326}
327
329 const UnitEntryPairTy &Entry) {
330 if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
331 return;
332
333 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
334 bool NeedKeepTypeChildren = Info.needToPlaceInTypeTable();
335 bool NeedKeepPlainChildren = Info.needToKeepInPlainDwarf();
336
337 bool AreTypeParentsDone = !NeedKeepTypeChildren;
338 bool ArePlainParentsDone = !NeedKeepPlainChildren;
339
340 // Mark parents as 'Keep*Children'.
341 std::optional<uint32_t> ParentIdx = Entry.DieEntry->getParentIdx();
342 while (ParentIdx) {
343 const DWARFDebugInfoEntry *ParentEntry =
344 Entry.CU->getDebugInfoEntry(*ParentIdx);
345 CompileUnit::DIEInfo &ParentInfo = Entry.CU->getDIEInfo(*ParentIdx);
346
347 if (!AreTypeParentsDone && NeedKeepTypeChildren) {
348 if (ParentInfo.getKeepTypeChildren())
349 AreTypeParentsDone = true;
350 else {
351 bool AddToWorklist = !isAlreadyMarked(
353 ParentInfo.setKeepTypeChildren();
354 if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
357 UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
358 }
359 }
360 }
361
362 if (!ArePlainParentsDone && NeedKeepPlainChildren) {
363 if (ParentInfo.getKeepPlainChildren())
364 ArePlainParentsDone = true;
365 else {
366 bool AddToWorklist = !isAlreadyMarked(
368 ParentInfo.setKeepPlainChildren();
369 if (AddToWorklist && !isNamespaceLikeEntry(ParentEntry)) {
372 UnitEntryPairTy{Entry.CU, ParentEntry}, std::nullopt);
373 }
374 }
375 }
376
377 if (AreTypeParentsDone && ArePlainParentsDone)
378 break;
379
380 ParentIdx = ParentEntry->getParentIdx();
381 }
382}
383
384// This function tries to set specified \p Placement for the \p Entry.
385// Depending on the concrete entry, the placement could be:
386// a) changed to another.
387// b) joined with current entry placement.
388// c) set as requested.
392 assert((Placement != CompileUnit::NotSet) && "Placement is not set");
393 CompileUnit::DIEInfo &EntryInfo = Entry.CU->getDIEInfo(Entry.DieEntry);
394
395 if (!EntryInfo.getODRAvailable())
397
398 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_variable) {
399 // Do not put variable into the "TypeTable" and "PlainDwarf" at the same
400 // time.
401 if (EntryInfo.getPlacement() == CompileUnit::PlainDwarf ||
402 EntryInfo.getPlacement() == CompileUnit::Both)
404
407 }
408
409 switch (EntryInfo.getPlacement()) {
411 return Placement;
412
415
418
420 return CompileUnit::Both;
421 };
422
423 llvm_unreachable("Unknown placement type.");
424 return Placement;
425}
426
428 LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
429 const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
430 std::atomic<bool> &HasNewInterconnectedCUs) {
431 if (Entry.DieEntry->getAbbreviationDeclarationPtr() == nullptr)
432 return true;
433
434 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
435
436 // Calculate final placement placement.
438 Entry,
440 assert((Info.getODRAvailable() || isLiveAction(Action) ||
442 "Wrong kind of placement for ODR unavailable entry");
443
444 if (!isChildrenAction(Action))
445 if (isAlreadyMarked(Entry, Placement))
446 return true;
447
448 // Mark current DIE as kept.
449 Info.setKeep();
450 Info.setPlacement(Placement);
451
452 // Set keep children property for parents.
454
455 UnitEntryPairTy FinalRootEntry =
456 Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram ? Entry : RootEntry;
457
458 // Analyse referenced DIEs.
459 bool Res = true;
460 if (!maybeAddReferencedRoots(Action, FinalRootEntry, Entry,
461 InterCUProcessingStarted,
462 HasNewInterconnectedCUs))
463 Res = false;
464
465 // Return if we do not need to process children.
466 if (isSingleAction(Action))
467 return Res;
468
469 // Process children.
470 // Check for subprograms special case.
471 if (Entry.DieEntry->getTag() == dwarf::DW_TAG_subprogram &&
472 Info.getODRAvailable()) {
473 // Subprograms is a special case. As it can be root for type DIEs
474 // and itself may be subject to move into the artificial type unit.
475 // a) Non removable children(like DW_TAG_formal_parameter) should always
476 // be cloned. They are placed into the "PlainDwarf" and into the
477 // "TypeTable".
478 // b) ODR deduplication candidates(type DIEs) children should not be put
479 // into the "PlainDwarf".
480 // c) Children keeping addresses and locations(like DW_TAG_call_site)
481 // should not be put into the "TypeTable".
482 for (const DWARFDebugInfoEntry *CurChild =
483 Entry.CU->getFirstChildEntry(Entry.DieEntry);
484 CurChild && CurChild->getAbbreviationDeclarationPtr();
485 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
486 CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
487
488 switch (CurChild->getTag()) {
489 case dwarf::DW_TAG_variable:
490 case dwarf::DW_TAG_constant:
491 case dwarf::DW_TAG_subprogram:
492 case dwarf::DW_TAG_label: {
493 if (ChildInfo.getHasAnAddress())
494 continue;
495 } break;
496
497 // Entries having following tags could not be removed from the subprogram.
498 case dwarf::DW_TAG_lexical_block:
499 case dwarf::DW_TAG_friend:
500 case dwarf::DW_TAG_inheritance:
501 case dwarf::DW_TAG_formal_parameter:
502 case dwarf::DW_TAG_unspecified_parameters:
503 case dwarf::DW_TAG_template_type_parameter:
504 case dwarf::DW_TAG_template_value_parameter:
505 case dwarf::DW_TAG_GNU_template_parameter_pack:
506 case dwarf::DW_TAG_GNU_formal_parameter_pack:
507 case dwarf::DW_TAG_GNU_template_template_param:
508 case dwarf::DW_TAG_thrown_type: {
509 // Go to the default child handling.
510 } break;
511
512 default: {
513 bool ChildIsTypeTableCandidate = isTypeTableCandidate(CurChild);
514
515 // Skip child marked to be copied into the artificial type unit.
516 if (isLiveAction(Action) && ChildIsTypeTableCandidate)
517 continue;
518
519 // Skip child marked to be copied into the plain unit.
520 if (isTypeAction(Action) && !ChildIsTypeTableCandidate)
521 continue;
522
523 // Go to the default child handling.
524 } break;
525 }
526
528 Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
529 InterCUProcessingStarted, HasNewInterconnectedCUs))
530 Res = false;
531 }
532
533 return Res;
534 }
535
536 // Recursively process children.
537 for (const DWARFDebugInfoEntry *CurChild =
538 Entry.CU->getFirstChildEntry(Entry.DieEntry);
539 CurChild && CurChild->getAbbreviationDeclarationPtr();
540 CurChild = Entry.CU->getSiblingEntry(CurChild)) {
541 CompileUnit::DIEInfo ChildInfo = Entry.CU->getDIEInfo(CurChild);
542 switch (CurChild->getTag()) {
543 case dwarf::DW_TAG_variable:
544 case dwarf::DW_TAG_constant:
545 case dwarf::DW_TAG_subprogram:
546 case dwarf::DW_TAG_label: {
547 if (ChildInfo.getHasAnAddress())
548 continue;
549 } break;
550 default:
551 break; // Nothing to do.
552 };
553
555 Action, FinalRootEntry, UnitEntryPairTy{Entry.CU, CurChild},
556 InterCUProcessingStarted, HasNewInterconnectedCUs))
557 Res = false;
558 }
559
560 return Res;
561}
562
565 switch (DIEEntry->getTag()) {
566 default:
567 return false;
568
569 case dwarf::DW_TAG_imported_module:
570 case dwarf::DW_TAG_imported_declaration:
571 case dwarf::DW_TAG_imported_unit:
572 case dwarf::DW_TAG_array_type:
573 case dwarf::DW_TAG_class_type:
574 case dwarf::DW_TAG_enumeration_type:
575 case dwarf::DW_TAG_pointer_type:
576 case dwarf::DW_TAG_reference_type:
577 case dwarf::DW_TAG_string_type:
578 case dwarf::DW_TAG_structure_type:
579 case dwarf::DW_TAG_subroutine_type:
580 case dwarf::DW_TAG_typedef:
581 case dwarf::DW_TAG_union_type:
582 case dwarf::DW_TAG_variant:
583 case dwarf::DW_TAG_module:
584 case dwarf::DW_TAG_ptr_to_member_type:
585 case dwarf::DW_TAG_set_type:
586 case dwarf::DW_TAG_subrange_type:
587 case dwarf::DW_TAG_base_type:
588 case dwarf::DW_TAG_const_type:
589 case dwarf::DW_TAG_enumerator:
590 case dwarf::DW_TAG_file_type:
591 case dwarf::DW_TAG_packed_type:
592 case dwarf::DW_TAG_thrown_type:
593 case dwarf::DW_TAG_volatile_type:
594 case dwarf::DW_TAG_dwarf_procedure:
595 case dwarf::DW_TAG_restrict_type:
596 case dwarf::DW_TAG_interface_type:
597 case dwarf::DW_TAG_namespace:
598 case dwarf::DW_TAG_unspecified_type:
599 case dwarf::DW_TAG_shared_type:
600 case dwarf::DW_TAG_rvalue_reference_type:
601 case dwarf::DW_TAG_coarray_type:
602 case dwarf::DW_TAG_dynamic_type:
603 case dwarf::DW_TAG_atomic_type:
604 case dwarf::DW_TAG_immutable_type:
605 case dwarf::DW_TAG_function_template:
606 case dwarf::DW_TAG_class_template:
607 return true;
608 }
609}
610
612 LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry,
613 const UnitEntryPairTy &Entry, bool InterCUProcessingStarted,
614 std::atomic<bool> &HasNewInterconnectedCUs) {
615 const auto *Abbrev = Entry.DieEntry->getAbbreviationDeclarationPtr();
616 if (Abbrev == nullptr)
617 return true;
618
619 DWARFUnit &Unit = Entry.CU->getOrigUnit();
620 DWARFDataExtractor Data = Unit.getDebugInfoExtractor();
622 Entry.DieEntry->getOffset() + getULEB128Size(Abbrev->getCode());
623
624 // For each DIE attribute...
625 for (const auto &AttrSpec : Abbrev->attributes()) {
626 DWARFFormValue Val(AttrSpec.Form);
628 AttrSpec.Attr == dwarf::DW_AT_sibling) {
629 DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
630 Unit.getFormParams());
631 continue;
632 }
633 Val.extractValue(Data, &Offset, Unit.getFormParams(), &Unit);
634
635 // Resolve reference.
636 std::optional<UnitEntryPairTy> RefDie = Entry.CU->resolveDIEReference(
637 Val, InterCUProcessingStarted
640 if (!RefDie) {
641 Entry.CU->warn("cann't find referenced DIE", Entry.DieEntry);
642 continue;
643 }
644
645 if (!RefDie->DieEntry) {
646 // Delay resolving reference.
647 RefDie->CU->setInterconnectedCU();
648 Entry.CU->setInterconnectedCU();
649 HasNewInterconnectedCUs = true;
650 return false;
651 }
652
653 assert((Entry.CU->getUniqueID() == RefDie->CU->getUniqueID() ||
654 InterCUProcessingStarted) &&
655 "Inter-CU reference while inter-CU processing is not started");
656
657 CompileUnit::DIEInfo &RefInfo = RefDie->CU->getDIEInfo(RefDie->DieEntry);
658 if (!RefInfo.getODRAvailable())
660 else if (RefInfo.getODRAvailable() &&
661 llvm::is_contained(getODRAttributes(), AttrSpec.Attr))
662 // Note: getODRAttributes does not include DW_AT_containing_type.
663 // It should be OK as we do getRootForSpecifiedEntry(). So any containing
664 // type would be found as the root for the entry.
666 else if (isLiveAction(Action))
668 else
670
671 if (AttrSpec.Attr == dwarf::DW_AT_import) {
672 if (isNamespaceLikeEntry(RefDie->DieEntry)) {
674 isTypeAction(Action)
677 *RefDie, RootEntry);
678 continue;
679 }
680
681 addActionToRootEntriesWorkList(Action, *RefDie, RootEntry);
682 continue;
683 }
684
685 UnitEntryPairTy RootForReferencedDie = getRootForSpecifiedEntry(*RefDie);
686 addActionToRootEntriesWorkList(Action, RootForReferencedDie, RootEntry);
687 }
688
689 return true;
690}
691
694 UnitEntryPairTy Result = Entry;
695
696 do {
697 switch (Entry.DieEntry->getTag()) {
698 case dwarf::DW_TAG_subprogram:
699 case dwarf::DW_TAG_label:
700 case dwarf::DW_TAG_variable:
701 case dwarf::DW_TAG_constant: {
702 return Result;
703 } break;
704
705 default: {
706 // Nothing to do.
707 }
708 }
709
710 std::optional<uint32_t> ParentIdx = Result.DieEntry->getParentIdx();
711 if (!ParentIdx)
712 return Result;
713
714 const DWARFDebugInfoEntry *ParentEntry =
715 Result.CU->getDebugInfoEntry(*ParentIdx);
716 if (isNamespaceLikeEntry(ParentEntry))
717 break;
718 Result.DieEntry = ParentEntry;
719 } while (true);
720
721 return Result;
722}
723
725 bool IsLiveParent) {
726 DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
727 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(DIE);
728
729 if (Info.getTrackLiveness()) {
730 const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
731
732 if (!Info.getIsInFunctionScope() &&
733 Abbrev->findAttributeIndex(dwarf::DW_AT_const_value)) {
734 // Global variables with constant value can always be kept.
735 } else {
736 // See if there is a relocation to a valid debug map entry inside this
737 // variable's location. The order is important here. We want to always
738 // check if the variable has a location expression address. However, we
739 // don't want a static variable in a function to force us to keep the
740 // enclosing function, unless requested explicitly.
741 std::pair<bool, std::optional<int64_t>> LocExprAddrAndRelocAdjustment =
742 Entry.CU->getContaingFile().Addresses->getVariableRelocAdjustment(
743 DIE);
744
745 if (LocExprAddrAndRelocAdjustment.first)
746 Info.setHasAnAddress();
747
748 if (!LocExprAddrAndRelocAdjustment.second)
749 return false;
750
751 if (!IsLiveParent && Info.getIsInFunctionScope() &&
752 !Entry.CU->getGlobalData().getOptions().KeepFunctionForStatic)
753 return false;
754 }
755 }
756 Info.setHasAnAddress();
757
758 if (Entry.CU->getGlobalData().getOptions().Verbose) {
759 outs() << "Keeping variable DIE:";
760 DIDumpOptions DumpOpts;
761 DumpOpts.ChildRecurseDepth = 0;
762 DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
763 DIE.dump(outs(), 8 /* Indent */, DumpOpts);
764 }
765
766 return true;
767}
768
770 DWARFDie DIE = Entry.CU->getDIE(Entry.DieEntry);
771 CompileUnit::DIEInfo &Info = Entry.CU->getDIEInfo(Entry.DieEntry);
772 std::optional<DWARFFormValue> LowPCVal = DIE.find(dwarf::DW_AT_low_pc);
773
774 std::optional<uint64_t> LowPc;
775 std::optional<uint64_t> HighPc;
776 std::optional<int64_t> RelocAdjustment;
777 if (Info.getTrackLiveness()) {
778 LowPc = dwarf::toAddress(LowPCVal);
779 if (!LowPc)
780 return false;
781
782 Info.setHasAnAddress();
783
784 RelocAdjustment =
785 Entry.CU->getContaingFile().Addresses->getSubprogramRelocAdjustment(
786 DIE);
787 if (!RelocAdjustment)
788 return false;
789
790 if (DIE.getTag() == dwarf::DW_TAG_subprogram) {
791 // Validate subprogram address range.
792
793 HighPc = DIE.getHighPC(*LowPc);
794 if (!HighPc) {
795 Entry.CU->warn("function without high_pc. Range will be discarded.",
796 &DIE);
797 return false;
798 }
799
800 if (*LowPc > *HighPc) {
801 Entry.CU->warn("low_pc greater than high_pc. Range will be discarded.",
802 &DIE);
803 return false;
804 }
805 } else if (DIE.getTag() == dwarf::DW_TAG_label) {
806 if (Entry.CU->hasLabelAt(*LowPc))
807 return false;
808
809 // FIXME: dsymutil-classic compat. dsymutil-classic doesn't consider
810 // labels that don't fall into the CU's aranges. This is wrong IMO. Debug
811 // info generation bugs aside, this is really wrong in the case of labels,
812 // where a label marking the end of a function will have a PC == CU's
813 // high_pc.
814 if (dwarf::toAddress(Entry.CU->find(Entry.DieEntry, dwarf::DW_AT_high_pc))
815 .value_or(UINT64_MAX) <= LowPc)
816 return false;
817
818 Entry.CU->addLabelLowPc(*LowPc, *RelocAdjustment);
819 }
820 } else
821 Info.setHasAnAddress();
822
823 if (Entry.CU->getGlobalData().getOptions().Verbose) {
824 outs() << "Keeping subprogram DIE:";
825 DIDumpOptions DumpOpts;
826 DumpOpts.ChildRecurseDepth = 0;
827 DumpOpts.Verbose = Entry.CU->getGlobalData().getOptions().Verbose;
828 DIE.dump(outs(), 8 /* Indent */, DumpOpts);
829 }
830
831 if (!Info.getTrackLiveness() || DIE.getTag() == dwarf::DW_TAG_label)
832 return true;
833
834 Entry.CU->addFunctionRange(*LowPc, *HighPc, *RelocAdjustment);
835 return true;
836}
837
838} // end of namespace dwarflinker_parallel
839} // namespace llvm
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
Branch Probability Basic Block Placement
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A pointer to another debug information entry.
Definition: DIE.h:319
A structured debug information entry.
Definition: DIE.h:819
dwarf::Tag getTag() const
Definition: DIE.h:855
void dump() const
Definition: DIE.cpp:265
A DataExtractor (typically for an in-memory copy of an object-file section) plus a relocation map for...
DWARFDebugInfoEntry - A DIE with only the minimum required data.
std::optional< uint32_t > getParentIdx() const
Returns index of the parent die.
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
Definition: DWARFDie.h:42
iterator_range< iterator > children() const
Definition: DWARFDie.h:395
const DWARFDebugInfoEntry * getDebugInfoEntry() const
Definition: DWARFDie.h:52
bool isValid() const
Definition: DWARFDie.h:50
bool isFormClass(FormClass FC) const
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.
bool empty() const
Definition: SmallVector.h:94
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:941
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
static raw_ostream & error()
Convenience method for printing "error: " to stderr.
Definition: WithColor.cpp:83
DieOutputPlacement
Kinds of placement for the output die.
@ TypeTable
Corresponding DIE goes to the type table only.
@ PlainDwarf
Corresponding DIE goes to the plain dwarf only.
@ Both
Corresponding DIE goes to type table and to plain dwarf.
RootEntriesListTy RootEntriesWorkList
List of entries which are 'root DIE's.
bool markCollectedLiveRootsAsKept(bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Examine worklist and mark all 'root DIE's as kept and set "Placement" property.
bool updateDependenciesCompleteness()
Check if dependencies have incompatible placement.
bool isChildrenAction(LiveRootWorklistActionTy Action)
static bool isLiveSubprogramEntry(const UnitEntryPairTy &Entry)
Returns true if specified subprogram references live code section.
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 markDIEEntryAsKeptRec(LiveRootWorklistActionTy Action, const UnitEntryPairTy &RootEntry, const UnitEntryPairTy &Entry, bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Mark whole DIE tree as kept recursively.
void markParentsAsKeepingChildren(const UnitEntryPairTy &Entry)
Mark parents as keeping children.
void setPlainDwarfPlacementRec(const UnitEntryPairTy &Entry)
Mark whole DIE tree as placed in "PlainDwarf".
bool isLiveAction(LiveRootWorklistActionTy Action)
void verifyKeepChain()
Recursively walk the DIE tree and check "keepness" and "placement" information.
void collectRootsToKeep(const UnitEntryPairTy &Entry, std::optional< UnitEntryPairTy > ReferencedBy, bool IsLiveParent)
This function navigates DIEs tree starting from specified Entry.
UnitEntryPairTy getRootForSpecifiedEntry(UnitEntryPairTy Entry)
static bool isLiveVariableEntry(const UnitEntryPairTy &Entry, bool IsLiveParent)
Returns true if specified variable references live code section.
bool resolveDependenciesAndMarkLiveness(bool InterCUProcessingStarted, std::atomic< bool > &HasNewInterconnectedCUs)
Recursively walk the DIE tree and look for DIEs to keep.
RootEntriesListTy Dependencies
List of entries dependencies.
bool isSingleAction(LiveRootWorklistActionTy Action)
bool isTypeTableCandidate(const DWARFDebugInfoEntry *DIEEntry)
void addActionToRootEntriesWorkList(LiveRootWorklistActionTy Action, const UnitEntryPairTy &Entry, std::optional< UnitEntryPairTy > ReferencedBy)
Add action item to the work list.
bool isTypeAction(LiveRootWorklistActionTy Action)
@ 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.
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.
std::optional< uint64_t > toAddress(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an address.
static bool isNamespaceLikeEntry(const DWARFDebugInfoEntry *Entry)
static CompileUnit::DieOutputPlacement getFinalPlacementForEntry(const UnitEntryPairTy &Entry, CompileUnit::DieOutputPlacement Placement)
ArrayRef< dwarf::Attribute > getODRAttributes()
bool isAlreadyMarked(const CompileUnit::DIEInfo &Info, CompileUnit::DieOutputPlacement NewPlacement)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:440
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:428
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:156
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
unsigned getULEB128Size(uint64_t Value)
Utility function to get the size of the ULEB128-encoded value.
Definition: LEB128.cpp:19
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition: STLExtras.h:1883
Container for dump options that control which debug information will be dumped.
Definition: DIContext.h:193
unsigned ChildRecurseDepth
Definition: DIContext.h:195
Information gathered about source DIEs.
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.