1 //===- DebugTypeODRUniquingTest.cpp - Debug type ODR uniquing tests -------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
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 
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   EXPECT_EQ(UUID.getString(), CT.getIdentifier());
44 
45   // Check that we get it back, even if we change a field.
46   EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID));
47   EXPECT_EQ(&CT, DICompositeType::getODRType(
48                      Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr,
49                      0, nullptr, nullptr, 0, 0, 0, DINode::FlagZero, nullptr, 0,
50                      nullptr, nullptr, nullptr));
51   EXPECT_EQ(&CT,
52             DICompositeType::getODRType(
53                 Context, UUID, dwarf::DW_TAG_class_type,
54                 MDString::get(Context, "name"), nullptr, 0, nullptr, nullptr, 0,
55                 0, 0, DINode::FlagZero, nullptr, 0, nullptr, nullptr, nullptr));
56 
57   // Check that it's discarded with the type map.
58   Context.disableDebugTypeODRUniquing();
59   EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID));
60 
61   // And it shouldn't magically reappear...
62   Context.enableDebugTypeODRUniquing();
63   EXPECT_FALSE(DICompositeType::getODRTypeIfExists(Context, UUID));
64 }
65 
TEST(DebugTypeODRUniquingTest,buildODRType)66 TEST(DebugTypeODRUniquingTest, buildODRType) {
67   LLVMContext Context;
68   Context.enableDebugTypeODRUniquing();
69 
70   // Build an ODR type that's a forward decl.
71   MDString &UUID = *MDString::get(Context, "Type");
72   auto &CT = *DICompositeType::buildODRType(
73       Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr,
74       nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr);
75   EXPECT_EQ(&CT, DICompositeType::getODRTypeIfExists(Context, UUID));
76   EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag());
77 
78   // Update with another forward decl.  This should be a no-op.
79   EXPECT_EQ(&CT, DICompositeType::buildODRType(
80       Context, UUID, dwarf::DW_TAG_structure_type, nullptr, nullptr, 0, nullptr,
81       nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr));
82   EXPECT_EQ(dwarf::DW_TAG_class_type, CT.getTag());
83 
84   // Update with a definition.  This time we should see a change.
85   EXPECT_EQ(&CT, DICompositeType::buildODRType(
86                      Context, UUID, dwarf::DW_TAG_structure_type, nullptr,
87                      nullptr, 0, nullptr, nullptr, 0, 0, 0, DINode::FlagZero,
88                      nullptr, 0, nullptr, nullptr, nullptr));
89   EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag());
90 
91   // Further updates should be ignored.
92   EXPECT_EQ(&CT, DICompositeType::buildODRType(
93       Context, UUID, dwarf::DW_TAG_class_type, nullptr, nullptr, 0, nullptr,
94       nullptr, 0, 0, 0, DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr));
95   EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag());
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));
100   EXPECT_EQ(dwarf::DW_TAG_structure_type, CT.getTag());
101 }
102 
TEST(DebugTypeODRUniquingTest,buildODRTypeFields)103 TEST(DebugTypeODRUniquingTest, buildODRTypeFields) {
104   LLVMContext Context;
105   Context.enableDebugTypeODRUniquing();
106 
107   // Build an ODR type that's a forward decl with no other fields set.
108   MDString &UUID = *MDString::get(Context, "UUID");
109   auto &CT = *DICompositeType::buildODRType(
110       Context, UUID, 0, nullptr, nullptr, 0, nullptr, nullptr, 0, 0, 0,
111       DINode::FlagFwdDecl, nullptr, 0, nullptr, nullptr, nullptr);
112 
113 // Create macros for running through all the fields except Identifier and Flags.
114 #define FOR_EACH_MDFIELD()                                                     \
115   DO_FOR_FIELD(Name)                                                           \
116   DO_FOR_FIELD(File)                                                           \
117   DO_FOR_FIELD(Scope)                                                          \
118   DO_FOR_FIELD(BaseType)                                                       \
119   DO_FOR_FIELD(Elements)                                                       \
120   DO_FOR_FIELD(VTableHolder)                                                   \
121   DO_FOR_FIELD(TemplateParams)
122 #define FOR_EACH_INLINEFIELD()                                                 \
123   DO_FOR_FIELD(Tag)                                                            \
124   DO_FOR_FIELD(Line)                                                           \
125   DO_FOR_FIELD(SizeInBits)                                                     \
126   DO_FOR_FIELD(AlignInBits)                                                    \
127   DO_FOR_FIELD(OffsetInBits)                                                   \
128   DO_FOR_FIELD(RuntimeLang)
129 
130 // Create all the fields.
131 #define DO_FOR_FIELD(X) auto *X = MDString::get(Context, #X);
132   FOR_EACH_MDFIELD();
133 #undef DO_FOR_FIELD
134   unsigned NonZeroInit = 0;
135 #define DO_FOR_FIELD(X) auto X = ++NonZeroInit;
136   FOR_EACH_INLINEFIELD();
137 #undef DO_FOR_FIELD
138 
139   // Replace all the fields with new values that are distinct from each other.
140   EXPECT_EQ(&CT,
141             DICompositeType::buildODRType(
142                 Context, UUID, Tag, Name, File, Line, Scope, BaseType,
143                 SizeInBits, AlignInBits, OffsetInBits, DINode::FlagArtificial,
144                 Elements, RuntimeLang, VTableHolder, TemplateParams, nullptr));
145 
146   // Confirm that all the right fields got updated.
147 #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.getRaw##X());
148   FOR_EACH_MDFIELD();
149 #undef DO_FOR_FIELD
150 #undef FOR_EACH_MDFIELD
151 #define DO_FOR_FIELD(X) EXPECT_EQ(X, CT.get##X());
152   FOR_EACH_INLINEFIELD();
153 #undef DO_FOR_FIELD
154 #undef FOR_EACH_INLINEFIELD
155   EXPECT_EQ(DINode::FlagArtificial, CT.getFlags());
156   EXPECT_EQ(&UUID, CT.getRawIdentifier());
157 }
158 
159 } // end namespace
160