[llvm] r242847 - [dsymutil] Implement ODR uniquing for C++ code.

David Blaikie dblaikie at gmail.com
Tue Jul 21 16:05:19 PDT 2015


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?


>
> 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?)

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?

- 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/20150721/2af3bc18/attachment.html>


More information about the llvm-commits mailing list