diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index c28c20d68a7..c0badde3685 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -316,20 +316,6 @@ DIE &DwarfDebug::updateSubprogramScopeDIE(DwarfCompileUnit &SPCU, DISubprogram SP) { DIE *SPDie = SPCU.getOrCreateSubprogramDIE(SP); - assert(SPDie && "Unable to find subprogram DIE!"); - - // If we're updating an abstract DIE, then we will be adding the children and - // object pointer later on. But what we don't want to do is process the - // concrete DIE twice. - if (DIE *AbsSPDIE = AbstractSPDies.lookup(SP)) { - assert(SPDie == AbsSPDIE); - // Pick up abstract subprogram DIE. - SPDie = &SPCU.createAndAddDIE( - dwarf::DW_TAG_subprogram, - *SPCU.getOrCreateContextDIE(resolve(SP.getContext()))); - SPCU.addDIEEntry(*SPDie, dwarf::DW_AT_abstract_origin, *AbsSPDIE); - } - attachLowHighPC(SPCU, *SPDie, FunctionBeginSym, FunctionEndSym); const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo(); @@ -525,6 +511,8 @@ void DwarfDebug::constructAbstractSubprogramScopeDIE(DwarfCompileUnit &TheCU, DISubprogram SP(Scope->getScopeNode()); + ProcessedSPNodes.insert(SP); + DIE *&AbsDef = AbstractSPDies[SP]; if (AbsDef) return; @@ -532,10 +520,24 @@ void DwarfDebug::constructAbstractSubprogramScopeDIE(DwarfCompileUnit &TheCU, // Find the subprogram's DwarfCompileUnit in the SPMap in case the subprogram // was inlined from another compile unit. DwarfCompileUnit &SPCU = *SPMap[SP]; - AbsDef = SPCU.getOrCreateSubprogramDIE(SP); + DIE *ContextDIE; - if (!ProcessedSPNodes.insert(SP)) - return; + // Some of this is duplicated from DwarfUnit::getOrCreateSubprogramDIE, with + // the important distinction that the DIDescriptor is not associated with the + // DIE (since the DIDescriptor will be associated with the concrete DIE, if + // any). It could be refactored to some common utility function. + if (DISubprogram SPDecl = SP.getFunctionDeclaration()) { + ContextDIE = &SPCU.getUnitDie(); + SPCU.getOrCreateSubprogramDIE(SPDecl); + } else + ContextDIE = SPCU.getOrCreateContextDIE(resolve(SP.getContext())); + + // Passing null as the associated DIDescriptor because the abstract definition + // shouldn't be found by lookup. + AbsDef = &SPCU.createAndAddDIE(dwarf::DW_TAG_subprogram, *ContextDIE, + DIDescriptor()); + SPCU.applySubprogramAttributes(SP, *AbsDef); + SPCU.addGlobalName(SP.getName(), *AbsDef, resolve(SP.getContext())); SPCU.addUInt(*AbsDef, dwarf::DW_AT_inline, None, dwarf::DW_INL_inlined); createAndAddScopeChildren(SPCU, Scope, *AbsDef); @@ -686,28 +688,6 @@ DwarfCompileUnit &DwarfDebug::constructDwarfCompileUnit(DICompileUnit DIUnit) { return NewCU; } -// Construct subprogram DIE. -void DwarfDebug::constructSubprogramDIE(DwarfCompileUnit &TheCU, - const MDNode *N) { - // FIXME: We should only call this routine once, however, during LTO if a - // program is defined in multiple CUs we could end up calling it out of - // beginModule as we walk the CUs. - - DwarfCompileUnit *&CURef = SPMap[N]; - if (CURef) - return; - CURef = &TheCU; - - DISubprogram SP(N); - assert(SP.isSubprogram()); - assert(SP.isDefinition()); - - DIE &SubprogramDie = *TheCU.getOrCreateSubprogramDIE(SP); - - // Expose as a global name. - TheCU.addGlobalName(SP.getName(), SubprogramDie, resolve(SP.getContext())); -} - void DwarfDebug::constructImportedEntityDIE(DwarfCompileUnit &TheCU, const MDNode *N) { DIImportedEntity Module(N); @@ -826,12 +806,19 @@ void DwarfDebug::finishSubprogramDefinitions() { if (SPMap[SP] != SPCU) continue; DIE *D = SPCU->getDIE(SP); - if (!D) - // Lazily construct the subprogram if we didn't see either concrete or - // inlined versions during codegen. - D = SPCU->getOrCreateSubprogramDIE(SP); - SPCU->applySubprogramAttributes(SP, *D); - SPCU->addGlobalName(SP.getName(), *D, resolve(SP.getContext())); + if (DIE *AbsSPDIE = AbstractSPDies.lookup(SP)) { + if (D) + // If this subprogram has an abstract definition, reference that + SPCU->addDIEEntry(*D, dwarf::DW_AT_abstract_origin, *AbsSPDIE); + } else { + if (!D) + // Lazily construct the subprogram if we didn't see either concrete or + // inlined versions during codegen. + D = SPCU->getOrCreateSubprogramDIE(SP); + // And attach the attributes + SPCU->applySubprogramAttributes(SP, *D); + SPCU->addGlobalName(SP.getName(), *D, resolve(SP.getContext())); + } } } } @@ -861,7 +848,9 @@ void DwarfDebug::collectDeadVariables() { if (Variables.getNumElements() == 0) continue; - DIE *SPDIE = SPCU->getDIE(SP); + DIE *SPDIE = AbstractSPDies.lookup(SP); + if (!SPDIE) + SPDIE = SPCU->getDIE(SP); assert(SPDIE); for (unsigned vi = 0, ve = Variables.getNumElements(); vi != ve; ++vi) { DIVariable DV(Variables.getElement(vi)); diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index 4a4d01246c2..2f5abc829ea 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -491,9 +491,6 @@ class DwarfDebug : public AsmPrinterHandler { /// DW_TAG_compile_unit. DwarfCompileUnit &constructDwarfCompileUnit(DICompileUnit DIUnit); - /// \brief Construct subprogram DIE. - void constructSubprogramDIE(DwarfCompileUnit &TheCU, const MDNode *N); - /// \brief Construct imported_module or imported_declaration DIE. void constructImportedEntityDIE(DwarfCompileUnit &TheCU, const MDNode *N); diff --git a/test/DebugInfo/X86/concrete_out_of_line.ll b/test/DebugInfo/X86/concrete_out_of_line.ll index 5d9f6a5779b..40300de793d 100644 --- a/test/DebugInfo/X86/concrete_out_of_line.ll +++ b/test/DebugInfo/X86/concrete_out_of_line.ll @@ -15,15 +15,15 @@ ; CHECK: [[DTOR_DECL:0x........]]: DW_TAG_subprogram ; CHECK: [[D2_ABS:.*]]: DW_TAG_subprogram -; CHECK-NEXT: DW_AT_inline ; CHECK-NEXT: DW_AT_{{.*}}linkage_name {{.*}}D2 ; CHECK-NEXT: DW_AT_specification {{.*}} {[[DTOR_DECL]]} +; CHECK-NEXT: DW_AT_inline ; CHECK-NOT: DW_AT ; CHECK: DW_TAG ; CHECK: [[D1_ABS:.*]]: DW_TAG_subprogram -; CHECK-NEXT: DW_AT_inline ; CHECK-NEXT: DW_AT_{{.*}}linkage_name {{.*}}D1 ; CHECK-NEXT: DW_AT_specification {{.*}} {[[DTOR_DECL]]} +; CHECK-NEXT: DW_AT_inline ; CHECK-NOT: DW_AT ; CHECK: [[D1_THIS_ABS:.*]]: DW_TAG_formal_parameter @@ -49,9 +49,11 @@ ; and then that a TAG_subprogram refers to it with AT_abstract_origin. ; CHECK: DW_TAG_subprogram -; CHECK-NEXT: DW_AT_abstract_origin {{.*}} {[[D1_ABS]]} +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_abstract_origin {{.*}} {[[D1_ABS]]} ; CHECK: DW_TAG_formal_parameter -; CHECK-NEXT: DW_AT_abstract_origin {{.*}} {[[D1_THIS_ABS]]} +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_abstract_origin {{.*}} {[[D1_THIS_ABS]]} ; CHECK: DW_TAG_inlined_subroutine ; CHECK-NEXT: DW_AT_abstract_origin {{.*}} {[[D2_ABS]]} diff --git a/test/DebugInfo/X86/dbg-value-inlined-parameter.ll b/test/DebugInfo/X86/dbg-value-inlined-parameter.ll index 74b2f8bc338..1922272cab9 100644 --- a/test/DebugInfo/X86/dbg-value-inlined-parameter.ll +++ b/test/DebugInfo/X86/dbg-value-inlined-parameter.ll @@ -5,12 +5,16 @@ ; RUN: llc -mtriple=x86_64-apple-darwin < %s -filetype=obj -regalloc=basic \ ; RUN: | llvm-dwarfdump -debug-dump=info - | FileCheck --check-prefix=CHECK --check-prefix=DARWIN %s -; FIXME: This is both a concrete and abstract definition, which is -; incorrect. They should be separate -; CHECK: [[ABS:.*]]: DW_TAG_subprogram -; CHECK-NOT: DW_TAG -; CHECK: DW_AT_high_pc -; CHECK-NOT: DW_TAG +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_abstract_origin {{.*}}{[[ABS:.*]]} +; FIXME: An out of line definition preceeding an inline usage doesn't properly +; reference abstract variables. +; CHECK: DW_TAG_formal_parameter +; CHECK-NEXT: DW_AT_name {{.*}} "sp" +; CHECK: DW_TAG_formal_parameter +; CHECK-NEXT: DW_AT_name {{.*}} "nums" + +; CHECK: [[ABS]]: DW_TAG_subprogram ; CHECK: DW_AT_name {{.*}} "foo" ; CHECK: [[ABS_SP:.*]]: DW_TAG_formal_parameter ; CHECK-NEXT: DW_AT_name {{.*}} "sp" @@ -26,10 +30,9 @@ ;CHECK: DW_TAG_formal_parameter ;FIXME: Linux shouldn't drop this parameter either... -;FIXME: These parameters should have DW_AT_abstract_origin, instead of names. -;DARWIN-NEXT: DW_AT_name {{.*}} "sp" +;DARWIN-NEXT: DW_AT_abstract_origin {{.*}}{[[ABS_SP]]} ;DARWIN: DW_TAG_formal_parameter -;CHECK-NEXT: DW_AT_name {{.*}} "nums" +;CHECK-NEXT: DW_AT_abstract_origin {{.*}}{[[ABS_NUMS]]} ;CHECK-NOT: DW_TAG_formal_parameter %struct.S1 = type { float*, i32 } diff --git a/test/DebugInfo/cross-cu-inlining.ll b/test/DebugInfo/cross-cu-inlining.ll index 6e0378d57f0..266a24ddc67 100644 --- a/test/DebugInfo/cross-cu-inlining.ll +++ b/test/DebugInfo/cross-cu-inlining.ll @@ -25,9 +25,11 @@ ; CHECK: DW_TAG_subprogram ; CHECK: DW_AT_type [DW_FORM_ref_addr] (0x00000000[[INT:.*]]) ; CHECK: DW_TAG_inlined_subroutine -; CHECK-NEXT: DW_AT_abstract_origin {{.*}}[[ABS_FUNC:........]]) +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_abstract_origin {{.*}}[[ABS_FUNC:........]]) ; CHECK: DW_TAG_formal_parameter -; CHECK-NEXT: DW_AT_abstract_origin {{.*}}[[ABS_VAR:........]]) +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_abstract_origin {{.*}}[[ABS_VAR:........]]) ; Check the abstract definition is in the 'b.cpp' CU and doesn't contain any ; concrete information (address range or variable location) @@ -48,10 +50,13 @@ ; Check the concrete out of line definition references the abstract and ; provides the address range and variable location ; CHECK: DW_TAG_subprogram -; CHECK-NEXT: DW_AT_abstract_origin {{.*}} {0x[[ABS_FUNC]]} +; CHECK-NOT: DW_TAG ; CHECK: DW_AT_low_pc +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_abstract_origin {{.*}} {0x[[ABS_FUNC]]} ; CHECK: DW_TAG_formal_parameter -; CHECK-NEXT: DW_AT_abstract_origin {{.*}} {0x[[ABS_VAR]]} +; CHECK-NOT: DW_TAG +; CHECK: DW_AT_abstract_origin {{.*}} {0x[[ABS_VAR]]} ; CHECK: DW_AT_location