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/IR/DebugInfoMetadata.h"
10 #include "llvm/IR/LLVMContext.h"
11 #include "gtest/gtest.h"
12 using namespace llvm;
13 
14 namespace {
15 
16 TEST(DebugTypeODRUniquingTest, enableDebugTypeODRUniquing) {
17   LLVMContext Context;
18   EXPECT_FALSE(Context.isODRUniquingDebugTypes());
19   Context.enableDebugTypeODRUniquing();
20   EXPECT_TRUE(Context.isODRUniquingDebugTypes());
21   Context.disableDebugTypeODRUniquing();
22   EXPECT_FALSE(Context.isODRUniquingDebugTypes());
23 }
24 
25 TEST(DebugTypeODRUniquingTest, getODRType) {
26   LLVMContext Context;
27   MDString &UUID = *MDString::get(Context, "string");
28 
29   // Without a type map, this should return null.
30   EXPECT_FALSE(DICompositeType::getODRType(
31       Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr,
32       nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr, nullptr,
33       nullptr, nullptr, nullptr, nullptr, nullptr));
34 
35   // Enable the mapping.  There still shouldn't be a type.
36   Context.enableDebugTypeODRUniquing();
37   EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID));
38 
39   // Create some ODR-uniqued type.
40   auto &CT = *DICompositeType::getODRType(
41       Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr,
42       nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr, nullptr,
43       nullptr, nullptr, nullptr, nullptr, nullptr);
44   EXPECT_EQ(UUID.getString(), CT.getIdentifier());
45 
46   // Check that we get it back, even if we change a field.
47   EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID));
48   EXPECT_EQ(&CT,
49             DICompositeType::getODRType(
50                 Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0,
51                 nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0,
52                 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
53                 nullptr));
54   EXPECT_EQ(&CT, DICompositeType::getODRType(
55                      Context, UUID, dwarf::DW_TAG_class_type,
56                      MDString::get(Context, "name"), nullptr, 0, nullptr,
57                      nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0, nullptr,
58                      nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
59                      nullptr));
60 
61   // Check that it's discarded with the type map.
62   Context.disableDebugTypeODRUniquing();
63   EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID));
64 
65   // And it shouldn't magically reappear...
66   Context.enableDebugTypeODRUniquing();
67   EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID));
68 }
69 
70 TEST(DebugTypeODRUniquingTest, buildODRType) {
71   LLVMContext Context;
72   Context.enableDebugTypeODRUniquing();
73 
74   // Build an ODR type that's a forward decl.
75   MDString &UUID = *MDString::get(Context, "Type");
76   auto &CT = *DICompositeType::buildODRType(
77       Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr,
78       nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr,
79       nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
80   EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID));
81   EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag());
82 
83   // Update with another forward decl.  This should be a no-op.
84   EXPECT_EQ(&CT, DICompositeType::buildODRType(
85                      Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr,
86                      0, nullptr, nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr,
87                      0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
88                      nullptr, nullptr));
89 
90   EXPECT_FALSE(DICompositeType::buildODRType(
91       Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr,
92       nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr,
93       nullptr, nullptr, nullptr, nullptr, nullptr, nullptr));
94 
95   // Update with a definition.  This time we should see a change.
96   EXPECT_EQ(&CT, DICompositeType::buildODRType(
97                      Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr,
98                      0, nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0,
99                      nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
100                      nullptr, nullptr));
101   EXPECT_FALSE(CT.isForwardDecl());
102 
103   // Further updates should be ignored.
104   EXPECT_EQ(&CT, DICompositeType::buildODRType(
105                      Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr,
106                      0, nullptr, nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr,
107                      0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
108                      nullptr, nullptr));
109   EXPECT_FALSE(CT.isForwardDecl());
110   EXPECT_EQ(&CT, DICompositeType::buildODRType(
111                      Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr,
112                      111u, nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr,
113                      0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
114                      nullptr, nullptr));
115   EXPECT_NE(111u, CT.getLine());
116 }
117 
118 TEST(DebugTypeODRUniquingTest, buildODRTypeFields) {
119   LLVMContext Context;
120   Context.enableDebugTypeODRUniquing();
121 
122   // Build an ODR type that's a forward decl with no other fields set.
123   MDString &UUID = *MDString::get(Context, "UUID");
124   auto &CT = *DICompositeType::buildODRType(
125       Context, UUID, 0, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0,
126       DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr, nullptr,
127       nullptr, nullptr, nullptr, nullptr);
128 
129 // Create macros for running through all the fields except Identifier and Flags.
130 #define FOR_EACH_MDFIELD()                                                     \
131   DO_FOR_FIELD(Name)                                                           \
132   DO_FOR_FIELD(File)                                                           \
133   DO_FOR_FIELD(Scope)                                                          \
134   DO_FOR_FIELD(BaseType)                                                       \
135   DO_FOR_FIELD(Elements)                                                       \
136   DO_FOR_FIELD(VTableHolder)                                                   \
137   DO_FOR_FIELD(TemplateParams)
138 #define FOR_EACH_INLINEFIELD()                                                 \
139   DO_FOR_FIELD(Line)                                                           \
140   DO_FOR_FIELD(SizeInBits)                                                     \
141   DO_FOR_FIELD(AlignInBits)                                                    \
142   DO_FOR_FIELD(OffsetInBits)                                                   \
143   DO_FOR_FIELD(RuntimeLang)
144 
145 // Create all the fields.
146 #define DO_FOR_FIELD(X) auto *X = MDString::get(Context, #X);
147   FOR_EACH_MDFIELD();
148 #undef DO_FOR_FIELD
149   unsigned NonZeroInit = 0;
150 #define DO_FOR_FIELD(X) auto X = ++NonZeroInit;
151   FOR_EACH_INLINEFIELD();
152 #undef DO_FOR_FIELD
153 
154   // Replace all the fields with new values that are distinct from each other.
155   EXPECT_EQ(&CT,
156             DICompositeType::buildODRType(
157                 Context, UUID, 0, Name, File, Line, Scope, BaseType, SizeInBits,
158                 AlignInBits, OffsetInBits, DINode::FlagArtificial, Elements,
159                 RuntimeLang, VTableHolder, TemplateParams, nullptr, nullptr,
160                 nullptr, nullptr, nullptr, nullptr));
161 
162   // Confirm that all the right fields got updated.
163 #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.getRaw##X());
164   FOR_EACH_MDFIELD();
165 #undef DO_FOR_FIELD
166 #undef FOR_EACH_MDFIELD
167 #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.get##X());
168   FOR_EACH_INLINEFIELD();
169 #undef DO_FOR_FIELD
170 #undef FOR_EACH_INLINEFIELD
171   EXPECT_EQ(DINode::FlagArtificial, CT.getFlags());
172   EXPECT_EQ(&UUID, CT.getRawIdentifier());
173 }
174 
175 } // end namespace
176