1 //===- DebugTypeODRUniquingTest.cpp - Debug type ODR uniquing tests -------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/BinaryFormat/Dwarf.h"
10 #include "llvm/IR/DebugInfoMetadata.h"
11 #include "llvm/IR/LLVMContext.h"
12 #include "gtest/gtest.h"
17 TEST(DebugTypeODRUniquingTest
, enableDebugTypeODRUniquing
) {
19 EXPECT_FALSE(Context
.isODRUniquingDebugTypes());
20 Context
.enableDebugTypeODRUniquing();
21 EXPECT_TRUE(Context
.isODRUniquingDebugTypes());
22 Context
.disableDebugTypeODRUniquing();
23 EXPECT_FALSE(Context
.isODRUniquingDebugTypes());
26 TEST(DebugTypeODRUniquingTest
, getODRType
) {
28 MDString
&UUID
= *MDString::get(Context
, "string");
30 // Without a type map, this should return null.
31 EXPECT_FALSE(DICompositeType::getODRType(
32 Context
, UUID
, dwarf::DW_TAG_class_type
, nullptr, nullptr, 0, nullptr,
33 nullptr, 0, 0, 0, DINode::FlagZero
, nullptr, 0, nullptr, nullptr, nullptr,
34 nullptr, nullptr, nullptr, nullptr, nullptr));
36 // Enable the mapping. There still shouldn't be a type.
37 Context
.enableDebugTypeODRUniquing();
38 EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context
, UUID
));
40 // Create some ODR-uniqued type.
41 auto &CT
= *DICompositeType::getODRType(
42 Context
, UUID
, dwarf::DW_TAG_class_type
, nullptr, nullptr, 0, nullptr,
43 nullptr, 0, 0, 0, DINode::FlagZero
, nullptr, 0, nullptr, nullptr, nullptr,
44 nullptr, nullptr, nullptr, nullptr, nullptr);
45 EXPECT_EQ(UUID
.getString(), CT
.getIdentifier());
47 // Check that we get it back, even if we change a field.
48 EXPECT_EQ(&CT
, DICompositeType::getODRTypeIfExists(Context
, UUID
));
50 DICompositeType::getODRType(
51 Context
, UUID
, dwarf::DW_TAG_class_type
, nullptr, nullptr, 0,
52 nullptr, nullptr, 0, 0, 0, DINode::FlagZero
, nullptr, 0,
53 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
55 EXPECT_EQ(&CT
, DICompositeType::getODRType(
56 Context
, UUID
, dwarf::DW_TAG_class_type
,
57 MDString::get(Context
, "name"), nullptr, 0, nullptr,
58 nullptr, 0, 0, 0, DINode::FlagZero
, nullptr, 0, nullptr,
59 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
62 // Check that it's discarded with the type map.
63 Context
.disableDebugTypeODRUniquing();
64 EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context
, UUID
));
66 // And it shouldn't magically reappear...
67 Context
.enableDebugTypeODRUniquing();
68 EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context
, UUID
));
71 TEST(DebugTypeODRUniquingTest
, buildODRType
) {
73 Context
.enableDebugTypeODRUniquing();
75 // Build an ODR type that's a forward decl.
76 MDString
&UUID
= *MDString::get(Context
, "Type");
77 auto &CT
= *DICompositeType::buildODRType(
78 Context
, UUID
, dwarf::DW_TAG_class_type
, nullptr, nullptr, 0, nullptr,
79 nullptr, 0, 0, 0, DINode::FlagFwdDecl
, nullptr, 0, nullptr, nullptr,
80 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
81 EXPECT_EQ(&CT
, DICompositeType::getODRTypeIfExists(Context
, UUID
));
82 EXPECT_EQ(dwarf::DW_TAG_class_type
, CT
.getTag());
84 // Update with another forward decl. This should be a no-op.
85 EXPECT_EQ(&CT
, DICompositeType::buildODRType(
86 Context
, UUID
, dwarf::DW_TAG_class_type
, nullptr, nullptr,
87 0, nullptr, nullptr, 0, 0, 0, DINode::FlagFwdDecl
, nullptr,
88 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
91 EXPECT_FALSE(DICompositeType::buildODRType(
92 Context
, UUID
, dwarf::DW_TAG_structure_type
, nullptr, nullptr, 0, nullptr,
93 nullptr, 0, 0, 0, DINode::FlagFwdDecl
, nullptr, 0, nullptr, nullptr,
94 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr));
96 // Update with a definition. This time we should see a change.
97 EXPECT_EQ(&CT
, DICompositeType::buildODRType(
98 Context
, UUID
, dwarf::DW_TAG_class_type
, nullptr, nullptr,
99 0, nullptr, nullptr, 0, 0, 0, DINode::FlagZero
, nullptr, 0,
100 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
102 EXPECT_FALSE(CT
.isForwardDecl());
104 // Further updates should be ignored.
105 EXPECT_EQ(&CT
, DICompositeType::buildODRType(
106 Context
, UUID
, dwarf::DW_TAG_class_type
, nullptr, nullptr,
107 0, nullptr, nullptr, 0, 0, 0, DINode::FlagFwdDecl
, nullptr,
108 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
110 EXPECT_FALSE(CT
.isForwardDecl());
111 EXPECT_EQ(&CT
, DICompositeType::buildODRType(
112 Context
, UUID
, dwarf::DW_TAG_class_type
, nullptr, nullptr,
113 111u, nullptr, nullptr, 0, 0, 0, DINode::FlagZero
, nullptr,
114 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
116 EXPECT_NE(111u, CT
.getLine());
119 TEST(DebugTypeODRUniquingTest
, buildODRTypeFields
) {
121 Context
.enableDebugTypeODRUniquing();
123 // Build an ODR type that's a forward decl with no other fields set.
124 MDString
&UUID
= *MDString::get(Context
, "UUID");
125 auto &CT
= *DICompositeType::buildODRType(
126 Context
, UUID
, 0, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0,
127 DINode::FlagFwdDecl
, nullptr, 0, nullptr, nullptr, nullptr, nullptr,
128 nullptr, nullptr, nullptr, nullptr);
130 // Create macros for running through all the fields except Identifier and Flags.
131 #define FOR_EACH_MDFIELD() \
134 DO_FOR_FIELD(Scope) \
135 DO_FOR_FIELD(BaseType) \
136 DO_FOR_FIELD(Elements) \
137 DO_FOR_FIELD(VTableHolder) \
138 DO_FOR_FIELD(TemplateParams)
139 #define FOR_EACH_INLINEFIELD() \
141 DO_FOR_FIELD(SizeInBits) \
142 DO_FOR_FIELD(AlignInBits) \
143 DO_FOR_FIELD(OffsetInBits) \
144 DO_FOR_FIELD(RuntimeLang)
146 // Create all the fields.
147 #define DO_FOR_FIELD(X) auto *X = MDString::get(Context, #X);
150 unsigned NonZeroInit
= 0;
151 #define DO_FOR_FIELD(X) auto X = ++NonZeroInit;
152 FOR_EACH_INLINEFIELD();
155 // Replace all the fields with new values that are distinct from each other.
157 DICompositeType::buildODRType(
158 Context
, UUID
, 0, Name
, File
, Line
, Scope
, BaseType
, SizeInBits
,
159 AlignInBits
, OffsetInBits
, DINode::FlagArtificial
, Elements
,
160 RuntimeLang
, VTableHolder
, TemplateParams
, nullptr, nullptr,
161 nullptr, nullptr, nullptr, nullptr));
163 // Confirm that all the right fields got updated.
164 #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.getRaw##X());
167 #undef FOR_EACH_MDFIELD
168 #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.get##X());
169 FOR_EACH_INLINEFIELD();
171 #undef FOR_EACH_INLINEFIELD
172 EXPECT_EQ(DINode::FlagArtificial
, CT
.getFlags());
173 EXPECT_EQ(&UUID
, CT
.getRawIdentifier());