Skip to content

Commit d80fdc6

Browse files
committed
[DebugMetadata][DwarfDebug] Fix DWARF emisson of function-local imported entities (3/7)
RFC https://discourse.llvm.org/t/rfc-dwarfdebug-fix-and-improve-handling-imported-entities-types-and-static-local-in-subprogram-and-lexical-block-scopes/68544 Fixed PR51501 (tests from D112337). 1. Reuse of DISubprogram's 'retainedNodes' to track other function-local entities together with local variables and labels (this patch cares about function-local import while D144006 and D144008 use the same approach for local types and static variables). So, effectively this patch moves ownership of tracking local import from DICompileUnit's 'imports' field to DISubprogram's 'retainedNodes' and adjusts DWARF emitter for the new layout. The old layout is considered unsupported (DwarfDebug would assert on such debug metadata). DICompileUnit's 'imports' field is supposed to track global imported declarations as it does before. This addresses various FIXMEs and simplifies the next part of the patch. 2. Postpone emission of function-local imported entities from `DwarfDebug::endFunctionImpl()` to `DwarfDebug::endModule()`. While in `DwarfDebug::endFunctionImpl()` we do not have all the information about a parent subprogram or a referring subprogram (whether a subprogram inlined or not), so we can't guarantee we emit an imported entity correctly and place it in a proper subprogram tree. So now, we just gather needed details about the import itself and its parent entity (either a Subprogram or a LexicalBlock) during processing in `DwarfDebug::endFunctionImpl()`, but all the real work is done in `DwarfDebug::endModule()` when we have all the required information to make proper emission. Authored-by: Kristina Bessonova <[email protected]> Differential Revision: https://reviews.llvm.org/D144004
1 parent aee3a9f commit d80fdc6

35 files changed

+769
-278
lines changed

clang/test/CodeGenCXX/debug-info-namespace.cpp

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -81,44 +81,43 @@ void C::c() {}
8181
// CHECK: !DINamespace(scope: null)
8282
// CHECK: [[CU:![0-9]+]] = distinct !DICompileUnit(
8383
// CHECK-SAME: imports: [[MODULES:![0-9]*]]
84-
// CHECK: [[MODULES]] = !{[[M1:![0-9]+]], [[M2:![0-9]+]], [[M3:![0-9]+]], [[M4:![0-9]+]], [[M5:![0-9]+]], [[M6:![0-9]+]], [[M7:![0-9]+]], [[M8:![0-9]+]], [[M9:![0-9]+]], [[M10:![0-9]+]], [[M11:![0-9]+]], [[M12:![0-9]+]], [[M13:![0-9]+]], [[M14:![0-9]+]], [[M15:![0-9]+]], [[M16:![0-9]+]], [[M17:![0-9]+]]
84+
// CHECK: [[MODULES]] = !{[[M1:![0-9]+]], [[M2:![0-9]+]], [[M3:![0-9]+]], [[M4:![0-9]+]]}
8585
// CHECK: [[M1]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CTXT]], entity: [[NS]], file: [[FOOCPP]], line: 15)
86-
8786
// CHECK: [[M2]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[CU]], entity: [[CTXT]],
8887
// CHECK: [[M3]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "E", scope: [[CU]], entity: [[CTXT]], file: [[FOOCPP]], line: 19)
89-
// CHECK: [[M4]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[LEX2:![0-9]+]], entity: [[NS]], file: [[FOOCPP]], line: 23)
88+
// CHECK: [[M4]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[CTXT]], entity: [[I]]
89+
// CHECK: [[F1:![0-9]+]] = distinct !DISubprogram(name: "f1",{{.*}} line: 4
90+
// CHECK-SAME: DISPFlagDefinition
91+
// CHECK: [[FUNC:![0-9]+]] = distinct !DISubprogram(name: "func",{{.*}} DISPFlagDefinition
92+
// CHECK-SAME: retainedNodes: [[FUNC_NODES:![0-9]*]]
93+
// CHECK: [[FUNC_NODES]] = !{[[M5:![0-9]+]], [[M6:![0-9]+]], [[M7:![0-9]+]], [[M8:![0-9]+]], [[M9:![0-9]+]], [[M10:![0-9]+]], [[M11:![0-9]+]], [[M12:![0-9]+]], [[M13:![0-9]+]], [[M14:![0-9]+]], [[M15:![0-9]+]], [[M16:![0-9]+]], [[M17:![0-9]+]]}
94+
// CHECK: [[M5]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[LEX2:![0-9]+]], entity: [[NS]], file: [[FOOCPP]], line: 23)
9095
// CHECK: [[LEX2]] = distinct !DILexicalBlock(scope: [[LEX1:![0-9]+]], file: [[FOOCPP]],
9196
// CHECK: [[LEX1]] = distinct !DILexicalBlock(scope: [[FUNC:![0-9]+]], file: [[FOOCPP]],
92-
93-
// CHECK: [[FUNC:![0-9]+]] = distinct !DISubprogram(name: "func",{{.*}} DISPFlagDefinition
94-
// CHECK: [[M5]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[FUNC]], entity: [[CTXT:![0-9]+]],
95-
// CHECK: [[M6]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FOO:![0-9]+]], file: [[FOOCPP]], line: 27)
97+
// CHECK: [[M6]] = !DIImportedEntity(tag: DW_TAG_imported_module, scope: [[FUNC]], entity: [[CTXT]],
98+
// CHECK: [[M7]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FOO:![0-9]+]], file: [[FOOCPP]], line: 27)
9699
// CHECK: [[FOO]] = !DICompositeType(tag: DW_TAG_structure_type, name: "foo",
97100
// CHECK-SAME: line: 5
98101
// CHECK-SAME: DIFlagFwdDecl
99-
// CHECK: [[M7]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAR:![0-9]+]]
102+
// CHECK: [[M8]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAR:![0-9]+]]
100103
// CHECK: [[BAR]] = !DICompositeType(tag: DW_TAG_structure_type, name: "bar",
101104
// CHECK-SAME: line: 6
102105
// CHECK-SAME: DIFlagFwdDecl
103-
104-
// CHECK: [[M8]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[F1:![0-9]+]]
105-
// CHECK: [[F1:![0-9]+]] = distinct !DISubprogram(name: "f1",{{.*}} line: 4
106-
// CHECK-SAME: DISPFlagDefinition
107-
// CHECK: [[M9]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[I]]
108-
// CHECK: [[M10]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAZ:![0-9]+]]
106+
// CHECK: [[M9]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[F1]]
107+
// CHECK: [[M10]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[I]]
108+
// CHECK: [[M11]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[BAZ:![0-9]+]]
109109
// CHECK: [[BAZ]] = !DIDerivedType(tag: DW_TAG_typedef, name: "baz", scope: [[NS]], file: [[FOOCPP]],
110110
// CHECK-SAME: baseType: [[BAR]]
111-
// CHECK: [[M11]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "X", scope: [[FUNC]], entity: [[CTXT]]
112-
// CHECK: [[M12]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "Y", scope: [[FUNC]], entity: [[M11]]
113-
// CHECK: [[M13]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_DECL:![0-9]+]]
111+
// CHECK: [[M12]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "X", scope: [[FUNC]], entity: [[CTXT]]
112+
// CHECK: [[M13]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "Y", scope: [[FUNC]], entity: [[M12]]
113+
// CHECK: [[M14]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_DECL:![0-9]+]]
114114
// CHECK: [[VAR_DECL]] = !DIGlobalVariable(name: "var_decl", linkageName: "{{[^"]*var_decl[^"]*}}", scope: [[NS]],{{.*}} line: 8,
115-
// CHECK: [[M14]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_DECL:![0-9]+]]
115+
// CHECK: [[M15]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_DECL:![0-9]+]]
116116
// CHECK: [[FUNC_DECL]] = !DISubprogram(name: "func_decl",
117117
// CHECK-SAME: scope: [[NS]], file: [[FOOCPP]], line: 9
118-
// CHECK: [[M15]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_FWD:![0-9]+]]
119-
// CHECK: [[M16]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_FWD:![0-9]+]]
118+
// CHECK: [[M16]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[VAR_FWD:![0-9]+]]
119+
// CHECK: [[M17]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[FUNC]], entity: [[FUNC_FWD:![0-9]+]]
120120
// CHECK: [[FUNC_FWD]] = distinct !DISubprogram(name: "func_fwd",{{.*}} line: 53,{{.*}} DISPFlagDefinition
121-
// CHECK: [[M17]] = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: [[CTXT]], entity: [[I]]
122121
// CHECK: distinct !DISubprogram(name: "c",{{.*}}, scope: ![[C:[0-9]+]],{{.*}}, line: 60,{{.*}} DISPFlagDefinition
123122
// CHECK: ![[C]] = !DINamespace(name: "C",
124123

llvm/include/llvm/IR/DIBuilder.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ namespace llvm {
5454
SmallVector<TrackingMDNodeRef, 4> AllRetainTypes;
5555
SmallVector<DISubprogram *, 4> AllSubprograms;
5656
SmallVector<Metadata *, 4> AllGVs;
57-
SmallVector<TrackingMDNodeRef, 4> AllImportedModules;
57+
SmallVector<TrackingMDNodeRef, 4> ImportedModules;
5858
/// Map Macro parent (which can be DIMacroFile or nullptr) to a list of
5959
/// Metadata all of type DIMacroNode.
6060
/// DIMacroNode's with nullptr parent are DICompileUnit direct children.
@@ -64,14 +64,21 @@ namespace llvm {
6464
SmallVector<TrackingMDNodeRef, 4> UnresolvedNodes;
6565
bool AllowUnresolvedNodes;
6666

67-
/// Each subprogram's preserved local variables and labels.
67+
/// Each subprogram's preserved local variables, labels and imported
68+
/// entities.
6869
///
6970
/// Do not use a std::vector. Some versions of libc++ apparently copy
7071
/// instead of move on grow operations, and TrackingMDRef is expensive to
7172
/// copy.
7273
DenseMap<DISubprogram *, SmallVector<TrackingMDNodeRef, 4>>
7374
SubprogramTrackedNodes;
7475

76+
SmallVectorImpl<TrackingMDNodeRef> &
77+
getImportTrackingVector(const DIScope *S) {
78+
return isa_and_nonnull<DILocalScope>(S)
79+
? getSubprogramNodesTrackingVector(S)
80+
: ImportedModules;
81+
}
7582
SmallVectorImpl<TrackingMDNodeRef> &
7683
getSubprogramNodesTrackingVector(const DIScope *S) {
7784
return SubprogramTrackedNodes[cast<DILocalScope>(S)->getSubprogram()];

llvm/lib/Bitcode/Reader/MetadataLoader.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "llvm/ADT/DenseMap.h"
1616
#include "llvm/ADT/DenseSet.h"
1717
#include "llvm/ADT/STLFunctionalExtras.h"
18+
#include "llvm/ADT/SetVector.h"
1819
#include "llvm/ADT/SmallString.h"
1920
#include "llvm/ADT/SmallVector.h"
2021
#include "llvm/ADT/Statistic.h"
@@ -53,6 +54,7 @@
5354
#include <deque>
5455
#include <iterator>
5556
#include <limits>
57+
#include <map>
5658
#include <optional>
5759
#include <string>
5860
#include <tuple>
@@ -463,6 +465,9 @@ class MetadataLoader::MetadataLoaderImpl {
463465
bool NeedUpgradeToDIGlobalVariableExpression = false;
464466
bool NeedDeclareExpressionUpgrade = false;
465467

468+
/// Map DILocalScope to the enclosing DISubprogram, if any.
469+
DenseMap<DILocalScope *, DISubprogram *> ParentSubprogram;
470+
466471
/// True if metadata is being parsed for a module being ThinLTO imported.
467472
bool IsImporting = false;
468473

@@ -521,6 +526,84 @@ class MetadataLoader::MetadataLoaderImpl {
521526
}
522527
}
523528

529+
DISubprogram *findEnclosingSubprogram(DILocalScope *S) {
530+
if (!S)
531+
return nullptr;
532+
if (auto *SP = ParentSubprogram[S]) {
533+
return SP;
534+
}
535+
536+
DILocalScope *InitialScope = S;
537+
DenseSet<DILocalScope *> Visited;
538+
while (S && !isa<DISubprogram>(S)) {
539+
S = dyn_cast_or_null<DILocalScope>(S->getScope());
540+
if (Visited.contains(S))
541+
break;
542+
Visited.insert(S);
543+
}
544+
ParentSubprogram[InitialScope] = llvm::dyn_cast_or_null<DISubprogram>(S);
545+
546+
return ParentSubprogram[InitialScope];
547+
}
548+
549+
/// Move local imports from DICompileUnit's 'imports' field to
550+
/// DISubprogram's retainedNodes.
551+
void upgradeCULocals() {
552+
if (NamedMDNode *CUNodes = TheModule.getNamedMetadata("llvm.dbg.cu")) {
553+
for (unsigned I = 0, E = CUNodes->getNumOperands(); I != E; ++I) {
554+
auto *CU = dyn_cast<DICompileUnit>(CUNodes->getOperand(I));
555+
if (!CU)
556+
continue;
557+
558+
if (auto *RawImported = CU->getRawImportedEntities()) {
559+
// Collect a set of imported entities to be moved.
560+
SmallPtrSet<Metadata *, 8> EntitiesToRemove;
561+
for (Metadata *Op : CU->getImportedEntities()->operands()) {
562+
auto *IE = cast<DIImportedEntity>(Op);
563+
if (auto *S = dyn_cast_or_null<DILocalScope>(IE->getScope())) {
564+
EntitiesToRemove.insert(IE);
565+
}
566+
}
567+
568+
if (!EntitiesToRemove.empty()) {
569+
// Make a new list of CU's 'imports'.
570+
SmallVector<Metadata *> NewImports;
571+
for (Metadata *Op : CU->getImportedEntities()->operands()) {
572+
if (!EntitiesToRemove.contains(cast<DIImportedEntity>(Op))) {
573+
NewImports.push_back(Op);
574+
}
575+
}
576+
577+
// Find DISubprogram corresponding to each entity.
578+
std::map<DISubprogram *, SmallVector<Metadata *>> SPToEntities;
579+
for (auto *I : EntitiesToRemove) {
580+
auto *Entity = cast<DIImportedEntity>(I);
581+
if (auto *SP = findEnclosingSubprogram(
582+
cast<DILocalScope>(Entity->getScope()))) {
583+
SPToEntities[SP].push_back(Entity);
584+
}
585+
}
586+
587+
// Update DISubprograms' retainedNodes.
588+
for (auto I = SPToEntities.begin(); I != SPToEntities.end(); ++I) {
589+
auto *SP = I->first;
590+
auto RetainedNodes = SP->getRetainedNodes();
591+
SmallVector<Metadata *> MDs(RetainedNodes.begin(),
592+
RetainedNodes.end());
593+
MDs.append(I->second);
594+
SP->replaceRetainedNodes(MDNode::get(Context, MDs));
595+
}
596+
597+
// Remove entities with local scope from CU.
598+
CU->replaceImportedEntities(MDTuple::get(Context, NewImports));
599+
}
600+
}
601+
}
602+
}
603+
604+
ParentSubprogram.clear();
605+
}
606+
524607
/// Remove a leading DW_OP_deref from DIExpressions in a dbg.declare that
525608
/// describes a function argument.
526609
void upgradeDeclareExpressions(Function &F) {
@@ -625,6 +708,7 @@ class MetadataLoader::MetadataLoaderImpl {
625708
void upgradeDebugInfo() {
626709
upgradeCUSubprograms();
627710
upgradeCUVariables();
711+
upgradeCULocals();
628712
}
629713

630714
void callMDTypeCallback(Metadata **Val, unsigned TypeID);

0 commit comments

Comments
 (0)