1 //===- DebugTypeODRUniquingTest.cpp - Debug type ODR uniquing tests -------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/BinaryFormat/Dwarf.h"
10 #include "llvm/IR/DebugInfoMetadata.h"
11 #include "llvm/IR/LLVMContext.h"
12 #include "gtest/gtest.h"
13 using namespace llvm;
14 
15 namespace {
16 
TEST(DebugTypeODRUniquingTest,enableDebugTypeODRUniquing)17 TEST(DebugTypeODRUniquingTest, enableDebugTypeODRUniquing) {
18   LLVMContext Context;
19   EXPECT_FALSE(Context.isODRUniquingDebugTypes());
20   Context.enableDebugTypeODRUniquing();
21   EXPECT_TRUE(Context.isODRUniquingDebugTypes());
22   Context.disableDebugTypeODRUniquing();
23   EXPECT_FALSE(Context.isODRUniquingDebugTypes());
24 }
25 
TEST(DebugTypeODRUniquingTest,getODRType)26 TEST(DebugTypeODRUniquingTest, getODRType) {
27   LLVMContext Context;
28   MDString &UUID = *MDString::get(Context, "string");
29 
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));
35 
36   // Enable the mapping.  There still shouldn't be a type.
37   Context.enableDebugTypeODRUniquing();
38   EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID));
39 
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());
46 
47   // Check that we get it back, even if we change a field.
48   EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID));
49   EXPECT_EQ(&CT,
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,
54                 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,
60                      nullptr));
61 
62   // Check that it's discarded with the type map.
63   Context.disableDebugTypeODRUniquing();
64   EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID));
65 
66   // And it shouldn't magically reappear...
67   Context.enableDebugTypeODRUniquing();
68   EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID));
69 }
70 
TEST(DebugTypeODRUniquingTest,buildODRType)71 TEST(DebugTypeODRUniquingTest, buildODRType) {
72   LLVMContext Context;
73   Context.enableDebugTypeODRUniquing();
74 
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());
83 
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,
89                      nullptr, nullptr));
90 
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));
95 
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,
101                      nullptr, nullptr));
102   EXPECT_FALSE(CT.isForwardDecl());
103 
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,
109                      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,
115                      nullptr, nullptr));
116   EXPECT_NE(111u, CT.getLine());
117 }
118 
TEST(DebugTypeODRUniquingTest,buildODRTypeFields)119 TEST(DebugTypeODRUniquingTest, buildODRTypeFields) {
120   LLVMContext Context;
121   Context.enableDebugTypeODRUniquing();
122 
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);
129 
130 // Create macros for running through all the fields except Identifier and Flags.
131 #define FOR_EACH_MDFIELD()                                                     \
132   DO_FOR_FIELD(Name)                                                           \
133   DO_FOR_FIELD(File)                                                           \
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()                                                 \
140   DO_FOR_FIELD(Line)                                                           \
141   DO_FOR_FIELD(SizeInBits)                                                     \
142   DO_FOR_FIELD(AlignInBits)                                                    \
143   DO_FOR_FIELD(OffsetInBits)                                                   \
144   DO_FOR_FIELD(RuntimeLang)
145 
146 // Create all the fields.
147 #define DO_FOR_FIELD(X) auto *X = MDString::get(Context, #X);
148   FOR_EACH_MDFIELD();
149 #undef DO_FOR_FIELD
150   unsigned NonZeroInit = 0;
151 #define DO_FOR_FIELD(X) auto X = ++NonZeroInit;
152   FOR_EACH_INLINEFIELD();
153 #undef DO_FOR_FIELD
154 
155   // Replace all the fields with new values that are distinct from each other.
156   EXPECT_EQ(&CT,
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));
162 
163   // Confirm that all the right fields got updated.
164 #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.getRaw##X());
165   FOR_EACH_MDFIELD();
166 #undef DO_FOR_FIELD
167 #undef FOR_EACH_MDFIELD
168 #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.get##X());
169   FOR_EACH_INLINEFIELD();
170 #undef DO_FOR_FIELD
171 #undef FOR_EACH_INLINEFIELD
172   EXPECT_EQ(DINode::FlagArtificial, CT.getFlags());
173   EXPECT_EQ(&UUID, CT.getRawIdentifier());
174 }
175 
176 } // end namespace
177