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