Debug Info: Fix LTO type uniquing for C++ member declarations
authorAdrian Prantl <aprantl@apple.com>
Fri, 14 Mar 2014 23:08:25 +0000 (23:08 +0000)
committerAdrian Prantl <aprantl@apple.com>
Fri, 14 Mar 2014 23:08:25 +0000 (23:08 +0000)
based on the ODR.

This adds an OdrMemberMap to DwarfDebug which is used to unique C++
member function declarations based on the unique identifier of their
containing class and their mangled name.
We can't use the usual DIRef mechanism here because DIScopes are indexed
using their entire MDNode, including decl_file and decl_line, which need
not be unique (see testcase).

Prior to this change multiple redundant member function declarations would
end up in the same uniqued DW_TAG_class_type.

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

lib/CodeGen/AsmPrinter/DwarfDebug.cpp
lib/CodeGen/AsmPrinter/DwarfDebug.h
lib/CodeGen/AsmPrinter/DwarfUnit.cpp
lib/CodeGen/AsmPrinter/DwarfUnit.h
test/Linker/type-unique-odr-a.ll [new file with mode: 0644]
test/Linker/type-unique-odr-b.ll [new file with mode: 0644]

index 4b2b7b01f172ed6b300f8fa72de6d1e82a4eb6ad..a03da3c452a66467439e6a93d408a8594f794bc6 100644 (file)
@@ -364,6 +364,7 @@ bool DwarfDebug::isSubprogramContext(const MDNode *Context) {
 // scope then create and insert DIEs for these variables.
 DIE *DwarfDebug::updateSubprogramScopeDIE(DwarfCompileUnit *SPCU,
                                           DISubprogram SP) {
 // scope then create and insert DIEs for these variables.
 DIE *DwarfDebug::updateSubprogramScopeDIE(DwarfCompileUnit *SPCU,
                                           DISubprogram SP) {
+  SP = SPCU->getOdrUniqueSubprogram(resolve(SP.getContext()), SP);
   DIE *SPDie = SPCU->getDIE(SP);
 
   assert(SPDie && "Unable to find subprogram DIE!");
   DIE *SPDie = SPCU->getDIE(SP);
 
   assert(SPDie && "Unable to find subprogram DIE!");
index bd1d304b71dcbff6f8ccd4a2fe4572e9f846b429..baf87323178d119bac99cc26555c0ea17d7e3d51 100644 (file)
@@ -353,6 +353,9 @@ class DwarfDebug : public AsmPrinterHandler {
   /// of in DwarfCompileUnit.
   DenseMap<const MDNode *, DIE *> MDTypeNodeToDieMap;
 
   /// of in DwarfCompileUnit.
   DenseMap<const MDNode *, DIE *> MDTypeNodeToDieMap;
 
+  // Used to unique C++ member function declarations.
+  StringMap<const MDNode *> OdrMemberMap;
+
   // Stores the current file ID for a given compile unit.
   DenseMap<unsigned, unsigned> FileIDCUMap;
   // Source id map, i.e. CUID, source filename and directory,
   // Stores the current file ID for a given compile unit.
   DenseMap<unsigned, unsigned> FileIDCUMap;
   // Source id map, i.e. CUID, source filename and directory,
@@ -702,6 +705,11 @@ public:
     return MDTypeNodeToDieMap.lookup(TypeMD);
   }
 
     return MDTypeNodeToDieMap.lookup(TypeMD);
   }
 
+  /// \brief Look up or create an entry in the OdrMemberMap.
+  const MDNode *&getOrCreateOdrMember(StringRef Key) {
+    return OdrMemberMap.GetOrCreateValue(Key).getValue();
+  }
+
   /// \brief Emit all Dwarf sections that should come prior to the
   /// content.
   void beginModule();
   /// \brief Emit all Dwarf sections that should come prior to the
   /// content.
   void beginModule();
index dbdcf9d2e118767281afadac1d509b9afa84c044..836beb89b45ff07fd0a0890e922aa1c36ec87038 100644 (file)
@@ -1405,12 +1405,33 @@ DIE *DwarfUnit::getOrCreateNameSpace(DINameSpace NS) {
   return NDie;
 }
 
   return NDie;
 }
 
+/// Unique C++ member function declarations based on their
+/// context and mangled name.
+DISubprogram
+DwarfUnit::getOdrUniqueSubprogram(DIScope Context, DISubprogram SP) const {
+  if (!hasODR() ||
+      !Context.isCompositeType() ||
+      SP.getLinkageName().empty() ||
+      SP.isDefinition())
+    return SP;
+  // Create a key with the UID of the parent class and this SP's name.
+  Twine Key = SP.getContext().getName() + SP.getLinkageName();
+  const MDNode *&Entry = DD->getOrCreateOdrMember(Key.str());
+  if (!Entry)
+    Entry = &*SP;
+
+  return DISubprogram(Entry);
+}
+
 /// getOrCreateSubprogramDIE - Create new DIE using SP.
 DIE *DwarfUnit::getOrCreateSubprogramDIE(DISubprogram SP) {
   // Construct the context before querying for the existence of the DIE in case
   // such construction creates the DIE (as is the case for member function
   // declarations).
 /// getOrCreateSubprogramDIE - Create new DIE using SP.
 DIE *DwarfUnit::getOrCreateSubprogramDIE(DISubprogram SP) {
   // Construct the context before querying for the existence of the DIE in case
   // such construction creates the DIE (as is the case for member function
   // declarations).
-  DIE *ContextDIE = getOrCreateContextDIE(resolve(SP.getContext()));
+  DIScope Context = resolve(SP.getContext());
+  DIE *ContextDIE = getOrCreateContextDIE(Context);
+  // Unique declarations based on the ODR, where applicable.
+  SP = getOdrUniqueSubprogram(Context, SP);
 
   DIE *SPDie = getDIE(SP);
   if (SPDie)
 
   DIE *SPDie = getDIE(SP);
   if (SPDie)
index af465c006ed485306270c4910e4eb2510f873c3c..d82087376638ec28a41d5f176dd3431bf2bebd10 100644 (file)
@@ -485,6 +485,28 @@ public:
 
   virtual DwarfCompileUnit &getCU() = 0;
 
 
   virtual DwarfCompileUnit &getCU() = 0;
 
+  /// \brief Return whether this compilation unit has the
+  /// one-definition-rule (ODR).  In C++ this allows the compiler to
+  /// perform type unique during LTO.
+  bool hasODR() const {
+    switch (getLanguage()) {
+    case dwarf::DW_LANG_C_plus_plus:
+    case dwarf::DW_LANG_C_plus_plus_03:
+    case dwarf::DW_LANG_C_plus_plus_11:
+      // For all we care, the C++ part of the language has the ODR and
+      // ObjC methods are not represented in a way that they could be
+      // confused with C++ member functions.
+    case dwarf::DW_LANG_ObjC_plus_plus:
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  /// \brief Unique C++ member function declarations based on their
+  /// context+mangled name.
+  DISubprogram getOdrUniqueSubprogram(DIScope Context, DISubprogram SP) const;
+
 protected:
   /// getOrCreateStaticMemberDIE - Create new static data member DIE.
   DIE *getOrCreateStaticMemberDIE(DIDerivedType DT);
 protected:
   /// getOrCreateStaticMemberDIE - Create new static data member DIE.
   DIE *getOrCreateStaticMemberDIE(DIDerivedType DT);
diff --git a/test/Linker/type-unique-odr-a.ll b/test/Linker/type-unique-odr-a.ll
new file mode 100644 (file)
index 0000000..6edb0c4
--- /dev/null
@@ -0,0 +1,94 @@
+; REQUIRES: object-emission
+;
+; RUN: llvm-link %s %p/type-unique-odr-b.ll -S -o - | %llc_dwarf -filetype=obj -O0 | llvm-dwarfdump -debug-dump=info - | FileCheck %s
+;
+; Test ODR-based type uniquing for C++ class members.
+; rdar://problem/15851313.
+;
+; $ cat -n type-unique-odr-a.cpp
+;     1        class A {
+;     2          int data;
+;     3        protected:
+;     4          void getFoo();
+;     5        };
+;     6
+;     7        static void bar() {
+;     8          A a;
+;     9        }
+;    10
+;    11        void baz() { bar(); }
+;; #include "ab.h"
+; foo_t bar() {
+;     return A().getFoo();
+; }
+;
+; CHECK:      DW_TAG_subprogram
+; CHECK-NEXT:   DW_AT_MIPS_linkage_name {{.*}} "_Z3bazv"
+; CHECK:      DW_TAG_subprogram
+; CHECK-NEXT:   DW_AT_MIPS_linkage_name {{.*}} "_ZL3barv"
+; CHECK:      DW_TAG_class_type
+; CHECK-NEXT:   DW_AT_name {{.*}} "A"
+; CHECK:      DW_TAG_subprogram
+; CHECK-NEXT:   DW_AT_MIPS_linkage_name {{.*}} "_ZN1A6getFooEv"
+; CHECK-NEXT:   DW_AT_name {{.*}} "getFoo"
+
+; getFoo and A may only appear once.
+; CHECK-NOT:  {{(getFoo)|("A")}}
+
+
+; ModuleID = 'type-unique-odr-a.cpp'
+
+%class.A = type { i32 }
+
+; Function Attrs: nounwind
+define void @_Z3bazv() #0 {
+entry:
+  call void @_ZL3barv(), !dbg !23
+  ret void, !dbg !23
+}
+
+; Function Attrs: nounwind
+define internal void @_ZL3barv() #0 {
+entry:
+  %a = alloca %class.A, align 4
+  call void @llvm.dbg.declare(metadata !{%class.A* %a}, metadata !24), !dbg !25
+  ret void, !dbg !26
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata) #1
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!20, !21}
+!llvm.ident = !{!22}
+
+!0 = metadata !{i32 786449, metadata !1, i32 4, metadata !"clang version 3.5.0 ", i1 false, metadata !"", i32 0, metadata !2, metadata !3, metadata !14, metadata !2, metadata !2, metadata !"", i32 1} ; [ DW_TAG_compile_unit ] [<unknown>] [DW_LANG_C_plus_plus]
+!1 = metadata !{metadata !"<unknown>", metadata !""}
+!2 = metadata !{}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786434, metadata !5, null, metadata !"A", i32 1, i64 32, i64 32, i32 0, i32 0, null, metadata !6, i32 0, null, null, metadata !"_ZTS1A"} ; [ DW_TAG_class_type ] [A] [line 1, size 32, align 32, offset 0] [def] [from ]
+!5 = metadata !{metadata !"type-unique-odr-a.cpp", metadata !""}
+!6 = metadata !{metadata !7, metadata !9}
+!7 = metadata !{i32 786445, metadata !5, metadata !"_ZTS1A", metadata !"data", i32 2, i64 32, i64 32, i64 0, i32 1, metadata !8} ; [ DW_TAG_member ] [data] [line 2, size 32, align 32, offset 0] [private] [from int]
+!8 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
+!9 = metadata !{i32 786478, metadata !5, metadata !"_ZTS1A", metadata !"getFoo", metadata !"getFoo", metadata !"_ZN1A6getFooEv", i32 4, metadata !10, i1 false, i1 false, i32 0, i32 0, null, i32 258, i1 false, null, null, i32 0, metadata !13, i32 4} ; [ DW_TAG_subprogram ] [line 4] [protected] [getFoo]
+!10 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !11, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!11 = metadata !{null, metadata !12}
+!12 = metadata !{i32 786447, null, null, metadata !"", i32 0, i64 64, i64 64, i64 0, i32 1088, metadata !"_ZTS1A"} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from _ZTS1A]
+!13 = metadata !{i32 786468}
+!14 = metadata !{metadata !15, metadata !19}
+!15 = metadata !{i32 786478, metadata !5, metadata !16, metadata !"baz", metadata !"baz", metadata !"_Z3bazv", i32 11, metadata !17, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void ()* @_Z3bazv, null, null, metadata !2, i32 11} ; [ DW_TAG_subprogram ] [line 11] [def] [baz]
+!16 = metadata !{i32 786473, metadata !5}         ; [ DW_TAG_file_type ] [type-unique-odr-a.cpp]
+!17 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !18, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!18 = metadata !{null}
+!19 = metadata !{i32 786478, metadata !5, metadata !16, metadata !"bar", metadata !"bar", metadata !"_ZL3barv", i32 7, metadata !17, i1 true, i1 true, i32 0, i32 0, null, i32 256, i1 false, void ()* @_ZL3barv, null, null, metadata !2, i32 7} ; [ DW_TAG_subprogram ] [line 7] [local] [def] [bar]
+!20 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!21 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
+!22 = metadata !{metadata !"clang version 3.5.0 "}
+!23 = metadata !{i32 11, i32 0, metadata !15, null}
+!24 = metadata !{i32 786688, metadata !19, metadata !"a", metadata !16, i32 8, metadata !4, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [a] [line 8]
+!25 = metadata !{i32 8, i32 0, metadata !19, null} ; [ DW_TAG_imported_declaration ]
+!26 = metadata !{i32 9, i32 0, metadata !19, null}
diff --git a/test/Linker/type-unique-odr-b.ll b/test/Linker/type-unique-odr-b.ll
new file mode 100644 (file)
index 0000000..3c8b7a1
--- /dev/null
@@ -0,0 +1,86 @@
+; RUN: true
+; This file belongs to type-unique-odr-a.ll.
+;
+; Test ODR-based type uniquing for C++ class members.
+; rdar://problem/15851313.
+;
+; $ cat -n type-unique-odr-b.cpp
+;     1        // Make this declaration start on a different line.
+;     2        class A {
+;     3          int data;
+;     4        protected:
+;     5          void getFoo();
+;     6        };
+;     7
+;     8        void A::getFoo() {}
+;     9
+;    10        static void bar() {}
+;    11        void f() { bar(); };
+
+; ModuleID = 'type-unique-odr-b.cpp'
+
+%class.A = type { i32 }
+
+; Function Attrs: nounwind
+define void @_ZN1A6getFooEv(%class.A* %this) #0 align 2 {
+entry:
+  %this.addr = alloca %class.A*, align 8
+  store %class.A* %this, %class.A** %this.addr, align 8
+  call void @llvm.dbg.declare(metadata !{%class.A** %this.addr}, metadata !24), !dbg !26
+  %this1 = load %class.A** %this.addr
+  ret void, !dbg !27
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata) #1
+
+; Function Attrs: nounwind
+define void @_Z1fv() #0 {
+entry:
+  call void @_ZL3barv(), !dbg !28
+  ret void, !dbg !28
+}
+
+; Function Attrs: nounwind
+define internal void @_ZL3barv() #0 {
+entry:
+  ret void, !dbg !29
+}
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!21, !22}
+!llvm.ident = !{!23}
+
+!0 = metadata !{i32 786449, metadata !1, i32 4, metadata !"clang version 3.5.0 ", i1 false, metadata !"", i32 0, metadata !2, metadata !3, metadata !14, metadata !2, metadata !2, metadata !"", i32 1} ; [ DW_TAG_compile_unit ] [<unknown>] [DW_LANG_C_plus_plus]
+!1 = metadata !{metadata !"<unknown>", metadata !""}
+!2 = metadata !{}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786434, metadata !5, null, metadata !"A", i32 2, i64 32, i64 32, i32 0, i32 0, null, metadata !6, i32 0, null, null, metadata !"_ZTS1A"} ; [ DW_TAG_class_type ] [A] [line 2, size 32, align 32, offset 0] [def] [from ]
+!5 = metadata !{metadata !"type-unique-odr-b.cpp", metadata !""}
+!6 = metadata !{metadata !7, metadata !9}
+!7 = metadata !{i32 786445, metadata !5, metadata !"_ZTS1A", metadata !"data", i32 3, i64 32, i64 32, i64 0, i32 1, metadata !8} ; [ DW_TAG_member ] [data] [line 3, size 32, align 32, offset 0] [private] [from int]
+!8 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
+!9 = metadata !{i32 786478, metadata !5, metadata !"_ZTS1A", metadata !"getFoo", metadata !"getFoo", metadata !"_ZN1A6getFooEv", i32 5, metadata !10, i1 false, i1 false, i32 0, i32 0, null, i32 258, i1 false, null, null, i32 0, metadata !13, i32 5} ; [ DW_TAG_subprogram ] [line 5] [protected] [getFoo]
+!10 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !11, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!11 = metadata !{null, metadata !12}
+!12 = metadata !{i32 786447, null, null, metadata !"", i32 0, i64 64, i64 64, i64 0, i32 1088, metadata !"_ZTS1A"} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from _ZTS1A]
+!13 = metadata !{i32 786468}
+!14 = metadata !{metadata !15, metadata !16, metadata !20}
+!15 = metadata !{i32 786478, metadata !5, metadata !"_ZTS1A", metadata !"getFoo", metadata !"getFoo", metadata !"_ZN1A6getFooEv", i32 8, metadata !10, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void (%class.A*)* @_ZN1A6getFooEv, null, metadata !9, metadata !2, i32 8} ; [ DW_TAG_subprogram ] [line 8] [def] [getFoo]
+!16 = metadata !{i32 786478, metadata !5, metadata !17, metadata !"f", metadata !"f", metadata !"_Z1fv", i32 11, metadata !18, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void ()* @_Z1fv, null, null, metadata !2, i32 11} ; [ DW_TAG_subprogram ] [line 11] [def] [f]
+!17 = metadata !{i32 786473, metadata !5}         ; [ DW_TAG_file_type ] [type-unique-odr-b.cpp]
+!18 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !19, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!19 = metadata !{null}
+!20 = metadata !{i32 786478, metadata !5, metadata !17, metadata !"bar", metadata !"bar", metadata !"_ZL3barv", i32 10, metadata !18, i1 true, i1 true, i32 0, i32 0, null, i32 256, i1 false, void ()* @_ZL3barv, null, null, metadata !2, i32 10} ; [ DW_TAG_subprogram ] [line 10] [local] [def] [bar]
+!21 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!22 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
+!23 = metadata !{metadata !"clang version 3.5.0 "}
+!24 = metadata !{i32 786689, metadata !15, metadata !"this", null, i32 16777216, metadata !25, i32 1088, i32 0} ; [ DW_TAG_arg_variable ] [this] [line 0]
+!25 = metadata !{i32 786447, null, null, metadata !"", i32 0, i64 64, i64 64, i64 0, i32 0, metadata !"_ZTS1A"} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from _ZTS1A]
+!26 = metadata !{i32 0, i32 0, metadata !15, null}
+!27 = metadata !{i32 8, i32 0, metadata !15, null} ; [ DW_TAG_imported_declaration ]
+!28 = metadata !{i32 11, i32 0, metadata !16, null}
+!29 = metadata !{i32 10, i32 0, metadata !20, null}