DebugInfo: Create abstract function definitions even when concrete definitions precee...
authorDavid Blaikie <dblaikie@gmail.com>
Tue, 27 May 2014 18:37:55 +0000 (18:37 +0000)
committerDavid Blaikie <dblaikie@gmail.com>
Tue, 27 May 2014 18:37:55 +0000 (18:37 +0000)
After much puppetry, here's the major piece of the work to ensure that
even when a concrete definition preceeds all inline definitions, an
abstract definition is still created and referenced from both concrete
and inline definitions.

Variables are still broken in this case (see comment in
dbg-value-inlined-parameter.ll test case) and will be addressed in
follow up work.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@209677 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/AsmPrinter/DwarfDebug.cpp
lib/CodeGen/AsmPrinter/DwarfDebug.h
test/DebugInfo/X86/concrete_out_of_line.ll
test/DebugInfo/X86/dbg-value-inlined-parameter.ll
test/DebugInfo/cross-cu-inlining.ll

index c28c20d68a7ad1378cac7ad7c8e56cef5c6faee0..c0badde3685ac24e3d8aeec090b5378f8b026533 100644 (file)
@@ -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;
+
+  // 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()));
 
-  if (!ProcessedSPNodes.insert(SP))
-    return;
+  // 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));
index 4a4d01246c23be151527bfbe010b60d4318de1a6..2f5abc829ea19cdf187b02c21f61b361f07bd9c0 100644 (file)
@@ -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);
 
index 5d9f6a5779bbefe4b3e7e1d7ac0228255dcee492..40300de793d55bbd58a4ff1fd83396912c4a3c10 100644 (file)
 ; 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
 
 ; 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]]}
 
index 74b2f8bc338c300f469e999324c953c5af4bcf39..1922272cab90e7184ab5f095b742b1edd4864781 100644 (file)
@@ -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"
 
 ;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 }
index 6e0378d57f0b66505aea8063108091310776a6f6..266a24ddc67017bfc984a4c954ccc38a0f9c7719 100644 (file)
 ; 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)
 ; 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