diff --git a/lib/CodeGen/AsmPrinter/DIE.cpp b/lib/CodeGen/AsmPrinter/DIE.cpp index 334c1083161..69444285f4e 100644 --- a/lib/CodeGen/AsmPrinter/DIE.cpp +++ b/lib/CodeGen/AsmPrinter/DIE.cpp @@ -115,13 +115,21 @@ DIE::~DIE() { /// Climb up the parent chain to get the compile unit DIE to which this DIE /// belongs. const DIE *DIE::getCompileUnit() const { + const DIE *Cu = getCompileUnitOrNull(); + assert(Cu && "We should not have orphaned DIEs."); + return Cu; +} + +/// Climb up the parent chain to get the compile unit DIE this DIE belongs +/// to. Return NULL if DIE is not added to an owner yet. +const DIE *DIE::getCompileUnitOrNull() const { const DIE *p = this; while (p) { if (p->getTag() == dwarf::DW_TAG_compile_unit) return p; p = p->getParent(); } - llvm_unreachable("We should not have orphaned DIEs."); + return NULL; } DIEValue *DIE::findAttribute(uint16_t Attribute) { diff --git a/lib/CodeGen/AsmPrinter/DIE.h b/lib/CodeGen/AsmPrinter/DIE.h index 96a01327f76..f4fa326ef67 100644 --- a/lib/CodeGen/AsmPrinter/DIE.h +++ b/lib/CodeGen/AsmPrinter/DIE.h @@ -149,6 +149,9 @@ namespace llvm { /// Climb up the parent chain to get the compile unit DIE this DIE belongs /// to. const DIE *getCompileUnit() const; + /// Similar to getCompileUnit, returns null when DIE is not added to an + /// owner yet. + const DIE *getCompileUnitOrNull() const; void setOffset(unsigned O) { Offset = O; } void setSize(unsigned S) { Size = S; } diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 703e2c12d8d..575cf31eaa6 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -98,6 +98,35 @@ int64_t CompileUnit::getDefaultLowerBound() const { return -1; } +/// Check whether the DIE for this MDNode can be shared across CUs. +static bool isShareableAcrossCUs(const MDNode *N) { + // When the MDNode can be part of the type system, the DIE can be + // shared across CUs. + return DIDescriptor(N).isType() || + (DIDescriptor(N).isSubprogram() && !DISubprogram(N).isDefinition()); +} + +/// getDIE - Returns the debug information entry map slot for the +/// specified debug variable. We delegate the request to DwarfDebug +/// when the DIE for this MDNode can be shared across CUs. The mappings +/// will be kept in DwarfDebug for shareable DIEs. +DIE *CompileUnit::getDIE(const MDNode *N) const { + if (isShareableAcrossCUs(N)) + return DD->getDIE(N); + return MDNodeToDieMap.lookup(N); +} + +/// insertDIE - Insert DIE into the map. We delegate the request to DwarfDebug +/// when the DIE for this MDNode can be shared across CUs. The mappings +/// will be kept in DwarfDebug for shareable DIEs. +void CompileUnit::insertDIE(const MDNode *N, DIE *D) { + if (isShareableAcrossCUs(N)) { + DD->insertDIE(N, D); + return; + } + MDNodeToDieMap.insert(std::make_pair(N, D)); +} + /// addFlag - Add a flag that is true. void CompileUnit::addFlag(DIE *Die, dwarf::Attribute Attribute) { if (DD->getDwarfVersion() >= 4) @@ -245,8 +274,21 @@ void CompileUnit::addDelta(DIE *Die, dwarf::Attribute Attribute, dwarf::Form For /// addDIEEntry - Add a DIE attribute data and value. /// void CompileUnit::addDIEEntry(DIE *Die, dwarf::Attribute Attribute, DIE *Entry) { - // We currently only use ref4. - Die->addValue(Attribute, dwarf::DW_FORM_ref4, createDIEEntry(Entry)); + addDIEEntry(Die, Attribute, createDIEEntry(Entry)); +} + +void CompileUnit::addDIEEntry(DIE *Die, dwarf::Attribute Attribute, + DIEEntry *Entry) { + const DIE *DieCU = Die->getCompileUnitOrNull(); + const DIE *EntryCU = Entry->getEntry()->getCompileUnitOrNull(); + if (!DieCU) + // We assume that Die belongs to this CU, if it is not linked to any CU yet. + DieCU = getCUDie(); + if (!EntryCU) + EntryCU = getCUDie(); + Die->addValue(Attribute, EntryCU == DieCU ? dwarf::DW_FORM_ref4 + : dwarf::DW_FORM_ref_addr, + Entry); } /// Create a DIE with the given Tag, add the DIE to its parent, and @@ -882,7 +924,7 @@ void CompileUnit::addType(DIE *Entity, DIType Ty, dwarf::Attribute Attribute) { DIEEntry *Entry = getDIEEntry(Ty); // If it exists then use the existing value. if (Entry) { - Entity->addValue(Attribute, dwarf::DW_FORM_ref4, Entry); + addDIEEntry(Entity, Attribute, Entry); return; } @@ -892,7 +934,7 @@ void CompileUnit::addType(DIE *Entity, DIType Ty, dwarf::Attribute Attribute) { // Set up proxy. Entry = createDIEEntry(Buffer); insertDIEEntry(Ty, Entry); - Entity->addValue(Attribute, dwarf::DW_FORM_ref4, Entry); + addDIEEntry(Entity, Attribute, Entry); // If this is a complete composite type then include it in the // list of global types. diff --git a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index 8e2d69de727..a177d1910ba 100644 --- a/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -155,15 +155,19 @@ public: void addAccelType(StringRef Name, std::pair Die); /// getDIE - Returns the debug information entry map slot for the - /// specified debug variable. - DIE *getDIE(const MDNode *N) const { return MDNodeToDieMap.lookup(N); } + /// specified debug variable. We delegate the request to DwarfDebug + /// when the MDNode can be part of the type system, since DIEs for + /// the type system can be shared across CUs and the mappings are + /// kept in DwarfDebug. + DIE *getDIE(const MDNode *N) const; DIEBlock *getDIEBlock() { return new (DIEValueAllocator) DIEBlock(); } - /// insertDIE - Insert DIE into the map. - void insertDIE(const MDNode *N, DIE *D) { - MDNodeToDieMap.insert(std::make_pair(N, D)); - } + /// insertDIE - Insert DIE into the map. We delegate the request to DwarfDebug + /// when the MDNode can be part of the type system, since DIEs for + /// the type system can be shared across CUs and the mappings are + /// kept in DwarfDebug. + void insertDIE(const MDNode *N, DIE *D); /// addDie - Adds or interns the DIE to the compile unit. /// @@ -224,6 +228,10 @@ public: /// void addDIEEntry(DIE *Die, dwarf::Attribute Attribute, DIE *Entry); + /// addDIEEntry - Add a DIE attribute data and value. + /// + void addDIEEntry(DIE *Die, dwarf::Attribute Attribute, DIEEntry *Entry); + /// addBlock - Add block data. /// void addBlock(DIE *Die, dwarf::Attribute Attribute, DIEBlock *Block); diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 771cb3215a3..d18b7a55d31 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2083,6 +2083,9 @@ void DwarfDebug::emitDIE(DIE *Die, ArrayRef Abbrevs) { DwarfInfoSectionSym, DIEEntry::getRefAddrSize(Asm)); } else { + // Make sure Origin belong to the same CU. + assert(Die->getCompileUnit() == Origin->getCompileUnit() && + "The referenced DIE should belong to the same CU in ref4"); Asm->EmitInt32(Addr); } break; diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index 90ca2763e6b..84fdcdd75e9 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -332,6 +332,11 @@ class DwarfDebug { // Maps a CU DIE with its corresponding CompileUnit. DenseMap CUDieMap; + /// Maps MDNodes for type sysstem with the corresponding DIEs. These DIEs can + /// be shared across CUs, that is why we keep the map here instead + /// of in CompileUnit. + DenseMap MDTypeNodeToDieMap; + // Used to uniquely define abbreviations. FoldingSet AbbreviationsSet; @@ -662,6 +667,13 @@ public: // DwarfDebug(AsmPrinter *A, Module *M); + void insertDIE(const MDNode *TypeMD, DIE *Die) { + MDTypeNodeToDieMap.insert(std::make_pair(TypeMD, Die)); + } + DIE *getDIE(const MDNode *TypeMD) { + return MDTypeNodeToDieMap.lookup(TypeMD); + } + /// \brief Emit all Dwarf sections that should come prior to the /// content. void beginModule(); diff --git a/test/DebugInfo/X86/ref_addr_relocation.ll b/test/DebugInfo/X86/ref_addr_relocation.ll new file mode 100644 index 00000000000..3c1221fcbae --- /dev/null +++ b/test/DebugInfo/X86/ref_addr_relocation.ll @@ -0,0 +1,70 @@ +; RUN: llc -filetype=asm -O0 -mtriple=x86_64-linux-gnu < %s | FileCheck %s +; RUN: llc -filetype=obj -O0 %s -mtriple=x86_64-linux-gnu -o %t +; RUN: llvm-dwarfdump %t | FileCheck %s -check-prefix=CHECK-DWARF + +; RUN: llc -filetype=obj %s -mtriple=x86_64-apple-darwin -o %t2 +; RUN: llvm-dwarfdump %t2 | FileCheck %s -check-prefix=DARWIN-DWARF + +; Testing case generated from: +; clang++ tu1.cpp tu2.cpp -g -emit-llvm -c +; llvm-link tu1.bc tu2.bc -o tu12.ll -S +; cat hdr.h +; struct foo { +; }; +; cat tu1.cpp +; #include "hdr.h" +; foo f; +; cat tu2.cpp +; #include "hdr.h" +; foo g; + +; Make sure we use relocation for ref_addr on non-darwin platforms. +; CHECK: DW_TAG_compile_unit +; CHECK: DW_TAG_variable +; CHECK: .long [[TYPE:.*]] # DW_AT_type +; CHECK: DW_TAG_structure_type +; CHECK: debug_info_end0 +; CHECK: DW_TAG_compile_unit +; CHECK-NOT: DW_TAG_structure_type +; This variable's type is in the 1st CU. +; CHECK: DW_TAG_variable +; Make sure this is relocatable. +; CHECK: .quad .Lsection_info+[[TYPE]] # DW_AT_type +; CHECK-NOT: DW_TAG_structure_type +; CHECK: debug_info_end1 + +; CHECK-DWARF: DW_TAG_compile_unit +; CHECK-DWARF: 0x[[ADDR:.*]]: DW_TAG_structure_type +; CHECK-DWARF: DW_TAG_compile_unit +; CHECK-DWARF: DW_TAG_variable +; CHECK-DWARF: DW_AT_type [DW_FORM_ref_addr] {{.*}}[[ADDR]]) + +; DARWIN-DWARF: DW_TAG_compile_unit +; DARWIN-DWARF: 0x[[ADDR:.*]]: DW_TAG_structure_type +; DARWIN-DWARF: DW_TAG_compile_unit +; DARWIN-DWARF: DW_TAG_variable +; DARWIN-DWARF: DW_AT_type [DW_FORM_ref_addr] {{.*}}[[ADDR]]) + +%struct.foo = type { i8 } + +@f = global %struct.foo zeroinitializer, align 1 +@g = global %struct.foo zeroinitializer, align 1 + +!llvm.dbg.cu = !{!0, !9} +!llvm.module.flags = !{!14} + +!0 = metadata !{i32 786449, metadata !1, i32 4, metadata !"clang version 3.4 (trunk 191799)", i1 false, metadata !"", i32 0, metadata !2, metadata !3, metadata !2, metadata !6, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [/Users/manmanren/test-Nov/type_unique_air/ref_addr/tu1.cpp] [DW_LANG_C_plus_plus] +!1 = metadata !{metadata !"tu1.cpp", metadata !"/Users/manmanren/test-Nov/type_unique_air/ref_addr"} +!2 = metadata !{i32 0} +!3 = metadata !{metadata !4} +!4 = metadata !{i32 786451, metadata !5, null, metadata !"foo", i32 1, i64 8, i64 8, i32 0, i32 0, null, metadata !2, i32 0, null, null, metadata !"_ZTS3foo"} ; [ DW_TAG_structure_type ] [foo] [line 1, size 8, align 8, offset 0] [def] [from ] +!5 = metadata !{metadata !"./hdr.h", metadata !"/Users/manmanren/test-Nov/type_unique_air/ref_addr"} +!6 = metadata !{metadata !7} +!7 = metadata !{i32 786484, i32 0, null, metadata !"f", metadata !"f", metadata !"", metadata !8, i32 2, metadata !4, i32 0, i32 1, %struct.foo* @f, null} ; [ DW_TAG_variable ] [f] [line 2] [def] +!8 = metadata !{i32 786473, metadata !1} ; [ DW_TAG_file_type ] [/Users/manmanren/test-Nov/type_unique_air/ref_addr/tu1.cpp] +!9 = metadata !{i32 786449, metadata !10, i32 4, metadata !"clang version 3.4 (trunk 191799)", i1 false, metadata !"", i32 0, metadata !2, metadata !3, metadata !2, metadata !11, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [/Users/manmanren/test-Nov/type_unique_air/ref_addr/tu2.cpp] [DW_LANG_C_plus_plus] +!10 = metadata !{metadata !"tu2.cpp", metadata !"/Users/manmanren/test-Nov/type_unique_air/ref_addr"} +!11 = metadata !{metadata !12} +!12 = metadata !{i32 786484, i32 0, null, metadata !"g", metadata !"g", metadata !"", metadata !13, i32 2, metadata !4, i32 0, i32 1, %struct.foo* @g, null} ; [ DW_TAG_variable ] [g] [line 2] [def] +!13 = metadata !{i32 786473, metadata !10} ; [ DW_TAG_file_type ] [/Users/manmanren/test-Nov/type_unique_air/ref_addr/tu2.cpp] +!14 = metadata !{i32 2, metadata !"Dwarf Version", i32 2} diff --git a/test/Linker/Inputs/type-unique-simple2-a.ll b/test/Linker/Inputs/type-unique-simple2-a.ll index 20cfd545053..50581267d57 100644 --- a/test/Linker/Inputs/type-unique-simple2-a.ll +++ b/test/Linker/Inputs/type-unique-simple2-a.ll @@ -1,14 +1,18 @@ -; CHECK: 0x[[INT:.*]]: DW_TAG_base_type -; CHECK-NEXT: DW_AT_name {{.*}} = "int" -; CHECK-NOT: DW_TAG_base_type +; Make sure the backend generates a single DIE and uses ref_addr. ; CHECK: 0x[[BASE:.*]]: DW_TAG_structure_type ; CHECK-NEXT: DW_AT_name {{.*}} = "Base" ; CHECK-NOT: DW_TAG_structure_type +; CHECK: 0x[[INT:.*]]: DW_TAG_base_type +; CHECK-NEXT: DW_AT_name {{.*}} = "int" +; CHECK-NOT: DW_TAG_base_type + +; CHECK: DW_TAG_compile_unit ; CHECK: DW_TAG_formal_parameter ; CHECK: DW_AT_type [DW_FORM_ref_addr] {{.*}}[[INT]]) ; CHECK: DW_TAG_variable ; CHECK: DW_AT_type [DW_FORM_ref_addr] {{.*}}[[BASE]]) +; Make sure llvm-link only generates a single copy of the struct. ; LINK: DW_TAG_structure_type ; LINK-NOT: DW_TAG_structure_type diff --git a/test/Linker/type-unique-simple-a.ll b/test/Linker/type-unique-simple-a.ll index c8f9462d80d..808563f2939 100644 --- a/test/Linker/type-unique-simple-a.ll +++ b/test/Linker/type-unique-simple-a.ll @@ -1,7 +1,27 @@ -; RUN: llvm-link %s %p/type-unique-simple-b.ll -S -o - | FileCheck %s +; REQUIRES: object-emission -; CHECK: DW_TAG_structure_type +; RUN: llvm-link %s %p/type-unique-simple-b.ll -S -o %t +; RUN: cat %t | FileCheck %s -check-prefix=LINK +; RUN: llc -filetype=obj -O0 < %t > %t2 +; RUN: llvm-dwarfdump -debug-dump=info %t2 | FileCheck %s + +; Make sure the backend generates a single DIE and uses ref_addr. +; CHECK: 0x[[BASE:.*]]: DW_TAG_structure_type +; CHECK-NEXT: DW_AT_name {{.*}} = "Base" ; CHECK-NOT: DW_TAG_structure_type +; CHECK: 0x[[INT:.*]]: DW_TAG_base_type +; CHECK-NEXT: DW_AT_name {{.*}} = "int" +; CHECK-NOT: DW_TAG_base_type + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_TAG_formal_parameter +; CHECK: DW_AT_type [DW_FORM_ref_addr] {{.*}}[[INT]]) +; CHECK: DW_TAG_variable +; CHECK: DW_AT_type [DW_FORM_ref_addr] {{.*}}[[BASE]]) + +; Make sure llvm-link only generates a single copy of the struct. +; LINK: DW_TAG_structure_type +; LINK-NOT: DW_TAG_structure_type ; Content of header files: ; struct Base { ; int a; diff --git a/test/Linker/type-unique-simple2.ll b/test/Linker/type-unique-simple2.ll index 83e4715bf0d..ead91df6da1 100644 --- a/test/Linker/type-unique-simple2.ll +++ b/test/Linker/type-unique-simple2.ll @@ -2,3 +2,5 @@ ; RUN: llvm-link %S/Inputs/type-unique-simple2-a.ll %S/Inputs/type-unique-simple2-b.ll -S -o %t ; RUN: cat %t | FileCheck %S/Inputs/type-unique-simple2-a.ll -check-prefix=LINK +; RUN: llc -filetype=obj -O0 < %t > %t2 +; RUN: llvm-dwarfdump -debug-dump=info %t2 | FileCheck %S/Inputs/type-unique-simple2-a.ll