[llvm] r203982 - Debug Info: Fix LTO type uniquing for C++ member declarations

Adrian Prantl aprantl at apple.com
Fri Mar 14 16:08:25 PDT 2014


Author: adrian
Date: Fri Mar 14 18:08:25 2014
New Revision: 203982

URL: http://llvm.org/viewvc/llvm-project?rev=203982&view=rev
Log:
Debug Info: Fix LTO type uniquing for C++ member declarations
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.

Added:
    llvm/trunk/test/Linker/type-unique-odr-a.ll
    llvm/trunk/test/Linker/type-unique-odr-b.ll
Modified:
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
    llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.h

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp?rev=203982&r1=203981&r2=203982&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp Fri Mar 14 18:08:25 2014
@@ -364,6 +364,7 @@ bool DwarfDebug::isSubprogramContext(con
 // 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!");

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h?rev=203982&r1=203981&r2=203982&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h Fri Mar 14 18:08:25 2014
@@ -353,6 +353,9 @@ class DwarfDebug : public AsmPrinterHand
   /// 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,
@@ -702,6 +705,11 @@ public:
     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();

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp?rev=203982&r1=203981&r2=203982&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp Fri Mar 14 18:08:25 2014
@@ -1405,12 +1405,33 @@ DIE *DwarfUnit::getOrCreateNameSpace(DIN
   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).
-  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)

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.h?rev=203982&r1=203981&r2=203982&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.h (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.h Fri Mar 14 18:08:25 2014
@@ -485,6 +485,28 @@ public:
 
   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);

Added: llvm/trunk/test/Linker/type-unique-odr-a.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Linker/type-unique-odr-a.ll?rev=203982&view=auto
==============================================================================
--- llvm/trunk/test/Linker/type-unique-odr-a.ll (added)
+++ llvm/trunk/test/Linker/type-unique-odr-a.ll Fri Mar 14 18:08:25 2014
@@ -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}

Added: llvm/trunk/test/Linker/type-unique-odr-b.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Linker/type-unique-odr-b.ll?rev=203982&view=auto
==============================================================================
--- llvm/trunk/test/Linker/type-unique-odr-b.ll (added)
+++ llvm/trunk/test/Linker/type-unique-odr-b.ll Fri Mar 14 18:08:25 2014
@@ -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}





More information about the llvm-commits mailing list