diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -45,6 +45,14 @@ enum class UnitKind { Skeleton, Full }; class DwarfCompileUnit final : public DwarfUnit { +public: + /// A pair of GlobalVariable and DIExpression. + struct GlobalExpr { + const GlobalVariable *Var; + const DIExpression *Expr; + }; + +private: /// A numeric ID unique among all CUs in the module unsigned UniqueID; bool HasRangeLists = false; @@ -83,6 +91,14 @@ DenseMap AbstractSPDies; DenseMap> AbstractEntities; + /// A global variable whose DIE does not yet have a parent. + struct DeferredGlobalVariable { + const DIGlobalVariable *GV; + DIE *Die; + ArrayRef Exprs; + }; + SmallVector DeferredGlobalVariables; + /// DWO ID for correlating skeleton and split units. uint64_t DWOId = 0; @@ -128,12 +144,6 @@ /// Get line table start symbol for this unit. MCSymbol *getLineTableStartSym() const { return LineTableStartSym; } - /// A pair of GlobalVariable and DIExpression. - struct GlobalExpr { - const GlobalVariable *Var; - const DIExpression *Expr; - }; - struct BaseTypeRef { BaseTypeRef(unsigned BitSize, dwarf::TypeKind Encoding) : BitSize(BitSize), Encoding(Encoding) {} @@ -144,6 +154,9 @@ std::vector ExprRefedBaseTypes; + /// Get or create the parent DIE of the global variable. + DIE *getOrCreateGlobalVariableParentDIE(const DIGlobalVariable *GV, + ArrayRef GlobalExprs); /// Get or create global variable DIE. DIE * getOrCreateGlobalVariableDIE(const DIGlobalVariable *GV, @@ -270,6 +283,8 @@ void finishSubprogramDefinition(const DISubprogram *SP); void finishEntityDefinition(const DbgEntity *Entity); + /// Move static variable DIEs to the appropriate parent DIE. + void finishStaticVariableDIEs(); /// Find abstract variable associated with Var. using InlinedEntity = DbgValueHistoryMap::InlinedEntity; diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -132,6 +132,21 @@ File->getSource(), CUID); } +DIE *DwarfCompileUnit::getOrCreateGlobalVariableParentDIE( + const DIGlobalVariable *GV, ArrayRef GlobalExprs) { + auto *Scope = GV->getScope(); + if (auto *ParentDie = getAbstractSPDies()[Scope]) + return ParentDie; + if (auto *CB = Scope ? dyn_cast(Scope) : nullptr) + return getOrCreateCommonBlock(CB, GlobalExprs); + return getOrCreateContextDIE(Scope); +} + +void DwarfCompileUnit::finishStaticVariableDIEs() { + for (auto &Var : DeferredGlobalVariables) + getOrCreateGlobalVariableParentDIE(Var.GV, Var.Exprs)->addChild(Var.Die); +} + DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( const DIGlobalVariable *GV, ArrayRef GlobalExprs) { // Check for pre-existence. @@ -139,18 +154,22 @@ return Die; assert(GV); - - auto *GVContext = GV->getScope(); const DIType *GTy = GV->getType(); - // Construct the context before querying for the existence of the DIE in - // case such construction creates the DIE. - auto *CB = GVContext ? dyn_cast(GVContext) : nullptr; - DIE *ContextDIE = CB ? getOrCreateCommonBlock(CB, GlobalExprs) - : getOrCreateContextDIE(GVContext); + DIE *VariableDIE = DIE::get(DIEValueAllocator, GV->getTag()); + const auto *Scope = GV->getScope(); + if (Scope && isa(Scope)) { + // If a DIGlobalVariable's scope is a DILocalScope, it is a function-local + // static global variable. At this point it is not possible to know whether + // the parent will be a separate abstract origin DIE or an out-of-line + // subprogram DIE. Defer adding these DIEs to their parent DIE until all + // subprograms have been found and created. + DeferredGlobalVariables.push_back({GV, VariableDIE, GlobalExprs}); + } else { + getOrCreateGlobalVariableParentDIE(GV, GlobalExprs)->addChild(VariableDIE); + } + insertDIE(GV, VariableDIE); - // Add to map. - DIE *VariableDIE = &createAndAddDIE(GV->getTag(), *ContextDIE, GV); DIScope *DeclContext; if (auto *SDMDecl = GV->getStaticDataMemberDeclaration()) { DeclContext = SDMDecl->getScope(); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1290,6 +1290,7 @@ auto &TheCU = *P.second; if (TheCU.getCUNode()->isDebugDirectivesOnly()) continue; + TheCU.finishStaticVariableDIEs(); // Emit DW_AT_containing_type attribute to connect types with their // vtable holding type. TheCU.constructContainingTypeDIEs(); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -376,9 +376,12 @@ DIEEntry Entry) { const DIEUnit *CU = Die.getUnit(); const DIEUnit *EntryCU = Entry.getEntry().getUnit(); - if (!CU) + if (!CU) { // We assume that Die belongs to this CU, if it is not linked to any CU yet. CU = getUnitDie().getUnit(); + // for (auto &DGV : ((const DwarfCompileUnit *)CU)->DeferredGlobalVariables) + // assert(DGV.Die != &Die); + } if (!EntryCU) EntryCU = getUnitDie().getUnit(); addAttribute(Die, Attribute, diff --git a/llvm/test/DebugInfo/Generic/static-var-inlined.ll b/llvm/test/DebugInfo/Generic/static-var-inlined.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/static-var-inlined.ll @@ -0,0 +1,59 @@ +; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -v -debug-info - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_TAG_base_type +; CHECK: DW_TAG_imported_declaration +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name {{.*}} "foo" +; CHECK: DW_AT_inline [DW_FORM_data1] (DW_INL_inlined) +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name {{.*}} "local_var" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name {{.*}} "static_var" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name {{.*}} "imported_static_var" +; CHECK: NULL +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name {{.*}} "main" +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_AT_abstract_origin {{.*}} "foo" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_abstract_origin {{.*}} "local_var" +; CHECK: NULL +; CHECK: NULL +; CHECK: NULL + +@static_var = internal global i32 4, align 4, !dbg !0 + +define i32 @main() !dbg !7 { + store i32 0, i32* @static_var, align 4, !dbg !15 + %local_var = alloca i32, align 4 + call void @llvm.dbg.declare(metadata i32* %local_var, metadata !2, metadata !DIExpression()), !dbg !15 + store i32 0, i32* %local_var, align 4, !dbg !15 + ret i32 0 +} + +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!4} +!llvm.module.flags = !{!11, !12, !13} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = !DIGlobalVariable(name: "static_var", scope: !6, file: !5, line: 3, type: !10, isLocal: false, isDefinition: true) +!2 = !DILocalVariable(name: "local_var", scope: !6, file: !5, line: 4, type: !10) +!3 = !DISubroutineType(types: !8) +!4 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !5, emissionKind: FullDebug, globals: !9, splitDebugInlining: false, imports: !17) +!5 = !DIFile(filename: "test.cpp", directory: "/") +!6 = distinct !DISubprogram(name: "foo", scope: !5, file: !5, line: 2, type: !3, scopeLine: 2, unit: !4) +!7 = distinct !DISubprogram(name: "main", scope: !5, file: !5, line: 7, type: !3, scopeLine: 7, unit: !4) +!8 = !{} +!9 = !{!0} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{i32 7, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!15 = !DILocation(line: 4, column: 7, scope: !6, inlinedAt: !16) +!16 = !DILocation(line: 9, column: 3, scope: !7) +!17 = !{!18} +!18 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !4, entity: !19, line: 122) +!19 = !DIGlobalVariable(name: "imported_static_var", scope: !6, file: !5, line: 3, type: !10, isLocal: false, isDefinition: true) diff --git a/llvm/test/DebugInfo/X86/gnu-public-names.ll b/llvm/test/DebugInfo/X86/gnu-public-names.ll --- a/llvm/test/DebugInfo/X86/gnu-public-names.ll +++ b/llvm/test/DebugInfo/X86/gnu-public-names.ll @@ -137,19 +137,6 @@ ; CHECK-NOT: {{DW_TAG|NULL}} ; CHECK: DW_AT_name {{.*}} "global_namespace_function" -; CHECK: DW_TAG_subprogram -; CHECK-NOT: {{DW_TAG|NULL}} -; CHECK: DW_AT_name {{.*}} "f3" -; CHECK-NOT: {{DW_TAG|NULL}} -; CHECK: [[F3_Z:.*]]: DW_TAG_variable -; CHECK-NOT: DW_TAG -; CHECK: DW_AT_name {{.*}} "z" -; CHECK-NOT: {{DW_TAG|NULL}} -; CHECK: DW_AT_location -; CHECK-NOT: {{DW_TAG|NULL}} -; CHECK: NULL -; CHECK-NOT: {{DW_TAG|NULL}} - ; CHECK: [[ANON:.*]]: DW_TAG_namespace ; CHECK-NOT: DW_AT_name ; CHECK: [[ANON_I:.*]]: DW_TAG_variable @@ -238,6 +225,18 @@ ; CHECK-NOT: {{DW_TAG|NULL}} ; CHECK: DW_AT_name {{.*}} "global_function" +; CHECK: DW_TAG_subprogram +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_AT_name {{.*}} "f3" +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: [[F3_Z:.*]]: DW_TAG_variable +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_name {{.*}} "z" +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: DW_AT_location +; CHECK-NOT: {{DW_TAG|NULL}} +; CHECK: NULL + ; CHECK-LABEL: .debug_gnu_pubnames contents: ; CHECK-NEXT: length = {{.*}}, version = 0x0002, unit_offset = 0x00000000, unit_size = {{.*}} ; CHECK-NEXT: Offset Linkage Kind Name