Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit 7e1a383

Browse files
committed
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@203982 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 2110a0d commit 7e1a383

File tree

6 files changed

+233
-1
lines changed

6 files changed

+233
-1
lines changed

lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ bool DwarfDebug::isSubprogramContext(const MDNode *Context) {
364364
// scope then create and insert DIEs for these variables.
365365
DIE *DwarfDebug::updateSubprogramScopeDIE(DwarfCompileUnit *SPCU,
366366
DISubprogram SP) {
367+
SP = SPCU->getOdrUniqueSubprogram(resolve(SP.getContext()), SP);
367368
DIE *SPDie = SPCU->getDIE(SP);
368369

369370
assert(SPDie && "Unable to find subprogram DIE!");

lib/CodeGen/AsmPrinter/DwarfDebug.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,9 @@ class DwarfDebug : public AsmPrinterHandler {
353353
/// of in DwarfCompileUnit.
354354
DenseMap<const MDNode *, DIE *> MDTypeNodeToDieMap;
355355

356+
// Used to unique C++ member function declarations.
357+
StringMap<const MDNode *> OdrMemberMap;
358+
356359
// Stores the current file ID for a given compile unit.
357360
DenseMap<unsigned, unsigned> FileIDCUMap;
358361
// Source id map, i.e. CUID, source filename and directory,
@@ -702,6 +705,11 @@ class DwarfDebug : public AsmPrinterHandler {
702705
return MDTypeNodeToDieMap.lookup(TypeMD);
703706
}
704707

708+
/// \brief Look up or create an entry in the OdrMemberMap.
709+
const MDNode *&getOrCreateOdrMember(StringRef Key) {
710+
return OdrMemberMap.GetOrCreateValue(Key).getValue();
711+
}
712+
705713
/// \brief Emit all Dwarf sections that should come prior to the
706714
/// content.
707715
void beginModule();

lib/CodeGen/AsmPrinter/DwarfUnit.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1405,12 +1405,33 @@ DIE *DwarfUnit::getOrCreateNameSpace(DINameSpace NS) {
14051405
return NDie;
14061406
}
14071407

1408+
/// Unique C++ member function declarations based on their
1409+
/// context and mangled name.
1410+
DISubprogram
1411+
DwarfUnit::getOdrUniqueSubprogram(DIScope Context, DISubprogram SP) const {
1412+
if (!hasODR() ||
1413+
!Context.isCompositeType() ||
1414+
SP.getLinkageName().empty() ||
1415+
SP.isDefinition())
1416+
return SP;
1417+
// Create a key with the UID of the parent class and this SP's name.
1418+
Twine Key = SP.getContext().getName() + SP.getLinkageName();
1419+
const MDNode *&Entry = DD->getOrCreateOdrMember(Key.str());
1420+
if (!Entry)
1421+
Entry = &*SP;
1422+
1423+
return DISubprogram(Entry);
1424+
}
1425+
14081426
/// getOrCreateSubprogramDIE - Create new DIE using SP.
14091427
DIE *DwarfUnit::getOrCreateSubprogramDIE(DISubprogram SP) {
14101428
// Construct the context before querying for the existence of the DIE in case
14111429
// such construction creates the DIE (as is the case for member function
14121430
// declarations).
1413-
DIE *ContextDIE = getOrCreateContextDIE(resolve(SP.getContext()));
1431+
DIScope Context = resolve(SP.getContext());
1432+
DIE *ContextDIE = getOrCreateContextDIE(Context);
1433+
// Unique declarations based on the ODR, where applicable.
1434+
SP = getOdrUniqueSubprogram(Context, SP);
14141435

14151436
DIE *SPDie = getDIE(SP);
14161437
if (SPDie)

lib/CodeGen/AsmPrinter/DwarfUnit.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,28 @@ class DwarfUnit {
485485

486486
virtual DwarfCompileUnit &getCU() = 0;
487487

488+
/// \brief Return whether this compilation unit has the
489+
/// one-definition-rule (ODR). In C++ this allows the compiler to
490+
/// perform type unique during LTO.
491+
bool hasODR() const {
492+
switch (getLanguage()) {
493+
case dwarf::DW_LANG_C_plus_plus:
494+
case dwarf::DW_LANG_C_plus_plus_03:
495+
case dwarf::DW_LANG_C_plus_plus_11:
496+
// For all we care, the C++ part of the language has the ODR and
497+
// ObjC methods are not represented in a way that they could be
498+
// confused with C++ member functions.
499+
case dwarf::DW_LANG_ObjC_plus_plus:
500+
return true;
501+
default:
502+
return false;
503+
}
504+
}
505+
506+
/// \brief Unique C++ member function declarations based on their
507+
/// context+mangled name.
508+
DISubprogram getOdrUniqueSubprogram(DIScope Context, DISubprogram SP) const;
509+
488510
protected:
489511
/// getOrCreateStaticMemberDIE - Create new static data member DIE.
490512
DIE *getOrCreateStaticMemberDIE(DIDerivedType DT);

test/Linker/type-unique-odr-a.ll

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
; REQUIRES: object-emission
2+
;
3+
; RUN: llvm-link %s %p/type-unique-odr-b.ll -S -o - | %llc_dwarf -filetype=obj -O0 | llvm-dwarfdump -debug-dump=info - | FileCheck %s
4+
;
5+
; Test ODR-based type uniquing for C++ class members.
6+
; rdar://problem/15851313.
7+
;
8+
; $ cat -n type-unique-odr-a.cpp
9+
; 1 class A {
10+
; 2 int data;
11+
; 3 protected:
12+
; 4 void getFoo();
13+
; 5 };
14+
; 6
15+
; 7 static void bar() {
16+
; 8 A a;
17+
; 9 }
18+
; 10
19+
; 11 void baz() { bar(); }
20+
;; #include "ab.h"
21+
; foo_t bar() {
22+
; return A().getFoo();
23+
; }
24+
;
25+
; CHECK: DW_TAG_subprogram
26+
; CHECK-NEXT: DW_AT_MIPS_linkage_name {{.*}} "_Z3bazv"
27+
; CHECK: DW_TAG_subprogram
28+
; CHECK-NEXT: DW_AT_MIPS_linkage_name {{.*}} "_ZL3barv"
29+
; CHECK: DW_TAG_class_type
30+
; CHECK-NEXT: DW_AT_name {{.*}} "A"
31+
; CHECK: DW_TAG_subprogram
32+
; CHECK-NEXT: DW_AT_MIPS_linkage_name {{.*}} "_ZN1A6getFooEv"
33+
; CHECK-NEXT: DW_AT_name {{.*}} "getFoo"
34+
35+
; getFoo and A may only appear once.
36+
; CHECK-NOT: {{(getFoo)|("A")}}
37+
38+
39+
; ModuleID = 'type-unique-odr-a.cpp'
40+
41+
%class.A = type { i32 }
42+
43+
; Function Attrs: nounwind
44+
define void @_Z3bazv() #0 {
45+
entry:
46+
call void @_ZL3barv(), !dbg !23
47+
ret void, !dbg !23
48+
}
49+
50+
; Function Attrs: nounwind
51+
define internal void @_ZL3barv() #0 {
52+
entry:
53+
%a = alloca %class.A, align 4
54+
call void @llvm.dbg.declare(metadata !{%class.A* %a}, metadata !24), !dbg !25
55+
ret void, !dbg !26
56+
}
57+
58+
; Function Attrs: nounwind readnone
59+
declare void @llvm.dbg.declare(metadata, metadata) #1
60+
61+
attributes #0 = { nounwind }
62+
attributes #1 = { nounwind readnone }
63+
64+
!llvm.dbg.cu = !{!0}
65+
!llvm.module.flags = !{!20, !21}
66+
!llvm.ident = !{!22}
67+
68+
!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]
69+
!1 = metadata !{metadata !"<unknown>", metadata !""}
70+
!2 = metadata !{}
71+
!3 = metadata !{metadata !4}
72+
!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 ]
73+
!5 = metadata !{metadata !"type-unique-odr-a.cpp", metadata !""}
74+
!6 = metadata !{metadata !7, metadata !9}
75+
!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]
76+
!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]
77+
!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]
78+
!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 ]
79+
!11 = metadata !{null, metadata !12}
80+
!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]
81+
!13 = metadata !{i32 786468}
82+
!14 = metadata !{metadata !15, metadata !19}
83+
!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]
84+
!16 = metadata !{i32 786473, metadata !5} ; [ DW_TAG_file_type ] [type-unique-odr-a.cpp]
85+
!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 ]
86+
!18 = metadata !{null}
87+
!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]
88+
!20 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
89+
!21 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
90+
!22 = metadata !{metadata !"clang version 3.5.0 "}
91+
!23 = metadata !{i32 11, i32 0, metadata !15, null}
92+
!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]
93+
!25 = metadata !{i32 8, i32 0, metadata !19, null} ; [ DW_TAG_imported_declaration ]
94+
!26 = metadata !{i32 9, i32 0, metadata !19, null}

test/Linker/type-unique-odr-b.ll

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
; RUN: true
2+
; This file belongs to type-unique-odr-a.ll.
3+
;
4+
; Test ODR-based type uniquing for C++ class members.
5+
; rdar://problem/15851313.
6+
;
7+
; $ cat -n type-unique-odr-b.cpp
8+
; 1 // Make this declaration start on a different line.
9+
; 2 class A {
10+
; 3 int data;
11+
; 4 protected:
12+
; 5 void getFoo();
13+
; 6 };
14+
; 7
15+
; 8 void A::getFoo() {}
16+
; 9
17+
; 10 static void bar() {}
18+
; 11 void f() { bar(); };
19+
20+
; ModuleID = 'type-unique-odr-b.cpp'
21+
22+
%class.A = type { i32 }
23+
24+
; Function Attrs: nounwind
25+
define void @_ZN1A6getFooEv(%class.A* %this) #0 align 2 {
26+
entry:
27+
%this.addr = alloca %class.A*, align 8
28+
store %class.A* %this, %class.A** %this.addr, align 8
29+
call void @llvm.dbg.declare(metadata !{%class.A** %this.addr}, metadata !24), !dbg !26
30+
%this1 = load %class.A** %this.addr
31+
ret void, !dbg !27
32+
}
33+
34+
; Function Attrs: nounwind readnone
35+
declare void @llvm.dbg.declare(metadata, metadata) #1
36+
37+
; Function Attrs: nounwind
38+
define void @_Z1fv() #0 {
39+
entry:
40+
call void @_ZL3barv(), !dbg !28
41+
ret void, !dbg !28
42+
}
43+
44+
; Function Attrs: nounwind
45+
define internal void @_ZL3barv() #0 {
46+
entry:
47+
ret void, !dbg !29
48+
}
49+
50+
attributes #0 = { nounwind }
51+
attributes #1 = { nounwind readnone }
52+
53+
!llvm.dbg.cu = !{!0}
54+
!llvm.module.flags = !{!21, !22}
55+
!llvm.ident = !{!23}
56+
57+
!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]
58+
!1 = metadata !{metadata !"<unknown>", metadata !""}
59+
!2 = metadata !{}
60+
!3 = metadata !{metadata !4}
61+
!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 ]
62+
!5 = metadata !{metadata !"type-unique-odr-b.cpp", metadata !""}
63+
!6 = metadata !{metadata !7, metadata !9}
64+
!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]
65+
!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]
66+
!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]
67+
!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 ]
68+
!11 = metadata !{null, metadata !12}
69+
!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]
70+
!13 = metadata !{i32 786468}
71+
!14 = metadata !{metadata !15, metadata !16, metadata !20}
72+
!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]
73+
!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]
74+
!17 = metadata !{i32 786473, metadata !5} ; [ DW_TAG_file_type ] [type-unique-odr-b.cpp]
75+
!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 ]
76+
!19 = metadata !{null}
77+
!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]
78+
!21 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
79+
!22 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
80+
!23 = metadata !{metadata !"clang version 3.5.0 "}
81+
!24 = metadata !{i32 786689, metadata !15, metadata !"this", null, i32 16777216, metadata !25, i32 1088, i32 0} ; [ DW_TAG_arg_variable ] [this] [line 0]
82+
!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]
83+
!26 = metadata !{i32 0, i32 0, metadata !15, null}
84+
!27 = metadata !{i32 8, i32 0, metadata !15, null} ; [ DW_TAG_imported_declaration ]
85+
!28 = metadata !{i32 11, i32 0, metadata !16, null}
86+
!29 = metadata !{i32 10, i32 0, metadata !20, null}

0 commit comments

Comments
 (0)