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"
13using namespace llvm;
14
15namespace {
16
17TEST(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
26TEST(DebugTypeODRUniquingTest, getODRType) {
27 LLVMContext Context;
28 MDString &UUID = *MDString::get(Context, Str: "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, Identifier&: UUID, Tag: dwarf::DW_TAG_class_type, Name: nullptr, File: nullptr, Line: 0, Scope: nullptr,
43 BaseType: nullptr, SizeInBits: 0, AlignInBits: 0, OffsetInBits: 0, Flags: DINode::FlagZero, Elements: nullptr, RuntimeLang: 0, VTableHolder: nullptr, TemplateParams: nullptr, Discriminator: nullptr,
44 DataLocation: nullptr, Associated: nullptr, Allocated: nullptr, Rank: nullptr, Annotations: 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
71TEST(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, Str: "Type");
77 auto &CT = *DICompositeType::buildODRType(
78 Context, Identifier&: UUID, Tag: dwarf::DW_TAG_class_type, Name: nullptr, File: nullptr, Line: 0, Scope: nullptr,
79 BaseType: nullptr, SizeInBits: 0, AlignInBits: 0, OffsetInBits: 0, Flags: DINode::FlagFwdDecl, Elements: nullptr, RuntimeLang: 0, VTableHolder: nullptr, TemplateParams: nullptr,
80 Discriminator: nullptr, DataLocation: nullptr, Associated: nullptr, Allocated: nullptr, Rank: nullptr, Annotations: 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
119TEST(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, Str: "UUID");
125 auto &CT = *DICompositeType::buildODRType(
126 Context, Identifier&: UUID, Tag: 0, Name: nullptr, File: nullptr, Line: 0, Scope: nullptr, BaseType: nullptr, SizeInBits: 0, AlignInBits: 0, OffsetInBits: 0,
127 Flags: DINode::FlagFwdDecl, Elements: nullptr, RuntimeLang: 0, VTableHolder: nullptr, TemplateParams: nullptr, Discriminator: nullptr, DataLocation: nullptr,
128 Associated: nullptr, Allocated: nullptr, Rank: nullptr, Annotations: 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

source code of llvm/unittests/IR/DebugTypeODRUniquingTest.cpp