summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/docs/LangRef.rst13
-rw-r--r--llvm/lib/IR/LLVMContextImpl.h64
-rw-r--r--llvm/test/Assembler/dicompositetype-members.ll54
-rw-r--r--llvm/test/Linker/type-unique-odr-a.ll4
4 files changed, 133 insertions, 2 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index b1edb500035..d3ad74ffd58 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -3976,7 +3976,10 @@ The following ``tag:`` values are valid:
``DW_TAG_member`` is used to define a member of a :ref:`composite type
<DICompositeType>`. The type of the member is the ``baseType:``. The
-``offset:`` is the member's bit offset.
+``offset:`` is the member's bit offset. If the composite type has a non-empty
+``identifier:``, then it respects ODR rules. In that case, the ``scope:``
+reference will be a :ref:`metadata string <metadata-string>`, and the member
+will be uniqued solely based on its ``name:`` and ``scope:``.
``DW_TAG_inheritance`` and ``DW_TAG_friend`` are used in the ``elements:``
field of :ref:`composite types <DICompositeType>` to describe parents and
@@ -4125,6 +4128,12 @@ metadata. The ``variables:`` field points at :ref:`variables <DILocalVariable>`
that must be retained, even if their IR counterparts are optimized out of
the IR. The ``type:`` field must point at an :ref:`DISubroutineType`.
+When ``isDefinition: false``, subprograms describe a declaration in the type
+tree as opposed to a definition of a funciton. If the scope is a
+:ref:`metadata string <metadata-string>` then the composite type follows ODR
+rules, and the subprogram declaration is uniqued based only on its
+``linkageName:`` and ``scope:``.
+
.. code-block:: llvm
define void @_Z3foov() !dbg !0 {
@@ -4133,7 +4142,7 @@ the IR. The ``type:`` field must point at an :ref:`DISubroutineType`.
!0 = distinct !DISubprogram(name: "foo", linkageName: "_Zfoov", scope: !1,
file: !2, line: 7, type: !3, isLocal: true,
- isDefinition: false, scopeLine: 8,
+ isDefinition: true, scopeLine: 8,
containingType: !4,
virtuality: DW_VIRTUALITY_pure_virtual,
virtualIndex: 10, flags: DIFlagPrototyped,
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index bd61648264d..8a2c43909b4 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -32,6 +32,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/ValueHandle.h"
+#include "llvm/Support/Dwarf.h"
#include <vector>
namespace llvm {
@@ -376,6 +377,12 @@ template <> struct MDNodeKeyImpl<DIDerivedType> {
ExtraData == RHS->getRawExtraData();
}
unsigned getHashValue() const {
+ // If this is a member inside an ODR type, only hash the type and the name.
+ // Otherwise the hash will be stronger than
+ // MDNodeSubsetEqualImpl::isODRMember().
+ if (Tag == dwarf::DW_TAG_member && Name && Scope && isa<MDString>(Scope))
+ return hash_combine(Name, Scope);
+
// Intentionally computes the hash on a subset of the operands for
// performance reason. The subset has to be significant enough to avoid
// collision "most of the time". There is no correctness issue in case of
@@ -384,6 +391,30 @@ template <> struct MDNodeKeyImpl<DIDerivedType> {
}
};
+template <> struct MDNodeSubsetEqualImpl<DIDerivedType> {
+ typedef MDNodeKeyImpl<DIDerivedType> KeyTy;
+ static bool isSubsetEqual(const KeyTy &LHS, const DIDerivedType *RHS) {
+ return isODRMember(LHS.Tag, LHS.Scope, LHS.Name, RHS);
+ }
+ static bool isSubsetEqual(const DIDerivedType *LHS, const DIDerivedType *RHS) {
+ return isODRMember(LHS->getTag(), LHS->getRawScope(), LHS->getRawName(),
+ RHS);
+ }
+
+ /// Subprograms compare equal if they declare the same function in an ODR
+ /// type.
+ static bool isODRMember(unsigned Tag, const Metadata *Scope,
+ const MDString *Name, const DIDerivedType *RHS) {
+ // Check whether the LHS is eligible.
+ if (Tag != dwarf::DW_TAG_member || !Name || !Scope || !isa<MDString>(Scope))
+ return false;
+
+ // Compare to the RHS.
+ return Tag == RHS->getTag() && Name == RHS->getRawName() &&
+ Scope == RHS->getRawScope();
+ }
+};
+
template <> struct MDNodeKeyImpl<DICompositeType> {
unsigned Tag;
MDString *Name;
@@ -537,6 +568,12 @@ template <> struct MDNodeKeyImpl<DISubprogram> {
Variables == RHS->getRawVariables();
}
unsigned getHashValue() const {
+ // If this is a declaration inside an ODR type, only hash the type and the
+ // name. Otherwise the hash will be stronger than
+ // MDNodeSubsetEqualImpl::isDeclarationOfODRMember().
+ if (!IsDefinition && LinkageName && Scope && isa<MDString>(Scope))
+ return hash_combine(LinkageName, Scope);
+
// Intentionally computes the hash on a subset of the operands for
// performance reason. The subset has to be significant enough to avoid
// collision "most of the time". There is no correctness issue in case of
@@ -545,6 +582,33 @@ template <> struct MDNodeKeyImpl<DISubprogram> {
}
};
+template <> struct MDNodeSubsetEqualImpl<DISubprogram> {
+ typedef MDNodeKeyImpl<DISubprogram> KeyTy;
+ static bool isSubsetEqual(const KeyTy &LHS, const DISubprogram *RHS) {
+ return isDeclarationOfODRMember(LHS.IsDefinition, LHS.Scope,
+ LHS.LinkageName, RHS);
+ }
+ static bool isSubsetEqual(const DISubprogram *LHS, const DISubprogram *RHS) {
+ return isDeclarationOfODRMember(LHS->isDefinition(), LHS->getRawScope(),
+ LHS->getRawLinkageName(), RHS);
+ }
+
+ /// Subprograms compare equal if they declare the same function in an ODR
+ /// type.
+ static bool isDeclarationOfODRMember(bool IsDefinition, const Metadata *Scope,
+ const MDString *LinkageName,
+ const DISubprogram *RHS) {
+ // Check whether the LHS is eligible.
+ if (IsDefinition || !Scope || !LinkageName || !Scope ||
+ !isa<MDString>(Scope))
+ return false;
+
+ // Compare to the RHS.
+ return IsDefinition == RHS->isDefinition() && Scope == RHS->getRawScope() &&
+ LinkageName == RHS->getRawLinkageName();
+ }
+};
+
template <> struct MDNodeKeyImpl<DILexicalBlock> {
Metadata *Scope;
Metadata *File;
diff --git a/llvm/test/Assembler/dicompositetype-members.ll b/llvm/test/Assembler/dicompositetype-members.ll
new file mode 100644
index 00000000000..631023e7a55
--- /dev/null
+++ b/llvm/test/Assembler/dicompositetype-members.ll
@@ -0,0 +1,54 @@
+; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
+; RUN: verify-uselistorder %s
+
+; Anchor the order of the nodes.
+!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, !16, !17}
+
+; Some basic building blocks.
+; CHECK: !0 = !DIBasicType
+; CHECK-NEXT: !1 = !DIFile
+; CHECK-NEXT: !2 = !DIFile
+!0 = !DIBasicType(tag: DW_TAG_base_type, name: "name", size: 1, align: 2, encoding: DW_ATE_unsigned_char)
+!1 = !DIFile(filename: "path/to/file", directory: "/path/to/dir")
+!2 = !DIFile(filename: "path/to/other", directory: "/path/to/dir")
+
+; Define an identified type with fields and functions.
+; CHECK-NEXT: !3 = !DICompositeType(tag: DW_TAG_structure_type, name: "has-uuid",
+; CHECK-NEXT: !4 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !"has-uuid", file: !1
+; CHECK-NEXT: !5 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !"has-uuid", file: !1
+; CHECK-NEXT: !6 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !"has-uuid", file: !1
+; CHECK-NEXT: !7 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !"has-uuid", file: !1
+!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "has-uuid", file: !1, line: 2, size: 64, align: 32, identifier: "uuid")
+!4 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !"has-uuid", file: !1, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
+!5 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !"has-uuid", file: !1, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
+!6 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !"has-uuid", file: !1, isDefinition: false)
+!7 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !"has-uuid", file: !1, isDefinition: false)
+
+; Define an un-identified type with fields and functions.
+; CHECK-NEXT: !8 = !DICompositeType(tag: DW_TAG_structure_type, name: "no-uuid", file: !1
+; CHECK-NEXT: !9 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !8, file: !1
+; CHECK-NEXT: !10 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !8, file: !1
+; CHECK-NEXT: !11 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !1
+; CHECK-NEXT: !12 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !8, file: !1
+!8 = !DICompositeType(tag: DW_TAG_structure_type, name: "no-uuid", file: !1, line: 2, size: 64, align: 32)
+!9 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !8, file: !1, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "field2", scope: !8, file: !1, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
+!11 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !1, isDefinition: false)
+!12 = !DISubprogram(name: "foo", linkageName: "foo2", scope: !8, file: !1, isDefinition: false)
+
+; Add duplicate fields and members of "no-uuid" in a different file. These
+; should stick around, since "no-uuid" does not have an "identifier:" field.
+; CHECK-NEXT: !13 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !8, file: !2,
+; CHECK-NEXT: !14 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !2,
+!13 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !8, file: !2, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
+!14 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !8, file: !2, isDefinition: false)
+
+; Add duplicate fields and members of "has-uuid" in a different file. These
+; should be merged.
+!15 = !DIDerivedType(tag: DW_TAG_member, name: "field1", scope: !"has-uuid", file: !2, line: 4, baseType: !0, size: 32, align: 32, offset: 32)
+!16 = !DISubprogram(name: "foo", linkageName: "foo1", scope: !"has-uuid", file: !2, isDefinition: false)
+
+; CHECK-NEXT: !15 = !{!4, !6}
+; CHECK-NOT: !DIDerivedType
+; CHECK-NOT: !DISubprogram
+!17 = !{!15, !16}
diff --git a/llvm/test/Linker/type-unique-odr-a.ll b/llvm/test/Linker/type-unique-odr-a.ll
index eeb1db763eb..d7640ea761c 100644
--- a/llvm/test/Linker/type-unique-odr-a.ll
+++ b/llvm/test/Linker/type-unique-odr-a.ll
@@ -4,6 +4,10 @@
; RUN: | %llc_dwarf -dwarf-linkage-names=Enable -filetype=obj -O0 \
; RUN: | llvm-dwarfdump -debug-dump=info - \
; RUN: | FileCheck %s
+; RUN: llvm-link %p/type-unique-odr-b.ll %s -S -o - \
+; RUN: | %llc_dwarf -dwarf-linkage-names=Enable -filetype=obj -O0 \
+; RUN: | llvm-dwarfdump -debug-dump=info - \
+; RUN: | FileCheck %s
;
; Test ODR-based type uniquing for C++ class members.
; rdar://problem/15851313.
OpenPOWER on IntegriCloud