llvm.org GIT mirror llvm / 12a8b14
IR: Use ODR to unique DICompositeType members Merge members that are describing the same member of the same ODR type, even if other bits differ. If the file or line differ, we don't care; if anything else differs, it's an ODR violation (and we still don't really care). For DISubprogram declarations, this looks at the LinkageName and Scope. For DW_TAG_member instances of DIDerivedType, this looks at the Name and Scope. In both cases, we know that the Scope follows ODR rules if it has a non-empty identifier. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@266548 91177308-0d34-0410-b5e6-96231b3b80d8 Duncan P. N. Exon Smith 4 years ago
4 changed file(s) with 133 addition(s) and 2 deletion(s). Raw diff Collapse all Expand all
39753975
39763976 ``DW_TAG_member`` is used to define a member of a :ref:`composite type
39773977 `. The type of the member is the ``baseType:``. The
3978 ``offset:`` is the member's bit offset.
3978 ``offset:`` is the member's bit offset. If the composite type has a non-empty
3979 ``identifier:``, then it respects ODR rules. In that case, the ``scope:``
3980 reference will be a :ref:`metadata string `, and the member
3981 will be uniqued solely based on its ``name:`` and ``scope:``.
39793982
39803983 ``DW_TAG_inheritance`` and ``DW_TAG_friend`` are used in the ``elements:``
39813984 field of :ref:`composite types ` to describe parents and
41244127 that must be retained, even if their IR counterparts are optimized out of
41254128 the IR. The ``type:`` field must point at an :ref:`DISubroutineType`.
41264129
4130 When ``isDefinition: false``, subprograms describe a declaration in the type
4131 tree as opposed to a definition of a funciton. If the scope is a
4132 :ref:`metadata string ` then the composite type follows ODR
4133 rules, and the subprogram declaration is uniqued based only on its
4134 ``linkageName:`` and ``scope:``.
4135
41274136 .. code-block:: llvm
41284137
41294138 define void @_Z3foov() !dbg !0 {
41324141
41334142 !0 = distinct !DISubprogram(name: "foo", linkageName: "_Zfoov", scope: !1,
41344143 file: !2, line: 7, type: !3, isLocal: true,
4135 isDefinition: false, scopeLine: 8,
4144 isDefinition: true, scopeLine: 8,
41364145 containingType: !4,
41374146 virtuality: DW_VIRTUALITY_pure_virtual,
41384147 virtualIndex: 10, flags: DIFlagPrototyped,
3131 #include "llvm/IR/LLVMContext.h"
3232 #include "llvm/IR/Metadata.h"
3333 #include "llvm/IR/ValueHandle.h"
34 #include "llvm/Support/Dwarf.h"
3435 #include
3536
3637 namespace llvm {
375376 ExtraData == RHS->getRawExtraData();
376377 }
377378 unsigned getHashValue() const {
379 // If this is a member inside an ODR type, only hash the type and the name.
380 // Otherwise the hash will be stronger than
381 // MDNodeSubsetEqualImpl::isODRMember().
382 if (Tag == dwarf::DW_TAG_member && Name && Scope && isa(Scope))
383 return hash_combine(Name, Scope);
384
378385 // Intentionally computes the hash on a subset of the operands for
379386 // performance reason. The subset has to be significant enough to avoid
380387 // collision "most of the time". There is no correctness issue in case of
381388 // collision because of the full check above.
382389 return hash_combine(Tag, Name, File, Line, Scope, BaseType, Flags);
390 }
391 };
392
393 template <> struct MDNodeSubsetEqualImpl {
394 typedef MDNodeKeyImpl KeyTy;
395 static bool isSubsetEqual(const KeyTy &LHS, const DIDerivedType *RHS) {
396 return isODRMember(LHS.Tag, LHS.Scope, LHS.Name, RHS);
397 }
398 static bool isSubsetEqual(const DIDerivedType *LHS, const DIDerivedType *RHS) {
399 return isODRMember(LHS->getTag(), LHS->getRawScope(), LHS->getRawName(),
400 RHS);
401 }
402
403 /// Subprograms compare equal if they declare the same function in an ODR
404 /// type.
405 static bool isODRMember(unsigned Tag, const Metadata *Scope,
406 const MDString *Name, const DIDerivedType *RHS) {
407 // Check whether the LHS is eligible.
408 if (Tag != dwarf::DW_TAG_member || !Name || !Scope || !isa(Scope))
409 return false;
410
411 // Compare to the RHS.
412 return Tag == RHS->getTag() && Name == RHS->getRawName() &&
413 Scope == RHS->getRawScope();
383414 }
384415 };
385416
536567 Variables == RHS->getRawVariables();
537568 }
538569 unsigned getHashValue() const {
570 // If this is a declaration inside an ODR type, only hash the type and the
571 // name. Otherwise the hash will be stronger than
572 // MDNodeSubsetEqualImpl::isDeclarationOfODRMember().
573 if (!IsDefinition && LinkageName && Scope && isa(Scope))
574 return hash_combine(LinkageName, Scope);
575
539576 // Intentionally computes the hash on a subset of the operands for
540577 // performance reason. The subset has to be significant enough to avoid
541578 // collision "most of the time". There is no correctness issue in case of
542579 // collision because of the full check above.
543580 return hash_combine(Name, Scope, File, Type, Line);
581 }
582 };
583
584 template <> struct MDNodeSubsetEqualImpl {
585 typedef MDNodeKeyImpl KeyTy;
586 static bool isSubsetEqual(const KeyTy &LHS, const DISubprogram *RHS) {
587 return isDeclarationOfODRMember(LHS.IsDefinition, LHS.Scope,
588 LHS.LinkageName, RHS);
589 }
590 static bool isSubsetEqual(const DISubprogram *LHS, const DISubprogram *RHS) {
591 return isDeclarationOfODRMember(LHS->isDefinition(), LHS->getRawScope(),
592 LHS->getRawLinkageName(), RHS);
593 }
594
595 /// Subprograms compare equal if they declare the same function in an ODR
596 /// type.
597 static bool isDeclarationOfODRMember(bool IsDefinition, const Metadata *Scope,
598 const MDString *LinkageName,
599 const DISubprogram *RHS) {
600 // Check whether the LHS is eligible.
601 if (IsDefinition || !Scope || !LinkageName || !Scope ||
602 !isa(Scope))
603 return false;
604
605 // Compare to the RHS.
606 return IsDefinition == RHS->isDefinition() && Scope == RHS->getRawScope() &&
607 LinkageName == RHS->getRawLinkageName();
544608 }
545609 };
546610
0 ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
1 ; RUN: verify-uselistorder %s
2
3 ; Anchor the order of the nodes.
4 !named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17}
5
6 ; Some basic building blocks.
7 ; CHECK: !0 = !DIBasicType
8 ; CHECK-NEXT: !1 = !DIFile
9 ; CHECK-NEXT: !2 = !DIFile
10 !0 = !DIBasicType(tag: DW_TAG_base_type, name: "name", size: 1, align: 2, encoding: DW_ATE_unsigned_char)
11 !1 = !DIFile(filename: "path/to/file", directory: "/path/to/dir")
12 !2 = !DIFile(filename: "path/to/other", directory: "/path/to/dir")
13
14 ; Define an identified type with fields and functions.
15 ; CHECK-NEXT: !3 = !DICompositeType(tag: DW_TAG_structure_type, name: "has-uuid",
16 ; CHECK-NEXT: !4 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !"has-uuid", file: !1
17 ; CHECK-NEXT: !5 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !"has-uuid", file: !1
18 ; CHECK-NEXT: !6 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !"has-uuid", file: !1
19 ; CHECK-NEXT: !7 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !"has-uuid", file: !1
20 !3 = !DICompositeType(tag: DW_TAG_structure_type, name: "has-uuid", file: !1, line: 2, size: 64, align: 32, identifier: "uuid")
21 !4 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !"has-uuid", file: !1, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
22 !5 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !"has-uuid", file: !1, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
23 !6 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !"has-uuid", file: !1, isDefinition: false)
24 !7 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !"has-uuid", file: !1, isDefinition: false)
25
26 ; Define an un-identified type with fields and functions.
27 ; CHECK-NEXT: !8 = !DICompositeType(tag: DW_TAG_structure_type, name: "no-uuid", file: !1
28 ; CHECK-NEXT: !9 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !8, file: !1
29 ; CHECK-NEXT: !10 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !8, file: !1
30 ; CHECK-NEXT: !11 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !1
31 ; CHECK-NEXT: !12 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !8, file: !1
32 !8 = !DICompositeType(tag: DW_TAG_structure_type, name: "no-uuid", file: !1, line: 2, size: 64, align: 32)
33 !9 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !8, file: !1, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
34 !10 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !8, file: !1, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
35 !11 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !1, isDefinition: false)
36 !12 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !8, file: !1, isDefinition: false)
37
38 ; Add duplicate fields and members of "no-uuid" in a different file. These
39 ; should stick around, since "no-uuid" does not have an "identifier:" field.
40 ; CHECK-NEXT: !13 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !8, file: !2,
41 ; CHECK-NEXT: !14 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !2,
42 !13 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !8, file: !2, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
43 !14 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !2, isDefinition: false)
44
45 ; Add duplicate fields and members of "has-uuid" in a different file. These
46 ; should be merged.
47 !15 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !"has-uuid", file: !2, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
48 !16 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !"has-uuid", file: !2, isDefinition: false)
49
50 ; CHECK-NEXT: !15 = !{!4, !6}
51 ; CHECK-NOT: !DIDerivedType
52 ; CHECK-NOT: !DISubprogram
53 !17 = !{!15, !16}
0 ; REQUIRES: default_triple, object-emission
11 ;
22 ; RUN: llvm-link %s %p/type-unique-odr-b.ll -S -o - \
3 ; RUN: | %llc_dwarf -dwarf-linkage-names=Enable -filetype=obj -O0 \
4 ; RUN: | llvm-dwarfdump -debug-dump=info - \
5 ; RUN: | FileCheck %s
6 ; RUN: llvm-link %p/type-unique-odr-b.ll %s -S -o - \
37 ; RUN: | %llc_dwarf -dwarf-linkage-names=Enable -filetype=obj -O0 \
48 ; RUN: | llvm-dwarfdump -debug-dump=info - \
59 ; RUN: | FileCheck %s