[llvm] r242847 - [dsymutil] Implement ODR uniquing for C++ code.
David Blaikie
dblaikie at gmail.com
Fri Jul 24 11:22:07 PDT 2015
On Tue, Jul 21, 2015 at 5:02 PM, Frédéric Riss <friss at apple.com> wrote:
>
> On Jul 21, 2015, at 4:05 PM, David Blaikie <dblaikie at gmail.com> wrote:
>
>
>
> On Tue, Jul 21, 2015 at 3:41 PM, Frederic Riss <friss at apple.com> wrote:
>
>> Author: friss
>> Date: Tue Jul 21 17:41:43 2015
>> New Revision: 242847
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=242847&view=rev
>> Log:
>> [dsymutil] Implement ODR uniquing for C++ code.
>>
>> This optimization allows the DWARF linker to reuse definition of
>> types it has emitted in previous CUs rather than reemitting them
>> in each CU that references them. The size and link time gains are
>> huge. For example when linking the DWARF for a debug build of
>> clang, this generates a ~150M dwarf file instead of a ~700M one
>> (the numbers date back a bit and must not be totally accurate
>> these days).
>>
>> As with all the other parts of the llvm-dsymutil codebase, the
>> goal is to keep bit-for-bit compatibility with dsymutil-classic.
>> The code is littered with a lot of FIXMEs that should be
>> addressed once we can get rid of the compatibilty goal.
>>
>
> Did dsymutil-classic do this ODR uniquing too? (not quite clear to me from
> your description here - where you mention compatibility, etc) How does its
> implementation compare?
>
>
> Yes it existed, but it wasn’t enabled by default before Xcode 7 (I
> actually wonder if it found its way into any previous release). But it was
> definitely there when I started llvm-dsymutil. The dsymutil-classic and
> llvm-dsymutil that come with Xcode 7 have it both enabled by default and
> should be bit-for-bit compatible (this has been tested for every dSYM
> bundle that our internal build system generates).
>
Do you mean bit-for-bit identical? Or compatible in some way (such as
"doesn't require changes to the debug info consumers on the platform" to
pass <some tests>?)? Or something else?
>
>
>> Added:
>> llvm/trunk/test/tools/dsymutil/Inputs/odr-types.h
>> llvm/trunk/test/tools/dsymutil/Inputs/odr1.cpp
>> llvm/trunk/test/tools/dsymutil/Inputs/odr1.ll
>>
>
> Might be useful to have more distinguishing names for the test files here?
> (I assume each ODR test only needs two files - or do some need more than
> that?)
>
>
> The tests are mostly between what’s in odr1.o and each every other file.
>
So parts of odr1 are used in various odrN?
(side note: why is the IR checked in, rather than built object files? Given
that the C++ source is provided, does the IR provide much else here?)
I'm wondering if we could use a more isolated approach rather than test
cases that seem to exercise several different things across many files.
Something more like:
// The checked in object files were produced by:
// compile -DOTHER -o testname-a.o
// compile testname-b.o
// CHECK: dsymutil testname-a.o testname-b.o | dwarfdump | FileCheck
struct foo {
};
namespace {
struct bar {
}
};
#ifdef OTHER
foo f1;
bar b1;
#else
foo f2;
bar b2;
#endif
// CHECK: that foo is defined once, bar is defined twice, and f1/b1/f2/b2
reference those definitions
(or this could even be two separate tests, one for anonymous namespaced
types, one for external types, etc - same sort of thing we do in other
tests, where we group some related things together, but while keeping more
of the information together so the checks are more legible because you can
see the scenario they're trying to check. Spreading a single set of CHECKs
across 8 files and a header makes it a bit difficult to follow - reading
the CHECK lines and then trying to consult all the files to see what it
should be)
> Some of them require more though for example odr6 and 7 (see specifics
> below) are separate on purpose, because want to check that the result of
> the odr7 link didn’t reuse the odr6 results.
>
> I see it's all in odr-1.test - it's a bit monolithic, isn't it? I'm not
> sure I understand the motivation for 7 different inputs and then checking
> all together. Could you explain it?
>
>
> You can see in the name (odr-*1*.test) that I initially planned on having
> multiple tests. However, I found it easier to put everything in the same
> file (which is big, I agree, but it’s also pretty well commented if one
> understands what it’s talking about :-)).
>
The big test file says things like "this is class N::C" - that doesn't mean
much to me as a reader without going through all the source files to see
how it is used and referenced.
"this is a lambda inside func" - if I could see the source, that would be
helpful. But as it is I don't know what interesting property you're trying
to test for in that thing - that it's not duplicated? That it is?
> The reason I did everything together, is to avoid recompiling odr1.ll
> multiple times and to avoid having to pattern match the contents of the
> DWARF for that file in every test. The story of the test in odr-1.test is:
>
> - compile all the odr[1-7].ll files into object files
> - using a dummy debug map,
>
What's a debug map?
> link all these together (including linking odr1.o twice) once with ODR
> uniquing and once without
> - The odr1.ll file instantiates all the types contained in odr-types.h,
> thus its debug info will contain all the definitions. This is basically the
> ODR context pool that should be reused
> - Then the other odr*.ll that have been linked are tested like this:
> * odr1.o is linked a second time, and I check that no types (except for
> one corner case) have been duplicated and that everything links to the
> first CU
> * odr2.o and odr3.o both instantiate a different version of an
> overloaded inline function. We test that both these CUs do not contain a
> copy of the corresponding type and that uniquing was applied correctly.
> * odr4.o checks that we do not unique different thing with the same name
> inside anonymous namespaces
> * odr5.o and odr6.o are similar to 2/3, except that they instantiate a
> template member function. These ones can’t be uniqued with the content in
> odr1.o because the type is extended with a different member function each
> time.
> * odr7.o checks that we can correctly reference directly a nested type.
>
> I could definitely merge some of the unrelated ones together (say 2 4 and
> 7), it just seemed nice that each one tackled a slightly different issue. I
> could have named them according to their contents though. Would you like
> that I rename them? Or I could merge some of them, but then renaming make
> less sense.
>
> Fred
>
> - Dave
>
>
>> llvm/trunk/test/tools/dsymutil/Inputs/odr2.cpp
>> llvm/trunk/test/tools/dsymutil/Inputs/odr2.ll
>> llvm/trunk/test/tools/dsymutil/Inputs/odr3.cpp
>> llvm/trunk/test/tools/dsymutil/Inputs/odr3.ll
>> llvm/trunk/test/tools/dsymutil/Inputs/odr4.cpp
>> llvm/trunk/test/tools/dsymutil/Inputs/odr4.ll
>> llvm/trunk/test/tools/dsymutil/Inputs/odr5.cpp
>> llvm/trunk/test/tools/dsymutil/Inputs/odr5.ll
>> llvm/trunk/test/tools/dsymutil/Inputs/odr6.cpp
>> llvm/trunk/test/tools/dsymutil/Inputs/odr6.ll
>> llvm/trunk/test/tools/dsymutil/Inputs/odr7.cpp
>> llvm/trunk/test/tools/dsymutil/Inputs/odr7.ll
>> llvm/trunk/test/tools/dsymutil/X86/odr-1.test
>> Modified:
>> llvm/trunk/tools/dsymutil/DwarfLinker.cpp
>> llvm/trunk/tools/dsymutil/dsymutil.cpp
>> llvm/trunk/tools/dsymutil/dsymutil.h
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr-types.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr-types.h?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr-types.h (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr-types.h Tue Jul 21 17:41:43
>> 2015
>> @@ -0,0 +1,51 @@
>> +struct S {
>> + int I;
>> +
>> + void incr() __attribute__((always_inline)) { I++; }
>> + void incr(int Add) __attribute__((always_inline)) { I += Add; }
>> +
>> + typedef int SInt;
>> +
>> + struct Nested {
>> + double D;
>> +
>> + template<typename T> void init(T Val) { D = double(Val); }
>> + };
>> +
>> + Nested D;
>> +
>> +public:
>> + int foo() { return I; }
>> +};
>> +
>> +typedef S AliasForS;
>> +
>> +namespace N {
>> +class C {
>> + AliasForS S;
>> +};
>> +}
>> +
>> +namespace N {
>> +namespace N {
>> +class C {
>> + int S;
>> +};
>> +}
>> +}
>> +
>> +namespace {
>> + class AnonC {
>> + };
>> +}
>> +
>> +union U {
>> + class C {} C;
>> + struct S {} S;
>> +};
>> +
>> +inline int func() {
>> + struct CInsideFunc { int i; };
>> + auto functor = []() { CInsideFunc dummy; return dummy.i; };
>> + return functor();
>> +}
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr1.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr1.cpp?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr1.cpp (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr1.cpp Tue Jul 21 17:41:43
>> 2015
>> @@ -0,0 +1,11 @@
>> +#include "odr-types.h"
>> +
>> +int foo() {
>> + AliasForS s;
>> + N::C nc;
>> + N::N::C nnc;
>> + AnonC ac;
>> + U u;
>> +
>> + return func();
>> +}
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr1.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr1.ll?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr1.ll (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr1.ll Tue Jul 21 17:41:43 2015
>> @@ -0,0 +1,153 @@
>> +; Generated from odr1.cpp and odr-types.h by running:
>> +; clang -emit-llvm -g -S -std=c++11 odr1.cpp
>> +; ModuleID = 'odr1.cpp'
>> +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
>> +target triple = "x86_64-apple-macosx10.11.0"
>> +
>> +%struct.S = type { i32, %"struct.S::Nested" }
>> +%"struct.S::Nested" = type { double }
>> +%"class.N::C" = type { %struct.S }
>> +%"class.N::N::C" = type { i32 }
>> +%"class.(anonymous namespace)::AnonC" = type { i8 }
>> +%union.U = type { %"class.U::C" }
>> +%"class.U::C" = type { i8 }
>> +%class.anon = type { i8 }
>> +%struct.CInsideFunc = type { i32 }
>> +
>> +; Function Attrs: ssp uwtable
>> +define i32 @_Z3foov() #0 {
>> +entry:
>> + %s = alloca %struct.S, align 8
>> + %nc = alloca %"class.N::C", align 8
>> + %nnc = alloca %"class.N::N::C", align 4
>> + %ac = alloca %"class.(anonymous namespace)::AnonC", align 1
>> + %u = alloca %union.U, align 1
>> + call void @llvm.dbg.declare(metadata %struct.S* %s, metadata !59,
>> metadata !60), !dbg !61
>> + call void @llvm.dbg.declare(metadata %"class.N::C"* %nc, metadata !62,
>> metadata !60), !dbg !63
>> + call void @llvm.dbg.declare(metadata %"class.N::N::C"* %nnc, metadata
>> !64, metadata !60), !dbg !65
>> + call void @llvm.dbg.declare(metadata %"class.(anonymous
>> namespace)::AnonC"* %ac, metadata !66, metadata !60), !dbg !69
>> + call void @llvm.dbg.declare(metadata %union.U* %u, metadata !70,
>> metadata !60), !dbg !71
>> + %call = call i32 @_Z4funcv(), !dbg !72
>> + ret i32 %call, !dbg !73
>> +}
>> +
>> +; Function Attrs: nounwind readnone
>> +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
>> +
>> +; Function Attrs: inlinehint ssp uwtable
>> +define linkonce_odr i32 @_Z4funcv() #2 {
>> +entry:
>> + %functor = alloca %class.anon, align 1
>> + call void @llvm.dbg.declare(metadata %class.anon* %functor, metadata
>> !74, metadata !60), !dbg !75
>> + %call = call i32 @_ZZ4funcvENKUlvE_clEv(%class.anon* %functor), !dbg
>> !76
>> + ret i32 %call, !dbg !77
>> +}
>> +
>> +; Function Attrs: inlinehint nounwind ssp uwtable
>> +define linkonce_odr i32 @_ZZ4funcvENKUlvE_clEv(%class.anon* %this) #3
>> align 2 {
>> +entry:
>> + %this.addr = alloca %class.anon*, align 8
>> + %dummy = alloca %struct.CInsideFunc, align 4
>> + store %class.anon* %this, %class.anon** %this.addr, align 8
>> + call void @llvm.dbg.declare(metadata %class.anon** %this.addr,
>> metadata !78, metadata !60), !dbg !80
>> + %this1 = load %class.anon*, %class.anon** %this.addr
>> + call void @llvm.dbg.declare(metadata %struct.CInsideFunc* %dummy,
>> metadata !81, metadata !60), !dbg !82
>> + %i = getelementptr inbounds %struct.CInsideFunc, %struct.CInsideFunc*
>> %dummy, i32 0, i32 0, !dbg !83
>> + %0 = load i32, i32* %i, align 4, !dbg !83
>> + ret i32 %0, !dbg !84
>> +}
>> +
>> +attributes #0 = { ssp uwtable "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +attributes #1 = { nounwind readnone }
>> +attributes #2 = { inlinehint ssp uwtable "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +attributes #3 = { inlinehint nounwind ssp uwtable
>> "disable-tail-calls"="false" "less-precise-fpmad"="false"
>> "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"
>> "no-infs-fp-math"="false" "no-nans-fp-math"="false"
>> "stack-protector-buffer-size"="8" "target-cpu"="core2"
>> "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false"
>> "use-soft-float"="false" }
>> +
>> +!llvm.dbg.cu = !{!0}
>> +!llvm.module.flags = !{!55, !56, !57}
>> +!llvm.ident = !{!58}
>> +
>> +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1,
>> producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false,
>> runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3,
>> subprograms: !52)
>> +!1 = !DIFile(filename: "odr1.cpp", directory: "/Inputs")
>> +!2 = !{}
>> +!3 = !{!4, !20, !24, !29, !33, !37, !38, !39, !49}
>> +!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5,
>> line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S")
>> +!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs")
>> +!6 = !{!7, !9, !10, !14, !17}
>> +!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S",
>> file: !5, line: 2, baseType: !8, size: 32, align: 32)
>> +!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding:
>> DW_ATE_signed)
>> +!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S",
>> file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64,
>> offset: 64)
>> +!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope:
>> !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition:
>> false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false)
>> +!11 = !DISubroutineType(types: !12)
>> +!12 = !{null, !13}
>> +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S",
>> size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope:
>> !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition:
>> false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
>> +!15 = !DISubroutineType(types: !16)
>> +!16 = !{null, !13, !8}
>> +!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope:
>> !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition:
>> false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
>> +!18 = !DISubroutineType(types: !19)
>> +!19 = !{!8, !13}
>> +!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested",
>> scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21,
>> identifier: "_ZTSN1S6NestedE")
>> +!21 = !{!22}
>> +!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope:
>> !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64)
>> +!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding:
>> DW_ATE_float)
>> +!24 = !DICompositeType(tag: DW_TAG_class_type, name: "C", scope: !25,
>> file: !5, line: 24, size: 128, align: 64, elements: !26, identifier:
>> "_ZTSN1N1CE")
>> +!25 = !DINamespace(name: "N", scope: null, file: !5, line: 23)
>> +!26 = !{!27}
>> +!27 = !DIDerivedType(tag: DW_TAG_member, name: "S", scope:
>> !"_ZTSN1N1CE", file: !5, line: 25, baseType: !28, size: 128, align: 64)
>> +!28 = !DIDerivedType(tag: DW_TAG_typedef, name: "AliasForS", file: !5,
>> line: 21, baseType: !"_ZTS1S")
>> +!29 = !DICompositeType(tag: DW_TAG_class_type, name: "C", scope: !30,
>> file: !5, line: 31, size: 32, align: 32, elements: !31, identifier:
>> "_ZTSN1N1N1CE")
>> +!30 = !DINamespace(name: "N", scope: !25, file: !5, line: 30)
>> +!31 = !{!32}
>> +!32 = !DIDerivedType(tag: DW_TAG_member, name: "S", scope:
>> !"_ZTSN1N1N1CE", file: !5, line: 32, baseType: !8, size: 32, align: 32)
>> +!33 = !DICompositeType(tag: DW_TAG_union_type, name: "U", file: !5,
>> line: 42, size: 8, align: 8, elements: !34, identifier: "_ZTS1U")
>> +!34 = !{!35, !36}
>> +!35 = !DIDerivedType(tag: DW_TAG_member, name: "C", scope: !"_ZTS1U",
>> file: !5, line: 43, baseType: !"_ZTSN1U1CE", size: 8, align: 8)
>> +!36 = !DIDerivedType(tag: DW_TAG_member, name: "S", scope: !"_ZTS1U",
>> file: !5, line: 44, baseType: !"_ZTSN1U1SE", size: 8, align: 8)
>> +!37 = !DICompositeType(tag: DW_TAG_class_type, name: "C", scope:
>> !"_ZTS1U", file: !5, line: 43, size: 8, align: 8, elements: !2, identifier:
>> "_ZTSN1U1CE")
>> +!38 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", scope:
>> !"_ZTS1U", file: !5, line: 44, size: 8, align: 8, elements: !2, identifier:
>> "_ZTSN1U1SE")
>> +!39 = !DICompositeType(tag: DW_TAG_class_type, scope: !40, file: !5,
>> line: 49, size: 8, align: 8, elements: !43, identifier: "_ZTSZ4funcvEUlvE_")
>> +!40 = !DISubprogram(name: "func", linkageName: "_Z4funcv", scope: !5,
>> file: !5, line: 47, type: !41, isLocal: false, isDefinition: true,
>> scopeLine: 47, flags: DIFlagPrototyped, isOptimized: false, function: i32
>> ()* @_Z4funcv, variables: !2)
>> +!41 = !DISubroutineType(types: !42)
>> +!42 = !{!8}
>> +!43 = !{!44}
>> +!44 = !DISubprogram(name: "operator()", scope: !"_ZTSZ4funcvEUlvE_",
>> file: !5, line: 49, type: !45, isLocal: false, isDefinition: false,
>> scopeLine: 49, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: false)
>> +!45 = !DISubroutineType(types: !46)
>> +!46 = !{!8, !47}
>> +!47 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !48, size: 64,
>> align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!48 = !DIDerivedType(tag: DW_TAG_const_type, baseType:
>> !"_ZTSZ4funcvEUlvE_")
>> +!49 = !DICompositeType(tag: DW_TAG_structure_type, name: "CInsideFunc",
>> scope: !40, file: !5, line: 48, size: 32, align: 32, elements: !50,
>> identifier: "_ZTSZ4funcvE11CInsideFunc")
>> +!50 = !{!51}
>> +!51 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope:
>> !"_ZTSZ4funcvE11CInsideFunc", file: !5, line: 48, baseType: !8, size: 32,
>> align: 32)
>> +!52 = !{!53, !40, !54}
>> +!53 = !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1,
>> file: !1, line: 3, type: !41, isLocal: false, isDefinition: true,
>> scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: i32
>> ()* @_Z3foov, variables: !2)
>> +!54 = !DISubprogram(name: "operator()", linkageName:
>> "_ZZ4funcvENKUlvE_clEv", scope: !"_ZTSZ4funcvEUlvE_", file: !5, line: 49,
>> type: !45, isLocal: false, isDefinition: true, scopeLine: 49, flags:
>> DIFlagPrototyped, isOptimized: false, function: i32 (%class.anon*)*
>> @_ZZ4funcvENKUlvE_clEv, declaration: !44, variables: !2)
>> +!55 = !{i32 2, !"Dwarf Version", i32 2}
>> +!56 = !{i32 2, !"Debug Info Version", i32 3}
>> +!57 = !{i32 1, !"PIC Level", i32 2}
>> +!58 = !{!"clang version 3.8.0 (trunk 242534)"}
>> +!59 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "s", scope: !53,
>> file: !1, line: 4, type: !28)
>> +!60 = !DIExpression()
>> +!61 = !DILocation(line: 4, column: 12, scope: !53)
>> +!62 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "nc", scope:
>> !53, file: !1, line: 5, type: !"_ZTSN1N1CE")
>> +!63 = !DILocation(line: 5, column: 7, scope: !53)
>> +!64 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "nnc", scope:
>> !53, file: !1, line: 6, type: !"_ZTSN1N1N1CE")
>> +!65 = !DILocation(line: 6, column: 10, scope: !53)
>> +!66 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "ac", scope:
>> !53, file: !1, line: 7, type: !67)
>> +!67 = !DICompositeType(tag: DW_TAG_class_type, name: "AnonC", scope:
>> !68, file: !5, line: 38, size: 8, align: 8, elements: !2)
>> +!68 = !DINamespace(scope: null, file: !5, line: 37)
>> +!69 = !DILocation(line: 7, column: 8, scope: !53)
>> +!70 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "u", scope: !53,
>> file: !1, line: 8, type: !"_ZTS1U")
>> +!71 = !DILocation(line: 8, column: 4, scope: !53)
>> +!72 = !DILocation(line: 10, column: 9, scope: !53)
>> +!73 = !DILocation(line: 10, column: 2, scope: !53)
>> +!74 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "functor",
>> scope: !40, file: !5, line: 49, type: !"_ZTSZ4funcvEUlvE_")
>> +!75 = !DILocation(line: 49, column: 7, scope: !40)
>> +!76 = !DILocation(line: 50, column: 9, scope: !40)
>> +!77 = !DILocation(line: 50, column: 2, scope: !40)
>> +!78 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1,
>> scope: !54, type: !79, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!79 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !48, size: 64,
>> align: 64)
>> +!80 = !DILocation(line: 0, scope: !54)
>> +!81 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "dummy", scope:
>> !54, file: !5, line: 49, type: !"_ZTSZ4funcvE11CInsideFunc")
>> +!82 = !DILocation(line: 49, column: 36, scope: !54)
>> +!83 = !DILocation(line: 49, column: 56, scope: !54)
>> +!84 = !DILocation(line: 49, column: 43, scope: !54)
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr2.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr2.cpp?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr2.cpp (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr2.cpp Tue Jul 21 17:41:43
>> 2015
>> @@ -0,0 +1,7 @@
>> +#include "odr-types.h"
>> +
>> +int bar() {
>> + S s;
>> + s.incr();
>> + return s.foo();
>> +}
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr2.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr2.ll?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr2.ll (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr2.ll Tue Jul 21 17:41:43 2015
>> @@ -0,0 +1,99 @@
>> +; Generated from odr2.cpp and odr-types.h by running:
>> +; clang -emit-llvm -g -S -std=c++11 odr2.cpp
>> +; ModuleID = 'odr2.cpp'
>> +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
>> +target triple = "x86_64-apple-macosx10.11.0"
>> +
>> +%struct.S = type { i32, %"struct.S::Nested" }
>> +%"struct.S::Nested" = type { double }
>> +
>> +; Function Attrs: ssp uwtable
>> +define i32 @_Z3barv() #0 {
>> +entry:
>> + %this.addr.i = alloca %struct.S*, align 8
>> + %s = alloca %struct.S, align 8
>> + call void @llvm.dbg.declare(metadata %struct.S* %s, metadata !34,
>> metadata !35), !dbg !36
>> + store %struct.S* %s, %struct.S** %this.addr.i, align 8, !dbg !37
>> + %this1.i = load %struct.S*, %struct.S** %this.addr.i, !dbg !37
>> + %I.i = getelementptr inbounds %struct.S, %struct.S* %this1.i, i32 0,
>> i32 0, !dbg !38
>> + %0 = load i32, i32* %I.i, align 4, !dbg !40
>> + %inc.i = add nsw i32 %0, 1, !dbg !40
>> + store i32 %inc.i, i32* %I.i, align 4, !dbg !40
>> + %call = call i32 @_ZN1S3fooEv(%struct.S* %s), !dbg !41
>> + call void @llvm.dbg.declare(metadata %struct.S** %this.addr.i,
>> metadata !42, metadata !35), !dbg !44
>> + ret i32 %call, !dbg !45
>> +}
>> +
>> +; Function Attrs: nounwind readnone
>> +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
>> +
>> +; Function Attrs: nounwind ssp uwtable
>> +define linkonce_odr i32 @_ZN1S3fooEv(%struct.S* %this) #2 align 2 {
>> +entry:
>> + %this.addr = alloca %struct.S*, align 8
>> + store %struct.S* %this, %struct.S** %this.addr, align 8
>> + call void @llvm.dbg.declare(metadata %struct.S** %this.addr, metadata
>> !46, metadata !35), !dbg !47
>> + %this1 = load %struct.S*, %struct.S** %this.addr
>> + %I = getelementptr inbounds %struct.S, %struct.S* %this1, i32 0, i32
>> 0, !dbg !48
>> + %0 = load i32, i32* %I, align 4, !dbg !48
>> + ret i32 %0, !dbg !49
>> +}
>> +
>> +attributes #0 = { ssp uwtable "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +attributes #1 = { nounwind readnone }
>> +attributes #2 = { nounwind ssp uwtable "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +
>> +!llvm.dbg.cu = !{!0}
>> +!llvm.module.flags = !{!30, !31, !32}
>> +!llvm.ident = !{!33}
>> +
>> +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1,
>> producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false,
>> runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3,
>> subprograms: !24)
>> +!1 = !DIFile(filename: "odr2.cpp", directory: "/Inputs")
>> +!2 = !{}
>> +!3 = !{!4, !20}
>> +!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5,
>> line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S")
>> +!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs")
>> +!6 = !{!7, !9, !10, !14, !17}
>> +!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S",
>> file: !5, line: 2, baseType: !8, size: 32, align: 32)
>> +!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding:
>> DW_ATE_signed)
>> +!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S",
>> file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64,
>> offset: 64)
>> +!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope:
>> !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition:
>> false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false)
>> +!11 = !DISubroutineType(types: !12)
>> +!12 = !{null, !13}
>> +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S",
>> size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope:
>> !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition:
>> false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
>> +!15 = !DISubroutineType(types: !16)
>> +!16 = !{null, !13, !8}
>> +!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope:
>> !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition:
>> false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
>> +!18 = !DISubroutineType(types: !19)
>> +!19 = !{!8, !13}
>> +!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested",
>> scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21,
>> identifier: "_ZTSN1S6NestedE")
>> +!21 = !{!22}
>> +!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope:
>> !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64)
>> +!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding:
>> DW_ATE_float)
>> +!24 = !{!25, !28, !29}
>> +!25 = !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1,
>> file: !1, line: 3, type: !26, isLocal: false, isDefinition: true,
>> scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: i32
>> ()* @_Z3barv, variables: !2)
>> +!26 = !DISubroutineType(types: !27)
>> +!27 = !{!8}
>> +!28 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope:
>> !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition:
>> true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false,
>> declaration: !10, variables: !2)
>> +!29 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope:
>> !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition:
>> true, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false, function:
>> i32 (%struct.S*)* @_ZN1S3fooEv, declaration: !17, variables: !2)
>> +!30 = !{i32 2, !"Dwarf Version", i32 2}
>> +!31 = !{i32 2, !"Debug Info Version", i32 3}
>> +!32 = !{i32 1, !"PIC Level", i32 2}
>> +!33 = !{!"clang version 3.8.0 (trunk 242534)"}
>> +!34 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "s", scope: !25,
>> file: !1, line: 4, type: !"_ZTS1S")
>> +!35 = !DIExpression()
>> +!36 = !DILocation(line: 4, column: 4, scope: !25)
>> +!37 = !DILocation(line: 5, column: 2, scope: !25)
>> +!38 = !DILocation(line: 4, column: 47, scope: !28, inlinedAt: !39)
>> +!39 = distinct !DILocation(line: 5, column: 2, scope: !25)
>> +!40 = !DILocation(line: 4, column: 48, scope: !28, inlinedAt: !39)
>> +!41 = !DILocation(line: 6, column: 9, scope: !25)
>> +!42 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1,
>> scope: !28, type: !43, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!43 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S",
>> size: 64, align: 64)
>> +!44 = !DILocation(line: 0, scope: !28, inlinedAt: !39)
>> +!45 = !DILocation(line: 6, column: 2, scope: !25)
>> +!46 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1,
>> scope: !29, type: !43, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!47 = !DILocation(line: 0, scope: !29)
>> +!48 = !DILocation(line: 18, column: 21, scope: !29)
>> +!49 = !DILocation(line: 18, column: 14, scope: !29)
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr3.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr3.cpp?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr3.cpp (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr3.cpp Tue Jul 21 17:41:43
>> 2015
>> @@ -0,0 +1,7 @@
>> +#include "odr-types.h"
>> +
>> +int bar() {
>> + S s;
>> + s.incr(42);
>> + return s.foo();
>> +}
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr3.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr3.ll?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr3.ll (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr3.ll Tue Jul 21 17:41:43 2015
>> @@ -0,0 +1,106 @@
>> +; Generated from odr3.cpp and odr-types.h by running:
>> +; clang -emit-llvm -g -S -std=c++11 odr3.cpp
>> +; ModuleID = 'odr3.cpp'
>> +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
>> +target triple = "x86_64-apple-macosx10.11.0"
>> +
>> +%struct.S = type { i32, %"struct.S::Nested" }
>> +%"struct.S::Nested" = type { double }
>> +
>> +; Function Attrs: ssp uwtable
>> +define i32 @_Z3barv() #0 {
>> +entry:
>> + %this.addr.i = alloca %struct.S*, align 8
>> + %Add.addr.i = alloca i32, align 4
>> + %s = alloca %struct.S, align 8
>> + call void @llvm.dbg.declare(metadata %struct.S* %s, metadata !34,
>> metadata !35), !dbg !36
>> + store %struct.S* %s, %struct.S** %this.addr.i, align 8, !dbg !37
>> + store i32 42, i32* %Add.addr.i, align 4, !dbg !37
>> + %this1.i = load %struct.S*, %struct.S** %this.addr.i, !dbg !37
>> + %0 = load i32, i32* %Add.addr.i, align 4, !dbg !38
>> + %I.i = getelementptr inbounds %struct.S, %struct.S* %this1.i, i32 0,
>> i32 0, !dbg !40
>> + %1 = load i32, i32* %I.i, align 4, !dbg !41
>> + %add.i = add nsw i32 %1, %0, !dbg !41
>> + store i32 %add.i, i32* %I.i, align 4, !dbg !41
>> + %call = call i32 @_ZN1S3fooEv(%struct.S* %s), !dbg !42
>> + call void @llvm.dbg.declare(metadata %struct.S** %this.addr.i,
>> metadata !43, metadata !35), !dbg !45
>> + call void @llvm.dbg.declare(metadata i32* %Add.addr.i, metadata !46,
>> metadata !35), !dbg !47
>> + ret i32 %call, !dbg !48
>> +}
>> +
>> +; Function Attrs: nounwind readnone
>> +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
>> +
>> +; Function Attrs: nounwind ssp uwtable
>> +define linkonce_odr i32 @_ZN1S3fooEv(%struct.S* %this) #2 align 2 {
>> +entry:
>> + %this.addr = alloca %struct.S*, align 8
>> + store %struct.S* %this, %struct.S** %this.addr, align 8
>> + call void @llvm.dbg.declare(metadata %struct.S** %this.addr, metadata
>> !49, metadata !35), !dbg !50
>> + %this1 = load %struct.S*, %struct.S** %this.addr
>> + %I = getelementptr inbounds %struct.S, %struct.S* %this1, i32 0, i32
>> 0, !dbg !51
>> + %0 = load i32, i32* %I, align 4, !dbg !51
>> + ret i32 %0, !dbg !52
>> +}
>> +
>> +attributes #0 = { ssp uwtable "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +attributes #1 = { nounwind readnone }
>> +attributes #2 = { nounwind ssp uwtable "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +
>> +!llvm.dbg.cu = !{!0}
>> +!llvm.module.flags = !{!30, !31, !32}
>> +!llvm.ident = !{!33}
>> +
>> +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1,
>> producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false,
>> runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3,
>> subprograms: !24)
>> +!1 = !DIFile(filename: "odr3.cpp", directory: "/Inputs")
>> +!2 = !{}
>> +!3 = !{!4, !20}
>> +!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5,
>> line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S")
>> +!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs")
>> +!6 = !{!7, !9, !10, !14, !17}
>> +!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S",
>> file: !5, line: 2, baseType: !8, size: 32, align: 32)
>> +!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding:
>> DW_ATE_signed)
>> +!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S",
>> file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64,
>> offset: 64)
>> +!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope:
>> !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition:
>> false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false)
>> +!11 = !DISubroutineType(types: !12)
>> +!12 = !{null, !13}
>> +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S",
>> size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope:
>> !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition:
>> false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
>> +!15 = !DISubroutineType(types: !16)
>> +!16 = !{null, !13, !8}
>> +!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope:
>> !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition:
>> false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
>> +!18 = !DISubroutineType(types: !19)
>> +!19 = !{!8, !13}
>> +!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested",
>> scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21,
>> identifier: "_ZTSN1S6NestedE")
>> +!21 = !{!22}
>> +!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope:
>> !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64)
>> +!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding:
>> DW_ATE_float)
>> +!24 = !{!25, !28, !29}
>> +!25 = !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1,
>> file: !1, line: 3, type: !26, isLocal: false, isDefinition: true,
>> scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: i32
>> ()* @_Z3barv, variables: !2)
>> +!26 = !DISubroutineType(types: !27)
>> +!27 = !{!8}
>> +!28 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope:
>> !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition:
>> true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false,
>> declaration: !14, variables: !2)
>> +!29 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope:
>> !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition:
>> true, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false, function:
>> i32 (%struct.S*)* @_ZN1S3fooEv, declaration: !17, variables: !2)
>> +!30 = !{i32 2, !"Dwarf Version", i32 2}
>> +!31 = !{i32 2, !"Debug Info Version", i32 3}
>> +!32 = !{i32 1, !"PIC Level", i32 2}
>> +!33 = !{!"clang version 3.8.0 (trunk 242534)"}
>> +!34 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "s", scope: !25,
>> file: !1, line: 4, type: !"_ZTS1S")
>> +!35 = !DIExpression()
>> +!36 = !DILocation(line: 4, column: 4, scope: !25)
>> +!37 = !DILocation(line: 5, column: 2, scope: !25)
>> +!38 = !DILocation(line: 5, column: 59, scope: !28, inlinedAt: !39)
>> +!39 = distinct !DILocation(line: 5, column: 2, scope: !25)
>> +!40 = !DILocation(line: 5, column: 54, scope: !28, inlinedAt: !39)
>> +!41 = !DILocation(line: 5, column: 56, scope: !28, inlinedAt: !39)
>> +!42 = !DILocation(line: 6, column: 9, scope: !25)
>> +!43 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1,
>> scope: !28, type: !44, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!44 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S",
>> size: 64, align: 64)
>> +!45 = !DILocation(line: 0, scope: !28, inlinedAt: !39)
>> +!46 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "Add", arg: 2,
>> scope: !28, file: !5, line: 5, type: !8)
>> +!47 = !DILocation(line: 5, column: 16, scope: !28, inlinedAt: !39)
>> +!48 = !DILocation(line: 6, column: 2, scope: !25)
>> +!49 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1,
>> scope: !29, type: !44, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!50 = !DILocation(line: 0, scope: !29)
>> +!51 = !DILocation(line: 18, column: 21, scope: !29)
>> +!52 = !DILocation(line: 18, column: 14, scope: !29)
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr4.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr4.cpp?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr4.cpp (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr4.cpp Tue Jul 21 17:41:43
>> 2015
>> @@ -0,0 +1,8 @@
>> +namespace {
>> + class AnonC {
>> + };
>> +}
>> +
>> +void baz() {
>> + AnonC ac;
>> +}
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr4.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr4.ll?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr4.ll (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr4.ll Tue Jul 21 17:41:43 2015
>> @@ -0,0 +1,43 @@
>> +; Generated from odr4.cpp and odr-types.h by running:
>> +; clang -emit-llvm -g -S -std=c++11 odr4.cpp
>> +; ModuleID = 'odr4.cpp'
>> +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
>> +target triple = "x86_64-apple-macosx10.11.0"
>> +
>> +%"class.(anonymous namespace)::AnonC" = type { i8 }
>> +
>> +; Function Attrs: nounwind ssp uwtable
>> +define void @_Z3bazv() #0 {
>> +entry:
>> + %ac = alloca %"class.(anonymous namespace)::AnonC", align 1
>> + call void @llvm.dbg.declare(metadata %"class.(anonymous
>> namespace)::AnonC"* %ac, metadata !11, metadata !14), !dbg !15
>> + ret void, !dbg !16
>> +}
>> +
>> +; Function Attrs: nounwind readnone
>> +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
>> +
>> +attributes #0 = { nounwind ssp uwtable "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +attributes #1 = { nounwind readnone }
>> +
>> +!llvm.dbg.cu = !{!0}
>> +!llvm.module.flags = !{!7, !8, !9}
>> +!llvm.ident = !{!10}
>> +
>> +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1,
>> producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false,
>> runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3)
>> +!1 = !DIFile(filename: "odr4.cpp", directory: "/Inputs")
>> +!2 = !{}
>> +!3 = !{!4}
>> +!4 = !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !1, file:
>> !1, line: 6, type: !5, isLocal: false, isDefinition: true, scopeLine: 6,
>> flags: DIFlagPrototyped, isOptimized: false, function: void ()* @_Z3bazv,
>> variables: !2)
>> +!5 = !DISubroutineType(types: !6)
>> +!6 = !{null}
>> +!7 = !{i32 2, !"Dwarf Version", i32 2}
>> +!8 = !{i32 2, !"Debug Info Version", i32 3}
>> +!9 = !{i32 1, !"PIC Level", i32 2}
>> +!10 = !{!"clang version 3.8.0 (trunk 242534)"}
>> +!11 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "ac", scope: !4,
>> file: !1, line: 7, type: !12)
>> +!12 = !DICompositeType(tag: DW_TAG_class_type, name: "AnonC", scope:
>> !13, file: !1, line: 2, size: 8, align: 8, elements: !2)
>> +!13 = !DINamespace(scope: null, file: !1, line: 1)
>> +!14 = !DIExpression()
>> +!15 = !DILocation(line: 7, column: 8, scope: !4)
>> +!16 = !DILocation(line: 8, column: 1, scope: !4)
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr5.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr5.cpp?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr5.cpp (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr5.cpp Tue Jul 21 17:41:43
>> 2015
>> @@ -0,0 +1,7 @@
>> +#include "odr-types.h"
>> +
>> +double baz() {
>> + S::Nested d;
>> + d.init(0);
>> + return d.D;
>> +}
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr5.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr5.ll?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr5.ll (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr5.ll Tue Jul 21 17:41:43 2015
>> @@ -0,0 +1,101 @@
>> +; Generated from odr5.cpp and odr-types.h by running:
>> +; clang -emit-llvm -g -S -std=c++11 odr5.cpp
>> +; ModuleID = 'odr5.cpp'
>> +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
>> +target triple = "x86_64-apple-macosx10.11.0"
>> +
>> +%"struct.S::Nested" = type { double }
>> +
>> +; Function Attrs: ssp uwtable
>> +define double @_Z3bazv() #0 {
>> +entry:
>> + %d = alloca %"struct.S::Nested", align 8
>> + call void @llvm.dbg.declare(metadata %"struct.S::Nested"* %d, metadata
>> !39, metadata !40), !dbg !41
>> + call void @_ZN1S6Nested4initIiEEvT_(%"struct.S::Nested"* %d, i32 0),
>> !dbg !42
>> + %D = getelementptr inbounds %"struct.S::Nested", %"struct.S::Nested"*
>> %d, i32 0, i32 0, !dbg !43
>> + %0 = load double, double* %D, align 8, !dbg !43
>> + ret double %0, !dbg !44
>> +}
>> +
>> +; Function Attrs: nounwind readnone
>> +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
>> +
>> +; Function Attrs: nounwind ssp uwtable
>> +define linkonce_odr void @_ZN1S6Nested4initIiEEvT_(%"struct.S::Nested"*
>> %this, i32 %Val) #2 align 2 {
>> +entry:
>> + %this.addr = alloca %"struct.S::Nested"*, align 8
>> + %Val.addr = alloca i32, align 4
>> + store %"struct.S::Nested"* %this, %"struct.S::Nested"** %this.addr,
>> align 8
>> + call void @llvm.dbg.declare(metadata %"struct.S::Nested"** %this.addr,
>> metadata !45, metadata !40), !dbg !47
>> + store i32 %Val, i32* %Val.addr, align 4
>> + call void @llvm.dbg.declare(metadata i32* %Val.addr, metadata !48,
>> metadata !40), !dbg !49
>> + %this1 = load %"struct.S::Nested"*, %"struct.S::Nested"** %this.addr
>> + %0 = load i32, i32* %Val.addr, align 4, !dbg !50
>> + %conv = sitofp i32 %0 to double, !dbg !50
>> + %D = getelementptr inbounds %"struct.S::Nested", %"struct.S::Nested"*
>> %this1, i32 0, i32 0, !dbg !51
>> + store double %conv, double* %D, align 8, !dbg !52
>> + ret void, !dbg !53
>> +}
>> +
>> +attributes #0 = { ssp uwtable "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +attributes #1 = { nounwind readnone }
>> +attributes #2 = { nounwind ssp uwtable "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +
>> +!llvm.dbg.cu = !{!0}
>> +!llvm.module.flags = !{!35, !36, !37}
>> +!llvm.ident = !{!38}
>> +
>> +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1,
>> producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false,
>> runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3,
>> subprograms: !24)
>> +!1 = !DIFile(filename: "odr5.cpp", directory: "/Inputs")
>> +!2 = !{}
>> +!3 = !{!4, !20, !23}
>> +!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5,
>> line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S")
>> +!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs")
>> +!6 = !{!7, !9, !10, !14, !17}
>> +!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S",
>> file: !5, line: 2, baseType: !8, size: 32, align: 32)
>> +!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding:
>> DW_ATE_signed)
>> +!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S",
>> file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64,
>> offset: 64)
>> +!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope:
>> !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition:
>> false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false)
>> +!11 = !DISubroutineType(types: !12)
>> +!12 = !{null, !13}
>> +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S",
>> size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope:
>> !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition:
>> false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
>> +!15 = !DISubroutineType(types: !16)
>> +!16 = !{null, !13, !8}
>> +!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope:
>> !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition:
>> false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
>> +!18 = !DISubroutineType(types: !19)
>> +!19 = !{!8, !13}
>> +!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested",
>> scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21,
>> identifier: "_ZTSN1S6NestedE")
>> +!21 = !{!22}
>> +!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope:
>> !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64)
>> +!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding:
>> DW_ATE_float)
>> +!24 = !{!25, !28}
>> +!25 = !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !1,
>> file: !1, line: 3, type: !26, isLocal: false, isDefinition: true,
>> scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: double
>> ()* @_Z3bazv, variables: !2)
>> +!26 = !DISubroutineType(types: !27)
>> +!27 = !{!23}
>> +!28 = !DISubprogram(name: "init<int>", linkageName:
>> "_ZN1S6Nested4initIiEEvT_", scope: !"_ZTSN1S6NestedE", file: !5, line: 12,
>> type: !29, isLocal: false, isDefinition: true, scopeLine: 12, flags:
>> DIFlagPrototyped, isOptimized: false, function: void (%"struct.S::Nested"*,
>> i32)* @_ZN1S6Nested4initIiEEvT_, templateParams: !32, declaration: !34,
>> variables: !2)
>> +!29 = !DISubroutineType(types: !30)
>> +!30 = !{null, !31, !8}
>> +!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType:
>> !"_ZTSN1S6NestedE", size: 64, align: 64, flags: DIFlagArtificial |
>> DIFlagObjectPointer)
>> +!32 = !{!33}
>> +!33 = !DITemplateTypeParameter(name: "T", type: !8)
>> +!34 = !DISubprogram(name: "init<int>", linkageName:
>> "_ZN1S6Nested4initIiEEvT_", scope: !"_ZTSN1S6NestedE", file: !5, line: 12,
>> type: !29, isLocal: false, isDefinition: false, scopeLine: 12, flags:
>> DIFlagPrototyped, isOptimized: false, templateParams: !32)
>> +!35 = !{i32 2, !"Dwarf Version", i32 2}
>> +!36 = !{i32 2, !"Debug Info Version", i32 3}
>> +!37 = !{i32 1, !"PIC Level", i32 2}
>> +!38 = !{!"clang version 3.8.0 (trunk 242534)"}
>> +!39 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "d", scope: !25,
>> file: !1, line: 4, type: !"_ZTSN1S6NestedE")
>> +!40 = !DIExpression()
>> +!41 = !DILocation(line: 4, column: 12, scope: !25)
>> +!42 = !DILocation(line: 5, column: 2, scope: !25)
>> +!43 = !DILocation(line: 6, column: 11, scope: !25)
>> +!44 = !DILocation(line: 6, column: 2, scope: !25)
>> +!45 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1,
>> scope: !28, type: !46, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!46 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType:
>> !"_ZTSN1S6NestedE", size: 64, align: 64)
>> +!47 = !DILocation(line: 0, scope: !28)
>> +!48 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "Val", arg: 2,
>> scope: !28, file: !5, line: 12, type: !8)
>> +!49 = !DILocation(line: 12, column: 36, scope: !28)
>> +!50 = !DILocation(line: 12, column: 54, scope: !28)
>> +!51 = !DILocation(line: 12, column: 43, scope: !28)
>> +!52 = !DILocation(line: 12, column: 45, scope: !28)
>> +!53 = !DILocation(line: 12, column: 60, scope: !28)
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr6.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr6.cpp?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr6.cpp (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr6.cpp Tue Jul 21 17:41:43
>> 2015
>> @@ -0,0 +1,7 @@
>> +#include "odr-types.h"
>> +
>> +double baz() {
>> + S::Nested d;
>> + d.init(0.0);
>> + return d.D;
>> +}
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr6.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr6.ll?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr6.ll (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr6.ll Tue Jul 21 17:41:43 2015
>> @@ -0,0 +1,100 @@
>> +; Generated from odr6.cpp and odr-types.h by running:
>> +; clang -emit-llvm -g -S -std=c++11 odr6.cpp
>> +; ModuleID = 'odr6.cpp'
>> +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
>> +target triple = "x86_64-apple-macosx10.11.0"
>> +
>> +%"struct.S::Nested" = type { double }
>> +
>> +; Function Attrs: ssp uwtable
>> +define double @_Z3bazv() #0 {
>> +entry:
>> + %d = alloca %"struct.S::Nested", align 8
>> + call void @llvm.dbg.declare(metadata %"struct.S::Nested"* %d, metadata
>> !39, metadata !40), !dbg !41
>> + call void @_ZN1S6Nested4initIdEEvT_(%"struct.S::Nested"* %d, double
>> 0.000000e+00), !dbg !42
>> + %D = getelementptr inbounds %"struct.S::Nested", %"struct.S::Nested"*
>> %d, i32 0, i32 0, !dbg !43
>> + %0 = load double, double* %D, align 8, !dbg !43
>> + ret double %0, !dbg !44
>> +}
>> +
>> +; Function Attrs: nounwind readnone
>> +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
>> +
>> +; Function Attrs: nounwind ssp uwtable
>> +define linkonce_odr void @_ZN1S6Nested4initIdEEvT_(%"struct.S::Nested"*
>> %this, double %Val) #2 align 2 {
>> +entry:
>> + %this.addr = alloca %"struct.S::Nested"*, align 8
>> + %Val.addr = alloca double, align 8
>> + store %"struct.S::Nested"* %this, %"struct.S::Nested"** %this.addr,
>> align 8
>> + call void @llvm.dbg.declare(metadata %"struct.S::Nested"** %this.addr,
>> metadata !45, metadata !40), !dbg !47
>> + store double %Val, double* %Val.addr, align 8
>> + call void @llvm.dbg.declare(metadata double* %Val.addr, metadata !48,
>> metadata !40), !dbg !49
>> + %this1 = load %"struct.S::Nested"*, %"struct.S::Nested"** %this.addr
>> + %0 = load double, double* %Val.addr, align 8, !dbg !50
>> + %D = getelementptr inbounds %"struct.S::Nested", %"struct.S::Nested"*
>> %this1, i32 0, i32 0, !dbg !51
>> + store double %0, double* %D, align 8, !dbg !52
>> + ret void, !dbg !53
>> +}
>> +
>> +attributes #0 = { ssp uwtable "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +attributes #1 = { nounwind readnone }
>> +attributes #2 = { nounwind ssp uwtable "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +
>> +!llvm.dbg.cu = !{!0}
>> +!llvm.module.flags = !{!35, !36, !37}
>> +!llvm.ident = !{!38}
>> +
>> +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1,
>> producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false,
>> runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3,
>> subprograms: !24)
>> +!1 = !DIFile(filename: "odr6.cpp", directory: "/Inputs")
>> +!2 = !{}
>> +!3 = !{!4, !20, !23}
>> +!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5,
>> line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S")
>> +!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs")
>> +!6 = !{!7, !9, !10, !14, !17}
>> +!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S",
>> file: !5, line: 2, baseType: !8, size: 32, align: 32)
>> +!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding:
>> DW_ATE_signed)
>> +!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S",
>> file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64,
>> offset: 64)
>> +!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope:
>> !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition:
>> false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false)
>> +!11 = !DISubroutineType(types: !12)
>> +!12 = !{null, !13}
>> +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S",
>> size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope:
>> !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition:
>> false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
>> +!15 = !DISubroutineType(types: !16)
>> +!16 = !{null, !13, !8}
>> +!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope:
>> !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition:
>> false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
>> +!18 = !DISubroutineType(types: !19)
>> +!19 = !{!8, !13}
>> +!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested",
>> scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21,
>> identifier: "_ZTSN1S6NestedE")
>> +!21 = !{!22}
>> +!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope:
>> !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64)
>> +!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding:
>> DW_ATE_float)
>> +!24 = !{!25, !28}
>> +!25 = !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !1,
>> file: !1, line: 3, type: !26, isLocal: false, isDefinition: true,
>> scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: double
>> ()* @_Z3bazv, variables: !2)
>> +!26 = !DISubroutineType(types: !27)
>> +!27 = !{!23}
>> +!28 = !DISubprogram(name: "init<double>", linkageName:
>> "_ZN1S6Nested4initIdEEvT_", scope: !"_ZTSN1S6NestedE", file: !5, line: 12,
>> type: !29, isLocal: false, isDefinition: true, scopeLine: 12, flags:
>> DIFlagPrototyped, isOptimized: false, function: void (%"struct.S::Nested"*,
>> double)* @_ZN1S6Nested4initIdEEvT_, templateParams: !32, declaration: !34,
>> variables: !2)
>> +!29 = !DISubroutineType(types: !30)
>> +!30 = !{null, !31, !23}
>> +!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType:
>> !"_ZTSN1S6NestedE", size: 64, align: 64, flags: DIFlagArtificial |
>> DIFlagObjectPointer)
>> +!32 = !{!33}
>> +!33 = !DITemplateTypeParameter(name: "T", type: !23)
>> +!34 = !DISubprogram(name: "init<double>", linkageName:
>> "_ZN1S6Nested4initIdEEvT_", scope: !"_ZTSN1S6NestedE", file: !5, line: 12,
>> type: !29, isLocal: false, isDefinition: false, scopeLine: 12, flags:
>> DIFlagPrototyped, isOptimized: false, templateParams: !32)
>> +!35 = !{i32 2, !"Dwarf Version", i32 2}
>> +!36 = !{i32 2, !"Debug Info Version", i32 3}
>> +!37 = !{i32 1, !"PIC Level", i32 2}
>> +!38 = !{!"clang version 3.8.0 (trunk 242534)"}
>> +!39 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "d", scope: !25,
>> file: !1, line: 4, type: !"_ZTSN1S6NestedE")
>> +!40 = !DIExpression()
>> +!41 = !DILocation(line: 4, column: 12, scope: !25)
>> +!42 = !DILocation(line: 5, column: 2, scope: !25)
>> +!43 = !DILocation(line: 6, column: 11, scope: !25)
>> +!44 = !DILocation(line: 6, column: 2, scope: !25)
>> +!45 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1,
>> scope: !28, type: !46, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!46 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType:
>> !"_ZTSN1S6NestedE", size: 64, align: 64)
>> +!47 = !DILocation(line: 0, scope: !28)
>> +!48 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "Val", arg: 2,
>> scope: !28, file: !5, line: 12, type: !23)
>> +!49 = !DILocation(line: 12, column: 36, scope: !28)
>> +!50 = !DILocation(line: 12, column: 54, scope: !28)
>> +!51 = !DILocation(line: 12, column: 43, scope: !28)
>> +!52 = !DILocation(line: 12, column: 45, scope: !28)
>> +!53 = !DILocation(line: 12, column: 60, scope: !28)
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr7.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr7.cpp?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr7.cpp (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr7.cpp Tue Jul 21 17:41:43
>> 2015
>> @@ -0,0 +1,5 @@
>> +#include "odr-types.h"
>> +
>> +void foo() {
>> + S::Nested N;
>> +}
>>
>> Added: llvm/trunk/test/tools/dsymutil/Inputs/odr7.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/odr7.ll?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/Inputs/odr7.ll (added)
>> +++ llvm/trunk/test/tools/dsymutil/Inputs/odr7.ll Tue Jul 21 17:41:43 2015
>> @@ -0,0 +1,62 @@
>> +; Generated from odr7.cpp and odr-types.h by running:
>> +; clang -emit-llvm -g -S -std=c++11 odr7.cpp
>> +; ModuleID = 'odr7.cpp'
>> +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
>> +target triple = "x86_64-apple-macosx10.11.0"
>> +
>> +%"struct.S::Nested" = type { double }
>> +
>> +; Function Attrs: nounwind ssp uwtable
>> +define void @_Z3foov() #0 {
>> +entry:
>> + %N = alloca %"struct.S::Nested", align 8
>> + call void @llvm.dbg.declare(metadata %"struct.S::Nested"* %N, metadata
>> !32, metadata !33), !dbg !34
>> + ret void, !dbg !35
>> +}
>> +
>> +; Function Attrs: nounwind readnone
>> +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
>> +
>> +attributes #0 = { nounwind ssp uwtable "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +attributes #1 = { nounwind readnone }
>> +
>> +!llvm.dbg.cu = !{!0}
>> +!llvm.module.flags = !{!28, !29, !30}
>> +!llvm.ident = !{!31}
>> +
>> +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1,
>> producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false,
>> runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3,
>> subprograms: !24)
>> +!1 = !DIFile(filename: "odr7.cpp", directory: "/Inputs")
>> +!2 = !{}
>> +!3 = !{!4, !20}
>> +!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5,
>> line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S")
>> +!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs")
>> +!6 = !{!7, !9, !10, !14, !17}
>> +!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S",
>> file: !5, line: 2, baseType: !8, size: 32, align: 32)
>> +!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding:
>> DW_ATE_signed)
>> +!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S",
>> file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64,
>> offset: 64)
>> +!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope:
>> !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition:
>> false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false)
>> +!11 = !DISubroutineType(types: !12)
>> +!12 = !{null, !13}
>> +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S",
>> size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
>> +!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope:
>> !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition:
>> false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
>> +!15 = !DISubroutineType(types: !16)
>> +!16 = !{null, !13, !8}
>> +!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope:
>> !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition:
>> false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false)
>> +!18 = !DISubroutineType(types: !19)
>> +!19 = !{!8, !13}
>> +!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested",
>> scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21,
>> identifier: "_ZTSN1S6NestedE")
>> +!21 = !{!22}
>> +!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope:
>> !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64)
>> +!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding:
>> DW_ATE_float)
>> +!24 = !{!25}
>> +!25 = !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1,
>> file: !1, line: 3, type: !26, isLocal: false, isDefinition: true,
>> scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: void
>> ()* @_Z3foov, variables: !2)
>> +!26 = !DISubroutineType(types: !27)
>> +!27 = !{null}
>> +!28 = !{i32 2, !"Dwarf Version", i32 2}
>> +!29 = !{i32 2, !"Debug Info Version", i32 3}
>> +!30 = !{i32 1, !"PIC Level", i32 2}
>> +!31 = !{!"clang version 3.8.0 (trunk 242534)"}
>> +!32 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "N", scope: !25,
>> file: !1, line: 4, type: !"_ZTSN1S6NestedE")
>> +!33 = !DIExpression()
>> +!34 = !DILocation(line: 4, column: 12, scope: !25)
>> +!35 = !DILocation(line: 5, column: 1, scope: !25)
>>
>> Added: llvm/trunk/test/tools/dsymutil/X86/odr-1.test
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/X86/odr-1.test?rev=242847&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/tools/dsymutil/X86/odr-1.test (added)
>> +++ llvm/trunk/test/tools/dsymutil/X86/odr-1.test Tue Jul 21 17:41:43 2015
>> @@ -0,0 +1,423 @@
>> +# REQUIRES: object-emission
>> +# RUN: rm -rf %t
>> +# RUN: mkdir -p %t
>> +# RUN: llc -filetype=obj %p/../Inputs/odr1.ll -o %t/odr1.o
>> +# RUN: llc -filetype=obj %p/../Inputs/odr2.ll -o %t/odr2.o
>> +# RUN: llc -filetype=obj %p/../Inputs/odr3.ll -o %t/odr3.o
>> +# RUN: llc -filetype=obj %p/../Inputs/odr4.ll -o %t/odr4.o
>> +# RUN: llc -filetype=obj %p/../Inputs/odr5.ll -o %t/odr5.o
>> +# RUN: llc -filetype=obj %p/../Inputs/odr6.ll -o %t/odr6.o
>> +# RUN: llc -filetype=obj %p/../Inputs/odr7.ll -o %t/odr7.o
>> +# RUN: llvm-dsymutil -oso-prepend-path=%t -y %s -o - | llvm-dwarfdump
>> -debug-dump=info - | FileCheck -check-prefix=ODR -check-prefix=CHECK %s
>> +# RUN: llvm-dsymutil -oso-prepend-path=%t -y %s -no-odr -o - |
>> llvm-dwarfdump -debug-dump=info - | FileCheck -check-prefix=NOODR
>> -check-prefix=CHECK %s
>> +
>> +# Totally made up debug map to test ODR uniquing
>> +
>> +---
>> +triple: 'x86_64-unknown-unknown-macho'
>> +objects:
>> + - filename: odr1.o
>> + symbols:
>> + - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x1000, size: 0x12 }
>> + - { sym: __Z4funcv, objAddr: 0x0, binAddr: 0x2000, size: 0x12 }
>> + - { sym: __ZZ4funcvENKUlvE_clEv, objAddr: 0x0, binAddr: 0x3000,
>> size: 0x12 }
>> +
>> +# Check that all our types are in the first CU.
>> +
>> +# CHECK: TAG_compile_unit
>> +# CHECK-NOT: {{DW_TAG|NULL}}
>> +# CHECK: AT_name{{.*}}"odr1.cpp"
>> +
>> +# This is "struct S"
>> +
>> +# CHECK: 0x[[S:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
>> +# CHECK-NEXT: DW_AT_name{{.*}}"S"
>> +# CHECK-NOT: NULL
>> +# CHECK: 0x[[NESTED:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
>> +# CHECK-NOT: {{DW_TAG|NULL}}
>> +# CHECK: DW_AT_name{{.*}}"Nested"
>> +# CHECK: NULL
>> +# CHECK: DW_TAG_subprogram
>> +# CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S4incrEv"
>> +# CHECK: NULL
>> +# CHECK: DW_TAG_subprogram
>> +# CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S4incrEi"
>> +# CHECK: NULL
>> +# CHECK: DW_TAG_subprogram
>> +# CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3fooEv"
>> +# CHECK: NULL
>> +# CHECK: NULL
>> +
>> +# This is "class N::C"
>> +
>> +# CHECK: DW_TAG_namespace
>> +# CHECK-NEXT: DW_AT_name{{.*}}"N"
>> +# CHECK-NOT: NULL
>> +# CHECK: 0x[[NC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
>> +# CHECK-NEXT: DW_AT_name{{.*}}"C"
>> +# CHECK: NULL
>> +
>> +# This is "class N::N::C"
>> +
>> +# CHECK: DW_TAG_namespace
>> +# CHECK-NEXT: DW_AT_name{{.*}}"N"
>> +# CHECK-NOT: NULL
>> +# CHECK: 0x[[NNC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
>> +# CHECK-NEXT: DW_AT_name{{.*}}"C"
>> +# CHECK: NULL
>> +# CHECK: NULL
>> +# CHECK: NULL
>> +
>> +# This is "AliasForS"
>> +# CHECK: 0x[[ALIASFORS:[0-9a-f]*]]:{{.*}}DW_TAG_typedef
>> +# CHECK-NEXT: DW_AT_type{{.*}}[[S]]
>> +# CHECK-NEXT: DW_AT_name{{.*}}"AliasForS"
>> +
>> +# This is "union U"
>> +
>> +# CHECK: 0x[[U:[0-9a-f]*]]:{{.*}}DW_TAG_union_type
>> +# CHECK-NEXT: DW_AT_name{{.*}}"U"
>> +# CHECK-NOT: NULL
>> +# CHECK: 0x[[UC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
>> +# CHECK-NOT: NULL
>> +# CHECK: 0x[[US:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
>> +# CHECK: NULL
>> +
>> +# This is "func" free function
>> +
>> +# CHECK: DW_TAG_subprogram
>> +# CHECK-NOT: {{DW_TAG|NULL}}
>> +# CHECK: DW_AT_name{{.*}}"func"
>> +# CHECK: 0x[[CINSIDEFUNC:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
>> +# CHECK-NEXT: DW_AT_name{{.*}}"CInsideFunc"
>> +
>> +# This is "(anonymous namespace)::AnonC"
>> +
>> +# CHECK: DW_TAG_namespace
>> +# CHECK-NOT: {{DW_AT_name|NULL|DW_TAG}}
>> +# CHECK: 0x[[ANONC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
>> +# CHECK-NEXT: DW_AT_name{{.*}}"AnonC"
>> +
>> + - filename: odr1.o
>> + symbols:
>> + - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x4000, size: 0x12 }
>> + - { sym: __Z4funcv, objAddr: 0x0, binAddr: 0x5000, size: 0x12 }
>> + - { sym: __ZZ4funcvENKUlvE_clEv, objAddr: 0x0, binAddr: 0x6000,
>> size: 0x12 }
>> +
>> +# We relink the same file a second time. In the ODR case, everything
>> (except for the
>> +# union for now) should be uniqued. In the non-ODR case, we should get
>> every type
>> +# duplicated.
>> +
>> +# CHECK: TAG_compile_unit
>> +# CHECK-NOT: {{DW_TAG|NULL}}
>> +# CHECK: AT_name{{.*}}"odr1.cpp"
>> +
>> +# ODR: DW_TAG_union_type
>> +# ODR-NEXT: DW_AT_name{{.*}}"U"
>> +# Types defined inside the union should be uniqued:
>> +# ODR: DW_TAG_member
>> +# ODR-NEXT: DW_AT_name{{.*}}"C"
>> +# ODR-NOT: {{NULL|DW_TAG}}
>> +# ODR: DW_AT_type{{.*}}[[UC]]
>> +# ODR: DW_TAG_member
>> +# ODR-NEXT: DW_AT_name{{.*}}"S"
>> +# ODR-NOT: {{NULL|DW_TAG}}
>> +# ODR: DW_AT_type{{.*}}[[US]]
>> +
>> +# Skip func
>> +# ODR: DW_TAG_subprogram
>> +# ODR-NOT: {{NULL|DW_TAG}}
>> +# ODR: DW_AT_name{{.*}}"func"
>> +# ODR: NULL
>> +
>> +# ODR: DW_TAG_subprogram
>> +# ODR-NOT: {{NULL|DW_TAG}}
>> +# ODR: DW_AT_name{{.*}}"foo"
>> +# ODR-NOT: NULL
>> +# ODR: DW_TAG_variable
>> +# ODR-NOT: {{DW_TAG|NULL}}
>> +# ODR: DW_AT_name{{.*}}"s"
>> +# ODR-NOT: {{DW_TAG|NULL}}
>> +# ODR: DW_AT_type{{.*}}[[ALIASFORS]]
>> +# ODR: DW_TAG_variable
>> +# ODR-NOT: {{DW_TAG|NULL}}
>> +# ODR: DW_AT_name{{.*}}"nc"
>> +# ODR-NOT: {{DW_TAG|NULL}}
>> +# ODR: DW_AT_type{{.*}}[[NC]]
>> +# ODR: DW_TAG_variable
>> +# ODR-NOT: {{DW_TAG|NULL}}
>> +# ODR: DW_AT_name{{.*}}"nnc"
>> +# ODR-NOT: {{DW_TAG|NULL}}
>> +# ODR: DW_AT_type{{.*}}[[NNC]]
>> +# ODR: DW_TAG_variable
>> +# ODR-NOT: {{DW_TAG|NULL}}
>> +# ODR: DW_AT_name{{.*}}"ac"
>> +# ODR-NOT: {{DW_TAG|NULL}}
>> +# ODR: DW_AT_type{{.*}}[[ANONC]]
>> +
>> +# ODR: DW_TAG_subprogram
>> +# ODR-NOT: {{NULL|DW_TAG}}
>> +# ODR: linkage_name{{.*}}"_ZZ4funcvENKUlvE_clEv"
>> +# ODR-NOT: NULL
>> +# ODR: DW_TAG_variable
>> +# ODR-NOT: DW_TAG
>> +# ODR: DW_AT_name{{.*}}"dummy"
>> +# ODR-NOT: NULL
>> +# ODR: DW_AT_type{{.*}}[[CINSIDEFUNC]]
>> +
>> +# With no ODR uniquing, we should get copies of all the types:
>> +
>> +# This is "struct S"
>> +# NOODR: 0x[[DUP_S:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
>> +# NOODR-NEXT: DW_AT_name{{.*}}"S"
>> +
>> +# This is "class N::C"
>> +# NOODR: DW_TAG_namespace
>> +# NOODR-NEXT: DW_AT_name{{.*}}"N"
>> +# NOODR: 0x[[DUP_NC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
>> +# NOODR-NEXT: DW_AT_name{{.*}}"C"
>> +
>> +# This is "class N::N::C"
>> +# NOODR: DW_TAG_namespace
>> +# NOODR-NEXT: DW_AT_name{{.*}}"N"
>> +# NOODR: 0x[[DUP_NNC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
>> +# NOODR-NEXT: DW_AT_name{{.*}}"C"
>> +
>> +# This is "AliasForS"
>> +# NOODR: 0x[[DUP_ALIASFORS:[0-9a-f]*]]:{{.*}}DW_TAG_typedef
>> +# NOODR-NOT: {{NULL|DW_TAG}}
>> +# NOODR: DW_AT_name{{.*}}"AliasForS"
>> +
>> +# This is "union U"
>> +
>> +# NOODR: 0x[[U:[0-9a-f]*]]:{{.*}}DW_TAG_union_type
>> +# NOODR-NEXT: DW_AT_name{{.*}}"U"
>> +# NOODR-NOT: NULL
>> +# NOODR: 0x[[DUP_UC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type
>> +# NOODR-NOT: NULL
>> +# NOODR: 0x[[DUP_US:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
>> +# NOODR: NULL
>> +
>> +# This is "func" free function
>> +
>> +# NOODR: DW_TAG_subprogram
>> +# NOODR-NOT: {{DW_TAG|NULL}}
>> +# NOODR: DW_AT_name{{.*}}"func"
>> +# NOODR: 0x[[DUP_CINSIDEFUNC:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
>> +# NOODR-NEXT: DW_AT_name{{.*}}"CInsideFunc"
>> +
>> +# NOODR: DW_TAG_subprogram
>> +# NOODR-NOT: {{NULL|DW_TAG}}
>> +# NOODR: DW_AT_name{{.*}}"foo"
>> +# NOODR-NOT: NULL
>> +# NOODR: DW_TAG_variable
>> +# NOODR-NOT: {{DW_TAG|NULL}}
>> +# NOODR: DW_AT_name{{.*}}"s"
>> +# NOODR-NOT: {{DW_TAG|NULL}}
>> +# NOODR: DW_AT_type{{.*}}[[DUP_ALIASFORS]]
>> +# NOODR: DW_TAG_variable
>> +# NOODR-NOT: {{DW_TAG|NULL}}
>> +# NOODR: DW_AT_name{{.*}}"nc"
>> +# NOODR-NOT: {{DW_TAG|NULL}}
>> +# NOODR: DW_AT_type{{.*}}[[DUP_NC]]
>> +# NOODR: DW_TAG_variable
>> +# NOODR-NOT: {{DW_TAG|NULL}}
>> +# NOODR: DW_AT_name{{.*}}"nnc"
>> +# NOODR-NOT: {{DW_TAG|NULL}}
>> +# NOODR: DW_AT_type{{.*}}[[DUP_NNC]]
>> +# NOODR: DW_TAG_variable
>> +# NOODR-NOT: {{DW_TAG|NULL}}
>> +# NOODR: DW_AT_name{{.*}}"ac"
>> +# NOODR-NOT: {{DW_TAG|NULL}}
>> +# NOODR: DW_AT_type{{.*}}0x[[DUP_ANONC:[0-9a-f]*]]
>> +
>> +# This is the lanbda inside func
>> +
>> +# NOODR: DW_TAG_subprogram
>> +# NOODR-NOT: {{NULL|DW_TAG}}
>> +# NOODR: linkage_name{{.*}}"_ZZ4funcvENKUlvE_clEv"
>> +# NOODR-NOT: NULL
>> +# NOODR: DW_TAG_variable
>> +# NOODR-NOT: DW_TAG
>> +# NOODR: DW_AT_name{{.*}}"dummy"
>> +# NOODR-NOT: NULL
>> +# NOODR: DW_AT_type{{.*}}[[DUP_CINSIDEFUNC]]
>> +
>> +# This is "(anonymous namespace)::AnonC"
>> +
>> +# NOODR: DW_TAG_namespace
>> +# NOODR-NOT: {{DW_AT_name|NULL|DW_TAG}}
>> +# NOODR: 0x[[DUP_ANONC]]:{{.*}}DW_TAG_class_type
>> +# NOODR-NEXT: DW_AT_name{{.*}}"AnonC"
>> +
>> + - filename: odr2.o
>> + symbols:
>> + - { sym: __ZN1S3fooEv, objAddr: 0x0, binAddr: 0x7000, size: 0x12 }
>> + - { sym: __Z3barv, objAddr: 0x0, binAddr: 0x8000, size: 0x12 }
>> + - filename: odr3.o
>> + symbols:
>> + - { sym: __ZN1S3fooEv, objAddr: 0x0, binAddr: 0x8000, size: 0x12 }
>> + - { sym: __Z3barv, objAddr: 0x0, binAddr: 0x9000, size: 0x12 }
>> +
>> +# odr2.cpp and odr3.cpp test that a simple overloaded function doesn't
>> break the
>> +# uniquing (contrary to what we'll see with template/artificial)
>> functions.
>> +
>> +# CHECK: TAG_compile_unit
>> +# CHECK-NOT: {{DW_TAG|NULL}}
>> +# CHECK: AT_name{{.*}}"odr2.cpp"
>> +
>> +# NO-ODR: DW_TAG_structure_type
>> +# ODR-NOT: DW_TAG_structure_type
>> +
>> +# ODR: DW_TAG_subprogram
>> +# ODR: DW_AT_specification{{.*}}4incr
>> +# ODR: DW_TAG_formal_parameter
>> +# ODR-NEXT: DW_AT_name{{.*}}"this"
>> +# ODR-NEXT: DW_AT_type{{.*}}0x00000000[[S_PTR:[0-9a-f]*]]
>> +# ODR: 0x[[S_PTR]]:{{.*}}DW_TAG_pointer_type
>> +# ODR-NEXT: DW_AT_type{{.*}}[[S]]
>> +# ODR: DW_TAG_subprogram
>> +# ODR-NOT: {{DW_TAG|NULL}}
>> +# ODR: DW_AT_name{{.*}}"bar"
>> +# ODR-NOT: NULL
>> +# ODR: DW_TAG_variable
>> +# ODR-NOT: {{DW_TAG|NULL}}
>> +# ODR: DW_AT_type{{.*}}[[S]]
>> +# ODR-NOT NULL
>> +# DOR: DW_TAG_inlined_subroutine
>> +# ODR-NOT NULL
>> +# ODR: DW_TAG_formal_parameter
>> +# ODR-NOT {{NULL|DW_TAG}}
>> +# ODR: DW_AT_type{{.*}}[[S_PTR]]
>> +
>> +# CHECK: TAG_compile_unit
>> +# CHECK-NOT: {{DW_TAG|NULL}}
>> +# CHECK: AT_name{{.*}}"odr3.cpp"
>> +
>> +# NO-ODR: DW_TAG_structure_type
>> +# ODR-NOT: DW_TAG_structure_type
>> +
>> +# ODR: DW_TAG_subprogram
>> +# ODR: DW_AT_specification{{.*}}4incr
>> +# ODR: DW_TAG_formal_parameter
>> +# ODR-NEXT: DW_AT_name{{.*}}"this"
>> +# ODR-NEXT: DW_AT_type{{.*}}0x00000000[[S_PTR2:[0-9a-f]*]]
>> +# ODR: 0x[[S_PTR2]]:{{.*}}DW_TAG_pointer_type
>> +# ODR-NEXT: DW_AT_type{{.*}}[[S]]
>> +# ODR: DW_TAG_subprogram
>> +# ODR-NOT: {{DW_TAG|NULL}}
>> +# ODR: DW_AT_name{{.*}}"bar"
>> +# ODR-NOT: NULL
>> +# ODR: DW_TAG_variable
>> +# ODR-NOT: {{DW_TAG|NULL}}
>> +# ODR: DW_AT_type{{.*}}[[S]]
>> +# ODR-NOT NULL
>> +# DOR: DW_TAG_inlined_subroutine
>> +# ODR-NOT NULL
>> +# ODR: DW_TAG_formal_parameter
>> +# ODR-NOT {{NULL|DW_TAG}}
>> +# ODR: DW_AT_type{{.*}}[[S_PTR2]]
>> +
>> + - filename: odr4.o
>> + symbols:
>> + - { sym: __Z3bazv, objAddr: 0x0, binAddr: 0xa000, size: 0x12 }
>> +
>> +# odr4.cpp helps check that anonymous namespaces with similarly named
>> contents do
>> +# not get uniqued.
>> +
>> +# CHECK: TAG_compile_unit
>> +# CHECK-NOT: {{DW_TAG|NULL}}
>> +# CHECK: AT_name{{.*}}"odr4.cpp"
>> +
>> +# CHECK: DW_TAG_subprogram
>> +# CHECK-NOT: NULL
>> +# CHECK: DW_TAG_variable
>> +# CHECK-NOT: DW_TAG
>> +# ODR: DW_AT_type{{.*}}[[LOCALANONC:........]])
>> +# NOODR: DW_AT_type{{.*}}[[LOCALANONC:........]]})
>> +
>> +# CHECK: DW_TAG_namespace
>> +# CHECK-NOT: DW_AT_name
>> +# CHECK: [[LOCALANONC]]{{.*}}DW_TAG_class_type
>> +# CHECK-NOT: {{NULL|DW_TAG}}
>> +# CHECK: DW_AT_name{{.*}}"AnonC"
>> +
>> + - filename: odr5.o
>> + symbols:
>> + - { sym: __Z3bazv, objAddr: 0x0, binAddr: 0xb000, size: 0x12 }
>> + - { sym: __ZN1S6Nested4initIiEEvT_, objAddr: 0x0, binAddr: 0xc000,
>> size: 0x12 }
>> + - filename: odr6.o
>> + symbols:
>> + - { sym: __Z3bazv, objAddr: 0x0, binAddr: 0xd000, size: 0x12 }
>> + - { sym: __ZN1S6Nested4initIdEEvT_, objAddr: 0x0, binAddr: 0xe000,
>> size: 0x12 }
>> +
>> +# odr5.cpp and odr6.cpp instanciate a template member function of the S
>> class.
>> +# They instanciate it with different types. As DWARF only describes the
>> actual
>> +# intances, these members aren't described in the uniqued class
>> definition of
>> +# odr1.cpp. Both these files should contain a new copy of S' definition
>> with
>> +# the template instance included.
>> +
>> +# CHECK: TAG_compile_unit
>> +# CHECK-NOT: {{DW_TAG|NULL}}
>> +# CHECK: AT_name{{.*}}"odr5.cpp"
>> +
>> +# CHECK: 0x{{[0-9a-f]*}}:{{.*}}DW_TAG_structure_type
>> +# CHECK-NEXT: DW_AT_name{{.*}}"S"
>> +# CHECK-NOT: NULL
>> +# CHECK: 0x[[NESTED2:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
>> +# CHECK-NOT: {{DW_TAG|NULL}}
>> +# CHECK: DW_AT_name{{.*}}"Nested"
>> +# CHECK-NOT: NULL
>> +# CHECK: 0x[[INITTEMPLATE:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
>> +# CHECK-NEXT:{{.*}}"_ZN1S6Nested4init
>> +
>> +# CHECK: DW_AT_specification{{.*}}[[INITTEMPLATE]]
>> +# CHECK: DW_TAG_formal_parameter
>> +# CHECK-NOT: DW_TAG
>> +# CHECK: DW_AT_type{{.*}}[[NESTED_PTR:[0-9a-f]{8}]]{{[}]?}})
>> +
>> +# CHECK: 0x[[NESTED_PTR]]{{.*}}DW_TAG_pointer_type
>> +# ODR-NEXT: DW_AT_type{{.*}}[[NESTED]]
>> +# NOODR-NEXT: DW_AT_type{{.*}}[[NESTED2]]
>> +
>> +# CHECK: TAG_compile_unit
>> +# CHECK-NOT: {{DW_TAG|NULL}}
>> +# CHECK: AT_name{{.*}}"odr6.cpp"
>> +
>> +# CHECK: 0x{{[0-9a-f]*}}:{{.*}}DW_TAG_structure_type
>> +# CHECK-NEXT: DW_AT_name{{.*}}"S"
>> +# CHECK-NOT: NULL
>> +# CHECK: 0x[[NESTED3:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type
>> +# CHECK-NOT: {{DW_TAG|NULL}}
>> +# CHECK: DW_AT_name{{.*}}"Nested"
>> +# CHECK-NOT: NULL
>> +# CHECK: 0x[[INITTEMPLATE2:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram
>> +# CHECK-NEXT:{{.*}}"_ZN1S6Nested4init
>> +
>> +# CHECK: DW_AT_specification{{.*}}[[INITTEMPLATE2]]
>> +# CHECK: DW_TAG_formal_parameter
>> +# CHECK-NOT: DW_TAG
>> +# CHECK: DW_AT_type{{.*}}[[NESTED_PTR2:[0-9a-f]{8}]]{{[}]?}})
>> +
>> +# CHECK: 0x[[NESTED_PTR2]]{{.*}}DW_TAG_pointer_type
>> +# ODR-NEXT: DW_AT_type{{.*}}[[NESTED]]
>> +# NOODR-NEXT: DW_AT_type{{.*}}[[NESTED3]]
>> +
>> + - filename: odr7.o
>> + symbols:
>> + - { sym: __Z3foov, objAddr: 0x0, binAddr: 0xf000, size: 0x12 }
>> +
>> +# Check that a reference to a nested class correctly refers to the
>> original
>> +# definition
>> +
>> +# CHECK: TAG_compile_unit
>> +# CHECK-NOT: {{DW_TAG|NULL}}
>> +# CHECK: AT_name{{.*}}"odr7.cpp"
>> +
>> +# ODR: DW_TAG_subprogram
>> +# ODR-NOT: NULL
>> +# ODR: DW_TAG_variable
>> +# ODR-NOT: DW_TAG
>> +# ODR: DW_AT_type{{.*}}[[NESTED]]
>> +...
>> +
>>
>> Modified: llvm/trunk/tools/dsymutil/DwarfLinker.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DwarfLinker.cpp?rev=242847&r1=242846&r2=242847&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/tools/dsymutil/DwarfLinker.cpp (original)
>> +++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp Tue Jul 21 17:41:43 2015
>> @@ -15,6 +15,7 @@
>> #include "llvm/ADT/STLExtras.h"
>> #include "llvm/CodeGen/AsmPrinter.h"
>> #include "llvm/CodeGen/DIE.h"
>> +#include "llvm/Config/config.h"
>> #include "llvm/DebugInfo/DWARF/DWARFContext.h"
>> #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
>> #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
>> @@ -80,6 +81,112 @@ struct PatchLocation {
>> }
>> };
>>
>> +class CompileUnit;
>> +struct DeclMapInfo;
>> +class NonRelocatableStringpool;
>> +
>> +/// A DeclContext is a named program scope that is used for ODR
>> +/// uniquing of types.
>> +/// The set of DeclContext for the ODR-subject parts of a Dwarf link
>> +/// is expanded (and uniqued) with each new object file processed. We
>> +/// need to determine the context of each DIE in an linked object file
>> +/// to see if the corresponding type has already been emitted.
>> +///
>> +/// The contexts are conceptually organised as a tree (eg. a function
>> +/// scope is contained in a namespace scope that contains other
>> +/// scopes), but storing/accessing them in an actual tree is too
>> +/// inefficient: we need to be able to very quickly query a context
>> +/// for a given child context by name. Storing a StringMap in each
>> +/// DeclContext would be too space inefficient.
>> +/// The solution here is to give each DeclContext a link to its parent
>> +/// (this allows to walk up the tree), but to query the existance of a
>> +/// specific DeclContext using a separate DenseMap keyed on the hash
>> +/// of the fully qualified name of the context.
>> +class DeclContext {
>> + unsigned QualifiedNameHash;
>> + uint32_t Line;
>> + uint32_t ByteSize;
>> + uint16_t Tag;
>> + StringRef Name;
>> + StringRef File;
>> + const DeclContext &Parent;
>> + const DWARFDebugInfoEntryMinimal *LastSeenDIE;
>> + uint32_t LastSeenCompileUnitID;
>> + uint32_t CanonicalDIEOffset;
>> +
>> + friend DeclMapInfo;
>> +
>> +public:
>> + typedef DenseSet<DeclContext *, DeclMapInfo> Map;
>> +
>> + DeclContext()
>> + : QualifiedNameHash(0), Line(0), ByteSize(0),
>> + Tag(dwarf::DW_TAG_compile_unit), Name(), File(), Parent(*this),
>> + LastSeenDIE(nullptr), LastSeenCompileUnitID(0),
>> CanonicalDIEOffset(0) {}
>> +
>> + DeclContext(unsigned Hash, uint32_t Line, uint32_t ByteSize, uint16_t
>> Tag,
>> + StringRef Name, StringRef File, const DeclContext &Parent,
>> + const DWARFDebugInfoEntryMinimal *LastSeenDIE = nullptr,
>> + unsigned CUId = 0)
>> + : QualifiedNameHash(Hash), Line(Line), ByteSize(ByteSize),
>> Tag(Tag),
>> + Name(Name), File(File), Parent(Parent), LastSeenDIE(LastSeenDIE),
>> + LastSeenCompileUnitID(CUId), CanonicalDIEOffset(0) {}
>> +
>> + uint32_t getQualifiedNameHash() const { return QualifiedNameHash; }
>> +
>> + bool setLastSeenDIE(CompileUnit &U, const DWARFDebugInfoEntryMinimal
>> *Die);
>> +
>> + uint32_t getCanonicalDIEOffset() const { return CanonicalDIEOffset; }
>> + void setCanonicalDIEOffset(uint32_t Offset) { CanonicalDIEOffset =
>> Offset; }
>> +
>> + uint16_t getTag() const { return Tag; }
>> + StringRef getName() const { return Name; }
>> +};
>> +
>> +/// Info type for the DenseMap storing the DeclContext pointers.
>> +struct DeclMapInfo : private DenseMapInfo<DeclContext *> {
>> + using DenseMapInfo<DeclContext *>::getEmptyKey;
>> + using DenseMapInfo<DeclContext *>::getTombstoneKey;
>> +
>> + static unsigned getHashValue(const DeclContext *Ctxt) {
>> + return Ctxt->QualifiedNameHash;
>> + }
>> +
>> + static bool isEqual(const DeclContext *LHS, const DeclContext *RHS) {
>> + if (RHS == getEmptyKey() || RHS == getTombstoneKey())
>> + return RHS == LHS;
>> + return LHS->QualifiedNameHash == RHS->QualifiedNameHash &&
>> + LHS->Line == RHS->Line && LHS->ByteSize == RHS->ByteSize &&
>> + LHS->Name.data() == RHS->Name.data() &&
>> + LHS->File.data() == RHS->File.data() &&
>> + LHS->Parent.QualifiedNameHash ==
>> RHS->Parent.QualifiedNameHash;
>> + }
>> +};
>> +
>> +/// This class gives a tree-like API to the DenseMap that stores the
>> +/// DeclContext objects. It also holds the BumpPtrAllocator where
>> +/// these objects will be allocated.
>> +class DeclContextTree {
>> + BumpPtrAllocator Allocator;
>> + DeclContext Root;
>> + DeclContext::Map Contexts;
>> +
>> +public:
>> + /// Get the child of \a Context described by \a DIE in \a Unit. The
>> + /// required strings will be interned in \a StringPool.
>> + /// \returns The child DeclContext along with one bit that is set if
>> + /// this context is invalid.
>> + /// FIXME: the invalid bit along the return value is to emulate some
>> + /// dsymutil-classic functionality. See the fucntion definition for
>> + /// a more thorough discussion of its use.
>> + PointerIntPair<DeclContext *, 1>
>> + getChildDeclContext(DeclContext &Context,
>> + const DWARFDebugInfoEntryMinimal *DIE, CompileUnit
>> &Unit,
>> + NonRelocatableStringpool &StringPool);
>> +
>> + DeclContext &getRoot() { return Root; }
>> +};
>> +
>> /// \brief Stores all information relating to a compile unit, be it in
>> /// its original instance in the object file to its brand new cloned
>> /// and linked DIE tree.
>> @@ -88,16 +195,26 @@ public:
>> /// \brief Information gathered about a DIE in the object file.
>> struct DIEInfo {
>> int64_t AddrAdjust; ///< Address offset to apply to the described
>> entity.
>> + DeclContext *Ctxt; ///< ODR Declaration context.
>> DIE *Clone; ///< Cloned version of that DIE.
>> uint32_t ParentIdx; ///< The index of this DIE's parent.
>> bool Keep; ///< Is the DIE part of the linked output?
>> bool InDebugMap; ///< Was this DIE's entity found in the map?
>> };
>>
>> - CompileUnit(DWARFUnit &OrigUnit, unsigned ID)
>> + CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR)
>> : OrigUnit(OrigUnit), ID(ID), LowPc(UINT64_MAX), HighPc(0),
>> RangeAlloc(),
>> Ranges(RangeAlloc) {
>> Info.resize(OrigUnit.getNumDIEs());
>> +
>> + const auto *CUDie = OrigUnit.getUnitDIE(false);
>> + unsigned Lang = CUDie->getAttributeValueAsUnsignedConstant(
>> + &OrigUnit, dwarf::DW_AT_language, 0);
>> + HasODR = CanUseODR && (Lang == dwarf::DW_LANG_C_plus_plus ||
>> + Lang == dwarf::DW_LANG_C_plus_plus_03 ||
>> + Lang == dwarf::DW_LANG_C_plus_plus_11 ||
>> + Lang == dwarf::DW_LANG_C_plus_plus_14 ||
>> + Lang == dwarf::DW_LANG_ObjC_plus_plus);
>> }
>>
>> CompileUnit(CompileUnit &&RHS)
>> @@ -116,6 +233,8 @@ public:
>> DIE *getOutputUnitDIE() const { return CUDie; }
>> void setOutputUnitDIE(DIE *Die) { CUDie = Die; }
>>
>> + bool hasODR() const { return HasODR; }
>> +
>> DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; }
>> const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; }
>>
>> @@ -147,9 +266,10 @@ public:
>>
>> /// \brief Keep track of a forward reference to DIE \p Die in \p
>> /// RefUnit by \p Attr. The attribute should be fixed up later to
>> - /// point to the absolute offset of \p Die in the debug_info section.
>> + /// point to the absolute offset of \p Die in the debug_info section
>> + /// or to the canonical offset of \p Ctxt if it is non-null.
>> void noteForwardReference(DIE *Die, const CompileUnit *RefUnit,
>> - PatchLocation Attr);
>> + DeclContext *Ctxt, PatchLocation Attr);
>>
>> /// \brief Apply all fixups recored by noteForwardReference().
>> void fixupForwardReferences();
>> @@ -190,11 +310,27 @@ public:
>> const std::vector<AccelInfo> &getPubnames() const { return Pubnames; }
>> const std::vector<AccelInfo> &getPubtypes() const { return Pubtypes; }
>>
>> + /// Get the full path for file \a FileNum in the line table
>> + const char *getResolvedPath(unsigned FileNum) {
>> + if (FileNum >= ResolvedPaths.size())
>> + return nullptr;
>> + return ResolvedPaths[FileNum].size() ? ResolvedPaths[FileNum].c_str()
>> + : nullptr;
>> + }
>> +
>> + /// Set the fully resolved path for the line-table's file \a FileNum
>> + /// to \a Path.
>> + void setResolvedPath(unsigned FileNum, const std::string &Path) {
>> + if (ResolvedPaths.size() <= FileNum)
>> + ResolvedPaths.resize(FileNum + 1);
>> + ResolvedPaths[FileNum] = Path;
>> + }
>> +
>> private:
>> DWARFUnit &OrigUnit;
>> unsigned ID;
>> - std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
>> - DIE *CUDie; ///< Root of the linked DIE tree.
>> + std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
>> + DIE *CUDie; ///< Root of the linked DIE tree.
>>
>> uint64_t StartOffset;
>> uint64_t NextUnitOffset;
>> @@ -208,8 +344,8 @@ private:
>> /// The offsets for the attributes in this array couldn't be set while
>> /// cloning because for cross-cu forward refences the target DIE's
>> /// offset isn't known you emit the reference attribute.
>> - std::vector<std::tuple<DIE *, const CompileUnit *, PatchLocation>>
>> - ForwardDIEReferences;
>> + std::vector<std::tuple<DIE *, const CompileUnit *, DeclContext *,
>> + PatchLocation>> ForwardDIEReferences;
>>
>> FunctionIntervals::Allocator RangeAlloc;
>> /// \brief The ranges in that interval map are the PC ranges for
>> @@ -236,6 +372,12 @@ private:
>> std::vector<AccelInfo> Pubnames;
>> std::vector<AccelInfo> Pubtypes;
>> /// @}
>> +
>> + /// Cached resolved paths from the line table.
>> + std::vector<std::string> ResolvedPaths;
>> +
>> + /// Is this unit subject to the ODR rule?
>> + bool HasODR;
>> };
>>
>> uint64_t CompileUnit::computeNextUnitOffset() {
>> @@ -251,8 +393,8 @@ uint64_t CompileUnit::computeNextUnitOff
>> /// \brief Keep track of a forward cross-cu reference from this unit
>> /// to \p Die that lives in \p RefUnit.
>> void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit
>> *RefUnit,
>> - PatchLocation Attr) {
>> - ForwardDIEReferences.emplace_back(Die, RefUnit, Attr);
>> + DeclContext *Ctxt, PatchLocation
>> Attr) {
>> + ForwardDIEReferences.emplace_back(Die, RefUnit, Ctxt, Attr);
>> }
>>
>> /// \brief Apply all fixups recorded by noteForwardReference().
>> @@ -261,8 +403,12 @@ void CompileUnit::fixupForwardReferences
>> DIE *RefDie;
>> const CompileUnit *RefUnit;
>> PatchLocation Attr;
>> - std::tie(RefDie, RefUnit, Attr) = Ref;
>> - Attr.set(RefDie->getOffset() + RefUnit->getStartOffset());
>> + DeclContext *Ctxt;
>> + std::tie(RefDie, RefUnit, Ctxt, Attr) = Ref;
>> + if (Ctxt && Ctxt->getCanonicalDIEOffset())
>> + Attr.set(Ctxt->getCanonicalDIEOffset());
>> + else
>> + Attr.set(RefDie->getOffset() + RefUnit->getStartOffset());
>> }
>> }
>>
>> @@ -324,6 +470,12 @@ public:
>> /// one.
>> uint32_t getStringOffset(StringRef S);
>>
>> + /// \brief Get permanent storage for \p S (but do not necessarily
>> + /// emit \p S in the output section).
>> + /// \returns The StringRef that points to permanent storage to use
>> + /// in place of \p S.
>> + StringRef internString(StringRef S);
>> +
>> // \brief Return the first entry of the string table.
>> const MapTy::MapEntryTy *getFirstEntry() const {
>> return getNextEntry(&Sentinel);
>> @@ -367,6 +519,16 @@ uint32_t NonRelocatableStringpool::getSt
>> return It->getValue().first;
>> }
>>
>> +/// \brief Put \p S into the StringMap so that it gets permanent
>> +/// storage, but do not actually link it in the chain of elements
>> +/// that go into the output section. A latter call to
>> +/// getStringOffset() with the same string will chain it though.
>> +StringRef NonRelocatableStringpool::internString(StringRef S) {
>> + std::pair<uint32_t, StringMapEntryBase *> Entry(0, nullptr);
>> + auto InsertResult = Strings.insert(std::make_pair(S, Entry));
>> + return InsertResult.first->getKey();
>> +};
>> +
>> /// \brief The Dwarf streaming logic
>> ///
>> /// All interactions with the MC layer that is used to build the debug
>> @@ -1089,6 +1251,7 @@ private:
>> TF_InFunctionScope = 1 << 1, ///< Current scope is a fucntion scope.
>> TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept
>> DIE.
>> TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept
>> DIE.
>> + TF_ODR = 1 << 4, ///< Use the ODR whhile keeping
>> dependants.
>> };
>>
>> /// \brief Mark the passed DIE as well as all the ones it depends on
>> @@ -1096,7 +1259,7 @@ private:
>> void keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &DIE,
>> CompileUnit::DIEInfo &MyInfo,
>> const DebugMapObject &DMO, CompileUnit
>> &CU,
>> - unsigned Flags);
>> + bool UseODR);
>>
>> unsigned shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE,
>> CompileUnit &Unit, CompileUnit::DIEInfo
>> &MyInfo,
>> @@ -1227,11 +1390,14 @@ private:
>> BumpPtrAllocator DIEAlloc;
>> /// @}
>>
>> + /// ODR Contexts for that link.
>> + DeclContextTree ODRContexts;
>> +
>> /// \defgroup Helpers Various helper methods.
>> ///
>> /// @{
>> const DWARFDebugInfoEntryMinimal *
>> - resolveDIEReference(DWARFFormValue &RefValue, const DWARFUnit &Unit,
>> + resolveDIEReference(const DWARFFormValue &RefValue, const DWARFUnit
>> &Unit,
>> const DWARFDebugInfoEntryMinimal &DIE,
>> CompileUnit *&ReferencedCU);
>>
>> @@ -1296,7 +1462,7 @@ CompileUnit *DwarfLinker::getUnitForOffs
>> /// CompileUnit which is stored into \p ReferencedCU.
>> /// \returns null if resolving fails for any reason.
>> const DWARFDebugInfoEntryMinimal *DwarfLinker::resolveDIEReference(
>> - DWARFFormValue &RefValue, const DWARFUnit &Unit,
>> + const DWARFFormValue &RefValue, const DWARFUnit &Unit,
>> const DWARFDebugInfoEntryMinimal &DIE, CompileUnit *&RefCU) {
>> assert(RefValue.isFormClass(DWARFFormValue::FC_Reference));
>> uint64_t RefOffset = *RefValue.getAsReference(&Unit);
>> @@ -1309,6 +1475,220 @@ const DWARFDebugInfoEntryMinimal *DwarfL
>> return nullptr;
>> }
>>
>> +/// \returns whether the passed \a Attr type might contain a DIE
>> +/// reference suitable for ODR uniquing.
>> +static bool isODRAttribute(uint16_t Attr) {
>> + switch (Attr) {
>> + default:
>> + return false;
>> + case dwarf::DW_AT_type:
>> + case dwarf::DW_AT_containing_type:
>> + case dwarf::DW_AT_specification:
>> + case dwarf::DW_AT_abstract_origin:
>> + case dwarf::DW_AT_import:
>> + return true;
>> + }
>> + llvm_unreachable("Improper attribute.");
>> +}
>> +
>> +/// Set the last DIE/CU a context was seen in and, possibly invalidate
>> +/// the context if it is ambiguous.
>> +///
>> +/// In the current implementation, we don't handle overloaded
>> +/// functions well, because the argument types are not taken into
>> +/// account when computing the DeclContext tree.
>> +///
>> +/// Some of this is mitigated byt using mangled names that do contain
>> +/// the arguments types, but sometimes (eg. with function templates)
>> +/// we don't have that. In that case, just do not unique anything that
>> +/// refers to the contexts we are not able to distinguish.
>> +///
>> +/// If a context that is not a namespace appears twice in the same CU,
>> +/// we know it is ambiguous. Make it invalid.
>> +bool DeclContext::setLastSeenDIE(CompileUnit &U,
>> + const DWARFDebugInfoEntryMinimal *Die) {
>> + if (LastSeenCompileUnitID == U.getUniqueID()) {
>> + DWARFUnit &OrigUnit = U.getOrigUnit();
>> + uint32_t FirstIdx = OrigUnit.getDIEIndex(LastSeenDIE);
>> + U.getInfo(FirstIdx).Ctxt = nullptr;
>> + return false;
>> + }
>> +
>> + LastSeenCompileUnitID = U.getUniqueID();
>> + LastSeenDIE = Die;
>> + return true;
>> +}
>> +
>> +/// Get the child context of \a Context corresponding to \a DIE.
>> +///
>> +/// \returns the child context or null if we shouldn't track children
>> +/// contexts. It also returns an additional bit meaning 'invalid'. An
>> +/// invalid context means it shouldn't be considered for uniquing, but
>> +/// its not returning null, because some children of that context
>> +/// might be uniquing candidates.
>> +/// FIXME: this is for dsymutil-classic compatibility, I don't think
>> +/// it buys us much.
>> +PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext(
>> + DeclContext &Context, const DWARFDebugInfoEntryMinimal *DIE,
>> CompileUnit &U,
>> + NonRelocatableStringpool &StringPool) {
>> + unsigned Tag = DIE->getTag();
>> +
>> + // FIXME: dsymutil-classic compat: We should bail out here if we
>> + // have a specification or an abstract_origin. We will get the
>> + // parent context wrong here.
>> +
>> + switch (Tag) {
>> + default:
>> + // By default stop gathering child contexts.
>> + return PointerIntPair<DeclContext *, 1>(nullptr);
>> + case dwarf::DW_TAG_compile_unit:
>> + // FIXME: Add support for DW_TAG_module.
>> + return PointerIntPair<DeclContext *, 1>(&Context);
>> + case dwarf::DW_TAG_subprogram:
>> + // Do not unique anything inside CU local functions.
>> + if ((Context.getTag() == dwarf::DW_TAG_namespace ||
>> + Context.getTag() == dwarf::DW_TAG_compile_unit) &&
>> + !DIE->getAttributeValueAsUnsignedConstant(&U.getOrigUnit(),
>> + dwarf::DW_AT_external,
>> 0))
>> + return PointerIntPair<DeclContext *, 1>(nullptr);
>> + // Fallthrough
>> + case dwarf::DW_TAG_member:
>> + case dwarf::DW_TAG_namespace:
>> + case dwarf::DW_TAG_structure_type:
>> + case dwarf::DW_TAG_class_type:
>> + case dwarf::DW_TAG_union_type:
>> + case dwarf::DW_TAG_enumeration_type:
>> + case dwarf::DW_TAG_typedef:
>> + // Artificial things might be ambiguous, because they might be
>> + // created on demand. For example implicitely defined constructors
>> + // are ambiguous because of the way we identify contexts, and they
>> + // won't be generated everytime everywhere.
>> + if (DIE->getAttributeValueAsUnsignedConstant(&U.getOrigUnit(),
>> +
>> dwarf::DW_AT_artificial, 0))
>> + return PointerIntPair<DeclContext *, 1>(nullptr);
>> + break;
>> + }
>> +
>> + const char *Name = DIE->getName(&U.getOrigUnit(),
>> DINameKind::LinkageName);
>> + const char *ShortName = DIE->getName(&U.getOrigUnit(),
>> DINameKind::ShortName);
>> + StringRef NameRef;
>> + StringRef ShortNameRef;
>> + StringRef FileRef;
>> +
>> + if (Name)
>> + NameRef = StringPool.internString(Name);
>> + else if (Tag == dwarf::DW_TAG_namespace)
>> + // FIXME: For dsymutil-classic compatibility. I think uniquing
>> + // within anonymous namespaces is wrong. There is no ODR guarantee
>> + // there.
>> + NameRef = StringPool.internString("(anonymous namespace)");
>> +
>> + if (ShortName && ShortName != Name)
>> + ShortNameRef = StringPool.internString(ShortName);
>> + else
>> + ShortNameRef = NameRef;
>> +
>> + if (Tag != dwarf::DW_TAG_class_type && Tag !=
>> dwarf::DW_TAG_structure_type &&
>> + Tag != dwarf::DW_TAG_union_type &&
>> + Tag != dwarf::DW_TAG_enumeration_type && NameRef.empty())
>> + return PointerIntPair<DeclContext *, 1>(nullptr);
>> +
>> + std::string File;
>> + unsigned Line = 0;
>> + unsigned ByteSize = 0;
>> +
>> + // Gather some discriminating data about the DeclContext we will be
>> + // creating: File, line number and byte size. This shouldn't be
>> + // necessary, because the ODR is just about names, but given that we
>> + // do some approximations with overloaded functions and anonymous
>> + // namespaces, use these additional data points to make the process
>> safer.
>> + ByteSize = DIE->getAttributeValueAsUnsignedConstant(
>> + &U.getOrigUnit(), dwarf::DW_AT_byte_size, UINT64_MAX);
>> + if (Tag != dwarf::DW_TAG_namespace || !Name) {
>> + if (unsigned FileNum = DIE->getAttributeValueAsUnsignedConstant(
>> + &U.getOrigUnit(), dwarf::DW_AT_decl_file, 0)) {
>> + if (const auto *LT =
>> U.getOrigUnit().getContext().getLineTableForUnit(
>> + &U.getOrigUnit())) {
>> + // FIXME: dsymutil-classic compatibility. I'd rather not
>> + // unique anything in anonymous namespaces, but if we do, then
>> + // verify that the file and line correspond.
>> + if (!Name && Tag == dwarf::DW_TAG_namespace)
>> + FileNum = 1;
>> +
>> + // FIXME: Passing U.getOrigUnit().getCompilationDir()
>> + // instead of "" would allow more uniquing, but for now, do
>> + // it this way to match dsymutil-classic.
>> + if (LT->getFileNameByIndex(
>> + FileNum, "",
>> + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
>> + File)) {
>> + Line = DIE->getAttributeValueAsUnsignedConstant(
>> + &U.getOrigUnit(), dwarf::DW_AT_decl_line, 0);
>> +#ifdef HAVE_REALPATH
>> + // Cache the resolved paths, because calling realpath is
>> expansive.
>> + if (const char *ResolvedPath = U.getResolvedPath(FileNum)) {
>> + File = ResolvedPath;
>> + } else {
>> + char RealPath[PATH_MAX + 1];
>> + RealPath[PATH_MAX] = 0;
>> + if (::realpath(File.c_str(), RealPath))
>> + File = RealPath;
>> + U.setResolvedPath(FileNum, File);
>> + }
>> +#endif
>> + FileRef = StringPool.internString(File);
>> + }
>> + }
>> + }
>> + }
>> +
>> + if (!Line && NameRef.empty())
>> + return PointerIntPair<DeclContext *, 1>(nullptr);
>> +
>> + // FIXME: dsymutil-classic compat won't unique the same type
>> + // presented once as a struct and once as a class. Use the Tag in
>> + // the fully qualified name hash to get the same effect.
>> + // We hash NameRef, which is the mangled name, in order to get most
>> + // overloaded functions resolvec correctly.
>> + unsigned Hash = hash_combine(Context.getQualifiedNameHash(), Tag,
>> NameRef);
>> +
>> + // FIXME: dsymutil-classic compatibility: when we don't have a name,
>> + // use the filename.
>> + if (Tag == dwarf::DW_TAG_namespace && NameRef == "(anonymous
>> namespace)")
>> + Hash = hash_combine(Hash, FileRef);
>> +
>> + // Now look if this context already exists.
>> + DeclContext Key(Hash, Line, ByteSize, Tag, NameRef, FileRef, Context);
>> + auto ContextIter = Contexts.find(&Key);
>> +
>> + if (ContextIter == Contexts.end()) {
>> + // The context wasn't found.
>> + bool Inserted;
>> + DeclContext *NewContext =
>> + new (Allocator) DeclContext(Hash, Line, ByteSize, Tag, NameRef,
>> FileRef,
>> + Context, DIE, U.getUniqueID());
>> + std::tie(ContextIter, Inserted) = Contexts.insert(NewContext);
>> + assert(Inserted && "Failed to insert DeclContext");
>> + (void)Inserted;
>> + } else if (Tag != dwarf::DW_TAG_namespace &&
>> + !(*ContextIter)->setLastSeenDIE(U, DIE)) {
>> + // The context was found, but it is ambiguous with another context
>> + // in the same file. Mark it invalid.
>> + return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */
>> 1);
>> + }
>> +
>> + assert(ContextIter != Contexts.end());
>> + // FIXME: dsymutil-classic compatibility. Union types aren't
>> + // uniques, but their children might be.
>> + if ((Tag == dwarf::DW_TAG_subprogram &&
>> + Context.getTag() != dwarf::DW_TAG_structure_type &&
>> + Context.getTag() != dwarf::DW_TAG_class_type) ||
>> + (Tag == dwarf::DW_TAG_union_type))
>> + return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */
>> 1);
>> +
>> + return PointerIntPair<DeclContext *, 1>(*ContextIter);
>> +}
>> +
>> /// \brief Get the potential name and mangled name for the entity
>> /// described by \p Die and store them in \Info if they are not
>> /// already there.
>> @@ -1355,14 +1735,30 @@ bool DwarfLinker::createStreamer(Triple
>> /// \brief Recursive helper to gather the child->parent relationships in
>> the
>> /// original compile unit.
>> static void gatherDIEParents(const DWARFDebugInfoEntryMinimal *DIE,
>> - unsigned ParentIdx, CompileUnit &CU) {
>> + unsigned ParentIdx, CompileUnit &CU,
>> + DeclContext *CurrentDeclContext,
>> + NonRelocatableStringpool &StringPool,
>> + DeclContextTree &Contexts) {
>> unsigned MyIdx = CU.getOrigUnit().getDIEIndex(DIE);
>> - CU.getInfo(MyIdx).ParentIdx = ParentIdx;
>> + CompileUnit::DIEInfo &Info = CU.getInfo(MyIdx);
>> +
>> + Info.ParentIdx = ParentIdx;
>> + if (CU.hasODR()) {
>> + if (CurrentDeclContext) {
>> + auto PtrInvalidPair =
>> Contexts.getChildDeclContext(*CurrentDeclContext,
>> + DIE, CU,
>> StringPool);
>> + CurrentDeclContext = PtrInvalidPair.getPointer();
>> + Info.Ctxt =
>> + PtrInvalidPair.getInt() ? nullptr :
>> PtrInvalidPair.getPointer();
>> + } else
>> + Info.Ctxt = CurrentDeclContext = nullptr;
>> + }
>>
>> if (DIE->hasChildren())
>> for (auto *Child = DIE->getFirstChild(); Child && !Child->isNULL();
>> Child = Child->getSibling())
>> - gatherDIEParents(Child, MyIdx, CU);
>> + gatherDIEParents(Child, MyIdx, CU, CurrentDeclContext, StringPool,
>> + Contexts);
>> }
>>
>> static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) {
>> @@ -1380,6 +1776,12 @@ static bool dieNeedsChildrenToBeMeaningf
>> llvm_unreachable("Invalid Tag");
>> }
>>
>> +static unsigned getRefAddrSize(const DWARFUnit &U) {
>> + if (U.getVersion() == 2)
>> + return U.getAddressByteSize();
>> + return 4;
>> +}
>> +
>> void DwarfLinker::startDebugObject(DWARFContext &Dwarf, DebugMapObject
>> &Obj) {
>> Units.reserve(Dwarf.getNumCompileUnits());
>> NextValidReloc = 0;
>> @@ -1686,15 +2088,16 @@ unsigned DwarfLinker::shouldKeepDIE(cons
>> void DwarfLinker::keepDIEAndDenpendencies(const
>> DWARFDebugInfoEntryMinimal &DIE,
>> CompileUnit::DIEInfo &MyInfo,
>> const DebugMapObject &DMO,
>> - CompileUnit &CU, unsigned
>> Flags) {
>> + CompileUnit &CU, bool UseODR) {
>> const DWARFUnit &Unit = CU.getOrigUnit();
>> MyInfo.Keep = true;
>>
>> // First mark all the parent chain as kept.
>> unsigned AncestorIdx = MyInfo.ParentIdx;
>> while (!CU.getInfo(AncestorIdx).Keep) {
>> + unsigned ODRFlag = UseODR ? TF_ODR : 0;
>> lookForDIEsToKeep(*Unit.getDIEAtIndex(AncestorIdx), DMO, CU,
>> - TF_ParentWalk | TF_Keep | TF_DependencyWalk);
>> + TF_ParentWalk | TF_Keep | TF_DependencyWalk |
>> ODRFlag);
>> AncestorIdx = CU.getInfo(AncestorIdx).ParentIdx;
>> }
>>
>> @@ -1715,9 +2118,27 @@ void DwarfLinker::keepDIEAndDenpendencie
>>
>> Val.extractValue(Data, &Offset, &Unit);
>> CompileUnit *ReferencedCU;
>> - if (const auto *RefDIE = resolveDIEReference(Val, Unit, DIE,
>> ReferencedCU))
>> + if (const auto *RefDIE =
>> + resolveDIEReference(Val, Unit, DIE, ReferencedCU)) {
>> + uint32_t RefIdx = ReferencedCU->getOrigUnit().getDIEIndex(RefDIE);
>> + CompileUnit::DIEInfo &Info = ReferencedCU->getInfo(RefIdx);
>> + // If the referenced DIE has a DeclContext that has already been
>> + // emitted, then do not keep the one in this CU. We'll link to
>> + // the canonical DIE in cloneDieReferenceAttribute.
>> + // FIXME: compatibility with dsymutil-classic. UseODR shouldn't
>> + // be necessary and could be advantageously replaced by
>> + // ReferencedCU->hasODR() && CU.hasODR().
>> + // FIXME: compatibility with dsymutil-classic. There is no
>> + // reason not to unique ref_addr references.
>> + if (AttrSpec.Form != dwarf::DW_FORM_ref_addr && UseODR &&
>> Info.Ctxt &&
>> + Info.Ctxt != ReferencedCU->getInfo(Info.ParentIdx).Ctxt &&
>> + Info.Ctxt->getCanonicalDIEOffset() &&
>> isODRAttribute(AttrSpec.Attr))
>> + continue;
>> +
>> + unsigned ODRFlag = UseODR ? TF_ODR : 0;
>> lookForDIEsToKeep(*RefDIE, DMO, *ReferencedCU,
>> - TF_Keep | TF_DependencyWalk);
>> + TF_Keep | TF_DependencyWalk | ODRFlag);
>> + }
>> }
>> }
>>
>> @@ -1752,9 +2173,10 @@ void DwarfLinker::lookForDIEsToKeep(cons
>> Flags = shouldKeepDIE(DIE, CU, MyInfo, Flags);
>>
>> // If it is a newly kept DIE mark it as well as all its dependencies
>> as kept.
>> - if (!AlreadyKept && (Flags & TF_Keep))
>> - keepDIEAndDenpendencies(DIE, MyInfo, DMO, CU, Flags);
>> -
>> + if (!AlreadyKept && (Flags & TF_Keep)) {
>> + bool UseOdr = (Flags & TF_DependencyWalk) ? (Flags & TF_ODR) :
>> CU.hasODR();
>> + keepDIEAndDenpendencies(DIE, MyInfo, DMO, CU, UseOdr);
>> + }
>> // The TF_ParentWalk flag tells us that we are currently walking up
>> // the parent chain of a required DIE, and we don't want to mark all
>> // the children of the parents as kept (consider for example a
>> @@ -1823,24 +2245,34 @@ unsigned DwarfLinker::cloneDieReferenceA
>> DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE,
>> AttributeSpec AttrSpec, unsigned AttrSize, const DWARFFormValue &Val,
>> CompileUnit &Unit) {
>> - uint32_t Ref = *Val.getAsReference(&Unit.getOrigUnit());
>> + const DWARFUnit &U = Unit.getOrigUnit();
>> + uint32_t Ref = *Val.getAsReference(&U);
>> DIE *NewRefDie = nullptr;
>> CompileUnit *RefUnit = nullptr;
>> - const DWARFDebugInfoEntryMinimal *RefDie = nullptr;
>> + DeclContext *Ctxt = nullptr;
>>
>> - if (!(RefUnit = getUnitForOffset(Ref)) ||
>> - !(RefDie = RefUnit->getOrigUnit().getDIEForOffset(Ref))) {
>> - const char *AttributeString = dwarf::AttributeString(AttrSpec.Attr);
>> - if (!AttributeString)
>> - AttributeString = "DW_AT_???";
>> - reportWarning(Twine("Missing DIE for ref in attribute ") +
>> AttributeString +
>> - ". Dropping.",
>> - &Unit.getOrigUnit(), &InputDIE);
>> + const DWARFDebugInfoEntryMinimal *RefDie =
>> + resolveDIEReference(Val, U, InputDIE, RefUnit);
>> +
>> + // If the referenced DIE is not found, drop the attribute.
>> + if (!RefDie)
>> return 0;
>> - }
>>
>> unsigned Idx = RefUnit->getOrigUnit().getDIEIndex(RefDie);
>> CompileUnit::DIEInfo &RefInfo = RefUnit->getInfo(Idx);
>> +
>> + // If we already have emitted an equivalent DeclContext, just point
>> + // at it.
>> + if (isODRAttribute(AttrSpec.Attr)) {
>> + Ctxt = RefInfo.Ctxt;
>> + if (Ctxt && Ctxt->getCanonicalDIEOffset()) {
>> + DIEInteger Attr(Ctxt->getCanonicalDIEOffset());
>> + Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
>> + dwarf::DW_FORM_ref_addr, Attr);
>> + return getRefAddrSize(U);
>> + }
>> + }
>> +
>> if (!RefInfo.Clone) {
>> assert(Ref > InputDIE.getOffset());
>> // We haven't cloned this DIE yet. Just create an empty one and
>> @@ -1849,7 +2281,8 @@ unsigned DwarfLinker::cloneDieReferenceA
>> }
>> NewRefDie = RefInfo.Clone;
>>
>> - if (AttrSpec.Form == dwarf::DW_FORM_ref_addr) {
>> + if (AttrSpec.Form == dwarf::DW_FORM_ref_addr ||
>> + (Unit.hasODR() && isODRAttribute(AttrSpec.Attr))) {
>> // We cannot currently rely on a DIEEntry to emit ref_addr
>> // references, because the implementation calls back to DwarfDebug
>> // to find the unit offset. (We don't have a DwarfDebug)
>> @@ -1867,11 +2300,11 @@ unsigned DwarfLinker::cloneDieReferenceA
>> // A forward reference. Note and fixup later.
>> Attr = 0xBADDEF;
>> Unit.noteForwardReference(
>> - NewRefDie, RefUnit,
>> + NewRefDie, RefUnit, Ctxt,
>> Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
>> dwarf::DW_FORM_ref_addr, DIEInteger(Attr)));
>> }
>> - return AttrSize;
>> + return getRefAddrSize(U);
>> }
>>
>> Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
>> @@ -2150,6 +2583,14 @@ DIE *DwarfLinker::cloneDIE(const DWARFDe
>> Die = Info.Clone = DIE::get(DIEAlloc, dwarf::Tag(InputDIE.getTag()));
>> assert(Die->getTag() == InputDIE.getTag());
>> Die->setOffset(OutOffset);
>> + if (Unit.hasODR() && Die->getTag() != dwarf::DW_TAG_namespace &&
>> Info.Ctxt &&
>> + Info.Ctxt != Unit.getInfo(Info.ParentIdx).Ctxt &&
>> + !Info.Ctxt->getCanonicalDIEOffset()) {
>> + // We are about to emit a DIE that is the root of its own valid
>> + // DeclContext tree. Make the current offset the canonical offset
>> + // for this context.
>> + Info.Ctxt->setCanonicalDIEOffset(OutOffset + Unit.getStartOffset());
>> + }
>>
>> // Extract and clone every attribute.
>> DataExtractor Data = U.getDebugInfoExtractor();
>> @@ -2611,8 +3052,9 @@ bool DwarfLinker::link(const DebugMap &M
>> outs() << "Input compilation unit:";
>> CUDie->dump(outs(), CU.get(), 0);
>> }
>> - Units.emplace_back(*CU, UnitID++);
>> - gatherDIEParents(CUDie, 0, Units.back());
>> + Units.emplace_back(*CU, UnitID++, !Options.NoODR);
>> + gatherDIEParents(CUDie, 0, Units.back(), &ODRContexts.getRoot(),
>> + StringPool, ODRContexts);
>> }
>>
>> // Then mark all the DIEs that need to be present in the linked
>>
>> Modified: llvm/trunk/tools/dsymutil/dsymutil.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/dsymutil.cpp?rev=242847&r1=242846&r2=242847&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/tools/dsymutil/dsymutil.cpp (original)
>> +++ llvm/trunk/tools/dsymutil/dsymutil.cpp Tue Jul 21 17:41:43 2015
>> @@ -47,6 +47,11 @@ static opt<bool>
>> desc("Do the link in memory, but do not emit the result
>> file."),
>> init(false));
>>
>> +static opt<bool>
>> + NoODR("no-odr",
>> + desc("Do not use ODR (One Definition Rule) for type
>> uniquing."),
>> + init(false));
>> +
>> static opt<bool> DumpDebugMap(
>> "dump-debug-map",
>> desc("Parse and dump the debug map to standard output. Not DWARF
>> link "
>> @@ -71,6 +76,7 @@ int main(int argc, char **argv) {
>>
>> Options.Verbose = Verbose;
>> Options.NoOutput = NoOutput;
>> + Options.NoODR = NoODR;
>>
>> llvm::InitializeAllTargetInfos();
>> llvm::InitializeAllTargetMCs();
>>
>> Modified: llvm/trunk/tools/dsymutil/dsymutil.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/dsymutil.h?rev=242847&r1=242846&r2=242847&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/tools/dsymutil/dsymutil.h (original)
>> +++ llvm/trunk/tools/dsymutil/dsymutil.h Tue Jul 21 17:41:43 2015
>> @@ -27,6 +27,7 @@ namespace dsymutil {
>> struct LinkOptions {
>> bool Verbose; ///< Verbosity
>> bool NoOutput; ///< Skip emitting output
>> + bool NoODR; ///< Do not unique types according to ODR
>>
>> LinkOptions() : Verbose(false), NoOutput(false) {}
>> };
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150724/6a75de73/attachment.html>
More information about the llvm-commits
mailing list