DebugInfo: Lazily construct subprogram definition DIEs.
authorDavid Blaikie <dblaikie@gmail.com>
Tue, 27 May 2014 18:37:48 +0000 (18:37 +0000)
committerDavid Blaikie <dblaikie@gmail.com>
Tue, 27 May 2014 18:37:48 +0000 (18:37 +0000)
A further step to correctly emitting concrete out of line definitions
preceeding inlined instances of the same program.

To do this, emission of subprograms must be delayed until required since
we don't know which (abstract only (if there's no out of line
definition), concrete only (if there are no inlined instances), or both)
DIEs are required at the start of the module.

To reduce the test churn in the following commit that actually fixes the
bug, this commit introduces the lazy DIE construction and cleans up test
cases that are impacted by the changes in the resulting DIE ordering.

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

lib/CodeGen/AsmPrinter/DwarfDebug.cpp
test/DebugInfo/X86/concrete_out_of_line.ll
test/DebugInfo/X86/debug-info-blocks.ll
test/DebugInfo/X86/inline-member-function.ll
test/DebugInfo/X86/inline-seldag-test.ll
test/DebugInfo/X86/sret.ll
test/DebugInfo/debug-info-qualifiers.ll
test/DebugInfo/namespace.ll
test/DebugInfo/varargs.ll
test/Linker/type-unique-odr-a.ll

index 6234f12dd2bea914656d51e077bdd647f2e17363..421cdbd95fa215dbe858ff7f4c1dc738cc753669 100644 (file)
@@ -314,7 +314,7 @@ bool DwarfDebug::isSubprogramContext(const MDNode *Context) {
 // scope then create and insert DIEs for these variables.
 DIE &DwarfDebug::updateSubprogramScopeDIE(DwarfCompileUnit &SPCU,
                                           DISubprogram SP) {
-  DIE *SPDie = SPCU.getDIE(SP);
+  DIE *SPDie = SPCU.getOrCreateSubprogramDIE(SP);
 
   assert(SPDie && "Unable to find subprogram DIE!");
 
@@ -525,15 +525,18 @@ void DwarfDebug::constructAbstractSubprogramScopeDIE(DwarfCompileUnit &TheCU,
 
   DISubprogram SP(Scope->getScopeNode());
 
-  if (!ProcessedSPNodes.insert(SP))
+  DIE *&AbsDef = AbstractSPDies[SP];
+  if (AbsDef)
     return;
 
   // Find the subprogram's DwarfCompileUnit in the SPMap in case the subprogram
   // was inlined from another compile unit.
   DwarfCompileUnit &SPCU = *SPMap[SP];
-  DIE *AbsDef = SPCU.getDIE(SP);
-  assert(AbsDef);
-  AbstractSPDies.insert(std::make_pair(SP, AbsDef));
+  AbsDef = SPCU.getOrCreateSubprogramDIE(SP);
+
+  if (!ProcessedSPNodes.insert(SP))
+    return;
+
   SPCU.addUInt(*AbsDef, dwarf::DW_AT_inline, None, dwarf::DW_INL_inlined);
   createAndAddScopeChildren(SPCU, Scope, *AbsDef);
 }
@@ -781,7 +784,7 @@ void DwarfDebug::beginModule() {
       CU.createGlobalVariableDIE(DIGlobalVariable(GVs.getElement(i)));
     DIArray SPs = CUNode.getSubprograms();
     for (unsigned i = 0, e = SPs.getNumElements(); i != e; ++i)
-      constructSubprogramDIE(CU, SPs.getElement(i));
+      SPMap.insert(std::make_pair(SPs.getElement(i), &CU));
     DIArray EnumTypes = CUNode.getEnumTypes();
     for (unsigned i = 0, e = EnumTypes.getNumElements(); i != e; ++i)
       CU.getOrCreateTypeDIE(EnumTypes.getElement(i));
@@ -818,8 +821,17 @@ void DwarfDebug::finishSubprogramDefinitions() {
     DIArray Subprograms = TheCU.getSubprograms();
     for (unsigned i = 0, e = Subprograms.getNumElements(); i != e; ++i) {
       DISubprogram SP(Subprograms.getElement(i));
-      if (DIE *D = SPCU->getDIE(SP))
-        SPCU->applySubprogramAttributes(SP, *D);
+      // Perhaps the subprogram is in another CU (such as due to comdat
+      // folding, etc), in which case ignore it here.
+      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()));
     }
   }
 }
@@ -863,11 +875,11 @@ void DwarfDebug::collectDeadVariables() {
 }
 
 void DwarfDebug::finalizeModuleInfo() {
+  finishSubprogramDefinitions();
+
   // Collect info for variables that were optimized out.
   collectDeadVariables();
 
-  finishSubprogramDefinitions();
-
   // Handle anything that needs to be done on a per-unit basis after
   // all other generation.
   for (const auto &TheU : getUnits()) {
index 5d4d5802bd1ac2e1824ae987cbb7e72f7c15cbc8..5d9f6a5779bbefe4b3e7e1d7ac0228255dcee492 100644 (file)
 ; CHECK: [[RELEASE_DECL:0x........]]:  DW_TAG_subprogram
 ; 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-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-NOT:     DW_AT
+; CHECK: [[D1_THIS_ABS:.*]]: DW_TAG_formal_parameter
+
 ; CHECK: [[RELEASE:0x........]]: DW_TAG_subprogram
 ; CHECK:     DW_AT_specification {{.*}} {[[RELEASE_DECL]]}
 ; CHECK: DW_TAG_formal_parameter
 ; CHECK-NOT: NULL
 ; CHECK-NOT: DW_TAG
 ; CHECK: DW_TAG_inlined_subroutine
-; CHECK-NEXT: DW_AT_abstract_origin {{.*}} {[[D1_ABS:0x........]]}
+; CHECK-NEXT: DW_AT_abstract_origin {{.*}} {[[D1_ABS]]}
 ; CHECK-NOT: NULL
 ; CHECK-NOT: DW_TAG
 ; CHECK: DW_TAG_inlined_subroutine
-; CHECK-NEXT: DW_AT_abstract_origin {{.*}} {[[D2_ABS:0x........]]}
-
-; CHECK: [[D1_ABS]]: DW_TAG_subprogram
-; CHECK-NEXT:     DW_AT_inline
-; CHECK-NEXT:     DW_AT_{{.*}}linkage_name
-; CHECK-NEXT:     DW_AT_specification {{.*}} {[[DTOR_DECL]]}
-; CHECK-NOT:     DW_AT
-; CHECK: [[D1_THIS_ABS:0x........]]: DW_TAG_formal_parameter
-; CHECK: [[D2_ABS]]: DW_TAG_subprogram
-; CHECK-NEXT:     DW_AT_inline
-; CHECK-NEXT:     DW_AT_{{.*}}linkage_name
-; CHECK-NEXT:     DW_AT_specification {{.*}} {[[DTOR_DECL]]}
-; CHECK-NOT:     DW_AT
-; CHECK: DW_TAG
+; CHECK-NEXT: DW_AT_abstract_origin {{.*}} {[[D2_ABS]]}
 
 ; and then that a TAG_subprogram refers to it with AT_abstract_origin.
 
-; CHECK: DW_TAG_subprogram
 ; CHECK: DW_TAG_subprogram
 ; CHECK-NEXT: DW_AT_abstract_origin {{.*}} {[[D1_ABS]]}
 ; CHECK: DW_TAG_formal_parameter
index 5feab24772395561085e799edd6f00829d330861..430c1575816a58a573caf51ca8319d52a5f15a31 100644 (file)
@@ -5,6 +5,11 @@
 ; rdar://problem/9279956
 ; test that the DW_AT_location of self is at ( fbreg +{{[0-9]+}}, deref, +{{[0-9]+}} )
 
+; CHECK: [[A:.*]]:   DW_TAG_structure_type
+; CHECK-NEXT: DW_AT_APPLE_objc_complete_type
+; CHECK-NEXT: DW_AT_name{{.*}}"A"
+
+; CHECK: DW_TAG_subprogram
 ; CHECK: DW_TAG_subprogram
 ; CHECK: DW_TAG_subprogram
 ; CHECK-NOT: DW_TAG
@@ -32,9 +37,6 @@
 ; 0x91 = DW_OP_fbreg
 ; CHECK: DW_AT_location{{.*}}91 {{[0-9]+}} 06 23 {{[0-9]+}} )
 
-; CHECK: [[A:.*]]:   DW_TAG_structure_type
-; CHECK-NEXT: DW_AT_APPLE_objc_complete_type
-; CHECK-NEXT: DW_AT_name{{.*}}"A"
 ; CHECK: [[APTR]]:   DW_TAG_pointer_type
 ; CHECK-NEXT: {[[A]]}
 
index 4a4a19c19130b70d658040fd6ba428fd04e2002e..3dc6043bf36c4c7b62d26254946c53ee8e52fc6d 100644 (file)
 ;   return foo().func(i);
 ; }
 
+; CHECK: DW_TAG_structure_type
+; CHECK:   DW_TAG_subprogram
+
+; But make sure we emit DW_AT_object_pointer on the abstract definition.
+; CHECK: [[ABSTRACT_ORIGIN:.*]]: DW_TAG_subprogram
+; CHECK-NOT: NULL
+; CHECK-NOT: TAG
+; CHECK: DW_AT_object_pointer
+
 ; Ensure we omit DW_AT_object_pointer on inlined subroutines.
 ; CHECK: DW_TAG_inlined_subroutine
-; CHECK-NEXT: DW_AT_abstract_origin {{.*}}{[[ABSTRACT_ORIGIN:0x[0-9a-e]*]]}
+; CHECK-NEXT: DW_AT_abstract_origin {{.*}}{[[ABSTRACT_ORIGIN]]}
 ; CHECK-NOT: NULL
 ; CHECK-NOT: DW_AT_object_pointer
 ; CHECK: DW_TAG_formal_parameter
 ; CHECK-NOT: DW_AT_artificial
 ; CHECK: DW_TAG
 
-; But make sure we emit DW_AT_object_pointer on the abstract definition.
-; CHECK: [[ABSTRACT_ORIGIN]]: DW_TAG_subprogram
-; CHECK-NOT: NULL
-; CHECK-NOT: TAG
-; CHECK: DW_AT_object_pointer
-
 %struct.foo = type { i8 }
 
 @i = global i32 0, align 4
index f139140ee758dc0c555d5b388532735c37e8eced..615f03a2ad28873fb3f28a50999c948371df4313 100644 (file)
 ;   x = f(x);
 ; }
 
-; CHECK: DW_TAG_inlined_subroutine
-; CHECK-NEXT: DW_AT_abstract_origin {{.*}} {[[F:0x.*]]}
-; CHECK: [[F]]: DW_TAG_subprogram
+; CHECK: [[F:.*]]: DW_TAG_subprogram
 ; CHECK-NOT: DW_TAG
 ; CHECK: DW_AT_name {{.*}} "f"
 
+; CHECK: DW_TAG_inlined_subroutine
+; CHECK-NEXT: DW_AT_abstract_origin {{.*}} {[[F]]}
+
 
 ; Make sure the condition test is attributed to the inline function, not the
 ; location of the test's operands within the caller.
index 004632814c2cd57d1ef5039ba29ec35f7a0f5dbb..fed4334c27f5a60efd9842e31e9a2de01b944230 100644 (file)
@@ -3,8 +3,8 @@
 
 ; Based on the debuginfo-tests/sret.cpp code.
 
-; CHECK: DW_AT_GNU_dwo_id [DW_FORM_data8] (0xc68148e4333befda)
-; CHECK: DW_AT_GNU_dwo_id [DW_FORM_data8] (0xc68148e4333befda)
+; CHECK: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x72aabf538392d298)
+; CHECK: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x72aabf538392d298)
 
 %class.A = type { i32 (...)**, i32 }
 %class.B = type { i8 }
index 2aea7360707695e0745c18d136a26d10f11ec643..b624d3874cb3ab0e14d493875cf59b05a59d5f78 100644 (file)
@@ -21,8 +21,6 @@
 ; CHECK-NEXT: DW_AT_rvalue_reference DW_FORM_flag_present
 ;
 ; CHECK: DW_TAG_subprogram
-;
-; CHECK: DW_TAG_subprogram
 ; CHECK-NOT: DW_TAG_subprogram
 ; CHECK:   DW_AT_name {{.*}}"l"
 ; CHECK-NOT: DW_TAG_subprogram
index ca5cf808d180a7d566280346e87b63ddd94c0d95..a9de62c39062685442fc35673b768916149aaa45 100644 (file)
 ; CHECK: [[I:0x[0-9a-f]*]]:{{ *}}DW_TAG_variable
 ; CHECK-NEXT: DW_AT_name{{.*}}= "i"
 ; CHECK-NOT: NULL
-; CHECK: DW_TAG_subprogram
+; CHECK: [[FOO:0x[0-9a-f]*]]:{{ *}}DW_TAG_structure_type
+; CHECK-NEXT: DW_AT_name{{.*}}= "foo"
+; CHECK-NEXT: DW_AT_declaration
+; CHECK-NOT: NULL
+; CHECK: [[BAR:0x[0-9a-f]*]]:{{ *}}DW_TAG_structure_type
+; CHECK-NEXT: DW_AT_name{{.*}}= "bar"
+; CHECK: NULL
+; CHECK: [[FUNC1:.*]]: DW_TAG_subprogram
 ; CHECK-NOT: DW_TAG
 ; CHECK: DW_AT_MIPS_linkage_name
 ; CHECK-NOT: DW_TAG
 ; CHECK: DW_AT_name{{.*}}= "f1"
-; CHECK: [[FUNC1:0x[0-9a-f]*]]:{{ *}}DW_TAG_subprogram
+; CHECK: DW_TAG_subprogram
 ; CHECK-NOT: DW_TAG
 ; CHECK: DW_AT_MIPS_linkage_name
 ; CHECK-NOT: DW_TAG
 ; CHECK: DW_AT_name{{.*}}= "f1"
 ; CHECK: NULL
-; CHECK-NOT: NULL
-; CHECK: [[FOO:0x[0-9a-f]*]]:{{ *}}DW_TAG_structure_type
-; CHECK-NEXT: DW_AT_name{{.*}}= "foo"
-; CHECK-NEXT: DW_AT_declaration
-; CHECK-NOT: NULL
-; CHECK: [[BAR:0x[0-9a-f]*]]:{{ *}}DW_TAG_structure_type
-; CHECK-NEXT: DW_AT_name{{.*}}= "bar"
-; CHECK: NULL
-; CHECK: NULL
-; CHECK: NULL
 
 ; CHECK-NOT: NULL
 ; CHECK: DW_TAG_imported_module
 ; CHECK: NULL
 ; CHECK-NOT: NULL
 
+; CHECK: DW_TAG_imported_module
+; Same bug as above, this should be F2, not F1
+; CHECK-NEXT: DW_AT_decl_file{{.*}}(0x0[[F1]])
+; CHECK-NEXT: DW_AT_decl_line{{.*}}(0x0b)
+; CHECK-NEXT: DW_AT_import{{.*}}=> {[[NS1]]})
+; CHECK-NOT: NULL
+
 ; CHECK: DW_TAG_subprogram
 ; CHECK-NOT: DW_TAG
 ; CHECK: DW_AT_MIPS_linkage_name
 ; CHECK-NEXT: DW_AT_import{{.*}}=> {[[NS2]]})
 ; CHECK: NULL
 ; CHECK: NULL
-; CHECK-NOT: NULL
-
-; CHECK: DW_TAG_imported_module
-; Same bug as above, this should be F2, not F1
-; CHECK-NEXT: DW_AT_decl_file{{.*}}(0x0[[F1]])
-; CHECK-NEXT: DW_AT_decl_line{{.*}}(0x0b)
-; CHECK-NEXT: DW_AT_import{{.*}}=> {[[NS1]]})
+; CHECK: NULL
 
 ; CHECK: file_names[  [[F1]]]{{.*}}debug-info-namespace.cpp
 ; CHECK: file_names[  [[F2]]]{{.*}}foo.cpp
index a32741426194ade57536a77250d4c9b5b7e7eeb5..ddfcd858f5393f98fea98b5a15d73bd2e6bdb7ea 100644 (file)
 ;
 ; CHECK: DW_TAG_subprogram
 ; CHECK-NOT: DW_TAG
-; CHECK: DW_AT_name {{.*}} "b"
+; CHECK: DW_AT_name {{.*}} "a"
+; CHECK-NOT: DW_TAG
+; CHECK: DW_TAG_formal_parameter
 ; CHECK-NOT: DW_TAG
 ; CHECK: DW_TAG_formal_parameter
 ; CHECK-NOT: DW_TAG
 ; CHECK: DW_TAG_unspecified_parameters
 ;
-; Variadic C++ member function.
-; struct A { void a(int c, ...); }
-;
 ; CHECK: DW_TAG_subprogram
 ; CHECK-NOT: DW_TAG
-; CHECK: DW_AT_name {{.*}} "a"
-; CHECK-NOT: DW_TAG
-; CHECK: DW_TAG_formal_parameter
+; CHECK: DW_AT_name {{.*}} "b"
 ; CHECK-NOT: DW_TAG
 ; CHECK: DW_TAG_formal_parameter
 ; CHECK-NOT: DW_TAG
 ; CHECK: DW_TAG_unspecified_parameters
 ;
+; Variadic C++ member function.
+; struct A { void a(int c, ...); }
+;
 ; Variadic function pointer.
 ; void (*fptr)(int, ...);
 ;
index 54befb75ba450246c0e71dc72719a1707231a4f0..91c80339ec033e6cd03c77289e1d5d8321ef198f 100644 (file)
 ;     return A().getFoo();
 ; }
 ;
-; CHECK:      DW_TAG_subprogram
-; CHECK-NOT: DW_TAG
-; CHECK:   DW_AT_MIPS_linkage_name {{.*}} "_Z3bazv"
-; CHECK:      DW_TAG_subprogram
-; CHECK-NOT: DW_TAG
-; CHECK:   DW_AT_MIPS_linkage_name {{.*}} "_ZL3barv"
 ; CHECK:      DW_TAG_class_type
 ; CHECK-NEXT:   DW_AT_name {{.*}} "A"
 ; CHECK-NOT:  DW_TAG
 ; CHECK:   DW_AT_MIPS_linkage_name {{.*}} "_ZN1A6getFooEv"
 ; CHECK-NOT: DW_TAG
 ; CHECK:   DW_AT_name {{.*}} "getFoo"
+; CHECK:      DW_TAG_subprogram
+; CHECK-NOT: DW_TAG
+; CHECK:   DW_AT_MIPS_linkage_name {{.*}} "_Z3bazv"
+; CHECK:      DW_TAG_subprogram
+; CHECK-NOT: DW_TAG
+; CHECK:   DW_AT_MIPS_linkage_name {{.*}} "_ZL3barv"
 
 ; getFoo and A may only appear once.
 ; CHECK-NOT:  {{(getFoo)|("A")}}