1 | //===- unittests/IR/MetadataTest.cpp - Metadata unit 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/Metadata.h" |
10 | #include "llvm/ADT/DenseMap.h" |
11 | #include "llvm/ADT/STLExtras.h" |
12 | #include "llvm/IR/Constants.h" |
13 | #include "llvm/IR/DIBuilder.h" |
14 | #include "llvm/IR/DebugInfo.h" |
15 | #include "llvm/IR/DebugInfoMetadata.h" |
16 | #include "llvm/IR/Function.h" |
17 | #include "llvm/IR/Instructions.h" |
18 | #include "llvm/IR/LLVMContext.h" |
19 | #include "llvm/IR/Module.h" |
20 | #include "llvm/IR/ModuleSlotTracker.h" |
21 | #include "llvm/IR/Type.h" |
22 | #include "llvm/IR/Verifier.h" |
23 | #include "llvm/Support/raw_ostream.h" |
24 | #include "gtest/gtest.h" |
25 | #include <optional> |
26 | using namespace llvm; |
27 | |
28 | namespace { |
29 | |
30 | TEST(ContextAndReplaceableUsesTest, FromContext) { |
31 | LLVMContext Context; |
32 | ContextAndReplaceableUses CRU(Context); |
33 | EXPECT_EQ(&Context, &CRU.getContext()); |
34 | EXPECT_FALSE(CRU.hasReplaceableUses()); |
35 | EXPECT_FALSE(CRU.getReplaceableUses()); |
36 | } |
37 | |
38 | TEST(ContextAndReplaceableUsesTest, FromReplaceableUses) { |
39 | LLVMContext Context; |
40 | ContextAndReplaceableUses CRU(std::make_unique<ReplaceableMetadataImpl>(args&: Context)); |
41 | EXPECT_EQ(&Context, &CRU.getContext()); |
42 | EXPECT_TRUE(CRU.hasReplaceableUses()); |
43 | EXPECT_TRUE(CRU.getReplaceableUses()); |
44 | } |
45 | |
46 | TEST(ContextAndReplaceableUsesTest, makeReplaceable) { |
47 | LLVMContext Context; |
48 | ContextAndReplaceableUses CRU(Context); |
49 | CRU.makeReplaceable(ReplaceableUses: std::make_unique<ReplaceableMetadataImpl>(args&: Context)); |
50 | EXPECT_EQ(&Context, &CRU.getContext()); |
51 | EXPECT_TRUE(CRU.hasReplaceableUses()); |
52 | EXPECT_TRUE(CRU.getReplaceableUses()); |
53 | } |
54 | |
55 | TEST(ContextAndReplaceableUsesTest, takeReplaceableUses) { |
56 | LLVMContext Context; |
57 | auto ReplaceableUses = std::make_unique<ReplaceableMetadataImpl>(args&: Context); |
58 | auto *Ptr = ReplaceableUses.get(); |
59 | ContextAndReplaceableUses CRU(std::move(ReplaceableUses)); |
60 | ReplaceableUses = CRU.takeReplaceableUses(); |
61 | EXPECT_EQ(&Context, &CRU.getContext()); |
62 | EXPECT_FALSE(CRU.hasReplaceableUses()); |
63 | EXPECT_FALSE(CRU.getReplaceableUses()); |
64 | EXPECT_EQ(Ptr, ReplaceableUses.get()); |
65 | } |
66 | |
67 | class MetadataTest : public testing::Test { |
68 | public: |
69 | MetadataTest() : M("test" , Context), Counter(0) {} |
70 | |
71 | protected: |
72 | LLVMContext Context; |
73 | Module M; |
74 | int Counter; |
75 | |
76 | MDNode *getNode() { return MDNode::get(Context, MDs: std::nullopt); } |
77 | MDNode *getNode(Metadata *MD) { return MDNode::get(Context, MDs: MD); } |
78 | MDNode *getNode(Metadata *MD1, Metadata *MD2) { |
79 | Metadata *MDs[] = {MD1, MD2}; |
80 | return MDNode::get(Context, MDs); |
81 | } |
82 | |
83 | MDTuple *getTuple() { return MDTuple::getDistinct(Context, MDs: std::nullopt); } |
84 | DISubroutineType *getSubroutineType() { |
85 | return DISubroutineType::getDistinct(Context, Flags: DINode::FlagZero, CC: 0, |
86 | TypeArray: getNode(MD: nullptr)); |
87 | } |
88 | DISubprogram *getSubprogram() { |
89 | return DISubprogram::getDistinct( |
90 | Context, Scope: nullptr, Name: "" , LinkageName: "" , File: nullptr, Line: 0, Type: nullptr, ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, |
91 | Flags: DINode::FlagZero, SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
92 | } |
93 | DIFile *getFile() { |
94 | return DIFile::getDistinct(Context, Filename: "file.c" , Directory: "/path/to/dir" ); |
95 | } |
96 | DICompileUnit *getUnit() { |
97 | return DICompileUnit::getDistinct( |
98 | Context, SourceLanguage: 1, File: getFile(), Producer: "clang" , IsOptimized: false, Flags: "-g" , RuntimeVersion: 2, SplitDebugFilename: "" , |
99 | EmissionKind: DICompileUnit::FullDebug, EnumTypes: getTuple(), RetainedTypes: getTuple(), GlobalVariables: getTuple(), |
100 | ImportedEntities: getTuple(), Macros: getTuple(), DWOId: 0, SplitDebugInlining: true, DebugInfoForProfiling: false, |
101 | NameTableKind: DICompileUnit::DebugNameTableKind::Default, RangesBaseAddress: false, SysRoot: "/" , SDK: "" ); |
102 | } |
103 | DIType *getBasicType(StringRef Name) { |
104 | return DIBasicType::get(Context, Tag: dwarf::DW_TAG_unspecified_type, Name); |
105 | } |
106 | DIType *getDerivedType() { |
107 | return DIDerivedType::getDistinct( |
108 | Context, Tag: dwarf::DW_TAG_pointer_type, Name: "" , File: nullptr, Line: 0, Scope: nullptr, |
109 | BaseType: getBasicType(Name: "basictype" ), SizeInBits: 1, AlignInBits: 2, OffsetInBits: 0, DWARFAddressSpace: std::nullopt, PtrAuthData: {}, Flags: DINode::FlagZero); |
110 | } |
111 | Constant *getConstant() { |
112 | return ConstantInt::get(Ty: Type::getInt32Ty(C&: Context), V: Counter++); |
113 | } |
114 | ConstantAsMetadata *getConstantAsMetadata() { |
115 | return ConstantAsMetadata::get(C: getConstant()); |
116 | } |
117 | DIType *getCompositeType() { |
118 | return DICompositeType::getDistinct( |
119 | Context, Tag: dwarf::DW_TAG_structure_type, Name: "" , File: nullptr, Line: 0, Scope: nullptr, BaseType: nullptr, |
120 | SizeInBits: 32, AlignInBits: 32, OffsetInBits: 0, Flags: DINode::FlagZero, Elements: nullptr, RuntimeLang: 0, VTableHolder: nullptr, TemplateParams: nullptr, Identifier: "" ); |
121 | } |
122 | Function *getFunction(StringRef Name) { |
123 | return Function::Create( |
124 | Ty: FunctionType::get(Result: Type::getVoidTy(C&: Context), Params: std::nullopt, isVarArg: false), |
125 | Linkage: Function::ExternalLinkage, N: Name, M); |
126 | } |
127 | }; |
128 | typedef MetadataTest MDStringTest; |
129 | |
130 | // Test that construction of MDString with different value produces different |
131 | // MDString objects, even with the same string pointer and nulls in the string. |
132 | TEST_F(MDStringTest, CreateDifferent) { |
133 | char x[3] = { 'f', 0, 'A' }; |
134 | MDString *s1 = MDString::get(Context, Str: StringRef(&x[0], 3)); |
135 | x[2] = 'B'; |
136 | MDString *s2 = MDString::get(Context, Str: StringRef(&x[0], 3)); |
137 | EXPECT_NE(s1, s2); |
138 | } |
139 | |
140 | // Test that creation of MDStrings with the same string contents produces the |
141 | // same MDString object, even with different pointers. |
142 | TEST_F(MDStringTest, CreateSame) { |
143 | char x[4] = { 'a', 'b', 'c', 'X' }; |
144 | char y[4] = { 'a', 'b', 'c', 'Y' }; |
145 | |
146 | MDString *s1 = MDString::get(Context, Str: StringRef(&x[0], 3)); |
147 | MDString *s2 = MDString::get(Context, Str: StringRef(&y[0], 3)); |
148 | EXPECT_EQ(s1, s2); |
149 | } |
150 | |
151 | // Test that MDString prints out the string we fed it. |
152 | TEST_F(MDStringTest, PrintingSimple) { |
153 | char str[14] = "testing 1 2 3" ; |
154 | MDString *s = MDString::get(Context, Str: StringRef(&str[0], 13)); |
155 | strncpy(dest: str, src: "aaaaaaaaaaaaa" , n: 14); |
156 | |
157 | std::string Str; |
158 | raw_string_ostream oss(Str); |
159 | s->print(OS&: oss); |
160 | EXPECT_STREQ("!\"testing 1 2 3\"" , oss.str().c_str()); |
161 | } |
162 | |
163 | // Test printing of MDString with non-printable characters. |
164 | TEST_F(MDStringTest, PrintingComplex) { |
165 | char str[5] = {0, '\n', '"', '\\', (char)-1}; |
166 | MDString *s = MDString::get(Context, Str: StringRef(str+0, 5)); |
167 | std::string Str; |
168 | raw_string_ostream oss(Str); |
169 | s->print(OS&: oss); |
170 | EXPECT_STREQ("!\"\\00\\0A\\22\\\\\\FF\"" , oss.str().c_str()); |
171 | } |
172 | |
173 | typedef MetadataTest MDNodeTest; |
174 | |
175 | // Test the two constructors, and containing other Constants. |
176 | TEST_F(MDNodeTest, Simple) { |
177 | char x[3] = { 'a', 'b', 'c' }; |
178 | char y[3] = { '1', '2', '3' }; |
179 | |
180 | MDString *s1 = MDString::get(Context, Str: StringRef(&x[0], 3)); |
181 | MDString *s2 = MDString::get(Context, Str: StringRef(&y[0], 3)); |
182 | ConstantAsMetadata *CI = |
183 | ConstantAsMetadata::get(C: ConstantInt::get(Context, V: APInt(8, 0))); |
184 | |
185 | std::vector<Metadata *> V; |
186 | V.push_back(x: s1); |
187 | V.push_back(x: CI); |
188 | V.push_back(x: s2); |
189 | |
190 | MDNode *n1 = MDNode::get(Context, MDs: V); |
191 | Metadata *const c1 = n1; |
192 | MDNode *n2 = MDNode::get(Context, MDs: c1); |
193 | Metadata *const c2 = n2; |
194 | MDNode *n3 = MDNode::get(Context, MDs: V); |
195 | MDNode *n4 = MDNode::getIfExists(Context, MDs: V); |
196 | MDNode *n5 = MDNode::getIfExists(Context, MDs: c1); |
197 | MDNode *n6 = MDNode::getIfExists(Context, MDs: c2); |
198 | EXPECT_NE(n1, n2); |
199 | EXPECT_EQ(n1, n3); |
200 | EXPECT_EQ(n4, n1); |
201 | EXPECT_EQ(n5, n2); |
202 | EXPECT_EQ(n6, (Metadata *)nullptr); |
203 | |
204 | EXPECT_EQ(3u, n1->getNumOperands()); |
205 | EXPECT_EQ(s1, n1->getOperand(0)); |
206 | EXPECT_EQ(CI, n1->getOperand(1)); |
207 | EXPECT_EQ(s2, n1->getOperand(2)); |
208 | |
209 | EXPECT_EQ(1u, n2->getNumOperands()); |
210 | EXPECT_EQ(n1, n2->getOperand(0)); |
211 | } |
212 | |
213 | TEST_F(MDNodeTest, Delete) { |
214 | Constant *C = ConstantInt::get(Ty: Type::getInt32Ty(C&: Context), V: 1); |
215 | Instruction *I = new BitCastInst(C, Type::getInt32Ty(C&: Context)); |
216 | |
217 | Metadata *const V = LocalAsMetadata::get(Local: I); |
218 | MDNode *n = MDNode::get(Context, MDs: V); |
219 | TrackingMDRef wvh(n); |
220 | |
221 | EXPECT_EQ(n, wvh); |
222 | |
223 | I->deleteValue(); |
224 | } |
225 | |
226 | TEST_F(MDNodeTest, SelfReference) { |
227 | // !0 = !{!0} |
228 | // !1 = !{!0} |
229 | { |
230 | auto Temp = MDNode::getTemporary(Context, MDs: std::nullopt); |
231 | Metadata *Args[] = {Temp.get()}; |
232 | MDNode *Self = MDNode::get(Context, MDs: Args); |
233 | Self->replaceOperandWith(I: 0, New: Self); |
234 | ASSERT_EQ(Self, Self->getOperand(0)); |
235 | |
236 | // Self-references should be distinct, so MDNode::get() should grab a |
237 | // uniqued node that references Self, not Self. |
238 | Args[0] = Self; |
239 | MDNode *Ref1 = MDNode::get(Context, MDs: Args); |
240 | MDNode *Ref2 = MDNode::get(Context, MDs: Args); |
241 | EXPECT_NE(Self, Ref1); |
242 | EXPECT_EQ(Ref1, Ref2); |
243 | } |
244 | |
245 | // !0 = !{!0, !{}} |
246 | // !1 = !{!0, !{}} |
247 | { |
248 | auto Temp = MDNode::getTemporary(Context, MDs: std::nullopt); |
249 | Metadata *Args[] = {Temp.get(), MDNode::get(Context, MDs: std::nullopt)}; |
250 | MDNode *Self = MDNode::get(Context, MDs: Args); |
251 | Self->replaceOperandWith(I: 0, New: Self); |
252 | ASSERT_EQ(Self, Self->getOperand(0)); |
253 | |
254 | // Self-references should be distinct, so MDNode::get() should grab a |
255 | // uniqued node that references Self, not Self itself. |
256 | Args[0] = Self; |
257 | MDNode *Ref1 = MDNode::get(Context, MDs: Args); |
258 | MDNode *Ref2 = MDNode::get(Context, MDs: Args); |
259 | EXPECT_NE(Self, Ref1); |
260 | EXPECT_EQ(Ref1, Ref2); |
261 | } |
262 | } |
263 | |
264 | TEST_F(MDNodeTest, Print) { |
265 | Constant *C = ConstantInt::get(Ty: Type::getInt32Ty(C&: Context), V: 7); |
266 | MDString *S = MDString::get(Context, Str: "foo" ); |
267 | MDNode *N0 = getNode(); |
268 | MDNode *N1 = getNode(MD: N0); |
269 | MDNode *N2 = getNode(MD1: N0, MD2: N1); |
270 | |
271 | Metadata *Args[] = {ConstantAsMetadata::get(C), S, nullptr, N0, N1, N2}; |
272 | MDNode *N = MDNode::get(Context, MDs: Args); |
273 | |
274 | std::string Expected; |
275 | { |
276 | raw_string_ostream OS(Expected); |
277 | OS << "<" << (void *)N << "> = !{" ; |
278 | C->printAsOperand(O&: OS); |
279 | OS << ", " ; |
280 | S->printAsOperand(OS); |
281 | OS << ", null" ; |
282 | MDNode *Nodes[] = {N0, N1, N2}; |
283 | for (auto *Node : Nodes) |
284 | OS << ", <" << (void *)Node << ">" ; |
285 | OS << "}" ; |
286 | } |
287 | |
288 | std::string Actual; |
289 | { |
290 | raw_string_ostream OS(Actual); |
291 | N->print(OS); |
292 | } |
293 | |
294 | EXPECT_EQ(Expected, Actual); |
295 | } |
296 | |
297 | #define EXPECT_PRINTER_EQ(EXPECTED, PRINT) \ |
298 | do { \ |
299 | std::string Actual_; \ |
300 | raw_string_ostream OS(Actual_); \ |
301 | PRINT; \ |
302 | OS.flush(); \ |
303 | std::string Expected_(EXPECTED); \ |
304 | EXPECT_EQ(Expected_, Actual_); \ |
305 | } while (false) |
306 | |
307 | TEST_F(MDNodeTest, PrintTemporary) { |
308 | MDNode *Arg = getNode(); |
309 | TempMDNode Temp = MDNode::getTemporary(Context, MDs: Arg); |
310 | MDNode *N = getNode(MD: Temp.get()); |
311 | Module M("test" , Context); |
312 | NamedMDNode *NMD = M.getOrInsertNamedMetadata(Name: "named" ); |
313 | NMD->addOperand(M: N); |
314 | |
315 | EXPECT_PRINTER_EQ("!0 = !{!1}" , N->print(OS, &M)); |
316 | EXPECT_PRINTER_EQ("!1 = <temporary!> !{!2}" , Temp->print(OS, &M)); |
317 | EXPECT_PRINTER_EQ("!2 = !{}" , Arg->print(OS, &M)); |
318 | |
319 | // Cleanup. |
320 | Temp->replaceAllUsesWith(MD: Arg); |
321 | } |
322 | |
323 | TEST_F(MDNodeTest, PrintFromModule) { |
324 | Constant *C = ConstantInt::get(Ty: Type::getInt32Ty(C&: Context), V: 7); |
325 | MDString *S = MDString::get(Context, Str: "foo" ); |
326 | MDNode *N0 = getNode(); |
327 | MDNode *N1 = getNode(MD: N0); |
328 | MDNode *N2 = getNode(MD1: N0, MD2: N1); |
329 | |
330 | Metadata *Args[] = {ConstantAsMetadata::get(C), S, nullptr, N0, N1, N2}; |
331 | MDNode *N = MDNode::get(Context, MDs: Args); |
332 | Module M("test" , Context); |
333 | NamedMDNode *NMD = M.getOrInsertNamedMetadata(Name: "named" ); |
334 | NMD->addOperand(M: N); |
335 | |
336 | std::string Expected; |
337 | { |
338 | raw_string_ostream OS(Expected); |
339 | OS << "!0 = !{" ; |
340 | C->printAsOperand(O&: OS); |
341 | OS << ", " ; |
342 | S->printAsOperand(OS); |
343 | OS << ", null, !1, !2, !3}" ; |
344 | } |
345 | |
346 | EXPECT_PRINTER_EQ(Expected, N->print(OS, &M)); |
347 | } |
348 | |
349 | TEST_F(MDNodeTest, PrintFromFunction) { |
350 | Module M("test" , Context); |
351 | auto *FTy = FunctionType::get(Result: Type::getVoidTy(C&: Context), isVarArg: false); |
352 | auto *F0 = Function::Create(Ty: FTy, Linkage: GlobalValue::ExternalLinkage, N: "F0" , M: &M); |
353 | auto *F1 = Function::Create(Ty: FTy, Linkage: GlobalValue::ExternalLinkage, N: "F1" , M: &M); |
354 | auto *BB0 = BasicBlock::Create(Context, Name: "entry" , Parent: F0); |
355 | auto *BB1 = BasicBlock::Create(Context, Name: "entry" , Parent: F1); |
356 | auto *R0 = ReturnInst::Create(C&: Context, InsertAtEnd: BB0); |
357 | auto *R1 = ReturnInst::Create(C&: Context, InsertAtEnd: BB1); |
358 | auto *N0 = MDNode::getDistinct(Context, MDs: std::nullopt); |
359 | auto *N1 = MDNode::getDistinct(Context, MDs: std::nullopt); |
360 | R0->setMetadata(Kind: "md" , Node: N0); |
361 | R1->setMetadata(Kind: "md" , Node: N1); |
362 | |
363 | EXPECT_PRINTER_EQ("!0 = distinct !{}" , N0->print(OS, &M)); |
364 | EXPECT_PRINTER_EQ("!1 = distinct !{}" , N1->print(OS, &M)); |
365 | |
366 | ModuleSlotTracker MST(&M); |
367 | EXPECT_PRINTER_EQ("!0 = distinct !{}" , N0->print(OS, MST)); |
368 | EXPECT_PRINTER_EQ("!1 = distinct !{}" , N1->print(OS, MST)); |
369 | } |
370 | |
371 | TEST_F(MDNodeTest, PrintFromMetadataAsValue) { |
372 | Module M("test" , Context); |
373 | |
374 | auto *Intrinsic = |
375 | Function::Create(Ty: FunctionType::get(Result: Type::getVoidTy(C&: Context), |
376 | Params: Type::getMetadataTy(C&: Context), isVarArg: false), |
377 | Linkage: GlobalValue::ExternalLinkage, N: "llvm.intrinsic" , M: &M); |
378 | |
379 | auto *FTy = FunctionType::get(Result: Type::getVoidTy(C&: Context), isVarArg: false); |
380 | auto *F0 = Function::Create(Ty: FTy, Linkage: GlobalValue::ExternalLinkage, N: "F0" , M: &M); |
381 | auto *F1 = Function::Create(Ty: FTy, Linkage: GlobalValue::ExternalLinkage, N: "F1" , M: &M); |
382 | auto *BB0 = BasicBlock::Create(Context, Name: "entry" , Parent: F0); |
383 | auto *BB1 = BasicBlock::Create(Context, Name: "entry" , Parent: F1); |
384 | auto *N0 = MDNode::getDistinct(Context, MDs: std::nullopt); |
385 | auto *N1 = MDNode::getDistinct(Context, MDs: std::nullopt); |
386 | auto *MAV0 = MetadataAsValue::get(Context, MD: N0); |
387 | auto *MAV1 = MetadataAsValue::get(Context, MD: N1); |
388 | CallInst::Create(Func: Intrinsic, Args: MAV0, NameStr: "" , InsertAtEnd: BB0); |
389 | CallInst::Create(Func: Intrinsic, Args: MAV1, NameStr: "" , InsertAtEnd: BB1); |
390 | |
391 | EXPECT_PRINTER_EQ("!0 = distinct !{}" , MAV0->print(OS)); |
392 | EXPECT_PRINTER_EQ("!1 = distinct !{}" , MAV1->print(OS)); |
393 | EXPECT_PRINTER_EQ("!0" , MAV0->printAsOperand(OS, false)); |
394 | EXPECT_PRINTER_EQ("!1" , MAV1->printAsOperand(OS, false)); |
395 | EXPECT_PRINTER_EQ("metadata !0" , MAV0->printAsOperand(OS, true)); |
396 | EXPECT_PRINTER_EQ("metadata !1" , MAV1->printAsOperand(OS, true)); |
397 | |
398 | ModuleSlotTracker MST(&M); |
399 | EXPECT_PRINTER_EQ("!0 = distinct !{}" , MAV0->print(OS, MST)); |
400 | EXPECT_PRINTER_EQ("!1 = distinct !{}" , MAV1->print(OS, MST)); |
401 | EXPECT_PRINTER_EQ("!0" , MAV0->printAsOperand(OS, false, MST)); |
402 | EXPECT_PRINTER_EQ("!1" , MAV1->printAsOperand(OS, false, MST)); |
403 | EXPECT_PRINTER_EQ("metadata !0" , MAV0->printAsOperand(OS, true, MST)); |
404 | EXPECT_PRINTER_EQ("metadata !1" , MAV1->printAsOperand(OS, true, MST)); |
405 | } |
406 | |
407 | TEST_F(MDNodeTest, PrintWithDroppedCallOperand) { |
408 | Module M("test" , Context); |
409 | |
410 | auto *FTy = FunctionType::get(Result: Type::getVoidTy(C&: Context), isVarArg: false); |
411 | auto *F0 = Function::Create(Ty: FTy, Linkage: GlobalValue::ExternalLinkage, N: "F0" , M: &M); |
412 | auto *F1 = Function::Create(Ty: FTy, Linkage: GlobalValue::ExternalLinkage, N: "F1" , M: &M); |
413 | auto *BB0 = BasicBlock::Create(Context, Name: "entry" , Parent: F0); |
414 | |
415 | CallInst *CI0 = CallInst::Create(Func: F1, NameStr: "" , InsertAtEnd: BB0); |
416 | CI0->dropAllReferences(); |
417 | |
418 | auto *R0 = ReturnInst::Create(C&: Context, InsertAtEnd: BB0); |
419 | auto *N0 = MDNode::getDistinct(Context, MDs: std::nullopt); |
420 | R0->setMetadata(Kind: "md" , Node: N0); |
421 | |
422 | // Printing the metadata node would previously result in a failed assertion |
423 | // due to the call instruction's dropped function operand. |
424 | ModuleSlotTracker MST(&M); |
425 | EXPECT_PRINTER_EQ("!0 = distinct !{}" , N0->print(OS, MST)); |
426 | } |
427 | |
428 | TEST_F(MDNodeTest, PrintTree) { |
429 | DILocalScope *Scope = getSubprogram(); |
430 | DIFile *File = getFile(); |
431 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(7); |
432 | { |
433 | DIType *Type = getDerivedType(); |
434 | auto *Var = DILocalVariable::get(Context, Scope, Name: "foo" , File, |
435 | /*LineNo=*/Line: 8, Type, /*ArgNo=*/Arg: 2, Flags, |
436 | /*Align=*/AlignInBits: 8, Annotations: nullptr); |
437 | std::string Expected; |
438 | { |
439 | raw_string_ostream SS(Expected); |
440 | Var->print(OS&: SS); |
441 | // indent level 1 |
442 | Scope->print(OS&: (SS << "\n" ).indent(NumSpaces: 2)); |
443 | File->print(OS&: (SS << "\n" ).indent(NumSpaces: 2)); |
444 | Type->print(OS&: (SS << "\n" ).indent(NumSpaces: 2)); |
445 | // indent level 2 |
446 | auto *BaseType = cast<DIDerivedType>(Val: Type)->getBaseType(); |
447 | BaseType->print(OS&: (SS << "\n" ).indent(NumSpaces: 4)); |
448 | } |
449 | |
450 | EXPECT_PRINTER_EQ(Expected, Var->printTree(OS)); |
451 | } |
452 | |
453 | { |
454 | // Test if printTree works correctly when there is |
455 | // a cycle in the MDNode and its dependencies. |
456 | // |
457 | // We're trying to create type like this: |
458 | // struct LinkedList { |
459 | // LinkedList *Head; |
460 | // }; |
461 | auto *StructTy = cast<DICompositeType>(Val: getCompositeType()); |
462 | DIType *PointerTy = DIDerivedType::getDistinct( |
463 | Context, Tag: dwarf::DW_TAG_pointer_type, Name: "" , File: nullptr, Line: 0, Scope: nullptr, BaseType: StructTy, |
464 | SizeInBits: 1, AlignInBits: 2, OffsetInBits: 0, DWARFAddressSpace: std::nullopt, PtrAuthData: {}, Flags: DINode::FlagZero); |
465 | StructTy->replaceElements(Elements: MDTuple::get(Context, MDs: PointerTy)); |
466 | |
467 | auto *Var = DILocalVariable::get(Context, Scope, Name: "foo" , File, |
468 | /*LineNo=*/Line: 8, Type: StructTy, /*ArgNo=*/Arg: 2, Flags, |
469 | /*Align=*/AlignInBits: 8, Annotations: nullptr); |
470 | std::string Expected; |
471 | { |
472 | raw_string_ostream SS(Expected); |
473 | Var->print(OS&: SS); |
474 | // indent level 1 |
475 | Scope->print(OS&: (SS << "\n" ).indent(NumSpaces: 2)); |
476 | File->print(OS&: (SS << "\n" ).indent(NumSpaces: 2)); |
477 | StructTy->print(OS&: (SS << "\n" ).indent(NumSpaces: 2)); |
478 | // indent level 2 |
479 | StructTy->getRawElements()->print(OS&: (SS << "\n" ).indent(NumSpaces: 4)); |
480 | // indent level 3 |
481 | auto Elements = StructTy->getElements(); |
482 | Elements[0]->print(OS&: (SS << "\n" ).indent(NumSpaces: 6)); |
483 | } |
484 | |
485 | EXPECT_PRINTER_EQ(Expected, Var->printTree(OS)); |
486 | } |
487 | } |
488 | #undef EXPECT_PRINTER_EQ |
489 | |
490 | TEST_F(MDNodeTest, NullOperand) { |
491 | // metadata !{} |
492 | MDNode *Empty = MDNode::get(Context, MDs: std::nullopt); |
493 | |
494 | // metadata !{metadata !{}} |
495 | Metadata *Ops[] = {Empty}; |
496 | MDNode *N = MDNode::get(Context, MDs: Ops); |
497 | ASSERT_EQ(Empty, N->getOperand(0)); |
498 | |
499 | // metadata !{metadata !{}} => metadata !{null} |
500 | N->replaceOperandWith(I: 0, New: nullptr); |
501 | ASSERT_EQ(nullptr, N->getOperand(0)); |
502 | |
503 | // metadata !{null} |
504 | Ops[0] = nullptr; |
505 | MDNode *NullOp = MDNode::get(Context, MDs: Ops); |
506 | ASSERT_EQ(nullptr, NullOp->getOperand(0)); |
507 | EXPECT_EQ(N, NullOp); |
508 | } |
509 | |
510 | TEST_F(MDNodeTest, DistinctOnUniquingCollision) { |
511 | // !{} |
512 | MDNode *Empty = MDNode::get(Context, MDs: std::nullopt); |
513 | ASSERT_TRUE(Empty->isResolved()); |
514 | EXPECT_FALSE(Empty->isDistinct()); |
515 | |
516 | // !{!{}} |
517 | Metadata *Wrapped1Ops[] = {Empty}; |
518 | MDNode *Wrapped1 = MDNode::get(Context, MDs: Wrapped1Ops); |
519 | ASSERT_EQ(Empty, Wrapped1->getOperand(0)); |
520 | ASSERT_TRUE(Wrapped1->isResolved()); |
521 | EXPECT_FALSE(Wrapped1->isDistinct()); |
522 | |
523 | // !{!{!{}}} |
524 | Metadata *Wrapped2Ops[] = {Wrapped1}; |
525 | MDNode *Wrapped2 = MDNode::get(Context, MDs: Wrapped2Ops); |
526 | ASSERT_EQ(Wrapped1, Wrapped2->getOperand(0)); |
527 | ASSERT_TRUE(Wrapped2->isResolved()); |
528 | EXPECT_FALSE(Wrapped2->isDistinct()); |
529 | |
530 | // !{!{!{}}} => !{!{}} |
531 | Wrapped2->replaceOperandWith(I: 0, New: Empty); |
532 | ASSERT_EQ(Empty, Wrapped2->getOperand(0)); |
533 | EXPECT_TRUE(Wrapped2->isDistinct()); |
534 | EXPECT_FALSE(Wrapped1->isDistinct()); |
535 | } |
536 | |
537 | TEST_F(MDNodeTest, UniquedOnDeletedOperand) { |
538 | // temp !{} |
539 | TempMDTuple T = MDTuple::getTemporary(Context, MDs: std::nullopt); |
540 | |
541 | // !{temp !{}} |
542 | Metadata *Ops[] = {T.get()}; |
543 | MDTuple *N = MDTuple::get(Context, MDs: Ops); |
544 | |
545 | // !{temp !{}} => !{null} |
546 | T.reset(); |
547 | ASSERT_TRUE(N->isUniqued()); |
548 | Metadata *NullOps[] = {nullptr}; |
549 | ASSERT_EQ(N, MDTuple::get(Context, NullOps)); |
550 | } |
551 | |
552 | TEST_F(MDNodeTest, DistinctOnDeletedValueOperand) { |
553 | // i1* @GV |
554 | Type *Ty = PointerType::getUnqual(C&: Context); |
555 | std::unique_ptr<GlobalVariable> GV( |
556 | new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); |
557 | ConstantAsMetadata *Op = ConstantAsMetadata::get(C: GV.get()); |
558 | |
559 | // !{i1* @GV} |
560 | Metadata *Ops[] = {Op}; |
561 | MDTuple *N = MDTuple::get(Context, MDs: Ops); |
562 | |
563 | // !{i1* @GV} => !{null} |
564 | GV.reset(); |
565 | ASSERT_TRUE(N->isDistinct()); |
566 | ASSERT_EQ(nullptr, N->getOperand(0)); |
567 | Metadata *NullOps[] = {nullptr}; |
568 | ASSERT_NE(N, MDTuple::get(Context, NullOps)); |
569 | } |
570 | |
571 | TEST_F(MDNodeTest, getDistinct) { |
572 | // !{} |
573 | MDNode *Empty = MDNode::get(Context, MDs: std::nullopt); |
574 | ASSERT_TRUE(Empty->isResolved()); |
575 | ASSERT_FALSE(Empty->isDistinct()); |
576 | ASSERT_EQ(Empty, MDNode::get(Context, std::nullopt)); |
577 | |
578 | // distinct !{} |
579 | MDNode *Distinct1 = MDNode::getDistinct(Context, MDs: std::nullopt); |
580 | MDNode *Distinct2 = MDNode::getDistinct(Context, MDs: std::nullopt); |
581 | EXPECT_TRUE(Distinct1->isResolved()); |
582 | EXPECT_TRUE(Distinct2->isDistinct()); |
583 | EXPECT_NE(Empty, Distinct1); |
584 | EXPECT_NE(Empty, Distinct2); |
585 | EXPECT_NE(Distinct1, Distinct2); |
586 | |
587 | // !{} |
588 | ASSERT_EQ(Empty, MDNode::get(Context, std::nullopt)); |
589 | } |
590 | |
591 | TEST_F(MDNodeTest, isUniqued) { |
592 | MDNode *U = MDTuple::get(Context, MDs: std::nullopt); |
593 | MDNode *D = MDTuple::getDistinct(Context, MDs: std::nullopt); |
594 | auto T = MDTuple::getTemporary(Context, MDs: std::nullopt); |
595 | EXPECT_TRUE(U->isUniqued()); |
596 | EXPECT_FALSE(D->isUniqued()); |
597 | EXPECT_FALSE(T->isUniqued()); |
598 | } |
599 | |
600 | TEST_F(MDNodeTest, isDistinct) { |
601 | MDNode *U = MDTuple::get(Context, MDs: std::nullopt); |
602 | MDNode *D = MDTuple::getDistinct(Context, MDs: std::nullopt); |
603 | auto T = MDTuple::getTemporary(Context, MDs: std::nullopt); |
604 | EXPECT_FALSE(U->isDistinct()); |
605 | EXPECT_TRUE(D->isDistinct()); |
606 | EXPECT_FALSE(T->isDistinct()); |
607 | } |
608 | |
609 | TEST_F(MDNodeTest, isTemporary) { |
610 | MDNode *U = MDTuple::get(Context, MDs: std::nullopt); |
611 | MDNode *D = MDTuple::getDistinct(Context, MDs: std::nullopt); |
612 | auto T = MDTuple::getTemporary(Context, MDs: std::nullopt); |
613 | EXPECT_FALSE(U->isTemporary()); |
614 | EXPECT_FALSE(D->isTemporary()); |
615 | EXPECT_TRUE(T->isTemporary()); |
616 | } |
617 | |
618 | TEST_F(MDNodeTest, getDistinctWithUnresolvedOperands) { |
619 | // temporary !{} |
620 | auto Temp = MDTuple::getTemporary(Context, MDs: std::nullopt); |
621 | ASSERT_FALSE(Temp->isResolved()); |
622 | |
623 | // distinct !{temporary !{}} |
624 | Metadata *Ops[] = {Temp.get()}; |
625 | MDNode *Distinct = MDNode::getDistinct(Context, MDs: Ops); |
626 | EXPECT_TRUE(Distinct->isResolved()); |
627 | EXPECT_EQ(Temp.get(), Distinct->getOperand(0)); |
628 | |
629 | // temporary !{} => !{} |
630 | MDNode *Empty = MDNode::get(Context, MDs: std::nullopt); |
631 | Temp->replaceAllUsesWith(MD: Empty); |
632 | EXPECT_EQ(Empty, Distinct->getOperand(0)); |
633 | } |
634 | |
635 | TEST_F(MDNodeTest, handleChangedOperandRecursion) { |
636 | // !0 = !{} |
637 | MDNode *N0 = MDNode::get(Context, MDs: std::nullopt); |
638 | |
639 | // !1 = !{!3, null} |
640 | auto Temp3 = MDTuple::getTemporary(Context, MDs: std::nullopt); |
641 | Metadata *Ops1[] = {Temp3.get(), nullptr}; |
642 | MDNode *N1 = MDNode::get(Context, MDs: Ops1); |
643 | |
644 | // !2 = !{!3, !0} |
645 | Metadata *Ops2[] = {Temp3.get(), N0}; |
646 | MDNode *N2 = MDNode::get(Context, MDs: Ops2); |
647 | |
648 | // !3 = !{!2} |
649 | Metadata *Ops3[] = {N2}; |
650 | MDNode *N3 = MDNode::get(Context, MDs: Ops3); |
651 | Temp3->replaceAllUsesWith(MD: N3); |
652 | |
653 | // !4 = !{!1} |
654 | Metadata *Ops4[] = {N1}; |
655 | MDNode *N4 = MDNode::get(Context, MDs: Ops4); |
656 | |
657 | // Confirm that the cycle prevented RAUW from getting dropped. |
658 | EXPECT_TRUE(N0->isResolved()); |
659 | EXPECT_FALSE(N1->isResolved()); |
660 | EXPECT_FALSE(N2->isResolved()); |
661 | EXPECT_FALSE(N3->isResolved()); |
662 | EXPECT_FALSE(N4->isResolved()); |
663 | |
664 | // Create a couple of distinct nodes to observe what's going on. |
665 | // |
666 | // !5 = distinct !{!2} |
667 | // !6 = distinct !{!3} |
668 | Metadata *Ops5[] = {N2}; |
669 | MDNode *N5 = MDNode::getDistinct(Context, MDs: Ops5); |
670 | Metadata *Ops6[] = {N3}; |
671 | MDNode *N6 = MDNode::getDistinct(Context, MDs: Ops6); |
672 | |
673 | // Mutate !2 to look like !1, causing a uniquing collision (and an RAUW). |
674 | // This will ripple up, with !3 colliding with !4, and RAUWing. Since !2 |
675 | // references !3, this can cause a re-entry of handleChangedOperand() when !3 |
676 | // is not ready for it. |
677 | // |
678 | // !2->replaceOperandWith(1, nullptr) |
679 | // !2: !{!3, !0} => !{!3, null} |
680 | // !2->replaceAllUsesWith(!1) |
681 | // !3: !{!2] => !{!1} |
682 | // !3->replaceAllUsesWith(!4) |
683 | N2->replaceOperandWith(I: 1, New: nullptr); |
684 | |
685 | // If all has gone well, N2 and N3 will have been RAUW'ed and deleted from |
686 | // under us. Just check that the other nodes are sane. |
687 | // |
688 | // !1 = !{!4, null} |
689 | // !4 = !{!1} |
690 | // !5 = distinct !{!1} |
691 | // !6 = distinct !{!4} |
692 | EXPECT_EQ(N4, N1->getOperand(0)); |
693 | EXPECT_EQ(N1, N4->getOperand(0)); |
694 | EXPECT_EQ(N1, N5->getOperand(0)); |
695 | EXPECT_EQ(N4, N6->getOperand(0)); |
696 | } |
697 | |
698 | TEST_F(MDNodeTest, replaceResolvedOperand) { |
699 | // Check code for replacing one resolved operand with another. If doing this |
700 | // directly (via replaceOperandWith()) becomes illegal, change the operand to |
701 | // a global value that gets RAUW'ed. |
702 | // |
703 | // Use a temporary node to keep N from being resolved. |
704 | auto Temp = MDTuple::getTemporary(Context, MDs: std::nullopt); |
705 | Metadata *Ops[] = {nullptr, Temp.get()}; |
706 | |
707 | MDNode *Empty = MDTuple::get(Context, MDs: ArrayRef<Metadata *>()); |
708 | MDNode *N = MDTuple::get(Context, MDs: Ops); |
709 | EXPECT_EQ(nullptr, N->getOperand(0)); |
710 | ASSERT_FALSE(N->isResolved()); |
711 | |
712 | // Check code for replacing resolved nodes. |
713 | N->replaceOperandWith(I: 0, New: Empty); |
714 | EXPECT_EQ(Empty, N->getOperand(0)); |
715 | |
716 | // Check code for adding another unresolved operand. |
717 | N->replaceOperandWith(I: 0, New: Temp.get()); |
718 | EXPECT_EQ(Temp.get(), N->getOperand(0)); |
719 | |
720 | // Remove the references to Temp; required for teardown. |
721 | Temp->replaceAllUsesWith(MD: nullptr); |
722 | } |
723 | |
724 | TEST_F(MDNodeTest, replaceWithUniqued) { |
725 | auto *Empty = MDTuple::get(Context, MDs: std::nullopt); |
726 | MDTuple *FirstUniqued; |
727 | { |
728 | Metadata *Ops[] = {Empty}; |
729 | auto Temp = MDTuple::getTemporary(Context, MDs: Ops); |
730 | EXPECT_TRUE(Temp->isTemporary()); |
731 | |
732 | // Don't expect a collision. |
733 | auto *Current = Temp.get(); |
734 | FirstUniqued = MDNode::replaceWithUniqued(N: std::move(Temp)); |
735 | EXPECT_TRUE(FirstUniqued->isUniqued()); |
736 | EXPECT_TRUE(FirstUniqued->isResolved()); |
737 | EXPECT_EQ(Current, FirstUniqued); |
738 | } |
739 | { |
740 | Metadata *Ops[] = {Empty}; |
741 | auto Temp = MDTuple::getTemporary(Context, MDs: Ops); |
742 | EXPECT_TRUE(Temp->isTemporary()); |
743 | |
744 | // Should collide with Uniqued above this time. |
745 | auto *Uniqued = MDNode::replaceWithUniqued(N: std::move(Temp)); |
746 | EXPECT_TRUE(Uniqued->isUniqued()); |
747 | EXPECT_TRUE(Uniqued->isResolved()); |
748 | EXPECT_EQ(FirstUniqued, Uniqued); |
749 | } |
750 | { |
751 | auto Unresolved = MDTuple::getTemporary(Context, MDs: std::nullopt); |
752 | Metadata *Ops[] = {Unresolved.get()}; |
753 | auto Temp = MDTuple::getTemporary(Context, MDs: Ops); |
754 | EXPECT_TRUE(Temp->isTemporary()); |
755 | |
756 | // Shouldn't be resolved. |
757 | auto *Uniqued = MDNode::replaceWithUniqued(N: std::move(Temp)); |
758 | EXPECT_TRUE(Uniqued->isUniqued()); |
759 | EXPECT_FALSE(Uniqued->isResolved()); |
760 | |
761 | // Should be a different node. |
762 | EXPECT_NE(FirstUniqued, Uniqued); |
763 | |
764 | // Should resolve when we update its node (note: be careful to avoid a |
765 | // collision with any other nodes above). |
766 | Uniqued->replaceOperandWith(I: 0, New: nullptr); |
767 | EXPECT_TRUE(Uniqued->isResolved()); |
768 | } |
769 | } |
770 | |
771 | TEST_F(MDNodeTest, replaceWithUniquedResolvingOperand) { |
772 | // temp !{} |
773 | MDTuple *Op = MDTuple::getTemporary(Context, MDs: std::nullopt).release(); |
774 | EXPECT_FALSE(Op->isResolved()); |
775 | |
776 | // temp !{temp !{}} |
777 | Metadata *Ops[] = {Op}; |
778 | MDTuple *N = MDTuple::getTemporary(Context, MDs: Ops).release(); |
779 | EXPECT_FALSE(N->isResolved()); |
780 | |
781 | // temp !{temp !{}} => !{temp !{}} |
782 | ASSERT_EQ(N, MDNode::replaceWithUniqued(TempMDTuple(N))); |
783 | EXPECT_FALSE(N->isResolved()); |
784 | |
785 | // !{temp !{}} => !{!{}} |
786 | ASSERT_EQ(Op, MDNode::replaceWithUniqued(TempMDTuple(Op))); |
787 | EXPECT_TRUE(Op->isResolved()); |
788 | EXPECT_TRUE(N->isResolved()); |
789 | } |
790 | |
791 | TEST_F(MDNodeTest, replaceWithUniquedDeletedOperand) { |
792 | // i1* @GV |
793 | Type *Ty = PointerType::getUnqual(C&: Context); |
794 | std::unique_ptr<GlobalVariable> GV( |
795 | new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); |
796 | ConstantAsMetadata *Op = ConstantAsMetadata::get(C: GV.get()); |
797 | |
798 | // temp !{i1* @GV} |
799 | Metadata *Ops[] = {Op}; |
800 | MDTuple *N = MDTuple::getTemporary(Context, MDs: Ops).release(); |
801 | |
802 | // temp !{i1* @GV} => !{i1* @GV} |
803 | ASSERT_EQ(N, MDNode::replaceWithUniqued(TempMDTuple(N))); |
804 | ASSERT_TRUE(N->isUniqued()); |
805 | |
806 | // !{i1* @GV} => !{null} |
807 | GV.reset(); |
808 | ASSERT_TRUE(N->isDistinct()); |
809 | ASSERT_EQ(nullptr, N->getOperand(0)); |
810 | Metadata *NullOps[] = {nullptr}; |
811 | ASSERT_NE(N, MDTuple::get(Context, NullOps)); |
812 | } |
813 | |
814 | TEST_F(MDNodeTest, replaceWithUniquedChangedOperand) { |
815 | // i1* @GV |
816 | Type *Ty = PointerType::getUnqual(C&: Context); |
817 | std::unique_ptr<GlobalVariable> GV( |
818 | new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); |
819 | ConstantAsMetadata *Op = ConstantAsMetadata::get(C: GV.get()); |
820 | |
821 | // temp !{i1* @GV} |
822 | Metadata *Ops[] = {Op}; |
823 | MDTuple *N = MDTuple::getTemporary(Context, MDs: Ops).release(); |
824 | |
825 | // temp !{i1* @GV} => !{i1* @GV} |
826 | ASSERT_EQ(N, MDNode::replaceWithUniqued(TempMDTuple(N))); |
827 | ASSERT_TRUE(N->isUniqued()); |
828 | |
829 | // !{i1* @GV} => !{i1* @GV2} |
830 | std::unique_ptr<GlobalVariable> GV2( |
831 | new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); |
832 | GV->replaceAllUsesWith(V: GV2.get()); |
833 | ASSERT_TRUE(N->isUniqued()); |
834 | Metadata *NullOps[] = {ConstantAsMetadata::get(C: GV2.get())}; |
835 | ASSERT_EQ(N, MDTuple::get(Context, NullOps)); |
836 | } |
837 | |
838 | TEST_F(MDNodeTest, replaceWithDistinct) { |
839 | { |
840 | auto *Empty = MDTuple::get(Context, MDs: std::nullopt); |
841 | Metadata *Ops[] = {Empty}; |
842 | auto Temp = MDTuple::getTemporary(Context, MDs: Ops); |
843 | EXPECT_TRUE(Temp->isTemporary()); |
844 | |
845 | // Don't expect a collision. |
846 | auto *Current = Temp.get(); |
847 | auto *Distinct = MDNode::replaceWithDistinct(N: std::move(Temp)); |
848 | EXPECT_TRUE(Distinct->isDistinct()); |
849 | EXPECT_TRUE(Distinct->isResolved()); |
850 | EXPECT_EQ(Current, Distinct); |
851 | } |
852 | { |
853 | auto Unresolved = MDTuple::getTemporary(Context, MDs: std::nullopt); |
854 | Metadata *Ops[] = {Unresolved.get()}; |
855 | auto Temp = MDTuple::getTemporary(Context, MDs: Ops); |
856 | EXPECT_TRUE(Temp->isTemporary()); |
857 | |
858 | // Don't expect a collision. |
859 | auto *Current = Temp.get(); |
860 | auto *Distinct = MDNode::replaceWithDistinct(N: std::move(Temp)); |
861 | EXPECT_TRUE(Distinct->isDistinct()); |
862 | EXPECT_TRUE(Distinct->isResolved()); |
863 | EXPECT_EQ(Current, Distinct); |
864 | |
865 | // Cleanup; required for teardown. |
866 | Unresolved->replaceAllUsesWith(MD: nullptr); |
867 | } |
868 | } |
869 | |
870 | TEST_F(MDNodeTest, replaceWithPermanent) { |
871 | Metadata *Ops[] = {nullptr}; |
872 | auto Temp = MDTuple::getTemporary(Context, MDs: Ops); |
873 | auto *T = Temp.get(); |
874 | |
875 | // U is a normal, uniqued node that references T. |
876 | auto *U = MDTuple::get(Context, MDs: T); |
877 | EXPECT_TRUE(U->isUniqued()); |
878 | |
879 | // Make Temp self-referencing. |
880 | Temp->replaceOperandWith(I: 0, New: T); |
881 | |
882 | // Try to uniquify Temp. This should, despite the name in the API, give a |
883 | // 'distinct' node, since self-references aren't allowed to be uniqued. |
884 | // |
885 | // Since it's distinct, N should have the same address as when it was a |
886 | // temporary (i.e., be equal to T not U). |
887 | auto *N = MDNode::replaceWithPermanent(N: std::move(Temp)); |
888 | EXPECT_EQ(N, T); |
889 | EXPECT_TRUE(N->isDistinct()); |
890 | |
891 | // U should be the canonical unique node with N as the argument. |
892 | EXPECT_EQ(U, MDTuple::get(Context, N)); |
893 | EXPECT_TRUE(U->isUniqued()); |
894 | |
895 | // This temporary should collide with U when replaced, but it should still be |
896 | // uniqued. |
897 | EXPECT_EQ(U, MDNode::replaceWithPermanent(MDTuple::getTemporary(Context, N))); |
898 | EXPECT_TRUE(U->isUniqued()); |
899 | |
900 | // This temporary should become a new uniqued node. |
901 | auto Temp2 = MDTuple::getTemporary(Context, MDs: U); |
902 | auto *V = Temp2.get(); |
903 | EXPECT_EQ(V, MDNode::replaceWithPermanent(std::move(Temp2))); |
904 | EXPECT_TRUE(V->isUniqued()); |
905 | EXPECT_EQ(U, V->getOperand(0)); |
906 | } |
907 | |
908 | TEST_F(MDNodeTest, deleteTemporaryWithTrackingRef) { |
909 | TrackingMDRef Ref; |
910 | EXPECT_EQ(nullptr, Ref.get()); |
911 | { |
912 | auto Temp = MDTuple::getTemporary(Context, MDs: std::nullopt); |
913 | Ref.reset(MD: Temp.get()); |
914 | EXPECT_EQ(Temp.get(), Ref.get()); |
915 | } |
916 | EXPECT_EQ(nullptr, Ref.get()); |
917 | } |
918 | |
919 | typedef MetadataTest DILocationTest; |
920 | |
921 | TEST_F(DILocationTest, Merge) { |
922 | DISubprogram *N = getSubprogram(); |
923 | DIScope *S = DILexicalBlock::get(Context, Scope: N, File: getFile(), Line: 3, Column: 4); |
924 | |
925 | { |
926 | // Identical. |
927 | auto *A = DILocation::get(Context, Line: 2, Column: 7, Scope: N); |
928 | auto *B = DILocation::get(Context, Line: 2, Column: 7, Scope: N); |
929 | auto *M = DILocation::getMergedLocation(LocA: A, LocB: B); |
930 | EXPECT_EQ(2u, M->getLine()); |
931 | EXPECT_EQ(7u, M->getColumn()); |
932 | EXPECT_EQ(N, M->getScope()); |
933 | } |
934 | |
935 | { |
936 | // Identical, different scopes. |
937 | auto *A = DILocation::get(Context, Line: 2, Column: 7, Scope: N); |
938 | auto *B = DILocation::get(Context, Line: 2, Column: 7, Scope: S); |
939 | auto *M = DILocation::getMergedLocation(LocA: A, LocB: B); |
940 | EXPECT_EQ(2u, M->getLine()); |
941 | EXPECT_EQ(7u, M->getColumn()); |
942 | EXPECT_EQ(N, M->getScope()); |
943 | } |
944 | |
945 | { |
946 | // Same line, different column. |
947 | auto *A = DILocation::get(Context, Line: 2, Column: 7, Scope: N); |
948 | auto *B = DILocation::get(Context, Line: 2, Column: 10, Scope: S); |
949 | auto *M0 = DILocation::getMergedLocation(LocA: A, LocB: B); |
950 | auto *M1 = DILocation::getMergedLocation(LocA: B, LocB: A); |
951 | for (auto *M : {M0, M1}) { |
952 | EXPECT_EQ(2u, M->getLine()); |
953 | EXPECT_EQ(0u, M->getColumn()); |
954 | EXPECT_EQ(N, M->getScope()); |
955 | } |
956 | } |
957 | |
958 | { |
959 | // Different lines, same scopes. |
960 | auto *A = DILocation::get(Context, Line: 1, Column: 6, Scope: N); |
961 | auto *B = DILocation::get(Context, Line: 2, Column: 7, Scope: N); |
962 | auto *M = DILocation::getMergedLocation(LocA: A, LocB: B); |
963 | EXPECT_EQ(0u, M->getLine()); |
964 | EXPECT_EQ(0u, M->getColumn()); |
965 | EXPECT_EQ(N, M->getScope()); |
966 | } |
967 | |
968 | { |
969 | // Twisty locations, all different, same function. |
970 | auto *A = DILocation::get(Context, Line: 1, Column: 6, Scope: N); |
971 | auto *B = DILocation::get(Context, Line: 2, Column: 7, Scope: S); |
972 | auto *M = DILocation::getMergedLocation(LocA: A, LocB: B); |
973 | EXPECT_EQ(0u, M->getLine()); |
974 | EXPECT_EQ(0u, M->getColumn()); |
975 | EXPECT_EQ(N, M->getScope()); |
976 | } |
977 | |
978 | { |
979 | // Different function, same inlined-at. |
980 | auto *F = getFile(); |
981 | auto *SP1 = DISubprogram::getDistinct(Context, Scope: F, Name: "a" , LinkageName: "a" , File: F, Line: 0, Type: nullptr, |
982 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
983 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
984 | auto *SP2 = DISubprogram::getDistinct(Context, Scope: F, Name: "b" , LinkageName: "b" , File: F, Line: 0, Type: nullptr, |
985 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
986 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
987 | |
988 | auto *I = DILocation::get(Context, Line: 2, Column: 7, Scope: N); |
989 | auto *A = DILocation::get(Context, Line: 1, Column: 6, Scope: SP1, InlinedAt: I); |
990 | auto *B = DILocation::get(Context, Line: 3, Column: 8, Scope: SP2, InlinedAt: I); |
991 | auto *M = DILocation::getMergedLocation(LocA: A, LocB: B); |
992 | EXPECT_EQ(2u, M->getLine()); |
993 | EXPECT_EQ(7u, M->getColumn()); |
994 | EXPECT_EQ(N, M->getScope()); |
995 | EXPECT_EQ(nullptr, M->getInlinedAt()); |
996 | } |
997 | |
998 | { |
999 | // Different function, inlined-at same line, but different column. |
1000 | auto *F = getFile(); |
1001 | auto *SP1 = DISubprogram::getDistinct(Context, Scope: F, Name: "a" , LinkageName: "a" , File: F, Line: 0, Type: nullptr, |
1002 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1003 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1004 | auto *SP2 = DISubprogram::getDistinct(Context, Scope: F, Name: "b" , LinkageName: "b" , File: F, Line: 0, Type: nullptr, |
1005 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1006 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1007 | |
1008 | auto *IA = DILocation::get(Context, Line: 2, Column: 7, Scope: N); |
1009 | auto *IB = DILocation::get(Context, Line: 2, Column: 8, Scope: N); |
1010 | auto *A = DILocation::get(Context, Line: 1, Column: 6, Scope: SP1, InlinedAt: IA); |
1011 | auto *B = DILocation::get(Context, Line: 3, Column: 8, Scope: SP2, InlinedAt: IB); |
1012 | auto *M = DILocation::getMergedLocation(LocA: A, LocB: B); |
1013 | EXPECT_EQ(2u, M->getLine()); |
1014 | EXPECT_EQ(0u, M->getColumn()); |
1015 | EXPECT_EQ(N, M->getScope()); |
1016 | EXPECT_EQ(nullptr, M->getInlinedAt()); |
1017 | } |
1018 | |
1019 | { |
1020 | // Completely different. |
1021 | auto *I = DILocation::get(Context, Line: 2, Column: 7, Scope: N); |
1022 | auto *A = DILocation::get(Context, Line: 1, Column: 6, Scope: S, InlinedAt: I); |
1023 | auto *B = DILocation::get(Context, Line: 2, Column: 7, Scope: getSubprogram()); |
1024 | auto *M = DILocation::getMergedLocation(LocA: A, LocB: B); |
1025 | EXPECT_EQ(0u, M->getLine()); |
1026 | EXPECT_EQ(0u, M->getColumn()); |
1027 | EXPECT_TRUE(isa<DILocalScope>(M->getScope())); |
1028 | EXPECT_EQ(S, M->getScope()); |
1029 | EXPECT_EQ(nullptr, M->getInlinedAt()); |
1030 | } |
1031 | |
1032 | // Two locations, same line/column different file, inlined at the same place. |
1033 | { |
1034 | auto *FA = getFile(); |
1035 | auto *FB = getFile(); |
1036 | auto *FI = getFile(); |
1037 | |
1038 | auto *SPA = DISubprogram::getDistinct(Context, Scope: FA, Name: "a" , LinkageName: "a" , File: FA, Line: 0, Type: nullptr, |
1039 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1040 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1041 | |
1042 | auto *SPB = DISubprogram::getDistinct(Context, Scope: FB, Name: "b" , LinkageName: "b" , File: FB, Line: 0, Type: nullptr, |
1043 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1044 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1045 | |
1046 | auto *SPI = DISubprogram::getDistinct(Context, Scope: FI, Name: "i" , LinkageName: "i" , File: FI, Line: 0, Type: nullptr, |
1047 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1048 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1049 | |
1050 | auto *I = DILocation::get(Context, Line: 3, Column: 8, Scope: SPI); |
1051 | auto *A = DILocation::get(Context, Line: 2, Column: 7, Scope: SPA, InlinedAt: I); |
1052 | auto *B = DILocation::get(Context, Line: 2, Column: 7, Scope: SPB, InlinedAt: I); |
1053 | auto *M = DILocation::getMergedLocation(LocA: A, LocB: B); |
1054 | EXPECT_EQ(3u, M->getLine()); |
1055 | EXPECT_EQ(8u, M->getColumn()); |
1056 | EXPECT_TRUE(isa<DILocalScope>(M->getScope())); |
1057 | EXPECT_EQ(SPI, M->getScope()); |
1058 | EXPECT_EQ(nullptr, M->getInlinedAt()); |
1059 | } |
1060 | |
1061 | // Two locations, same line/column different file, one location with 2 scopes, |
1062 | // inlined at the same place. |
1063 | { |
1064 | auto *FA = getFile(); |
1065 | auto *FB = getFile(); |
1066 | auto *FI = getFile(); |
1067 | |
1068 | auto *SPA = DISubprogram::getDistinct(Context, Scope: FA, Name: "a" , LinkageName: "a" , File: FA, Line: 0, Type: nullptr, |
1069 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1070 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1071 | |
1072 | auto *SPB = DISubprogram::getDistinct(Context, Scope: FB, Name: "b" , LinkageName: "b" , File: FB, Line: 0, Type: nullptr, |
1073 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1074 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1075 | |
1076 | auto *SPI = DISubprogram::getDistinct(Context, Scope: FI, Name: "i" , LinkageName: "i" , File: FI, Line: 0, Type: nullptr, |
1077 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1078 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1079 | |
1080 | auto *SPAScope = DILexicalBlock::getDistinct(Context, Scope: SPA, File: FA, Line: 4, Column: 9); |
1081 | |
1082 | auto *I = DILocation::get(Context, Line: 3, Column: 8, Scope: SPI); |
1083 | auto *A = DILocation::get(Context, Line: 2, Column: 7, Scope: SPAScope, InlinedAt: I); |
1084 | auto *B = DILocation::get(Context, Line: 2, Column: 7, Scope: SPB, InlinedAt: I); |
1085 | auto *M = DILocation::getMergedLocation(LocA: A, LocB: B); |
1086 | EXPECT_EQ(3u, M->getLine()); |
1087 | EXPECT_EQ(8u, M->getColumn()); |
1088 | EXPECT_TRUE(isa<DILocalScope>(M->getScope())); |
1089 | EXPECT_EQ(SPI, M->getScope()); |
1090 | EXPECT_EQ(nullptr, M->getInlinedAt()); |
1091 | } |
1092 | |
1093 | // Merge a location in C, which is inlined-at in B that is inlined in A, |
1094 | // with a location in A that has the same scope, line and column as B's |
1095 | // inlined-at location. |
1096 | { |
1097 | auto *FA = getFile(); |
1098 | auto *FB = getFile(); |
1099 | auto *FC = getFile(); |
1100 | |
1101 | auto *SPA = DISubprogram::getDistinct(Context, Scope: FA, Name: "a" , LinkageName: "a" , File: FA, Line: 0, Type: nullptr, |
1102 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1103 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1104 | |
1105 | auto *SPB = DISubprogram::getDistinct(Context, Scope: FB, Name: "b" , LinkageName: "b" , File: FB, Line: 0, Type: nullptr, |
1106 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1107 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1108 | |
1109 | auto *SPC = DISubprogram::getDistinct(Context, Scope: FC, Name: "c" , LinkageName: "c" , File: FC, Line: 0, Type: nullptr, |
1110 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1111 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1112 | |
1113 | auto *A = DILocation::get(Context, Line: 3, Column: 2, Scope: SPA); |
1114 | auto *B = DILocation::get(Context, Line: 2, Column: 4, Scope: SPB, InlinedAt: A); |
1115 | auto *C = DILocation::get(Context, Line: 13, Column: 2, Scope: SPC, InlinedAt: B); |
1116 | auto *M = DILocation::getMergedLocation(LocA: A, LocB: C); |
1117 | EXPECT_EQ(3u, M->getLine()); |
1118 | EXPECT_EQ(2u, M->getColumn()); |
1119 | EXPECT_TRUE(isa<DILocalScope>(M->getScope())); |
1120 | EXPECT_EQ(SPA, M->getScope()); |
1121 | EXPECT_EQ(nullptr, M->getInlinedAt()); |
1122 | } |
1123 | |
1124 | // Two inlined locations with the same scope, line and column |
1125 | // in the same inlined-at function at different line and column. |
1126 | { |
1127 | auto *FA = getFile(); |
1128 | auto *FB = getFile(); |
1129 | auto *FC = getFile(); |
1130 | |
1131 | auto *SPA = DISubprogram::getDistinct(Context, Scope: FA, Name: "a" , LinkageName: "a" , File: FA, Line: 0, Type: nullptr, |
1132 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1133 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1134 | |
1135 | auto *SPB = DISubprogram::getDistinct(Context, Scope: FB, Name: "b" , LinkageName: "b" , File: FB, Line: 0, Type: nullptr, |
1136 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1137 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1138 | |
1139 | auto *SPC = DISubprogram::getDistinct(Context, Scope: FC, Name: "c" , LinkageName: "c" , File: FC, Line: 0, Type: nullptr, |
1140 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1141 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1142 | |
1143 | auto *A = DILocation::get(Context, Line: 10, Column: 20, Scope: SPA); |
1144 | auto *B1 = DILocation::get(Context, Line: 3, Column: 2, Scope: SPB, InlinedAt: A); |
1145 | auto *B2 = DILocation::get(Context, Line: 4, Column: 5, Scope: SPB, InlinedAt: A); |
1146 | auto *C1 = DILocation::get(Context, Line: 2, Column: 4, Scope: SPC, InlinedAt: B1); |
1147 | auto *C2 = DILocation::get(Context, Line: 2, Column: 4, Scope: SPC, InlinedAt: B2); |
1148 | |
1149 | auto *M = DILocation::getMergedLocation(LocA: C1, LocB: C2); |
1150 | EXPECT_EQ(2u, M->getLine()); |
1151 | EXPECT_EQ(4u, M->getColumn()); |
1152 | EXPECT_EQ(SPC, M->getScope()); |
1153 | ASSERT_NE(nullptr, M->getInlinedAt()); |
1154 | |
1155 | auto *I1 = M->getInlinedAt(); |
1156 | EXPECT_EQ(0u, I1->getLine()); |
1157 | EXPECT_EQ(0u, I1->getColumn()); |
1158 | EXPECT_EQ(SPB, I1->getScope()); |
1159 | EXPECT_EQ(A, I1->getInlinedAt()); |
1160 | } |
1161 | |
1162 | // Two locations, different line/column and scope in the same subprogram, |
1163 | // inlined at the same place. This should result in a 0:0 location with |
1164 | // the nearest common scope in the inlined function. |
1165 | { |
1166 | auto *FA = getFile(); |
1167 | auto *FI = getFile(); |
1168 | |
1169 | auto *SPA = DISubprogram::getDistinct(Context, Scope: FA, Name: "a" , LinkageName: "a" , File: FA, Line: 0, Type: nullptr, |
1170 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1171 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1172 | |
1173 | auto *SPI = DISubprogram::getDistinct(Context, Scope: FI, Name: "i" , LinkageName: "i" , File: FI, Line: 0, Type: nullptr, |
1174 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1175 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1176 | |
1177 | // Nearest common scope for the two locations in a. |
1178 | auto *SPAScope1 = DILexicalBlock::getDistinct(Context, Scope: SPA, File: FA, Line: 4, Column: 9); |
1179 | |
1180 | // Scope for the first location in a. |
1181 | auto *SPAScope2 = |
1182 | DILexicalBlock::getDistinct(Context, Scope: SPAScope1, File: FA, Line: 10, Column: 12); |
1183 | |
1184 | // Scope for the second location in a. |
1185 | auto *SPAScope3 = |
1186 | DILexicalBlock::getDistinct(Context, Scope: SPAScope1, File: FA, Line: 20, Column: 8); |
1187 | auto *SPAScope4 = |
1188 | DILexicalBlock::getDistinct(Context, Scope: SPAScope3, File: FA, Line: 21, Column: 12); |
1189 | |
1190 | auto *I = DILocation::get(Context, Line: 3, Column: 8, Scope: SPI); |
1191 | auto *A1 = DILocation::get(Context, Line: 12, Column: 7, Scope: SPAScope2, InlinedAt: I); |
1192 | auto *A2 = DILocation::get(Context, Line: 21, Column: 15, Scope: SPAScope4, InlinedAt: I); |
1193 | auto *M = DILocation::getMergedLocation(LocA: A1, LocB: A2); |
1194 | EXPECT_EQ(0u, M->getLine()); |
1195 | EXPECT_EQ(0u, M->getColumn()); |
1196 | EXPECT_TRUE(isa<DILocalScope>(M->getScope())); |
1197 | EXPECT_EQ(SPAScope1, M->getScope()); |
1198 | EXPECT_EQ(I, M->getInlinedAt()); |
1199 | } |
1200 | |
1201 | // Regression test to catch a case where an iterator was invalidated due to |
1202 | // handling the chain of inlined-at locations after the nearest common |
1203 | // location for the two arguments were found. |
1204 | { |
1205 | auto *FA = getFile(); |
1206 | auto *FB = getFile(); |
1207 | auto *FI = getFile(); |
1208 | |
1209 | auto *SPA = DISubprogram::getDistinct(Context, Scope: FA, Name: "a" , LinkageName: "a" , File: FA, Line: 0, Type: nullptr, |
1210 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1211 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1212 | |
1213 | auto *SPB = DISubprogram::getDistinct(Context, Scope: FB, Name: "b" , LinkageName: "b" , File: FB, Line: 0, Type: nullptr, |
1214 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1215 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1216 | |
1217 | auto *SPI = DISubprogram::getDistinct(Context, Scope: FI, Name: "i" , LinkageName: "i" , File: FI, Line: 0, Type: nullptr, |
1218 | ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero, |
1219 | SPFlags: DISubprogram::SPFlagZero, Unit: nullptr); |
1220 | |
1221 | auto *SPAScope1 = DILexicalBlock::getDistinct(Context, Scope: SPA, File: FA, Line: 4, Column: 9); |
1222 | auto *SPAScope2 = DILexicalBlock::getDistinct(Context, Scope: SPA, File: FA, Line: 8, Column: 3); |
1223 | |
1224 | DILocation *InlinedAt = nullptr; |
1225 | |
1226 | // Create a chain of inlined-at locations. |
1227 | for (int i = 0; i < 256; i++) { |
1228 | InlinedAt = DILocation::get(Context, Line: 3 + i, Column: 8 + i, Scope: SPI, InlinedAt); |
1229 | } |
1230 | |
1231 | auto *A1 = DILocation::get(Context, Line: 5, Column: 9, Scope: SPAScope1, InlinedAt); |
1232 | auto *A2 = DILocation::get(Context, Line: 9, Column: 8, Scope: SPAScope2, InlinedAt); |
1233 | auto *B = DILocation::get(Context, Line: 10, Column: 3, Scope: SPB, InlinedAt: A1); |
1234 | auto *M1 = DILocation::getMergedLocation(LocA: B, LocB: A2); |
1235 | EXPECT_EQ(0u, M1->getLine()); |
1236 | EXPECT_EQ(0u, M1->getColumn()); |
1237 | EXPECT_TRUE(isa<DILocalScope>(M1->getScope())); |
1238 | EXPECT_EQ(SPA, M1->getScope()); |
1239 | EXPECT_EQ(InlinedAt, M1->getInlinedAt()); |
1240 | |
1241 | // Test the other argument order for good measure. |
1242 | auto *M2 = DILocation::getMergedLocation(LocA: A2, LocB: B); |
1243 | EXPECT_EQ(M1, M2); |
1244 | } |
1245 | } |
1246 | |
1247 | TEST_F(DILocationTest, getDistinct) { |
1248 | MDNode *N = getSubprogram(); |
1249 | DILocation *L0 = DILocation::getDistinct(Context, Line: 2, Column: 7, Scope: N); |
1250 | EXPECT_TRUE(L0->isDistinct()); |
1251 | DILocation *L1 = DILocation::get(Context, Line: 2, Column: 7, Scope: N); |
1252 | EXPECT_FALSE(L1->isDistinct()); |
1253 | EXPECT_EQ(L1, DILocation::get(Context, 2, 7, N)); |
1254 | } |
1255 | |
1256 | TEST_F(DILocationTest, getTemporary) { |
1257 | MDNode *N = MDNode::get(Context, MDs: std::nullopt); |
1258 | auto L = DILocation::getTemporary(Context, Line: 2, Column: 7, Scope: N); |
1259 | EXPECT_TRUE(L->isTemporary()); |
1260 | EXPECT_FALSE(L->isResolved()); |
1261 | } |
1262 | |
1263 | TEST_F(DILocationTest, cloneTemporary) { |
1264 | MDNode *N = MDNode::get(Context, MDs: std::nullopt); |
1265 | auto L = DILocation::getTemporary(Context, Line: 2, Column: 7, Scope: N); |
1266 | EXPECT_TRUE(L->isTemporary()); |
1267 | auto L2 = L->clone(); |
1268 | EXPECT_TRUE(L2->isTemporary()); |
1269 | } |
1270 | |
1271 | TEST_F(DILocationTest, discriminatorEncoding) { |
1272 | EXPECT_EQ(0U, *DILocation::encodeDiscriminator(0, 0, 0)); |
1273 | |
1274 | // Encode base discriminator as a component: lsb is 0, then the value. |
1275 | // The other components are all absent, so we leave all the other bits 0. |
1276 | EXPECT_EQ(2U, *DILocation::encodeDiscriminator(1, 0, 0)); |
1277 | |
1278 | // Base discriminator component is empty, so lsb is 1. Next component is not |
1279 | // empty, so its lsb is 0, then its value (1). Next component is empty. |
1280 | // So the bit pattern is 101. |
1281 | EXPECT_EQ(5U, *DILocation::encodeDiscriminator(0, 1, 0)); |
1282 | |
1283 | // First 2 components are empty, so the bit pattern is 11. Then the |
1284 | // next component - ending up with 1011. |
1285 | EXPECT_EQ(0xbU, *DILocation::encodeDiscriminator(0, 0, 1)); |
1286 | |
1287 | // The bit pattern for the first 2 components is 11. The next bit is 0, |
1288 | // because the last component is not empty. We have 29 bits usable for |
1289 | // encoding, but we cap it at 12 bits uniformously for all components. We |
1290 | // encode the last component over 14 bits. |
1291 | EXPECT_EQ(0xfffbU, *DILocation::encodeDiscriminator(0, 0, 0xfff)); |
1292 | |
1293 | EXPECT_EQ(0x102U, *DILocation::encodeDiscriminator(1, 1, 0)); |
1294 | |
1295 | EXPECT_EQ(0x13eU, *DILocation::encodeDiscriminator(0x1f, 1, 0)); |
1296 | |
1297 | EXPECT_EQ(0x87feU, *DILocation::encodeDiscriminator(0x1ff, 1, 0)); |
1298 | |
1299 | EXPECT_EQ(0x1f3eU, *DILocation::encodeDiscriminator(0x1f, 0x1f, 0)); |
1300 | |
1301 | EXPECT_EQ(0x3ff3eU, *DILocation::encodeDiscriminator(0x1f, 0x1ff, 0)); |
1302 | |
1303 | EXPECT_EQ(0x1ff87feU, *DILocation::encodeDiscriminator(0x1ff, 0x1ff, 0)); |
1304 | |
1305 | EXPECT_EQ(0xfff9f3eU, *DILocation::encodeDiscriminator(0x1f, 0x1f, 0xfff)); |
1306 | |
1307 | EXPECT_EQ(0xffc3ff3eU, *DILocation::encodeDiscriminator(0x1f, 0x1ff, 0x1ff)); |
1308 | |
1309 | EXPECT_EQ(0xffcf87feU, *DILocation::encodeDiscriminator(0x1ff, 0x1f, 0x1ff)); |
1310 | |
1311 | EXPECT_EQ(0xe1ff87feU, *DILocation::encodeDiscriminator(0x1ff, 0x1ff, 7)); |
1312 | } |
1313 | |
1314 | TEST_F(DILocationTest, discriminatorEncodingNegativeTests) { |
1315 | EXPECT_EQ(std::nullopt, DILocation::encodeDiscriminator(0, 0, 0x1000)); |
1316 | EXPECT_EQ(std::nullopt, DILocation::encodeDiscriminator(0x1000, 0, 0)); |
1317 | EXPECT_EQ(std::nullopt, DILocation::encodeDiscriminator(0, 0x1000, 0)); |
1318 | EXPECT_EQ(std::nullopt, DILocation::encodeDiscriminator(0, 0, 0x1000)); |
1319 | EXPECT_EQ(std::nullopt, DILocation::encodeDiscriminator(0x1ff, 0x1ff, 8)); |
1320 | EXPECT_EQ(std::nullopt, DILocation::encodeDiscriminator( |
1321 | std::numeric_limits<uint32_t>::max(), |
1322 | std::numeric_limits<uint32_t>::max(), 0)); |
1323 | } |
1324 | |
1325 | TEST_F(DILocationTest, discriminatorSpecialCases) { |
1326 | // We don't test getCopyIdentifier here because the only way |
1327 | // to set it is by constructing an encoded discriminator using |
1328 | // encodeDiscriminator, which is already tested. |
1329 | auto L1 = DILocation::get(Context, Line: 1, Column: 2, Scope: getSubprogram()); |
1330 | EXPECT_EQ(0U, L1->getBaseDiscriminator()); |
1331 | EXPECT_EQ(1U, L1->getDuplicationFactor()); |
1332 | |
1333 | EXPECT_EQ(L1, *L1->cloneWithBaseDiscriminator(0)); |
1334 | EXPECT_EQ(L1, *L1->cloneByMultiplyingDuplicationFactor(0)); |
1335 | EXPECT_EQ(L1, *L1->cloneByMultiplyingDuplicationFactor(1)); |
1336 | |
1337 | auto L2 = *L1->cloneWithBaseDiscriminator(D: 1); |
1338 | EXPECT_EQ(0U, L1->getBaseDiscriminator()); |
1339 | EXPECT_EQ(1U, L1->getDuplicationFactor()); |
1340 | |
1341 | EXPECT_EQ(1U, L2->getBaseDiscriminator()); |
1342 | EXPECT_EQ(1U, L2->getDuplicationFactor()); |
1343 | |
1344 | auto L3 = *L2->cloneByMultiplyingDuplicationFactor(DF: 2); |
1345 | EXPECT_EQ(1U, L3->getBaseDiscriminator()); |
1346 | EXPECT_EQ(2U, L3->getDuplicationFactor()); |
1347 | |
1348 | EXPECT_EQ(L2, *L2->cloneByMultiplyingDuplicationFactor(1)); |
1349 | |
1350 | auto L4 = *L3->cloneByMultiplyingDuplicationFactor(DF: 4); |
1351 | EXPECT_EQ(1U, L4->getBaseDiscriminator()); |
1352 | EXPECT_EQ(8U, L4->getDuplicationFactor()); |
1353 | |
1354 | auto L5 = *L4->cloneWithBaseDiscriminator(D: 2); |
1355 | EXPECT_EQ(2U, L5->getBaseDiscriminator()); |
1356 | EXPECT_EQ(8U, L5->getDuplicationFactor()); |
1357 | |
1358 | // Check extreme cases |
1359 | auto L6 = *L1->cloneWithBaseDiscriminator(D: 0xfff); |
1360 | EXPECT_EQ(0xfffU, L6->getBaseDiscriminator()); |
1361 | EXPECT_EQ(0xfffU, (*L6->cloneByMultiplyingDuplicationFactor(0xfff)) |
1362 | ->getDuplicationFactor()); |
1363 | |
1364 | // Check we return std::nullopt for unencodable cases. |
1365 | EXPECT_EQ(std::nullopt, L4->cloneWithBaseDiscriminator(0x1000)); |
1366 | EXPECT_EQ(std::nullopt, L4->cloneByMultiplyingDuplicationFactor(0x1000)); |
1367 | } |
1368 | |
1369 | |
1370 | typedef MetadataTest GenericDINodeTest; |
1371 | |
1372 | TEST_F(GenericDINodeTest, get) { |
1373 | StringRef = "header" ; |
1374 | auto *Empty = MDNode::get(Context, MDs: std::nullopt); |
1375 | Metadata *Ops1[] = {Empty}; |
1376 | auto *N = GenericDINode::get(Context, Tag: 15, Header, DwarfOps: Ops1); |
1377 | EXPECT_EQ(15u, N->getTag()); |
1378 | EXPECT_EQ(2u, N->getNumOperands()); |
1379 | EXPECT_EQ(Header, N->getHeader()); |
1380 | EXPECT_EQ(MDString::get(Context, Header), N->getOperand(0)); |
1381 | EXPECT_EQ(1u, N->getNumDwarfOperands()); |
1382 | EXPECT_EQ(Empty, N->getDwarfOperand(0)); |
1383 | EXPECT_EQ(Empty, N->getOperand(1)); |
1384 | ASSERT_TRUE(N->isUniqued()); |
1385 | |
1386 | EXPECT_EQ(N, GenericDINode::get(Context, 15, Header, Ops1)); |
1387 | |
1388 | N->replaceOperandWith(I: 1, New: nullptr); |
1389 | EXPECT_EQ(15u, N->getTag()); |
1390 | EXPECT_EQ(Header, N->getHeader()); |
1391 | EXPECT_EQ(nullptr, N->getDwarfOperand(0)); |
1392 | ASSERT_TRUE(N->isUniqued()); |
1393 | |
1394 | Metadata *Ops2[] = {nullptr}; |
1395 | EXPECT_EQ(N, GenericDINode::get(Context, 15, Header, Ops2)); |
1396 | |
1397 | N->replaceDwarfOperandWith(I: 0, New: Empty); |
1398 | EXPECT_EQ(15u, N->getTag()); |
1399 | EXPECT_EQ(Header, N->getHeader()); |
1400 | EXPECT_EQ(Empty, N->getDwarfOperand(0)); |
1401 | ASSERT_TRUE(N->isUniqued()); |
1402 | EXPECT_EQ(N, GenericDINode::get(Context, 15, Header, Ops1)); |
1403 | |
1404 | TempGenericDINode Temp = N->clone(); |
1405 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
1406 | } |
1407 | |
1408 | TEST_F(GenericDINodeTest, getEmptyHeader) { |
1409 | // Canonicalize !"" to null. |
1410 | auto *N = GenericDINode::get(Context, Tag: 15, Header: StringRef(), DwarfOps: std::nullopt); |
1411 | EXPECT_EQ(StringRef(), N->getHeader()); |
1412 | EXPECT_EQ(nullptr, N->getOperand(0)); |
1413 | } |
1414 | |
1415 | typedef MetadataTest DISubrangeTest; |
1416 | |
1417 | TEST_F(DISubrangeTest, get) { |
1418 | auto *N = DISubrange::get(Context, Count: 5, LowerBound: 7); |
1419 | auto Count = N->getCount(); |
1420 | auto Lower = N->getLowerBound(); |
1421 | EXPECT_EQ(dwarf::DW_TAG_subrange_type, N->getTag()); |
1422 | ASSERT_TRUE(Count); |
1423 | ASSERT_TRUE(isa<ConstantInt *>(Count)); |
1424 | EXPECT_EQ(5, cast<ConstantInt *>(Count)->getSExtValue()); |
1425 | EXPECT_EQ(7, cast<ConstantInt *>(Lower)->getSExtValue()); |
1426 | EXPECT_EQ(N, DISubrange::get(Context, 5, 7)); |
1427 | EXPECT_EQ(DISubrange::get(Context, 5, 0), DISubrange::get(Context, 5)); |
1428 | |
1429 | TempDISubrange Temp = N->clone(); |
1430 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
1431 | } |
1432 | |
1433 | TEST_F(DISubrangeTest, getEmptyArray) { |
1434 | auto *N = DISubrange::get(Context, Count: -1, LowerBound: 0); |
1435 | auto Count = N->getCount(); |
1436 | auto Lower = N->getLowerBound(); |
1437 | EXPECT_EQ(dwarf::DW_TAG_subrange_type, N->getTag()); |
1438 | ASSERT_TRUE(Count); |
1439 | ASSERT_TRUE(isa<ConstantInt *>(Count)); |
1440 | EXPECT_EQ(-1, cast<ConstantInt *>(Count)->getSExtValue()); |
1441 | EXPECT_EQ(0, cast<ConstantInt *>(Lower)->getSExtValue()); |
1442 | EXPECT_EQ(N, DISubrange::get(Context, -1, 0)); |
1443 | } |
1444 | |
1445 | TEST_F(DISubrangeTest, getVariableCount) { |
1446 | DILocalScope *Scope = getSubprogram(); |
1447 | DIFile *File = getFile(); |
1448 | DIType *Type = getDerivedType(); |
1449 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(7); |
1450 | auto *VlaExpr = DILocalVariable::get(Context, Scope, Name: "vla_expr" , File, Line: 8, |
1451 | Type, Arg: 2, Flags, AlignInBits: 8, Annotations: nullptr); |
1452 | |
1453 | auto *N = DISubrange::get(Context, CountNode: VlaExpr, LowerBound: 0); |
1454 | auto Count = N->getCount(); |
1455 | auto Lower = N->getLowerBound(); |
1456 | ASSERT_TRUE(Count); |
1457 | ASSERT_TRUE(isa<DIVariable *>(Count)); |
1458 | EXPECT_EQ(VlaExpr, cast<DIVariable *>(Count)); |
1459 | ASSERT_TRUE(isa<DIVariable>(N->getRawCountNode())); |
1460 | EXPECT_EQ(0, cast<ConstantInt *>(Lower)->getSExtValue()); |
1461 | EXPECT_EQ("vla_expr" , cast<DIVariable *>(Count)->getName()); |
1462 | EXPECT_EQ(N, DISubrange::get(Context, VlaExpr, 0)); |
1463 | } |
1464 | |
1465 | TEST_F(DISubrangeTest, fortranAllocatableInt) { |
1466 | DILocalScope *Scope = getSubprogram(); |
1467 | DIFile *File = getFile(); |
1468 | DIType *Type = getDerivedType(); |
1469 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(7); |
1470 | auto *LI = ConstantAsMetadata::get( |
1471 | C: ConstantInt::getSigned(Ty: Type::getInt64Ty(C&: Context), V: -10)); |
1472 | auto *UI = ConstantAsMetadata::get( |
1473 | C: ConstantInt::getSigned(Ty: Type::getInt64Ty(C&: Context), V: 10)); |
1474 | auto *SI = ConstantAsMetadata::get( |
1475 | C: ConstantInt::getSigned(Ty: Type::getInt64Ty(C&: Context), V: 4)); |
1476 | auto *UIother = ConstantAsMetadata::get( |
1477 | C: ConstantInt::getSigned(Ty: Type::getInt64Ty(C&: Context), V: 20)); |
1478 | auto *UVother = DILocalVariable::get(Context, Scope, Name: "ubother" , File, Line: 8, Type, |
1479 | Arg: 2, Flags, AlignInBits: 8, Annotations: nullptr); |
1480 | auto *UEother = DIExpression::get(Context, Elements: {5, 6}); |
1481 | auto *LIZero = ConstantAsMetadata::get( |
1482 | C: ConstantInt::getSigned(Ty: Type::getInt64Ty(C&: Context), V: 0)); |
1483 | auto *UIZero = ConstantAsMetadata::get( |
1484 | C: ConstantInt::getSigned(Ty: Type::getInt64Ty(C&: Context), V: 0)); |
1485 | |
1486 | auto *N = DISubrange::get(Context, CountNode: nullptr, LowerBound: LI, UpperBound: UI, Stride: SI); |
1487 | |
1488 | auto Lower = N->getLowerBound(); |
1489 | ASSERT_TRUE(Lower); |
1490 | ASSERT_TRUE(isa<ConstantInt *>(Lower)); |
1491 | EXPECT_EQ(cast<ConstantInt>(LI->getValue()), cast<ConstantInt *>(Lower)); |
1492 | |
1493 | auto Upper = N->getUpperBound(); |
1494 | ASSERT_TRUE(Upper); |
1495 | ASSERT_TRUE(isa<ConstantInt *>(Upper)); |
1496 | EXPECT_EQ(cast<ConstantInt>(UI->getValue()), cast<ConstantInt *>(Upper)); |
1497 | |
1498 | auto Stride = N->getStride(); |
1499 | ASSERT_TRUE(Stride); |
1500 | ASSERT_TRUE(isa<ConstantInt *>(Stride)); |
1501 | EXPECT_EQ(cast<ConstantInt>(SI->getValue()), cast<ConstantInt *>(Stride)); |
1502 | |
1503 | EXPECT_EQ(N, DISubrange::get(Context, nullptr, LI, UI, SI)); |
1504 | |
1505 | EXPECT_NE(N, DISubrange::get(Context, nullptr, LI, UIother, SI)); |
1506 | EXPECT_NE(N, DISubrange::get(Context, nullptr, LI, UEother, SI)); |
1507 | EXPECT_NE(N, DISubrange::get(Context, nullptr, LI, UVother, SI)); |
1508 | |
1509 | auto *NZeroLower = DISubrange::get(Context, CountNode: nullptr, LowerBound: LIZero, UpperBound: UI, Stride: SI); |
1510 | EXPECT_NE(NZeroLower, DISubrange::get(Context, nullptr, nullptr, UI, SI)); |
1511 | |
1512 | auto *NZeroUpper = DISubrange::get(Context, CountNode: nullptr, LowerBound: LI, UpperBound: UIZero, Stride: SI); |
1513 | EXPECT_NE(NZeroUpper, DISubrange::get(Context, nullptr, LI, nullptr, SI)); |
1514 | } |
1515 | |
1516 | TEST_F(DISubrangeTest, fortranAllocatableVar) { |
1517 | DILocalScope *Scope = getSubprogram(); |
1518 | DIFile *File = getFile(); |
1519 | DIType *Type = getDerivedType(); |
1520 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(7); |
1521 | auto *LV = |
1522 | DILocalVariable::get(Context, Scope, Name: "lb" , File, Line: 8, Type, Arg: 2, Flags, AlignInBits: 8, |
1523 | Annotations: nullptr); |
1524 | auto *UV = |
1525 | DILocalVariable::get(Context, Scope, Name: "ub" , File, Line: 8, Type, Arg: 2, Flags, AlignInBits: 8, |
1526 | Annotations: nullptr); |
1527 | auto *SV = |
1528 | DILocalVariable::get(Context, Scope, Name: "st" , File, Line: 8, Type, Arg: 2, Flags, AlignInBits: 8, |
1529 | Annotations: nullptr); |
1530 | auto *SVother = DILocalVariable::get(Context, Scope, Name: "stother" , File, Line: 8, Type, |
1531 | Arg: 2, Flags, AlignInBits: 8, Annotations: nullptr); |
1532 | auto *SIother = ConstantAsMetadata::get( |
1533 | C: ConstantInt::getSigned(Ty: Type::getInt64Ty(C&: Context), V: 20)); |
1534 | auto *SEother = DIExpression::get(Context, Elements: {5, 6}); |
1535 | |
1536 | auto *N = DISubrange::get(Context, CountNode: nullptr, LowerBound: LV, UpperBound: UV, Stride: SV); |
1537 | |
1538 | auto Lower = N->getLowerBound(); |
1539 | ASSERT_TRUE(Lower); |
1540 | ASSERT_TRUE(isa<DIVariable *>(Lower)); |
1541 | EXPECT_EQ(LV, cast<DIVariable *>(Lower)); |
1542 | |
1543 | auto Upper = N->getUpperBound(); |
1544 | ASSERT_TRUE(Upper); |
1545 | ASSERT_TRUE(isa<DIVariable *>(Upper)); |
1546 | EXPECT_EQ(UV, cast<DIVariable *>(Upper)); |
1547 | |
1548 | auto Stride = N->getStride(); |
1549 | ASSERT_TRUE(Stride); |
1550 | ASSERT_TRUE(isa<DIVariable *>(Stride)); |
1551 | EXPECT_EQ(SV, cast<DIVariable *>(Stride)); |
1552 | |
1553 | EXPECT_EQ(N, DISubrange::get(Context, nullptr, LV, UV, SV)); |
1554 | |
1555 | EXPECT_NE(N, DISubrange::get(Context, nullptr, LV, UV, SVother)); |
1556 | EXPECT_NE(N, DISubrange::get(Context, nullptr, LV, UV, SEother)); |
1557 | EXPECT_NE(N, DISubrange::get(Context, nullptr, LV, UV, SIother)); |
1558 | } |
1559 | |
1560 | TEST_F(DISubrangeTest, fortranAllocatableExpr) { |
1561 | DILocalScope *Scope = getSubprogram(); |
1562 | DIFile *File = getFile(); |
1563 | DIType *Type = getDerivedType(); |
1564 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(7); |
1565 | auto *LE = DIExpression::get(Context, Elements: {1, 2}); |
1566 | auto *UE = DIExpression::get(Context, Elements: {2, 3}); |
1567 | auto *SE = DIExpression::get(Context, Elements: {3, 4}); |
1568 | auto *LEother = DIExpression::get(Context, Elements: {5, 6}); |
1569 | auto *LIother = ConstantAsMetadata::get( |
1570 | C: ConstantInt::getSigned(Ty: Type::getInt64Ty(C&: Context), V: 20)); |
1571 | auto *LVother = DILocalVariable::get(Context, Scope, Name: "lbother" , File, Line: 8, Type, |
1572 | Arg: 2, Flags, AlignInBits: 8, Annotations: nullptr); |
1573 | |
1574 | auto *N = DISubrange::get(Context, CountNode: nullptr, LowerBound: LE, UpperBound: UE, Stride: SE); |
1575 | |
1576 | auto Lower = N->getLowerBound(); |
1577 | ASSERT_TRUE(Lower); |
1578 | ASSERT_TRUE(isa<DIExpression *>(Lower)); |
1579 | EXPECT_EQ(LE, cast<DIExpression *>(Lower)); |
1580 | |
1581 | auto Upper = N->getUpperBound(); |
1582 | ASSERT_TRUE(Upper); |
1583 | ASSERT_TRUE(isa<DIExpression *>(Upper)); |
1584 | EXPECT_EQ(UE, cast<DIExpression *>(Upper)); |
1585 | |
1586 | auto Stride = N->getStride(); |
1587 | ASSERT_TRUE(Stride); |
1588 | ASSERT_TRUE(isa<DIExpression *>(Stride)); |
1589 | EXPECT_EQ(SE, cast<DIExpression *>(Stride)); |
1590 | |
1591 | EXPECT_EQ(N, DISubrange::get(Context, nullptr, LE, UE, SE)); |
1592 | |
1593 | EXPECT_NE(N, DISubrange::get(Context, nullptr, LEother, UE, SE)); |
1594 | EXPECT_NE(N, DISubrange::get(Context, nullptr, LIother, UE, SE)); |
1595 | EXPECT_NE(N, DISubrange::get(Context, nullptr, LVother, UE, SE)); |
1596 | } |
1597 | |
1598 | typedef MetadataTest DIGenericSubrangeTest; |
1599 | |
1600 | TEST_F(DIGenericSubrangeTest, fortranAssumedRankInt) { |
1601 | DILocalScope *Scope = getSubprogram(); |
1602 | DIFile *File = getFile(); |
1603 | DIType *Type = getDerivedType(); |
1604 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(7); |
1605 | auto *LI = DIExpression::get( |
1606 | Context, Elements: {dwarf::DW_OP_consts, static_cast<uint64_t>(-10)}); |
1607 | auto *UI = DIExpression::get(Context, Elements: {dwarf::DW_OP_consts, 10}); |
1608 | auto *SI = DIExpression::get(Context, Elements: {dwarf::DW_OP_consts, 4}); |
1609 | auto *UIother = DIExpression::get(Context, Elements: {dwarf::DW_OP_consts, 20}); |
1610 | auto *UVother = DILocalVariable::get(Context, Scope, Name: "ubother" , File, Line: 8, Type, |
1611 | Arg: 2, Flags, AlignInBits: 8, Annotations: nullptr); |
1612 | auto *UEother = DIExpression::get(Context, Elements: {5, 6}); |
1613 | auto *LIZero = DIExpression::get(Context, Elements: {dwarf::DW_OP_consts, 0}); |
1614 | auto *UIZero = DIExpression::get(Context, Elements: {dwarf::DW_OP_consts, 0}); |
1615 | |
1616 | auto *N = DIGenericSubrange::get(Context, CountNode: nullptr, LowerBound: LI, UpperBound: UI, Stride: SI); |
1617 | |
1618 | auto Lower = N->getLowerBound(); |
1619 | ASSERT_TRUE(Lower); |
1620 | ASSERT_TRUE(isa<DIExpression *>(Lower)); |
1621 | EXPECT_EQ(dyn_cast_or_null<DIExpression>(LI), cast<DIExpression *>(Lower)); |
1622 | |
1623 | auto Upper = N->getUpperBound(); |
1624 | ASSERT_TRUE(Upper); |
1625 | ASSERT_TRUE(isa<DIExpression *>(Upper)); |
1626 | EXPECT_EQ(dyn_cast_or_null<DIExpression>(UI), cast<DIExpression *>(Upper)); |
1627 | |
1628 | auto Stride = N->getStride(); |
1629 | ASSERT_TRUE(Stride); |
1630 | ASSERT_TRUE(isa<DIExpression *>(Stride)); |
1631 | EXPECT_EQ(dyn_cast_or_null<DIExpression>(SI), cast<DIExpression *>(Stride)); |
1632 | |
1633 | EXPECT_EQ(N, DIGenericSubrange::get(Context, nullptr, LI, UI, SI)); |
1634 | |
1635 | EXPECT_NE(N, DIGenericSubrange::get(Context, nullptr, LI, UIother, SI)); |
1636 | EXPECT_NE(N, DIGenericSubrange::get(Context, nullptr, LI, UEother, SI)); |
1637 | EXPECT_NE(N, DIGenericSubrange::get(Context, nullptr, LI, UVother, SI)); |
1638 | |
1639 | auto *NZeroLower = DIGenericSubrange::get(Context, CountNode: nullptr, LowerBound: LIZero, UpperBound: UI, Stride: SI); |
1640 | EXPECT_NE(NZeroLower, |
1641 | DIGenericSubrange::get(Context, nullptr, nullptr, UI, SI)); |
1642 | |
1643 | auto *NZeroUpper = DIGenericSubrange::get(Context, CountNode: nullptr, LowerBound: LI, UpperBound: UIZero, Stride: SI); |
1644 | EXPECT_NE(NZeroUpper, |
1645 | DIGenericSubrange::get(Context, nullptr, LI, nullptr, SI)); |
1646 | } |
1647 | |
1648 | TEST_F(DIGenericSubrangeTest, fortranAssumedRankVar) { |
1649 | DILocalScope *Scope = getSubprogram(); |
1650 | DIFile *File = getFile(); |
1651 | DIType *Type = getDerivedType(); |
1652 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(7); |
1653 | auto *LV = |
1654 | DILocalVariable::get(Context, Scope, Name: "lb" , File, Line: 8, Type, Arg: 2, Flags, AlignInBits: 8, |
1655 | Annotations: nullptr); |
1656 | auto *UV = |
1657 | DILocalVariable::get(Context, Scope, Name: "ub" , File, Line: 8, Type, Arg: 2, Flags, AlignInBits: 8, |
1658 | Annotations: nullptr); |
1659 | auto *SV = |
1660 | DILocalVariable::get(Context, Scope, Name: "st" , File, Line: 8, Type, Arg: 2, Flags, AlignInBits: 8, |
1661 | Annotations: nullptr); |
1662 | auto *SVother = DILocalVariable::get(Context, Scope, Name: "stother" , File, Line: 8, Type, |
1663 | Arg: 2, Flags, AlignInBits: 8, Annotations: nullptr); |
1664 | auto *SIother = DIExpression::get( |
1665 | Context, Elements: {dwarf::DW_OP_consts, static_cast<uint64_t>(-1)}); |
1666 | auto *SEother = DIExpression::get(Context, Elements: {5, 6}); |
1667 | |
1668 | auto *N = DIGenericSubrange::get(Context, CountNode: nullptr, LowerBound: LV, UpperBound: UV, Stride: SV); |
1669 | |
1670 | auto Lower = N->getLowerBound(); |
1671 | ASSERT_TRUE(Lower); |
1672 | ASSERT_TRUE(isa<DIVariable *>(Lower)); |
1673 | EXPECT_EQ(LV, cast<DIVariable *>(Lower)); |
1674 | |
1675 | auto Upper = N->getUpperBound(); |
1676 | ASSERT_TRUE(Upper); |
1677 | ASSERT_TRUE(isa<DIVariable *>(Upper)); |
1678 | EXPECT_EQ(UV, cast<DIVariable *>(Upper)); |
1679 | |
1680 | auto Stride = N->getStride(); |
1681 | ASSERT_TRUE(Stride); |
1682 | ASSERT_TRUE(isa<DIVariable *>(Stride)); |
1683 | EXPECT_EQ(SV, cast<DIVariable *>(Stride)); |
1684 | |
1685 | EXPECT_EQ(N, DIGenericSubrange::get(Context, nullptr, LV, UV, SV)); |
1686 | |
1687 | EXPECT_NE(N, DIGenericSubrange::get(Context, nullptr, LV, UV, SVother)); |
1688 | EXPECT_NE(N, DIGenericSubrange::get(Context, nullptr, LV, UV, SEother)); |
1689 | EXPECT_NE(N, DIGenericSubrange::get(Context, nullptr, LV, UV, SIother)); |
1690 | } |
1691 | |
1692 | TEST_F(DIGenericSubrangeTest, useDIBuilder) { |
1693 | DILocalScope *Scope = getSubprogram(); |
1694 | DIFile *File = getFile(); |
1695 | DIType *Type = getDerivedType(); |
1696 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(7); |
1697 | auto *LV = |
1698 | DILocalVariable::get(Context, Scope, Name: "lb" , File, Line: 8, Type, Arg: 2, Flags, AlignInBits: 8, Annotations: nullptr); |
1699 | auto *UE = DIExpression::get(Context, Elements: {2, 3}); |
1700 | auto *SE = DIExpression::get(Context, Elements: {3, 4}); |
1701 | |
1702 | auto *LVother = DILocalVariable::get(Context, Scope, Name: "lbother" , File, Line: 8, Type, |
1703 | Arg: 2, Flags, AlignInBits: 8, Annotations: nullptr); |
1704 | auto *LIother = DIExpression::get( |
1705 | Context, Elements: {dwarf::DW_OP_consts, static_cast<uint64_t>(-1)}); |
1706 | |
1707 | Module M("M" , Context); |
1708 | DIBuilder DIB(M); |
1709 | |
1710 | auto *N = DIB.getOrCreateGenericSubrange( |
1711 | Count: DIGenericSubrange::BoundType(nullptr), LowerBound: DIGenericSubrange::BoundType(LV), |
1712 | UpperBound: DIGenericSubrange::BoundType(UE), Stride: DIGenericSubrange::BoundType(SE)); |
1713 | |
1714 | auto Lower = N->getLowerBound(); |
1715 | ASSERT_TRUE(Lower); |
1716 | ASSERT_TRUE(isa<DIVariable *>(Lower)); |
1717 | EXPECT_EQ(LV, cast<DIVariable *>(Lower)); |
1718 | |
1719 | auto Upper = N->getUpperBound(); |
1720 | ASSERT_TRUE(Upper); |
1721 | ASSERT_TRUE(isa<DIExpression *>(Upper)); |
1722 | EXPECT_EQ(UE, cast<DIExpression *>(Upper)); |
1723 | |
1724 | auto Stride = N->getStride(); |
1725 | ASSERT_TRUE(Stride); |
1726 | ASSERT_TRUE(isa<DIExpression *>(Stride)); |
1727 | EXPECT_EQ(SE, cast<DIExpression *>(Stride)); |
1728 | |
1729 | EXPECT_EQ( |
1730 | N, DIB.getOrCreateGenericSubrange(DIGenericSubrange::BoundType(nullptr), |
1731 | DIGenericSubrange::BoundType(LV), |
1732 | DIGenericSubrange::BoundType(UE), |
1733 | DIGenericSubrange::BoundType(SE))); |
1734 | |
1735 | EXPECT_NE( |
1736 | N, DIB.getOrCreateGenericSubrange(DIGenericSubrange::BoundType(nullptr), |
1737 | DIGenericSubrange::BoundType(LVother), |
1738 | DIGenericSubrange::BoundType(UE), |
1739 | DIGenericSubrange::BoundType(SE))); |
1740 | EXPECT_NE( |
1741 | N, DIB.getOrCreateGenericSubrange(DIGenericSubrange::BoundType(nullptr), |
1742 | DIGenericSubrange::BoundType(LIother), |
1743 | DIGenericSubrange::BoundType(UE), |
1744 | DIGenericSubrange::BoundType(SE))); |
1745 | } |
1746 | typedef MetadataTest DIEnumeratorTest; |
1747 | |
1748 | TEST_F(DIEnumeratorTest, get) { |
1749 | auto *N = DIEnumerator::get(Context, Value: 7, IsUnsigned: false, Name: "name" ); |
1750 | EXPECT_EQ(dwarf::DW_TAG_enumerator, N->getTag()); |
1751 | EXPECT_EQ(7, N->getValue().getSExtValue()); |
1752 | EXPECT_FALSE(N->isUnsigned()); |
1753 | EXPECT_EQ("name" , N->getName()); |
1754 | EXPECT_EQ(N, DIEnumerator::get(Context, 7, false, "name" )); |
1755 | |
1756 | EXPECT_NE(N, DIEnumerator::get(Context, 7, true, "name" )); |
1757 | EXPECT_NE(N, DIEnumerator::get(Context, 8, false, "name" )); |
1758 | EXPECT_NE(N, DIEnumerator::get(Context, 7, false, "nam" )); |
1759 | |
1760 | TempDIEnumerator Temp = N->clone(); |
1761 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
1762 | } |
1763 | |
1764 | TEST_F(DIEnumeratorTest, getWithLargeValues) { |
1765 | auto *N = DIEnumerator::get(Context, Value: APInt::getMaxValue(numBits: 128), IsUnsigned: false, Name: "val" ); |
1766 | EXPECT_EQ(128U, N->getValue().popcount()); |
1767 | EXPECT_EQ(N, |
1768 | DIEnumerator::get(Context, APInt::getMaxValue(128), false, "val" )); |
1769 | EXPECT_NE(N, |
1770 | DIEnumerator::get(Context, APInt::getMinValue(128), false, "val" )); |
1771 | } |
1772 | |
1773 | typedef MetadataTest DIBasicTypeTest; |
1774 | |
1775 | TEST_F(DIBasicTypeTest, get) { |
1776 | auto *N = |
1777 | DIBasicType::get(Context, Tag: dwarf::DW_TAG_base_type, Name: "special" , SizeInBits: 33, AlignInBits: 26, Encoding: 7, |
1778 | Flags: DINode::FlagZero); |
1779 | EXPECT_EQ(dwarf::DW_TAG_base_type, N->getTag()); |
1780 | EXPECT_EQ("special" , N->getName()); |
1781 | EXPECT_EQ(33u, N->getSizeInBits()); |
1782 | EXPECT_EQ(26u, N->getAlignInBits()); |
1783 | EXPECT_EQ(7u, N->getEncoding()); |
1784 | EXPECT_EQ(0u, N->getLine()); |
1785 | EXPECT_EQ(DINode::FlagZero, N->getFlags()); |
1786 | EXPECT_EQ(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special" , 33, |
1787 | 26, 7, DINode::FlagZero)); |
1788 | |
1789 | EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, |
1790 | "special" , 33, 26, 7, DINode::FlagZero)); |
1791 | EXPECT_NE(N, |
1792 | DIBasicType::get(Context, dwarf::DW_TAG_base_type, "s" , 33, 26, 7, |
1793 | DINode::FlagZero)); |
1794 | EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special" , 32, |
1795 | 26, 7, DINode::FlagZero)); |
1796 | EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special" , 33, |
1797 | 25, 7, DINode::FlagZero)); |
1798 | EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special" , 33, |
1799 | 26, 6, DINode::FlagZero)); |
1800 | EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special" , 33, |
1801 | 26, 7, DINode::FlagBigEndian)); |
1802 | EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special" , 33, |
1803 | 26, 7, DINode::FlagLittleEndian)); |
1804 | |
1805 | TempDIBasicType Temp = N->clone(); |
1806 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
1807 | } |
1808 | |
1809 | TEST_F(DIBasicTypeTest, getWithLargeValues) { |
1810 | auto *N = DIBasicType::get(Context, Tag: dwarf::DW_TAG_base_type, Name: "special" , |
1811 | UINT64_MAX, UINT32_MAX - 1, Encoding: 7, Flags: DINode::FlagZero); |
1812 | EXPECT_EQ(UINT64_MAX, N->getSizeInBits()); |
1813 | EXPECT_EQ(UINT32_MAX - 1, N->getAlignInBits()); |
1814 | } |
1815 | |
1816 | TEST_F(DIBasicTypeTest, getUnspecified) { |
1817 | auto *N = |
1818 | DIBasicType::get(Context, Tag: dwarf::DW_TAG_unspecified_type, Name: "unspecified" ); |
1819 | EXPECT_EQ(dwarf::DW_TAG_unspecified_type, N->getTag()); |
1820 | EXPECT_EQ("unspecified" , N->getName()); |
1821 | EXPECT_EQ(0u, N->getSizeInBits()); |
1822 | EXPECT_EQ(0u, N->getAlignInBits()); |
1823 | EXPECT_EQ(0u, N->getEncoding()); |
1824 | EXPECT_EQ(0u, N->getLine()); |
1825 | EXPECT_EQ(DINode::FlagZero, N->getFlags()); |
1826 | } |
1827 | |
1828 | typedef MetadataTest DITypeTest; |
1829 | |
1830 | TEST_F(DITypeTest, clone) { |
1831 | // Check that DIType has a specialized clone that returns TempDIType. |
1832 | DIType *N = DIBasicType::get(Context, Tag: dwarf::DW_TAG_base_type, Name: "int" , SizeInBits: 32, AlignInBits: 32, |
1833 | Encoding: dwarf::DW_ATE_signed, Flags: DINode::FlagZero); |
1834 | |
1835 | TempDIType Temp = N->clone(); |
1836 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
1837 | } |
1838 | |
1839 | TEST_F(DITypeTest, cloneWithFlags) { |
1840 | // void (void) |
1841 | Metadata *TypesOps[] = {nullptr}; |
1842 | Metadata *Types = MDTuple::get(Context, MDs: TypesOps); |
1843 | |
1844 | DIType *D = |
1845 | DISubroutineType::getDistinct(Context, Flags: DINode::FlagZero, CC: 0, TypeArray: Types); |
1846 | EXPECT_EQ(DINode::FlagZero, D->getFlags()); |
1847 | TempDIType D2 = D->cloneWithFlags(NewFlags: DINode::FlagRValueReference); |
1848 | EXPECT_EQ(DINode::FlagRValueReference, D2->getFlags()); |
1849 | EXPECT_EQ(DINode::FlagZero, D->getFlags()); |
1850 | |
1851 | TempDIType T = |
1852 | DISubroutineType::getTemporary(Context, Flags: DINode::FlagZero, CC: 0, TypeArray: Types); |
1853 | EXPECT_EQ(DINode::FlagZero, T->getFlags()); |
1854 | TempDIType T2 = T->cloneWithFlags(NewFlags: DINode::FlagRValueReference); |
1855 | EXPECT_EQ(DINode::FlagRValueReference, T2->getFlags()); |
1856 | EXPECT_EQ(DINode::FlagZero, T->getFlags()); |
1857 | } |
1858 | |
1859 | typedef MetadataTest DIDerivedTypeTest; |
1860 | |
1861 | TEST_F(DIDerivedTypeTest, get) { |
1862 | DIFile *File = getFile(); |
1863 | DIScope *Scope = getSubprogram(); |
1864 | DIType *BaseType = getBasicType(Name: "basic" ); |
1865 | MDTuple * = getTuple(); |
1866 | unsigned DWARFAddressSpace = 8; |
1867 | DIDerivedType::PtrAuthData PtrAuthData(1, false, 1234, true, true); |
1868 | DIDerivedType::PtrAuthData PtrAuthData2(1, false, 1234, true, false); |
1869 | DINode::DIFlags Flags5 = static_cast<DINode::DIFlags>(5); |
1870 | DINode::DIFlags Flags4 = static_cast<DINode::DIFlags>(4); |
1871 | |
1872 | auto *N = DIDerivedType::get( |
1873 | Context, Tag: dwarf::DW_TAG_pointer_type, Name: "something" , File, Line: 1, Scope, |
1874 | BaseType, SizeInBits: 2, AlignInBits: 3, OffsetInBits: 4, DWARFAddressSpace, PtrAuthData: std::nullopt, Flags: Flags5, ExtraData); |
1875 | auto *N1 = DIDerivedType::get(Context, Tag: dwarf::DW_TAG_LLVM_ptrauth_type, Name: "" , |
1876 | File, Line: 1, Scope, BaseType: N, SizeInBits: 2, AlignInBits: 3, OffsetInBits: 4, DWARFAddressSpace, |
1877 | PtrAuthData, Flags: Flags5, ExtraData); |
1878 | EXPECT_EQ(dwarf::DW_TAG_pointer_type, N->getTag()); |
1879 | EXPECT_EQ("something" , N->getName()); |
1880 | EXPECT_EQ(File, N->getFile()); |
1881 | EXPECT_EQ(1u, N->getLine()); |
1882 | EXPECT_EQ(Scope, N->getScope()); |
1883 | EXPECT_EQ(BaseType, N->getBaseType()); |
1884 | EXPECT_EQ(2u, N->getSizeInBits()); |
1885 | EXPECT_EQ(3u, N->getAlignInBits()); |
1886 | EXPECT_EQ(4u, N->getOffsetInBits()); |
1887 | EXPECT_EQ(DWARFAddressSpace, *N->getDWARFAddressSpace()); |
1888 | EXPECT_EQ(std::nullopt, N->getPtrAuthData()); |
1889 | EXPECT_EQ(PtrAuthData, N1->getPtrAuthData()); |
1890 | EXPECT_NE(PtrAuthData2, N1->getPtrAuthData()); |
1891 | EXPECT_EQ(5u, N->getFlags()); |
1892 | EXPECT_EQ(ExtraData, N->getExtraData()); |
1893 | EXPECT_EQ(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, |
1894 | "something" , File, 1, Scope, BaseType, 2, 3, |
1895 | 4, DWARFAddressSpace, std::nullopt, Flags5, |
1896 | ExtraData)); |
1897 | |
1898 | EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_reference_type, |
1899 | "something" , File, 1, Scope, BaseType, 2, 3, |
1900 | 4, DWARFAddressSpace, std::nullopt, Flags5, |
1901 | ExtraData)); |
1902 | EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "else" , |
1903 | File, 1, Scope, BaseType, 2, 3, 4, |
1904 | DWARFAddressSpace, std::nullopt, Flags5, |
1905 | ExtraData)); |
1906 | EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, |
1907 | "something" , getFile(), 1, Scope, BaseType, 2, |
1908 | 3, 4, DWARFAddressSpace, std::nullopt, Flags5, |
1909 | ExtraData)); |
1910 | EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, |
1911 | "something" , File, 2, Scope, BaseType, 2, 3, |
1912 | 4, DWARFAddressSpace, std::nullopt, Flags5, |
1913 | ExtraData)); |
1914 | EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, |
1915 | "something" , File, 1, getSubprogram(), |
1916 | BaseType, 2, 3, 4, DWARFAddressSpace, |
1917 | std::nullopt, Flags5, ExtraData)); |
1918 | EXPECT_NE(N, DIDerivedType::get( |
1919 | Context, dwarf::DW_TAG_pointer_type, "something" , File, 1, |
1920 | Scope, getBasicType("basic2" ), 2, 3, 4, DWARFAddressSpace, |
1921 | std::nullopt, Flags5, ExtraData)); |
1922 | EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, |
1923 | "something" , File, 1, Scope, BaseType, 3, 3, |
1924 | 4, DWARFAddressSpace, std::nullopt, Flags5, |
1925 | ExtraData)); |
1926 | EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, |
1927 | "something" , File, 1, Scope, BaseType, 2, 2, |
1928 | 4, DWARFAddressSpace, std::nullopt, Flags5, |
1929 | ExtraData)); |
1930 | EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, |
1931 | "something" , File, 1, Scope, BaseType, 2, 3, |
1932 | 5, DWARFAddressSpace, std::nullopt, Flags5, |
1933 | ExtraData)); |
1934 | EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, |
1935 | "something" , File, 1, Scope, BaseType, 2, 3, |
1936 | 4, DWARFAddressSpace + 1, std::nullopt, |
1937 | Flags5, ExtraData)); |
1938 | EXPECT_NE(N1, |
1939 | DIDerivedType::get(Context, dwarf::DW_TAG_LLVM_ptrauth_type, "" , |
1940 | File, 1, Scope, N, 2, 3, 4, DWARFAddressSpace, |
1941 | std::nullopt, Flags5, ExtraData)); |
1942 | EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, |
1943 | "something" , File, 1, Scope, BaseType, 2, 3, |
1944 | 4, DWARFAddressSpace, std::nullopt, Flags4, |
1945 | ExtraData)); |
1946 | EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, |
1947 | "something" , File, 1, Scope, BaseType, 2, 3, |
1948 | 4, DWARFAddressSpace, std::nullopt, Flags5, |
1949 | getTuple())); |
1950 | |
1951 | TempDIDerivedType Temp = N->clone(); |
1952 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
1953 | TempDIDerivedType Temp1 = N1->clone(); |
1954 | EXPECT_EQ(N1, MDNode::replaceWithUniqued(std::move(Temp1))); |
1955 | } |
1956 | |
1957 | TEST_F(DIDerivedTypeTest, getWithLargeValues) { |
1958 | DIFile *File = getFile(); |
1959 | DIScope *Scope = getSubprogram(); |
1960 | DIType *BaseType = getBasicType(Name: "basic" ); |
1961 | MDTuple * = getTuple(); |
1962 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(5); |
1963 | |
1964 | auto *N = DIDerivedType::get(Context, Tag: dwarf::DW_TAG_pointer_type, Name: "something" , |
1965 | File, Line: 1, Scope, BaseType, UINT64_MAX, |
1966 | UINT32_MAX - 1, UINT64_MAX - 2, UINT32_MAX - 3, |
1967 | PtrAuthData: std::nullopt, Flags, ExtraData); |
1968 | EXPECT_EQ(UINT64_MAX, N->getSizeInBits()); |
1969 | EXPECT_EQ(UINT32_MAX - 1, N->getAlignInBits()); |
1970 | EXPECT_EQ(UINT64_MAX - 2, N->getOffsetInBits()); |
1971 | EXPECT_EQ(UINT32_MAX - 3, *N->getDWARFAddressSpace()); |
1972 | |
1973 | auto *N1 = DIDerivedType::get( |
1974 | Context, Tag: dwarf::DW_TAG_LLVM_ptrauth_type, Name: "" , File, Line: 1, Scope, BaseType: N, |
1975 | UINT64_MAX, UINT32_MAX - 1, UINT64_MAX - 2, UINT32_MAX - 3, |
1976 | PtrAuthData: DIDerivedType::PtrAuthData(7, true, 0xffff, true, false), Flags, |
1977 | ExtraData); |
1978 | EXPECT_EQ(7U, N1->getPtrAuthData()->key()); |
1979 | EXPECT_EQ(true, N1->getPtrAuthData()->isAddressDiscriminated()); |
1980 | EXPECT_EQ(0xffffU, N1->getPtrAuthData()->extraDiscriminator()); |
1981 | } |
1982 | |
1983 | typedef MetadataTest DICompositeTypeTest; |
1984 | |
1985 | TEST_F(DICompositeTypeTest, get) { |
1986 | unsigned Tag = dwarf::DW_TAG_structure_type; |
1987 | StringRef Name = "some name" ; |
1988 | DIFile *File = getFile(); |
1989 | unsigned Line = 1; |
1990 | DIScope *Scope = getSubprogram(); |
1991 | DIType *BaseType = getCompositeType(); |
1992 | uint64_t SizeInBits = 2; |
1993 | uint32_t AlignInBits = 3; |
1994 | uint64_t OffsetInBits = 4; |
1995 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(5); |
1996 | MDTuple *Elements = getTuple(); |
1997 | unsigned RuntimeLang = 6; |
1998 | DIType *VTableHolder = getCompositeType(); |
1999 | MDTuple *TemplateParams = getTuple(); |
2000 | StringRef Identifier = "some id" ; |
2001 | |
2002 | auto *N = DICompositeType::get(Context, Tag, Name, File, Line, Scope, |
2003 | BaseType, SizeInBits, AlignInBits, |
2004 | OffsetInBits, Flags, Elements, RuntimeLang, |
2005 | VTableHolder, TemplateParams, Identifier); |
2006 | EXPECT_EQ(Tag, N->getTag()); |
2007 | EXPECT_EQ(Name, N->getName()); |
2008 | EXPECT_EQ(File, N->getFile()); |
2009 | EXPECT_EQ(Line, N->getLine()); |
2010 | EXPECT_EQ(Scope, N->getScope()); |
2011 | EXPECT_EQ(BaseType, N->getBaseType()); |
2012 | EXPECT_EQ(SizeInBits, N->getSizeInBits()); |
2013 | EXPECT_EQ(AlignInBits, N->getAlignInBits()); |
2014 | EXPECT_EQ(OffsetInBits, N->getOffsetInBits()); |
2015 | EXPECT_EQ(Flags, N->getFlags()); |
2016 | EXPECT_EQ(Elements, N->getElements().get()); |
2017 | EXPECT_EQ(RuntimeLang, N->getRuntimeLang()); |
2018 | EXPECT_EQ(VTableHolder, N->getVTableHolder()); |
2019 | EXPECT_EQ(TemplateParams, N->getTemplateParams().get()); |
2020 | EXPECT_EQ(Identifier, N->getIdentifier()); |
2021 | |
2022 | EXPECT_EQ(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, |
2023 | BaseType, SizeInBits, AlignInBits, |
2024 | OffsetInBits, Flags, Elements, RuntimeLang, |
2025 | VTableHolder, TemplateParams, Identifier)); |
2026 | |
2027 | EXPECT_NE(N, DICompositeType::get(Context, Tag + 1, Name, File, Line, Scope, |
2028 | BaseType, SizeInBits, AlignInBits, |
2029 | OffsetInBits, Flags, Elements, RuntimeLang, |
2030 | VTableHolder, TemplateParams, Identifier)); |
2031 | EXPECT_NE(N, DICompositeType::get(Context, Tag, "abc" , File, Line, Scope, |
2032 | BaseType, SizeInBits, AlignInBits, |
2033 | OffsetInBits, Flags, Elements, RuntimeLang, |
2034 | VTableHolder, TemplateParams, Identifier)); |
2035 | EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, getFile(), Line, Scope, |
2036 | BaseType, SizeInBits, AlignInBits, |
2037 | OffsetInBits, Flags, Elements, RuntimeLang, |
2038 | VTableHolder, TemplateParams, Identifier)); |
2039 | EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line + 1, Scope, |
2040 | BaseType, SizeInBits, AlignInBits, |
2041 | OffsetInBits, Flags, Elements, RuntimeLang, |
2042 | VTableHolder, TemplateParams, Identifier)); |
2043 | EXPECT_NE(N, DICompositeType::get( |
2044 | Context, Tag, Name, File, Line, getSubprogram(), BaseType, |
2045 | SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, |
2046 | RuntimeLang, VTableHolder, TemplateParams, Identifier)); |
2047 | EXPECT_NE(N, DICompositeType::get( |
2048 | Context, Tag, Name, File, Line, Scope, getBasicType("other" ), |
2049 | SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, |
2050 | RuntimeLang, VTableHolder, TemplateParams, Identifier)); |
2051 | EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, |
2052 | BaseType, SizeInBits + 1, AlignInBits, |
2053 | OffsetInBits, Flags, Elements, RuntimeLang, |
2054 | VTableHolder, TemplateParams, Identifier)); |
2055 | EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, |
2056 | BaseType, SizeInBits, AlignInBits + 1, |
2057 | OffsetInBits, Flags, Elements, RuntimeLang, |
2058 | VTableHolder, TemplateParams, Identifier)); |
2059 | EXPECT_NE(N, DICompositeType::get( |
2060 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, |
2061 | AlignInBits, OffsetInBits + 1, Flags, Elements, RuntimeLang, |
2062 | VTableHolder, TemplateParams, Identifier)); |
2063 | DINode::DIFlags FlagsPOne = static_cast<DINode::DIFlags>(Flags + 1); |
2064 | EXPECT_NE(N, DICompositeType::get( |
2065 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, |
2066 | AlignInBits, OffsetInBits, FlagsPOne, Elements, RuntimeLang, |
2067 | VTableHolder, TemplateParams, Identifier)); |
2068 | EXPECT_NE(N, DICompositeType::get( |
2069 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, |
2070 | AlignInBits, OffsetInBits, Flags, getTuple(), RuntimeLang, |
2071 | VTableHolder, TemplateParams, Identifier)); |
2072 | EXPECT_NE(N, DICompositeType::get( |
2073 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, |
2074 | AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang + 1, |
2075 | VTableHolder, TemplateParams, Identifier)); |
2076 | EXPECT_NE(N, DICompositeType::get( |
2077 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, |
2078 | AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, |
2079 | getCompositeType(), TemplateParams, Identifier)); |
2080 | EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, |
2081 | BaseType, SizeInBits, AlignInBits, |
2082 | OffsetInBits, Flags, Elements, RuntimeLang, |
2083 | VTableHolder, getTuple(), Identifier)); |
2084 | EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, |
2085 | BaseType, SizeInBits, AlignInBits, |
2086 | OffsetInBits, Flags, Elements, RuntimeLang, |
2087 | VTableHolder, TemplateParams, "other" )); |
2088 | |
2089 | // Be sure that missing identifiers get null pointers. |
2090 | EXPECT_FALSE(DICompositeType::get(Context, Tag, Name, File, Line, Scope, |
2091 | BaseType, SizeInBits, AlignInBits, |
2092 | OffsetInBits, Flags, Elements, RuntimeLang, |
2093 | VTableHolder, TemplateParams, "" ) |
2094 | ->getRawIdentifier()); |
2095 | EXPECT_FALSE(DICompositeType::get(Context, Tag, Name, File, Line, Scope, |
2096 | BaseType, SizeInBits, AlignInBits, |
2097 | OffsetInBits, Flags, Elements, RuntimeLang, |
2098 | VTableHolder, TemplateParams) |
2099 | ->getRawIdentifier()); |
2100 | |
2101 | TempDICompositeType Temp = N->clone(); |
2102 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
2103 | } |
2104 | |
2105 | TEST_F(DICompositeTypeTest, getWithLargeValues) { |
2106 | unsigned Tag = dwarf::DW_TAG_structure_type; |
2107 | StringRef Name = "some name" ; |
2108 | DIFile *File = getFile(); |
2109 | unsigned Line = 1; |
2110 | DIScope *Scope = getSubprogram(); |
2111 | DIType *BaseType = getCompositeType(); |
2112 | uint64_t SizeInBits = UINT64_MAX; |
2113 | uint32_t AlignInBits = UINT32_MAX - 1; |
2114 | uint64_t OffsetInBits = UINT64_MAX - 2; |
2115 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(5); |
2116 | MDTuple *Elements = getTuple(); |
2117 | unsigned RuntimeLang = 6; |
2118 | DIType *VTableHolder = getCompositeType(); |
2119 | MDTuple *TemplateParams = getTuple(); |
2120 | StringRef Identifier = "some id" ; |
2121 | |
2122 | auto *N = DICompositeType::get(Context, Tag, Name, File, Line, Scope, |
2123 | BaseType, SizeInBits, AlignInBits, |
2124 | OffsetInBits, Flags, Elements, RuntimeLang, |
2125 | VTableHolder, TemplateParams, Identifier); |
2126 | EXPECT_EQ(SizeInBits, N->getSizeInBits()); |
2127 | EXPECT_EQ(AlignInBits, N->getAlignInBits()); |
2128 | EXPECT_EQ(OffsetInBits, N->getOffsetInBits()); |
2129 | } |
2130 | |
2131 | TEST_F(DICompositeTypeTest, replaceOperands) { |
2132 | unsigned Tag = dwarf::DW_TAG_structure_type; |
2133 | StringRef Name = "some name" ; |
2134 | DIFile *File = getFile(); |
2135 | unsigned Line = 1; |
2136 | DIScope *Scope = getSubprogram(); |
2137 | DIType *BaseType = getCompositeType(); |
2138 | uint64_t SizeInBits = 2; |
2139 | uint32_t AlignInBits = 3; |
2140 | uint64_t OffsetInBits = 4; |
2141 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(5); |
2142 | unsigned RuntimeLang = 6; |
2143 | StringRef Identifier = "some id" ; |
2144 | |
2145 | auto *N = DICompositeType::get( |
2146 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2147 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier); |
2148 | |
2149 | auto *Elements = MDTuple::getDistinct(Context, MDs: std::nullopt); |
2150 | EXPECT_EQ(nullptr, N->getElements().get()); |
2151 | N->replaceElements(Elements); |
2152 | EXPECT_EQ(Elements, N->getElements().get()); |
2153 | N->replaceElements(Elements: nullptr); |
2154 | EXPECT_EQ(nullptr, N->getElements().get()); |
2155 | |
2156 | DIType *VTableHolder = getCompositeType(); |
2157 | EXPECT_EQ(nullptr, N->getVTableHolder()); |
2158 | N->replaceVTableHolder(VTableHolder); |
2159 | EXPECT_EQ(VTableHolder, N->getVTableHolder()); |
2160 | // As an extension, the containing type can be anything. This is |
2161 | // used by Rust to associate vtables with their concrete type. |
2162 | DIType *BasicType = getBasicType(Name: "basic" ); |
2163 | N->replaceVTableHolder(VTableHolder: BasicType); |
2164 | EXPECT_EQ(BasicType, N->getVTableHolder()); |
2165 | N->replaceVTableHolder(VTableHolder: nullptr); |
2166 | EXPECT_EQ(nullptr, N->getVTableHolder()); |
2167 | |
2168 | auto *TemplateParams = MDTuple::getDistinct(Context, MDs: std::nullopt); |
2169 | EXPECT_EQ(nullptr, N->getTemplateParams().get()); |
2170 | N->replaceTemplateParams(TemplateParams); |
2171 | EXPECT_EQ(TemplateParams, N->getTemplateParams().get()); |
2172 | N->replaceTemplateParams(TemplateParams: nullptr); |
2173 | EXPECT_EQ(nullptr, N->getTemplateParams().get()); |
2174 | } |
2175 | |
2176 | TEST_F(DICompositeTypeTest, variant_part) { |
2177 | unsigned Tag = dwarf::DW_TAG_variant_part; |
2178 | StringRef Name = "some name" ; |
2179 | DIFile *File = getFile(); |
2180 | unsigned Line = 1; |
2181 | DIScope *Scope = getSubprogram(); |
2182 | DIType *BaseType = getCompositeType(); |
2183 | uint64_t SizeInBits = 2; |
2184 | uint32_t AlignInBits = 3; |
2185 | uint64_t OffsetInBits = 4; |
2186 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(5); |
2187 | unsigned RuntimeLang = 6; |
2188 | StringRef Identifier = "some id" ; |
2189 | DIDerivedType *Discriminator = cast<DIDerivedType>(Val: getDerivedType()); |
2190 | DIDerivedType *Discriminator2 = cast<DIDerivedType>(Val: getDerivedType()); |
2191 | |
2192 | EXPECT_NE(Discriminator, Discriminator2); |
2193 | |
2194 | auto *N = DICompositeType::get( |
2195 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2196 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2197 | Discriminator); |
2198 | |
2199 | // Test the hashing. |
2200 | auto *Same = DICompositeType::get( |
2201 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2202 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2203 | Discriminator); |
2204 | auto *Other = DICompositeType::get( |
2205 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2206 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2207 | Discriminator: Discriminator2); |
2208 | auto *NoDisc = DICompositeType::get( |
2209 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2210 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2211 | Discriminator: nullptr); |
2212 | |
2213 | EXPECT_EQ(N, Same); |
2214 | EXPECT_NE(Same, Other); |
2215 | EXPECT_NE(Same, NoDisc); |
2216 | EXPECT_NE(Other, NoDisc); |
2217 | |
2218 | EXPECT_EQ(N->getDiscriminator(), Discriminator); |
2219 | } |
2220 | |
2221 | TEST_F(DICompositeTypeTest, dynamicArray) { |
2222 | unsigned Tag = dwarf::DW_TAG_array_type; |
2223 | StringRef Name = "some name" ; |
2224 | DIFile *File = getFile(); |
2225 | unsigned Line = 1; |
2226 | DILocalScope *Scope = getSubprogram(); |
2227 | DIType *BaseType = getCompositeType(); |
2228 | uint64_t SizeInBits = 32; |
2229 | uint32_t AlignInBits = 32; |
2230 | uint64_t OffsetInBits = 4; |
2231 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(3); |
2232 | unsigned RuntimeLang = 6; |
2233 | StringRef Identifier = "some id" ; |
2234 | DIType *Type = getDerivedType(); |
2235 | Metadata *DlVar1 = DILocalVariable::get(Context, Scope, Name: "dl_var1" , File, Line: 8, |
2236 | Type, Arg: 2, Flags, AlignInBits: 8, Annotations: nullptr); |
2237 | Metadata *DlVar2 = DILocalVariable::get(Context, Scope, Name: "dl_var2" , File, Line: 8, |
2238 | Type, Arg: 2, Flags, AlignInBits: 8, Annotations: nullptr); |
2239 | uint64_t Elements1[] = {dwarf::DW_OP_push_object_address, dwarf::DW_OP_deref}; |
2240 | Metadata *DataLocation1 = DIExpression::get(Context, Elements: Elements1); |
2241 | |
2242 | uint64_t Elements2[] = {dwarf::DW_OP_constu, 0}; |
2243 | Metadata *DataLocation2 = DIExpression::get(Context, Elements: Elements2); |
2244 | |
2245 | uint64_t Elements3[] = {dwarf::DW_OP_constu, 3}; |
2246 | Metadata *Rank1 = DIExpression::get(Context, Elements: Elements3); |
2247 | |
2248 | uint64_t Elements4[] = {dwarf::DW_OP_constu, 4}; |
2249 | Metadata *Rank2 = DIExpression::get(Context, Elements: Elements4); |
2250 | |
2251 | ConstantInt *RankInt1 = ConstantInt::get(Context, V: APInt(7, 0)); |
2252 | ConstantAsMetadata *RankConst1 = ConstantAsMetadata::get(C: RankInt1); |
2253 | ConstantInt *RankInt2 = ConstantInt::get(Context, V: APInt(6, 0)); |
2254 | ConstantAsMetadata *RankConst2 = ConstantAsMetadata::get(C: RankInt2); |
2255 | auto *N1 = DICompositeType::get( |
2256 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2257 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2258 | Discriminator: nullptr, DataLocation: DlVar1); |
2259 | |
2260 | auto *Same1 = DICompositeType::get( |
2261 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2262 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2263 | Discriminator: nullptr, DataLocation: DlVar1); |
2264 | |
2265 | auto *Other1 = DICompositeType::get( |
2266 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2267 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2268 | Discriminator: nullptr, DataLocation: DlVar2); |
2269 | |
2270 | EXPECT_EQ(N1, Same1); |
2271 | EXPECT_NE(Same1, Other1); |
2272 | EXPECT_EQ(N1->getDataLocation(), DlVar1); |
2273 | |
2274 | auto *N2 = DICompositeType::get( |
2275 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2276 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2277 | Discriminator: nullptr, DataLocation: DataLocation1); |
2278 | |
2279 | auto *Same2 = DICompositeType::get( |
2280 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2281 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2282 | Discriminator: nullptr, DataLocation: DataLocation1); |
2283 | |
2284 | auto *Other2 = DICompositeType::get( |
2285 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2286 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2287 | Discriminator: nullptr, DataLocation: DataLocation2); |
2288 | |
2289 | EXPECT_EQ(N2, Same2); |
2290 | EXPECT_NE(Same2, Other2); |
2291 | EXPECT_EQ(N2->getDataLocationExp(), DataLocation1); |
2292 | |
2293 | auto *N3 = DICompositeType::get( |
2294 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2295 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2296 | Discriminator: nullptr, DataLocation: DataLocation1, Associated: nullptr, Allocated: nullptr, Rank: Rank1); |
2297 | |
2298 | auto *Same3 = DICompositeType::get( |
2299 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2300 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2301 | Discriminator: nullptr, DataLocation: DataLocation1, Associated: nullptr, Allocated: nullptr, Rank: Rank1); |
2302 | |
2303 | auto *Other3 = DICompositeType::get( |
2304 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2305 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2306 | Discriminator: nullptr, DataLocation: DataLocation1, Associated: nullptr, Allocated: nullptr, Rank: Rank2); |
2307 | |
2308 | EXPECT_EQ(N3, Same3); |
2309 | EXPECT_NE(Same3, Other3); |
2310 | EXPECT_EQ(N3->getRankExp(), Rank1); |
2311 | |
2312 | auto *N4 = DICompositeType::get( |
2313 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2314 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2315 | Discriminator: nullptr, DataLocation: DataLocation1, Associated: nullptr, Allocated: nullptr, Rank: RankConst1); |
2316 | |
2317 | auto *Same4 = DICompositeType::get( |
2318 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2319 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2320 | Discriminator: nullptr, DataLocation: DataLocation1, Associated: nullptr, Allocated: nullptr, Rank: RankConst1); |
2321 | |
2322 | auto *Other4 = DICompositeType::get( |
2323 | Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, |
2324 | OffsetInBits, Flags, Elements: nullptr, RuntimeLang, VTableHolder: nullptr, TemplateParams: nullptr, Identifier, |
2325 | Discriminator: nullptr, DataLocation: DataLocation1, Associated: nullptr, Allocated: nullptr, Rank: RankConst2); |
2326 | |
2327 | EXPECT_EQ(N4, Same4); |
2328 | EXPECT_NE(Same4, Other4); |
2329 | EXPECT_EQ(N4->getRankConst(), RankInt1); |
2330 | } |
2331 | |
2332 | typedef MetadataTest DISubroutineTypeTest; |
2333 | |
2334 | TEST_F(DISubroutineTypeTest, get) { |
2335 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(1); |
2336 | DINode::DIFlags FlagsPOne = static_cast<DINode::DIFlags>(Flags + 1); |
2337 | MDTuple *TypeArray = getTuple(); |
2338 | |
2339 | auto *N = DISubroutineType::get(Context, Flags, CC: 0, TypeArray); |
2340 | EXPECT_EQ(dwarf::DW_TAG_subroutine_type, N->getTag()); |
2341 | EXPECT_EQ(Flags, N->getFlags()); |
2342 | EXPECT_EQ(TypeArray, N->getTypeArray().get()); |
2343 | EXPECT_EQ(N, DISubroutineType::get(Context, Flags, 0, TypeArray)); |
2344 | |
2345 | EXPECT_NE(N, DISubroutineType::get(Context, FlagsPOne, 0, TypeArray)); |
2346 | EXPECT_NE(N, DISubroutineType::get(Context, Flags, 0, getTuple())); |
2347 | |
2348 | // Test the hashing of calling conventions. |
2349 | auto *Fast = DISubroutineType::get( |
2350 | Context, Flags, CC: dwarf::DW_CC_BORLAND_msfastcall, TypeArray); |
2351 | auto *Std = DISubroutineType::get(Context, Flags, |
2352 | CC: dwarf::DW_CC_BORLAND_stdcall, TypeArray); |
2353 | EXPECT_EQ(Fast, |
2354 | DISubroutineType::get(Context, Flags, |
2355 | dwarf::DW_CC_BORLAND_msfastcall, TypeArray)); |
2356 | EXPECT_EQ(Std, DISubroutineType::get( |
2357 | Context, Flags, dwarf::DW_CC_BORLAND_stdcall, TypeArray)); |
2358 | |
2359 | EXPECT_NE(N, Fast); |
2360 | EXPECT_NE(N, Std); |
2361 | EXPECT_NE(Fast, Std); |
2362 | |
2363 | TempDISubroutineType Temp = N->clone(); |
2364 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
2365 | |
2366 | // Test always-empty operands. |
2367 | EXPECT_EQ(nullptr, N->getScope()); |
2368 | EXPECT_EQ(nullptr, N->getFile()); |
2369 | EXPECT_EQ("" , N->getName()); |
2370 | } |
2371 | |
2372 | typedef MetadataTest DIFileTest; |
2373 | |
2374 | TEST_F(DIFileTest, get) { |
2375 | StringRef Filename = "file" ; |
2376 | StringRef Directory = "dir" ; |
2377 | DIFile::ChecksumKind CSKind = DIFile::ChecksumKind::CSK_MD5; |
2378 | StringRef ChecksumString = "000102030405060708090a0b0c0d0e0f" ; |
2379 | DIFile::ChecksumInfo<StringRef> Checksum(CSKind, ChecksumString); |
2380 | StringRef Source = "source" ; |
2381 | auto *N = DIFile::get(Context, Filename, Directory, CS: Checksum, Source); |
2382 | |
2383 | EXPECT_EQ(dwarf::DW_TAG_file_type, N->getTag()); |
2384 | EXPECT_EQ(Filename, N->getFilename()); |
2385 | EXPECT_EQ(Directory, N->getDirectory()); |
2386 | EXPECT_EQ(Checksum, N->getChecksum()); |
2387 | EXPECT_EQ(Source, N->getSource()); |
2388 | EXPECT_EQ(N, DIFile::get(Context, Filename, Directory, Checksum, Source)); |
2389 | |
2390 | EXPECT_NE(N, DIFile::get(Context, "other" , Directory, Checksum, Source)); |
2391 | EXPECT_NE(N, DIFile::get(Context, Filename, "other" , Checksum, Source)); |
2392 | DIFile::ChecksumInfo<StringRef> OtherChecksum(DIFile::ChecksumKind::CSK_SHA1, ChecksumString); |
2393 | EXPECT_NE( |
2394 | N, DIFile::get(Context, Filename, Directory, OtherChecksum)); |
2395 | StringRef OtherSource = "other" ; |
2396 | EXPECT_NE(N, DIFile::get(Context, Filename, Directory, Checksum, OtherSource)); |
2397 | EXPECT_NE(N, DIFile::get(Context, Filename, Directory, Checksum)); |
2398 | EXPECT_NE(N, DIFile::get(Context, Filename, Directory)); |
2399 | |
2400 | TempDIFile Temp = N->clone(); |
2401 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
2402 | } |
2403 | |
2404 | TEST_F(DIFileTest, EmptySource) { |
2405 | DIFile *N = DIFile::get(Context, Filename: "file" , Directory: "dir" ); |
2406 | EXPECT_EQ(std::nullopt, N->getSource()); |
2407 | |
2408 | std::optional<DIFile::ChecksumInfo<StringRef>> Checksum; |
2409 | std::optional<StringRef> Source; |
2410 | N = DIFile::get(Context, Filename: "file" , Directory: "dir" , CS: Checksum, Source); |
2411 | EXPECT_EQ(Source, N->getSource()); |
2412 | |
2413 | Source = "" ; |
2414 | N = DIFile::get(Context, Filename: "file" , Directory: "dir" , CS: Checksum, Source); |
2415 | EXPECT_EQ(Source, N->getSource()); |
2416 | } |
2417 | |
2418 | TEST_F(DIFileTest, ScopeGetFile) { |
2419 | // Ensure that DIScope::getFile() returns itself. |
2420 | DIScope *N = DIFile::get(Context, Filename: "file" , Directory: "dir" ); |
2421 | EXPECT_EQ(N, N->getFile()); |
2422 | } |
2423 | |
2424 | typedef MetadataTest DICompileUnitTest; |
2425 | |
2426 | TEST_F(DICompileUnitTest, get) { |
2427 | unsigned SourceLanguage = 1; |
2428 | DIFile *File = getFile(); |
2429 | StringRef Producer = "some producer" ; |
2430 | bool IsOptimized = false; |
2431 | StringRef Flags = "flag after flag" ; |
2432 | unsigned RuntimeVersion = 2; |
2433 | StringRef SplitDebugFilename = "another/file" ; |
2434 | auto EmissionKind = DICompileUnit::FullDebug; |
2435 | MDTuple *EnumTypes = getTuple(); |
2436 | MDTuple *RetainedTypes = getTuple(); |
2437 | MDTuple *GlobalVariables = getTuple(); |
2438 | MDTuple *ImportedEntities = getTuple(); |
2439 | uint64_t DWOId = 0x10000000c0ffee; |
2440 | MDTuple *Macros = getTuple(); |
2441 | StringRef SysRoot = "/" ; |
2442 | StringRef SDK = "MacOSX.sdk" ; |
2443 | auto *N = DICompileUnit::getDistinct( |
2444 | Context, SourceLanguage, File, Producer, IsOptimized, Flags, |
2445 | RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, |
2446 | RetainedTypes, GlobalVariables, ImportedEntities, Macros, DWOId, SplitDebugInlining: true, |
2447 | DebugInfoForProfiling: false, NameTableKind: DICompileUnit::DebugNameTableKind::Default, RangesBaseAddress: false, SysRoot, SDK); |
2448 | |
2449 | EXPECT_EQ(dwarf::DW_TAG_compile_unit, N->getTag()); |
2450 | EXPECT_EQ(SourceLanguage, N->getSourceLanguage()); |
2451 | EXPECT_EQ(File, N->getFile()); |
2452 | EXPECT_EQ(Producer, N->getProducer()); |
2453 | EXPECT_EQ(IsOptimized, N->isOptimized()); |
2454 | EXPECT_EQ(Flags, N->getFlags()); |
2455 | EXPECT_EQ(RuntimeVersion, N->getRuntimeVersion()); |
2456 | EXPECT_EQ(SplitDebugFilename, N->getSplitDebugFilename()); |
2457 | EXPECT_EQ(EmissionKind, N->getEmissionKind()); |
2458 | EXPECT_EQ(EnumTypes, N->getEnumTypes().get()); |
2459 | EXPECT_EQ(RetainedTypes, N->getRetainedTypes().get()); |
2460 | EXPECT_EQ(GlobalVariables, N->getGlobalVariables().get()); |
2461 | EXPECT_EQ(ImportedEntities, N->getImportedEntities().get()); |
2462 | EXPECT_EQ(Macros, N->getMacros().get()); |
2463 | EXPECT_EQ(DWOId, N->getDWOId()); |
2464 | EXPECT_EQ(SysRoot, N->getSysRoot()); |
2465 | EXPECT_EQ(SDK, N->getSDK()); |
2466 | |
2467 | TempDICompileUnit Temp = N->clone(); |
2468 | EXPECT_EQ(dwarf::DW_TAG_compile_unit, Temp->getTag()); |
2469 | EXPECT_EQ(SourceLanguage, Temp->getSourceLanguage()); |
2470 | EXPECT_EQ(File, Temp->getFile()); |
2471 | EXPECT_EQ(Producer, Temp->getProducer()); |
2472 | EXPECT_EQ(IsOptimized, Temp->isOptimized()); |
2473 | EXPECT_EQ(Flags, Temp->getFlags()); |
2474 | EXPECT_EQ(RuntimeVersion, Temp->getRuntimeVersion()); |
2475 | EXPECT_EQ(SplitDebugFilename, Temp->getSplitDebugFilename()); |
2476 | EXPECT_EQ(EmissionKind, Temp->getEmissionKind()); |
2477 | EXPECT_EQ(EnumTypes, Temp->getEnumTypes().get()); |
2478 | EXPECT_EQ(RetainedTypes, Temp->getRetainedTypes().get()); |
2479 | EXPECT_EQ(GlobalVariables, Temp->getGlobalVariables().get()); |
2480 | EXPECT_EQ(ImportedEntities, Temp->getImportedEntities().get()); |
2481 | EXPECT_EQ(Macros, Temp->getMacros().get()); |
2482 | EXPECT_EQ(SysRoot, Temp->getSysRoot()); |
2483 | EXPECT_EQ(SDK, Temp->getSDK()); |
2484 | |
2485 | auto *TempAddress = Temp.get(); |
2486 | auto *Clone = MDNode::replaceWithPermanent(N: std::move(Temp)); |
2487 | EXPECT_TRUE(Clone->isDistinct()); |
2488 | EXPECT_EQ(TempAddress, Clone); |
2489 | } |
2490 | |
2491 | TEST_F(DICompileUnitTest, replaceArrays) { |
2492 | unsigned SourceLanguage = 1; |
2493 | DIFile *File = getFile(); |
2494 | StringRef Producer = "some producer" ; |
2495 | bool IsOptimized = false; |
2496 | StringRef Flags = "flag after flag" ; |
2497 | unsigned RuntimeVersion = 2; |
2498 | StringRef SplitDebugFilename = "another/file" ; |
2499 | auto EmissionKind = DICompileUnit::FullDebug; |
2500 | MDTuple *EnumTypes = MDTuple::getDistinct(Context, MDs: std::nullopt); |
2501 | MDTuple *RetainedTypes = MDTuple::getDistinct(Context, MDs: std::nullopt); |
2502 | MDTuple *ImportedEntities = MDTuple::getDistinct(Context, MDs: std::nullopt); |
2503 | uint64_t DWOId = 0xc0ffee; |
2504 | StringRef SysRoot = "/" ; |
2505 | StringRef SDK = "MacOSX.sdk" ; |
2506 | auto *N = DICompileUnit::getDistinct( |
2507 | Context, SourceLanguage, File, Producer, IsOptimized, Flags, |
2508 | RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, |
2509 | RetainedTypes, GlobalVariables: nullptr, ImportedEntities, Macros: nullptr, DWOId, SplitDebugInlining: true, DebugInfoForProfiling: false, |
2510 | NameTableKind: DICompileUnit::DebugNameTableKind::Default, RangesBaseAddress: false, SysRoot, SDK); |
2511 | |
2512 | auto *GlobalVariables = MDTuple::getDistinct(Context, MDs: std::nullopt); |
2513 | EXPECT_EQ(nullptr, N->getGlobalVariables().get()); |
2514 | N->replaceGlobalVariables(N: GlobalVariables); |
2515 | EXPECT_EQ(GlobalVariables, N->getGlobalVariables().get()); |
2516 | N->replaceGlobalVariables(N: nullptr); |
2517 | EXPECT_EQ(nullptr, N->getGlobalVariables().get()); |
2518 | |
2519 | auto *Macros = MDTuple::getDistinct(Context, MDs: std::nullopt); |
2520 | EXPECT_EQ(nullptr, N->getMacros().get()); |
2521 | N->replaceMacros(N: Macros); |
2522 | EXPECT_EQ(Macros, N->getMacros().get()); |
2523 | N->replaceMacros(N: nullptr); |
2524 | EXPECT_EQ(nullptr, N->getMacros().get()); |
2525 | } |
2526 | |
2527 | typedef MetadataTest DISubprogramTest; |
2528 | |
2529 | TEST_F(DISubprogramTest, get) { |
2530 | DIScope *Scope = getCompositeType(); |
2531 | StringRef Name = "name" ; |
2532 | StringRef LinkageName = "linkage" ; |
2533 | DIFile *File = getFile(); |
2534 | unsigned Line = 2; |
2535 | DISubroutineType *Type = getSubroutineType(); |
2536 | bool IsLocalToUnit = false; |
2537 | bool IsDefinition = true; |
2538 | unsigned ScopeLine = 3; |
2539 | DIType *ContainingType = getCompositeType(); |
2540 | unsigned Virtuality = 2; |
2541 | unsigned VirtualIndex = 5; |
2542 | int ThisAdjustment = -3; |
2543 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(6); |
2544 | bool IsOptimized = false; |
2545 | MDTuple *TemplateParams = getTuple(); |
2546 | DISubprogram *Declaration = getSubprogram(); |
2547 | MDTuple *RetainedNodes = getTuple(); |
2548 | MDTuple *ThrownTypes = getTuple(); |
2549 | MDTuple *Annotations = getTuple(); |
2550 | StringRef TargetFuncName = "target" ; |
2551 | DICompileUnit *Unit = getUnit(); |
2552 | DISubprogram::DISPFlags SPFlags = |
2553 | static_cast<DISubprogram::DISPFlags>(Virtuality); |
2554 | assert(!IsLocalToUnit && IsDefinition && !IsOptimized && |
2555 | "bools and SPFlags have to match" ); |
2556 | SPFlags |= DISubprogram::SPFlagDefinition; |
2557 | |
2558 | auto *N = DISubprogram::get( |
2559 | Context, Scope, Name, LinkageName, File, Line, Type, ScopeLine, |
2560 | ContainingType, VirtualIndex, ThisAdjustment, Flags, SPFlags, Unit, |
2561 | TemplateParams, Declaration, RetainedNodes, ThrownTypes, Annotations, |
2562 | TargetFuncName); |
2563 | |
2564 | EXPECT_EQ(dwarf::DW_TAG_subprogram, N->getTag()); |
2565 | EXPECT_EQ(Scope, N->getScope()); |
2566 | EXPECT_EQ(Name, N->getName()); |
2567 | EXPECT_EQ(LinkageName, N->getLinkageName()); |
2568 | EXPECT_EQ(File, N->getFile()); |
2569 | EXPECT_EQ(Line, N->getLine()); |
2570 | EXPECT_EQ(Type, N->getType()); |
2571 | EXPECT_EQ(IsLocalToUnit, N->isLocalToUnit()); |
2572 | EXPECT_EQ(IsDefinition, N->isDefinition()); |
2573 | EXPECT_EQ(ScopeLine, N->getScopeLine()); |
2574 | EXPECT_EQ(ContainingType, N->getContainingType()); |
2575 | EXPECT_EQ(Virtuality, N->getVirtuality()); |
2576 | EXPECT_EQ(VirtualIndex, N->getVirtualIndex()); |
2577 | EXPECT_EQ(ThisAdjustment, N->getThisAdjustment()); |
2578 | EXPECT_EQ(Flags, N->getFlags()); |
2579 | EXPECT_EQ(IsOptimized, N->isOptimized()); |
2580 | EXPECT_EQ(Unit, N->getUnit()); |
2581 | EXPECT_EQ(TemplateParams, N->getTemplateParams().get()); |
2582 | EXPECT_EQ(Declaration, N->getDeclaration()); |
2583 | EXPECT_EQ(RetainedNodes, N->getRetainedNodes().get()); |
2584 | EXPECT_EQ(ThrownTypes, N->getThrownTypes().get()); |
2585 | EXPECT_EQ(Annotations, N->getAnnotations().get()); |
2586 | EXPECT_EQ(TargetFuncName, N->getTargetFuncName()); |
2587 | EXPECT_EQ(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, |
2588 | Type, ScopeLine, ContainingType, VirtualIndex, |
2589 | ThisAdjustment, Flags, SPFlags, Unit, |
2590 | TemplateParams, Declaration, RetainedNodes, |
2591 | ThrownTypes, Annotations, TargetFuncName)); |
2592 | |
2593 | EXPECT_NE(N, DISubprogram::get(Context, getCompositeType(), Name, LinkageName, |
2594 | File, Line, Type, ScopeLine, ContainingType, |
2595 | VirtualIndex, ThisAdjustment, Flags, SPFlags, |
2596 | Unit, TemplateParams, Declaration, |
2597 | RetainedNodes, ThrownTypes, Annotations, |
2598 | TargetFuncName)); |
2599 | EXPECT_NE(N, DISubprogram::get(Context, Scope, "other" , LinkageName, File, |
2600 | Line, Type, ScopeLine, ContainingType, |
2601 | VirtualIndex, ThisAdjustment, Flags, SPFlags, |
2602 | Unit, TemplateParams, Declaration, |
2603 | RetainedNodes, ThrownTypes, Annotations, |
2604 | TargetFuncName)); |
2605 | EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, "other" , File, Line, |
2606 | Type, ScopeLine, ContainingType, VirtualIndex, |
2607 | ThisAdjustment, Flags, SPFlags, Unit, |
2608 | TemplateParams, Declaration, RetainedNodes, |
2609 | ThrownTypes, Annotations, TargetFuncName)); |
2610 | EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, getFile(), |
2611 | Line, Type, ScopeLine, ContainingType, |
2612 | VirtualIndex, ThisAdjustment, Flags, SPFlags, |
2613 | Unit, TemplateParams, Declaration, |
2614 | RetainedNodes, ThrownTypes, Annotations, |
2615 | TargetFuncName)); |
2616 | EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, |
2617 | Line + 1, Type, ScopeLine, ContainingType, |
2618 | VirtualIndex, ThisAdjustment, Flags, SPFlags, |
2619 | Unit, TemplateParams, Declaration, |
2620 | RetainedNodes, ThrownTypes, Annotations, |
2621 | TargetFuncName)); |
2622 | EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, |
2623 | getSubroutineType(), ScopeLine, ContainingType, |
2624 | VirtualIndex, ThisAdjustment, Flags, SPFlags, |
2625 | Unit, TemplateParams, Declaration, |
2626 | RetainedNodes, ThrownTypes, Annotations, |
2627 | TargetFuncName)); |
2628 | EXPECT_NE(N, DISubprogram::get( |
2629 | Context, Scope, Name, LinkageName, File, Line, Type, |
2630 | ScopeLine, ContainingType, VirtualIndex, ThisAdjustment, |
2631 | Flags, SPFlags ^ DISubprogram::SPFlagLocalToUnit, Unit, |
2632 | TemplateParams, Declaration, RetainedNodes, ThrownTypes, |
2633 | Annotations, TargetFuncName)); |
2634 | EXPECT_NE(N, DISubprogram::get( |
2635 | Context, Scope, Name, LinkageName, File, Line, Type, |
2636 | ScopeLine, ContainingType, VirtualIndex, ThisAdjustment, |
2637 | Flags, SPFlags ^ DISubprogram::SPFlagDefinition, Unit, |
2638 | TemplateParams, Declaration, RetainedNodes, ThrownTypes, |
2639 | Annotations, TargetFuncName)); |
2640 | EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, |
2641 | Type, ScopeLine + 1, ContainingType, |
2642 | VirtualIndex, ThisAdjustment, Flags, SPFlags, |
2643 | Unit, TemplateParams, Declaration, |
2644 | RetainedNodes, ThrownTypes, Annotations, |
2645 | TargetFuncName)); |
2646 | EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, |
2647 | Type, ScopeLine, getCompositeType(), |
2648 | VirtualIndex, ThisAdjustment, Flags, SPFlags, |
2649 | Unit, TemplateParams, Declaration, |
2650 | RetainedNodes, ThrownTypes, Annotations, |
2651 | TargetFuncName)); |
2652 | EXPECT_NE(N, DISubprogram::get( |
2653 | Context, Scope, Name, LinkageName, File, Line, Type, |
2654 | ScopeLine, ContainingType, VirtualIndex, ThisAdjustment, |
2655 | Flags, SPFlags ^ DISubprogram::SPFlagVirtual, Unit, |
2656 | TemplateParams, Declaration, RetainedNodes, ThrownTypes, |
2657 | Annotations, TargetFuncName)); |
2658 | EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, |
2659 | Type, ScopeLine, ContainingType, |
2660 | VirtualIndex + 1, ThisAdjustment, Flags, |
2661 | SPFlags, Unit, TemplateParams, Declaration, |
2662 | RetainedNodes, ThrownTypes, Annotations, |
2663 | TargetFuncName)); |
2664 | EXPECT_NE(N, DISubprogram::get( |
2665 | Context, Scope, Name, LinkageName, File, Line, Type, |
2666 | ScopeLine, ContainingType, VirtualIndex, ThisAdjustment, |
2667 | Flags, SPFlags ^ DISubprogram::SPFlagOptimized, Unit, |
2668 | TemplateParams, Declaration, RetainedNodes, ThrownTypes, |
2669 | Annotations, TargetFuncName)); |
2670 | EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, |
2671 | Type, ScopeLine, ContainingType, VirtualIndex, |
2672 | ThisAdjustment, Flags, SPFlags, nullptr, |
2673 | TemplateParams, Declaration, RetainedNodes, |
2674 | ThrownTypes, Annotations, TargetFuncName)); |
2675 | EXPECT_NE(N, |
2676 | DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, |
2677 | Type, ScopeLine, ContainingType, VirtualIndex, |
2678 | ThisAdjustment, Flags, SPFlags, Unit, getTuple(), |
2679 | Declaration, RetainedNodes, ThrownTypes, |
2680 | Annotations, TargetFuncName)); |
2681 | EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, |
2682 | Type, ScopeLine, ContainingType, VirtualIndex, |
2683 | ThisAdjustment, Flags, SPFlags, Unit, |
2684 | TemplateParams, getSubprogram(), RetainedNodes, |
2685 | ThrownTypes, Annotations, TargetFuncName)); |
2686 | EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, |
2687 | Type, ScopeLine, ContainingType, VirtualIndex, |
2688 | ThisAdjustment, Flags, SPFlags, Unit, |
2689 | TemplateParams, Declaration, getTuple(), |
2690 | ThrownTypes, Annotations, TargetFuncName)); |
2691 | EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, |
2692 | Type, ScopeLine, ContainingType, VirtualIndex, |
2693 | ThisAdjustment, Flags, SPFlags, Unit, |
2694 | TemplateParams, Declaration, RetainedNodes, |
2695 | getTuple(), Annotations, TargetFuncName)); |
2696 | EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, |
2697 | Type, ScopeLine, ContainingType, VirtualIndex, |
2698 | ThisAdjustment, Flags, SPFlags, Unit, |
2699 | TemplateParams, Declaration, RetainedNodes, |
2700 | ThrownTypes, getTuple(), TargetFuncName)); |
2701 | EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, |
2702 | Type, ScopeLine, ContainingType, VirtualIndex, |
2703 | ThisAdjustment, Flags, SPFlags, Unit, |
2704 | TemplateParams, Declaration, RetainedNodes, |
2705 | ThrownTypes, Annotations, "other" )); |
2706 | |
2707 | TempDISubprogram Temp = N->clone(); |
2708 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
2709 | } |
2710 | |
2711 | typedef MetadataTest DILexicalBlockTest; |
2712 | |
2713 | TEST_F(DILexicalBlockTest, get) { |
2714 | DILocalScope *Scope = getSubprogram(); |
2715 | DIFile *File = getFile(); |
2716 | unsigned Line = 5; |
2717 | unsigned Column = 8; |
2718 | |
2719 | auto *N = DILexicalBlock::get(Context, Scope, File, Line, Column); |
2720 | |
2721 | EXPECT_EQ(dwarf::DW_TAG_lexical_block, N->getTag()); |
2722 | EXPECT_EQ(Scope, N->getScope()); |
2723 | EXPECT_EQ(File, N->getFile()); |
2724 | EXPECT_EQ(Line, N->getLine()); |
2725 | EXPECT_EQ(Column, N->getColumn()); |
2726 | EXPECT_EQ(N, DILexicalBlock::get(Context, Scope, File, Line, Column)); |
2727 | |
2728 | EXPECT_NE(N, |
2729 | DILexicalBlock::get(Context, getSubprogram(), File, Line, Column)); |
2730 | EXPECT_NE(N, DILexicalBlock::get(Context, Scope, getFile(), Line, Column)); |
2731 | EXPECT_NE(N, DILexicalBlock::get(Context, Scope, File, Line + 1, Column)); |
2732 | EXPECT_NE(N, DILexicalBlock::get(Context, Scope, File, Line, Column + 1)); |
2733 | |
2734 | TempDILexicalBlock Temp = N->clone(); |
2735 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
2736 | } |
2737 | |
2738 | TEST_F(DILexicalBlockTest, Overflow) { |
2739 | DISubprogram *SP = getSubprogram(); |
2740 | DIFile *F = getFile(); |
2741 | { |
2742 | auto *LB = DILexicalBlock::get(Context, Scope: SP, File: F, Line: 2, Column: 7); |
2743 | EXPECT_EQ(2u, LB->getLine()); |
2744 | EXPECT_EQ(7u, LB->getColumn()); |
2745 | } |
2746 | unsigned U16 = 1u << 16; |
2747 | { |
2748 | auto *LB = DILexicalBlock::get(Context, Scope: SP, File: F, UINT32_MAX, Column: U16 - 1); |
2749 | EXPECT_EQ(UINT32_MAX, LB->getLine()); |
2750 | EXPECT_EQ(U16 - 1, LB->getColumn()); |
2751 | } |
2752 | { |
2753 | auto *LB = DILexicalBlock::get(Context, Scope: SP, File: F, UINT32_MAX, Column: U16); |
2754 | EXPECT_EQ(UINT32_MAX, LB->getLine()); |
2755 | EXPECT_EQ(0u, LB->getColumn()); |
2756 | } |
2757 | { |
2758 | auto *LB = DILexicalBlock::get(Context, Scope: SP, File: F, UINT32_MAX, Column: U16 + 1); |
2759 | EXPECT_EQ(UINT32_MAX, LB->getLine()); |
2760 | EXPECT_EQ(0u, LB->getColumn()); |
2761 | } |
2762 | } |
2763 | |
2764 | typedef MetadataTest DILexicalBlockFileTest; |
2765 | |
2766 | TEST_F(DILexicalBlockFileTest, get) { |
2767 | DILocalScope *Scope = getSubprogram(); |
2768 | DIFile *File = getFile(); |
2769 | unsigned Discriminator = 5; |
2770 | |
2771 | auto *N = DILexicalBlockFile::get(Context, Scope, File, Discriminator); |
2772 | |
2773 | EXPECT_EQ(dwarf::DW_TAG_lexical_block, N->getTag()); |
2774 | EXPECT_EQ(Scope, N->getScope()); |
2775 | EXPECT_EQ(File, N->getFile()); |
2776 | EXPECT_EQ(Discriminator, N->getDiscriminator()); |
2777 | EXPECT_EQ(N, DILexicalBlockFile::get(Context, Scope, File, Discriminator)); |
2778 | |
2779 | EXPECT_NE(N, DILexicalBlockFile::get(Context, getSubprogram(), File, |
2780 | Discriminator)); |
2781 | EXPECT_NE(N, |
2782 | DILexicalBlockFile::get(Context, Scope, getFile(), Discriminator)); |
2783 | EXPECT_NE(N, |
2784 | DILexicalBlockFile::get(Context, Scope, File, Discriminator + 1)); |
2785 | |
2786 | TempDILexicalBlockFile Temp = N->clone(); |
2787 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
2788 | } |
2789 | |
2790 | typedef MetadataTest DINamespaceTest; |
2791 | |
2792 | TEST_F(DINamespaceTest, get) { |
2793 | DIScope *Scope = getFile(); |
2794 | StringRef Name = "namespace" ; |
2795 | bool ExportSymbols = true; |
2796 | |
2797 | auto *N = DINamespace::get(Context, Scope, Name, ExportSymbols); |
2798 | |
2799 | EXPECT_EQ(dwarf::DW_TAG_namespace, N->getTag()); |
2800 | EXPECT_EQ(Scope, N->getScope()); |
2801 | EXPECT_EQ(Name, N->getName()); |
2802 | EXPECT_EQ(N, DINamespace::get(Context, Scope, Name, ExportSymbols)); |
2803 | EXPECT_NE(N, DINamespace::get(Context, getFile(), Name, ExportSymbols)); |
2804 | EXPECT_NE(N, DINamespace::get(Context, Scope, "other" , ExportSymbols)); |
2805 | EXPECT_NE(N, DINamespace::get(Context, Scope, Name, !ExportSymbols)); |
2806 | |
2807 | TempDINamespace Temp = N->clone(); |
2808 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
2809 | } |
2810 | |
2811 | typedef MetadataTest DIModuleTest; |
2812 | |
2813 | TEST_F(DIModuleTest, get) { |
2814 | DIFile *File = getFile(); |
2815 | DIScope *Scope = getFile(); |
2816 | StringRef Name = "module" ; |
2817 | StringRef ConfigMacro = "-DNDEBUG" ; |
2818 | StringRef Includes = "-I." ; |
2819 | StringRef APINotes = "/tmp/m.apinotes" ; |
2820 | unsigned LineNo = 4; |
2821 | bool IsDecl = true; |
2822 | |
2823 | auto *N = DIModule::get(Context, File, Scope, Name, ConfigurationMacros: ConfigMacro, IncludePath: Includes, |
2824 | APINotesFile: APINotes, LineNo, IsDecl); |
2825 | |
2826 | EXPECT_EQ(dwarf::DW_TAG_module, N->getTag()); |
2827 | EXPECT_EQ(File, N->getFile()); |
2828 | EXPECT_EQ(Scope, N->getScope()); |
2829 | EXPECT_EQ(Name, N->getName()); |
2830 | EXPECT_EQ(ConfigMacro, N->getConfigurationMacros()); |
2831 | EXPECT_EQ(Includes, N->getIncludePath()); |
2832 | EXPECT_EQ(APINotes, N->getAPINotesFile()); |
2833 | EXPECT_EQ(LineNo, N->getLineNo()); |
2834 | EXPECT_EQ(IsDecl, N->getIsDecl()); |
2835 | EXPECT_EQ(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes, |
2836 | APINotes, LineNo, IsDecl)); |
2837 | EXPECT_NE(N, DIModule::get(Context, getFile(), getFile(), Name, ConfigMacro, |
2838 | Includes, APINotes, LineNo, IsDecl)); |
2839 | EXPECT_NE(N, DIModule::get(Context, File, Scope, "other" , ConfigMacro, |
2840 | Includes, APINotes, LineNo, IsDecl)); |
2841 | EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, "other" , Includes, |
2842 | APINotes, LineNo, IsDecl)); |
2843 | EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, "other" , |
2844 | APINotes, LineNo, IsDecl)); |
2845 | EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes, |
2846 | "other" , LineNo, IsDecl)); |
2847 | EXPECT_NE(N, DIModule::get(Context, getFile(), Scope, Name, ConfigMacro, |
2848 | Includes, APINotes, LineNo, IsDecl)); |
2849 | EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes, |
2850 | APINotes, 5, IsDecl)); |
2851 | EXPECT_NE(N, DIModule::get(Context, File, Scope, Name, ConfigMacro, Includes, |
2852 | APINotes, LineNo, false)); |
2853 | |
2854 | TempDIModule Temp = N->clone(); |
2855 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
2856 | } |
2857 | |
2858 | typedef MetadataTest DITemplateTypeParameterTest; |
2859 | |
2860 | TEST_F(DITemplateTypeParameterTest, get) { |
2861 | StringRef Name = "template" ; |
2862 | DIType *Type = getBasicType(Name: "basic" ); |
2863 | bool defaulted = false; |
2864 | |
2865 | auto *N = DITemplateTypeParameter::get(Context, Name, Type, IsDefault: defaulted); |
2866 | |
2867 | EXPECT_EQ(dwarf::DW_TAG_template_type_parameter, N->getTag()); |
2868 | EXPECT_EQ(Name, N->getName()); |
2869 | EXPECT_EQ(Type, N->getType()); |
2870 | EXPECT_EQ(N, DITemplateTypeParameter::get(Context, Name, Type, defaulted)); |
2871 | |
2872 | EXPECT_NE(N, DITemplateTypeParameter::get(Context, "other" , Type, defaulted)); |
2873 | EXPECT_NE(N, DITemplateTypeParameter::get(Context, Name, |
2874 | getBasicType("other" ), defaulted)); |
2875 | EXPECT_NE(N, DITemplateTypeParameter::get(Context, Name, Type, true)); |
2876 | |
2877 | TempDITemplateTypeParameter Temp = N->clone(); |
2878 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
2879 | } |
2880 | |
2881 | typedef MetadataTest DITemplateValueParameterTest; |
2882 | |
2883 | TEST_F(DITemplateValueParameterTest, get) { |
2884 | unsigned Tag = dwarf::DW_TAG_template_value_parameter; |
2885 | StringRef Name = "template" ; |
2886 | DIType *Type = getBasicType(Name: "basic" ); |
2887 | bool defaulted = false; |
2888 | Metadata *Value = getConstantAsMetadata(); |
2889 | |
2890 | auto *N = |
2891 | DITemplateValueParameter::get(Context, Tag, Name, Type, IsDefault: defaulted, Value); |
2892 | EXPECT_EQ(Tag, N->getTag()); |
2893 | EXPECT_EQ(Name, N->getName()); |
2894 | EXPECT_EQ(Type, N->getType()); |
2895 | EXPECT_EQ(Value, N->getValue()); |
2896 | EXPECT_EQ(N, DITemplateValueParameter::get(Context, Tag, Name, Type, |
2897 | defaulted, Value)); |
2898 | |
2899 | EXPECT_NE(N, DITemplateValueParameter::get( |
2900 | Context, dwarf::DW_TAG_GNU_template_template_param, Name, |
2901 | Type, defaulted, Value)); |
2902 | EXPECT_NE(N, DITemplateValueParameter::get(Context, Tag, "other" , Type, |
2903 | defaulted, Value)); |
2904 | EXPECT_NE(N, DITemplateValueParameter::get(Context, Tag, Name, |
2905 | getBasicType("other" ), defaulted, |
2906 | Value)); |
2907 | EXPECT_NE(N, |
2908 | DITemplateValueParameter::get(Context, Tag, Name, Type, defaulted, |
2909 | getConstantAsMetadata())); |
2910 | EXPECT_NE( |
2911 | N, DITemplateValueParameter::get(Context, Tag, Name, Type, true, Value)); |
2912 | |
2913 | TempDITemplateValueParameter Temp = N->clone(); |
2914 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
2915 | } |
2916 | |
2917 | typedef MetadataTest DIGlobalVariableTest; |
2918 | |
2919 | TEST_F(DIGlobalVariableTest, get) { |
2920 | DIScope *Scope = getSubprogram(); |
2921 | StringRef Name = "name" ; |
2922 | StringRef LinkageName = "linkage" ; |
2923 | DIFile *File = getFile(); |
2924 | unsigned Line = 5; |
2925 | DIType *Type = getDerivedType(); |
2926 | bool IsLocalToUnit = false; |
2927 | bool IsDefinition = true; |
2928 | MDTuple *templateParams = getTuple(); |
2929 | DIDerivedType *StaticDataMemberDeclaration = |
2930 | cast<DIDerivedType>(Val: getDerivedType()); |
2931 | |
2932 | uint32_t AlignInBits = 8; |
2933 | |
2934 | auto *N = DIGlobalVariable::get( |
2935 | Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, |
2936 | IsDefinition, StaticDataMemberDeclaration, TemplateParams: templateParams, AlignInBits, |
2937 | Annotations: nullptr); |
2938 | |
2939 | EXPECT_EQ(dwarf::DW_TAG_variable, N->getTag()); |
2940 | EXPECT_EQ(Scope, N->getScope()); |
2941 | EXPECT_EQ(Name, N->getName()); |
2942 | EXPECT_EQ(LinkageName, N->getLinkageName()); |
2943 | EXPECT_EQ(File, N->getFile()); |
2944 | EXPECT_EQ(Line, N->getLine()); |
2945 | EXPECT_EQ(Type, N->getType()); |
2946 | EXPECT_EQ(IsLocalToUnit, N->isLocalToUnit()); |
2947 | EXPECT_EQ(IsDefinition, N->isDefinition()); |
2948 | EXPECT_EQ(StaticDataMemberDeclaration, N->getStaticDataMemberDeclaration()); |
2949 | EXPECT_EQ(templateParams, N->getTemplateParams()); |
2950 | EXPECT_EQ(AlignInBits, N->getAlignInBits()); |
2951 | EXPECT_EQ(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, |
2952 | Line, Type, IsLocalToUnit, IsDefinition, |
2953 | StaticDataMemberDeclaration, |
2954 | templateParams, AlignInBits, nullptr)); |
2955 | |
2956 | EXPECT_NE(N, DIGlobalVariable::get( |
2957 | Context, getSubprogram(), Name, LinkageName, File, Line, |
2958 | Type, IsLocalToUnit, IsDefinition, |
2959 | StaticDataMemberDeclaration, templateParams, AlignInBits, |
2960 | nullptr)); |
2961 | EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, "other" , LinkageName, File, |
2962 | Line, Type, IsLocalToUnit, IsDefinition, |
2963 | StaticDataMemberDeclaration, |
2964 | templateParams, AlignInBits, nullptr)); |
2965 | EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, "other" , File, Line, |
2966 | Type, IsLocalToUnit, IsDefinition, |
2967 | StaticDataMemberDeclaration, |
2968 | templateParams, AlignInBits, nullptr)); |
2969 | EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, |
2970 | getFile(), Line, Type, IsLocalToUnit, |
2971 | IsDefinition, StaticDataMemberDeclaration, |
2972 | templateParams, AlignInBits, nullptr)); |
2973 | EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, |
2974 | Line + 1, Type, IsLocalToUnit, |
2975 | IsDefinition, StaticDataMemberDeclaration, |
2976 | templateParams, AlignInBits, nullptr)); |
2977 | EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, |
2978 | Line, getDerivedType(), IsLocalToUnit, |
2979 | IsDefinition, StaticDataMemberDeclaration, |
2980 | templateParams, AlignInBits, nullptr)); |
2981 | EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, |
2982 | Line, Type, !IsLocalToUnit, IsDefinition, |
2983 | StaticDataMemberDeclaration, |
2984 | templateParams, AlignInBits, nullptr)); |
2985 | EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, |
2986 | Line, Type, IsLocalToUnit, !IsDefinition, |
2987 | StaticDataMemberDeclaration, |
2988 | templateParams, AlignInBits, nullptr)); |
2989 | EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, |
2990 | Line, Type, IsLocalToUnit, IsDefinition, |
2991 | cast<DIDerivedType>(getDerivedType()), |
2992 | templateParams, AlignInBits, nullptr)); |
2993 | EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, |
2994 | Line, Type, IsLocalToUnit, IsDefinition, |
2995 | StaticDataMemberDeclaration, nullptr, |
2996 | AlignInBits, nullptr)); |
2997 | EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, |
2998 | Line, Type, IsLocalToUnit, IsDefinition, |
2999 | StaticDataMemberDeclaration, |
3000 | templateParams, (AlignInBits << 1), |
3001 | nullptr)); |
3002 | |
3003 | TempDIGlobalVariable Temp = N->clone(); |
3004 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
3005 | } |
3006 | |
3007 | typedef MetadataTest DIGlobalVariableExpressionTest; |
3008 | |
3009 | TEST_F(DIGlobalVariableExpressionTest, get) { |
3010 | DIScope *Scope = getSubprogram(); |
3011 | StringRef Name = "name" ; |
3012 | StringRef LinkageName = "linkage" ; |
3013 | DIFile *File = getFile(); |
3014 | unsigned Line = 5; |
3015 | DIType *Type = getDerivedType(); |
3016 | bool IsLocalToUnit = false; |
3017 | bool IsDefinition = true; |
3018 | MDTuple *templateParams = getTuple(); |
3019 | auto *Expr = DIExpression::get(Context, Elements: {1, 2}); |
3020 | auto *Expr2 = DIExpression::get(Context, Elements: {1, 2, 3}); |
3021 | DIDerivedType *StaticDataMemberDeclaration = |
3022 | cast<DIDerivedType>(Val: getDerivedType()); |
3023 | uint32_t AlignInBits = 8; |
3024 | |
3025 | auto *Var = DIGlobalVariable::get( |
3026 | Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, |
3027 | IsDefinition, StaticDataMemberDeclaration, TemplateParams: templateParams, AlignInBits, |
3028 | Annotations: nullptr); |
3029 | auto *Var2 = DIGlobalVariable::get( |
3030 | Context, Scope, Name: "other" , LinkageName, File, Line, Type, IsLocalToUnit, |
3031 | IsDefinition, StaticDataMemberDeclaration, TemplateParams: templateParams, AlignInBits, |
3032 | Annotations: nullptr); |
3033 | auto *N = DIGlobalVariableExpression::get(Context, Variable: Var, Expression: Expr); |
3034 | |
3035 | EXPECT_EQ(Var, N->getVariable()); |
3036 | EXPECT_EQ(Expr, N->getExpression()); |
3037 | EXPECT_EQ(N, DIGlobalVariableExpression::get(Context, Var, Expr)); |
3038 | EXPECT_NE(N, DIGlobalVariableExpression::get(Context, Var2, Expr)); |
3039 | EXPECT_NE(N, DIGlobalVariableExpression::get(Context, Var, Expr2)); |
3040 | |
3041 | TempDIGlobalVariableExpression Temp = N->clone(); |
3042 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
3043 | } |
3044 | |
3045 | typedef MetadataTest DILocalVariableTest; |
3046 | |
3047 | TEST_F(DILocalVariableTest, get) { |
3048 | DILocalScope *Scope = getSubprogram(); |
3049 | StringRef Name = "name" ; |
3050 | DIFile *File = getFile(); |
3051 | unsigned Line = 5; |
3052 | DIType *Type = getDerivedType(); |
3053 | unsigned Arg = 6; |
3054 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(7); |
3055 | uint32_t AlignInBits = 8; |
3056 | |
3057 | auto *N = |
3058 | DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, Flags, |
3059 | AlignInBits, Annotations: nullptr); |
3060 | EXPECT_TRUE(N->isParameter()); |
3061 | EXPECT_EQ(Scope, N->getScope()); |
3062 | EXPECT_EQ(Name, N->getName()); |
3063 | EXPECT_EQ(File, N->getFile()); |
3064 | EXPECT_EQ(Line, N->getLine()); |
3065 | EXPECT_EQ(Type, N->getType()); |
3066 | EXPECT_EQ(Arg, N->getArg()); |
3067 | EXPECT_EQ(Flags, N->getFlags()); |
3068 | EXPECT_EQ(AlignInBits, N->getAlignInBits()); |
3069 | EXPECT_EQ(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, |
3070 | Flags, AlignInBits, nullptr)); |
3071 | |
3072 | EXPECT_FALSE( |
3073 | DILocalVariable::get(Context, Scope, Name, File, Line, Type, 0, Flags, |
3074 | AlignInBits, nullptr)->isParameter()); |
3075 | EXPECT_NE(N, DILocalVariable::get(Context, getSubprogram(), Name, File, Line, |
3076 | Type, Arg, Flags, AlignInBits, nullptr)); |
3077 | EXPECT_NE(N, DILocalVariable::get(Context, Scope, "other" , File, Line, Type, |
3078 | Arg, Flags, AlignInBits, nullptr)); |
3079 | EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, getFile(), Line, Type, |
3080 | Arg, Flags, AlignInBits, nullptr)); |
3081 | EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line + 1, Type, |
3082 | Arg, Flags, AlignInBits, nullptr)); |
3083 | EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, |
3084 | getDerivedType(), Arg, Flags, AlignInBits, |
3085 | nullptr)); |
3086 | EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, |
3087 | Arg + 1, Flags, AlignInBits, nullptr)); |
3088 | EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, |
3089 | Arg, Flags, (AlignInBits << 1), nullptr)); |
3090 | |
3091 | TempDILocalVariable Temp = N->clone(); |
3092 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
3093 | } |
3094 | |
3095 | TEST_F(DILocalVariableTest, getArg256) { |
3096 | EXPECT_EQ(255u, DILocalVariable::get(Context, getSubprogram(), "" , getFile(), |
3097 | 0, nullptr, 255, DINode::FlagZero, 0, |
3098 | nullptr) |
3099 | ->getArg()); |
3100 | EXPECT_EQ(256u, DILocalVariable::get(Context, getSubprogram(), "" , getFile(), |
3101 | 0, nullptr, 256, DINode::FlagZero, 0, |
3102 | nullptr) |
3103 | ->getArg()); |
3104 | EXPECT_EQ(257u, DILocalVariable::get(Context, getSubprogram(), "" , getFile(), |
3105 | 0, nullptr, 257, DINode::FlagZero, 0, |
3106 | nullptr) |
3107 | ->getArg()); |
3108 | unsigned Max = UINT16_MAX; |
3109 | EXPECT_EQ(Max, DILocalVariable::get(Context, getSubprogram(), "" , getFile(), |
3110 | 0, nullptr, Max, DINode::FlagZero, 0, |
3111 | nullptr) |
3112 | ->getArg()); |
3113 | } |
3114 | |
3115 | typedef MetadataTest DIExpressionTest; |
3116 | |
3117 | TEST_F(DIExpressionTest, get) { |
3118 | uint64_t Elements[] = {2, 6, 9, 78, 0}; |
3119 | auto *N = DIExpression::get(Context, Elements); |
3120 | EXPECT_EQ(ArrayRef(Elements), N->getElements()); |
3121 | EXPECT_EQ(N, DIExpression::get(Context, Elements)); |
3122 | |
3123 | EXPECT_EQ(5u, N->getNumElements()); |
3124 | EXPECT_EQ(2u, N->getElement(0)); |
3125 | EXPECT_EQ(6u, N->getElement(1)); |
3126 | EXPECT_EQ(9u, N->getElement(2)); |
3127 | EXPECT_EQ(78u, N->getElement(3)); |
3128 | EXPECT_EQ(0u, N->getElement(4)); |
3129 | |
3130 | TempDIExpression Temp = N->clone(); |
3131 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
3132 | |
3133 | // Test DIExpression::prepend(). |
3134 | uint64_t Elts0[] = {dwarf::DW_OP_LLVM_fragment, 0, 32}; |
3135 | auto *N0 = DIExpression::get(Context, Elements: Elts0); |
3136 | uint8_t DIExprFlags = DIExpression::ApplyOffset; |
3137 | DIExprFlags |= DIExpression::DerefBefore; |
3138 | DIExprFlags |= DIExpression::DerefAfter; |
3139 | DIExprFlags |= DIExpression::StackValue; |
3140 | auto *N0WithPrependedOps = DIExpression::prepend(Expr: N0, Flags: DIExprFlags, Offset: 64); |
3141 | uint64_t Elts1[] = {dwarf::DW_OP_deref, |
3142 | dwarf::DW_OP_plus_uconst, 64, |
3143 | dwarf::DW_OP_deref, |
3144 | dwarf::DW_OP_stack_value, |
3145 | dwarf::DW_OP_LLVM_fragment, 0, 32}; |
3146 | auto *N1 = DIExpression::get(Context, Elements: Elts1); |
3147 | EXPECT_EQ(N0WithPrependedOps, N1); |
3148 | |
3149 | // Test DIExpression::append(). |
3150 | uint64_t Elts2[] = {dwarf::DW_OP_deref, dwarf::DW_OP_plus_uconst, 64, |
3151 | dwarf::DW_OP_deref, dwarf::DW_OP_stack_value}; |
3152 | auto *N2 = DIExpression::append(Expr: N0, Ops: Elts2); |
3153 | EXPECT_EQ(N0WithPrependedOps, N2); |
3154 | } |
3155 | |
3156 | TEST_F(DIExpressionTest, isValid) { |
3157 | #define EXPECT_VALID(...) \ |
3158 | do { \ |
3159 | uint64_t Elements[] = {__VA_ARGS__}; \ |
3160 | EXPECT_TRUE(DIExpression::get(Context, Elements)->isValid()); \ |
3161 | } while (false) |
3162 | #define EXPECT_INVALID(...) \ |
3163 | do { \ |
3164 | uint64_t Elements[] = {__VA_ARGS__}; \ |
3165 | EXPECT_FALSE(DIExpression::get(Context, Elements)->isValid()); \ |
3166 | } while (false) |
3167 | |
3168 | // Empty expression should be valid. |
3169 | EXPECT_TRUE(DIExpression::get(Context, std::nullopt)->isValid()); |
3170 | |
3171 | // Valid constructions. |
3172 | EXPECT_VALID(dwarf::DW_OP_plus_uconst, 6); |
3173 | EXPECT_VALID(dwarf::DW_OP_constu, 6, dwarf::DW_OP_plus); |
3174 | EXPECT_VALID(dwarf::DW_OP_deref); |
3175 | EXPECT_VALID(dwarf::DW_OP_LLVM_fragment, 3, 7); |
3176 | EXPECT_VALID(dwarf::DW_OP_plus_uconst, 6, dwarf::DW_OP_deref); |
3177 | EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus_uconst, 6); |
3178 | EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_LLVM_fragment, 3, 7); |
3179 | EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus_uconst, 6, |
3180 | dwarf::DW_OP_LLVM_fragment, 3, 7); |
3181 | EXPECT_VALID(dwarf::DW_OP_LLVM_entry_value, 1); |
3182 | EXPECT_VALID(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_entry_value, 1); |
3183 | |
3184 | // Invalid constructions. |
3185 | EXPECT_INVALID(~0u); |
3186 | EXPECT_INVALID(dwarf::DW_OP_plus, 0); |
3187 | EXPECT_INVALID(dwarf::DW_OP_plus_uconst); |
3188 | EXPECT_INVALID(dwarf::DW_OP_LLVM_fragment); |
3189 | EXPECT_INVALID(dwarf::DW_OP_LLVM_fragment, 3); |
3190 | EXPECT_INVALID(dwarf::DW_OP_LLVM_fragment, 3, 7, dwarf::DW_OP_plus_uconst, 3); |
3191 | EXPECT_INVALID(dwarf::DW_OP_LLVM_fragment, 3, 7, dwarf::DW_OP_deref); |
3192 | EXPECT_INVALID(dwarf::DW_OP_LLVM_entry_value, 2); |
3193 | EXPECT_INVALID(dwarf::DW_OP_plus_uconst, 5, dwarf::DW_OP_LLVM_entry_value, 1); |
3194 | EXPECT_INVALID(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_plus_uconst, 5, |
3195 | dwarf::DW_OP_LLVM_entry_value, 1); |
3196 | EXPECT_INVALID(dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_LLVM_entry_value, 1); |
3197 | |
3198 | #undef EXPECT_VALID |
3199 | #undef EXPECT_INVALID |
3200 | } |
3201 | |
3202 | TEST_F(DIExpressionTest, createFragmentExpression) { |
3203 | #define EXPECT_VALID_FRAGMENT(Offset, Size, ...) \ |
3204 | do { \ |
3205 | uint64_t Elements[] = {__VA_ARGS__}; \ |
3206 | DIExpression *Expression = DIExpression::get(Context, Elements); \ |
3207 | EXPECT_TRUE( \ |
3208 | DIExpression::createFragmentExpression(Expression, Offset, Size) \ |
3209 | .has_value()); \ |
3210 | } while (false) |
3211 | #define EXPECT_INVALID_FRAGMENT(Offset, Size, ...) \ |
3212 | do { \ |
3213 | uint64_t Elements[] = {__VA_ARGS__}; \ |
3214 | DIExpression *Expression = DIExpression::get(Context, Elements); \ |
3215 | EXPECT_FALSE( \ |
3216 | DIExpression::createFragmentExpression(Expression, Offset, Size) \ |
3217 | .has_value()); \ |
3218 | } while (false) |
3219 | |
3220 | // createFragmentExpression adds correct ops. |
3221 | std::optional<DIExpression*> R = DIExpression::createFragmentExpression( |
3222 | Expr: DIExpression::get(Context, Elements: {}), OffsetInBits: 0, SizeInBits: 32); |
3223 | EXPECT_EQ(R.has_value(), true); |
3224 | EXPECT_EQ(3u, (*R)->getNumElements()); |
3225 | EXPECT_EQ(dwarf::DW_OP_LLVM_fragment, (*R)->getElement(0)); |
3226 | EXPECT_EQ(0u, (*R)->getElement(1)); |
3227 | EXPECT_EQ(32u, (*R)->getElement(2)); |
3228 | |
3229 | // Valid fragment expressions. |
3230 | EXPECT_VALID_FRAGMENT(0, 32, {}); |
3231 | EXPECT_VALID_FRAGMENT(0, 32, dwarf::DW_OP_deref); |
3232 | EXPECT_VALID_FRAGMENT(0, 32, dwarf::DW_OP_LLVM_fragment, 0, 32); |
3233 | EXPECT_VALID_FRAGMENT(16, 16, dwarf::DW_OP_LLVM_fragment, 0, 32); |
3234 | |
3235 | // Invalid fragment expressions (incompatible ops). |
3236 | EXPECT_INVALID_FRAGMENT(0, 32, dwarf::DW_OP_constu, 6, dwarf::DW_OP_plus, |
3237 | dwarf::DW_OP_stack_value); |
3238 | EXPECT_INVALID_FRAGMENT(0, 32, dwarf::DW_OP_constu, 14, dwarf::DW_OP_minus, |
3239 | dwarf::DW_OP_stack_value); |
3240 | EXPECT_INVALID_FRAGMENT(0, 32, dwarf::DW_OP_constu, 16, dwarf::DW_OP_shr, |
3241 | dwarf::DW_OP_stack_value); |
3242 | EXPECT_INVALID_FRAGMENT(0, 32, dwarf::DW_OP_constu, 16, dwarf::DW_OP_shl, |
3243 | dwarf::DW_OP_stack_value); |
3244 | EXPECT_INVALID_FRAGMENT(0, 32, dwarf::DW_OP_constu, 16, dwarf::DW_OP_shra, |
3245 | dwarf::DW_OP_stack_value); |
3246 | EXPECT_INVALID_FRAGMENT(0, 32, dwarf::DW_OP_plus_uconst, 6, |
3247 | dwarf::DW_OP_stack_value); |
3248 | |
3249 | // Fragments can be created for expressions using DW_OP_plus to compute an |
3250 | // address. |
3251 | EXPECT_VALID_FRAGMENT(0, 32, dwarf::DW_OP_constu, 6, dwarf::DW_OP_plus); |
3252 | EXPECT_VALID_FRAGMENT(0, 32, dwarf::DW_OP_plus_uconst, 6, dwarf::DW_OP_deref); |
3253 | EXPECT_VALID_FRAGMENT(0, 32, dwarf::DW_OP_plus_uconst, 6, dwarf::DW_OP_deref, |
3254 | dwarf::DW_OP_stack_value); |
3255 | |
3256 | // Check the other deref operations work in the same way. |
3257 | EXPECT_VALID_FRAGMENT(0, 32, dwarf::DW_OP_plus_uconst, 6, |
3258 | dwarf::DW_OP_deref_size, 1); |
3259 | EXPECT_VALID_FRAGMENT(0, 32, dwarf::DW_OP_plus_uconst, 6, |
3260 | dwarf::DW_OP_deref_type, 1, 1); |
3261 | EXPECT_VALID_FRAGMENT(0, 32, dwarf::DW_OP_plus_uconst, 6, |
3262 | dwarf::DW_OP_xderef); |
3263 | EXPECT_VALID_FRAGMENT(0, 32, dwarf::DW_OP_plus_uconst, 6, |
3264 | dwarf::DW_OP_xderef_size, 1); |
3265 | EXPECT_VALID_FRAGMENT(0, 32, dwarf::DW_OP_plus_uconst, 6, |
3266 | dwarf::DW_OP_xderef_type, 1, 1); |
3267 | |
3268 | // Fragments cannot be created for expressions using DW_OP_plus to compute an |
3269 | // implicit value (check that this correctly fails even though there is a |
3270 | // deref in the expression). |
3271 | EXPECT_INVALID_FRAGMENT(0, 32, dwarf::DW_OP_deref, dwarf::DW_OP_plus_uconst, |
3272 | 2, dwarf::DW_OP_stack_value); |
3273 | |
3274 | #undef EXPECT_VALID_FRAGMENT |
3275 | #undef EXPECT_INVALID_FRAGMENT |
3276 | } |
3277 | |
3278 | TEST_F(DIExpressionTest, convertToUndefExpression) { |
3279 | #define EXPECT_UNDEF_OPS_EQUAL(TestExpr, Expected) \ |
3280 | do { \ |
3281 | const DIExpression *Undef = \ |
3282 | DIExpression::convertToUndefExpression(TestExpr); \ |
3283 | EXPECT_EQ(Undef, Expected); \ |
3284 | } while (false) |
3285 | #define GET_EXPR(...) DIExpression::get(Context, {__VA_ARGS__}) |
3286 | |
3287 | // Expressions which are single-location and non-complex should be unchanged. |
3288 | EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(), GET_EXPR()); |
3289 | EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_LLVM_fragment, 0, 32), |
3290 | GET_EXPR(dwarf::DW_OP_LLVM_fragment, 0, 32)); |
3291 | |
3292 | // Variadic expressions should become single-location. |
3293 | EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_LLVM_arg, 0), GET_EXPR()); |
3294 | EXPECT_UNDEF_OPS_EQUAL( |
3295 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_fragment, 32, 32), |
3296 | GET_EXPR(dwarf::DW_OP_LLVM_fragment, 32, 32)); |
3297 | EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, |
3298 | dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_mul), |
3299 | GET_EXPR()); |
3300 | EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, |
3301 | dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_mul, |
3302 | dwarf::DW_OP_LLVM_fragment, 64, 32), |
3303 | GET_EXPR(dwarf::DW_OP_LLVM_fragment, 64, 32)); |
3304 | |
3305 | // Any stack-computing ops should be removed. |
3306 | EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_plus_uconst, 8), GET_EXPR()); |
3307 | EXPECT_UNDEF_OPS_EQUAL( |
3308 | GET_EXPR(dwarf::DW_OP_plus_uconst, 8, dwarf::DW_OP_LLVM_fragment, 0, 16), |
3309 | GET_EXPR(dwarf::DW_OP_LLVM_fragment, 0, 16)); |
3310 | EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_constu, 24, dwarf::DW_OP_shra), |
3311 | GET_EXPR()); |
3312 | EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_constu, 24, dwarf::DW_OP_shra, |
3313 | dwarf::DW_OP_LLVM_fragment, 8, 16), |
3314 | GET_EXPR(dwarf::DW_OP_LLVM_fragment, 8, 16)); |
3315 | EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_deref), GET_EXPR()); |
3316 | EXPECT_UNDEF_OPS_EQUAL( |
3317 | GET_EXPR(dwarf::DW_OP_deref, dwarf::DW_OP_LLVM_fragment, 16, 16), |
3318 | GET_EXPR(dwarf::DW_OP_LLVM_fragment, 16, 16)); |
3319 | EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_constu, 4, dwarf::DW_OP_minus), |
3320 | GET_EXPR()); |
3321 | EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_constu, 4, dwarf::DW_OP_minus, |
3322 | dwarf::DW_OP_LLVM_fragment, 24, 16), |
3323 | GET_EXPR(dwarf::DW_OP_LLVM_fragment, 24, 16)); |
3324 | |
3325 | // Stack-value operators are also not preserved. |
3326 | EXPECT_UNDEF_OPS_EQUAL( |
3327 | GET_EXPR(dwarf::DW_OP_plus_uconst, 8, dwarf::DW_OP_stack_value), |
3328 | GET_EXPR()); |
3329 | EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_plus_uconst, 8, |
3330 | dwarf::DW_OP_stack_value, |
3331 | dwarf::DW_OP_LLVM_fragment, 32, 16), |
3332 | GET_EXPR(dwarf::DW_OP_LLVM_fragment, 32, 16)); |
3333 | |
3334 | #undef EXPECT_UNDEF_OPS_EQUAL |
3335 | #undef GET_EXPR |
3336 | } |
3337 | |
3338 | TEST_F(DIExpressionTest, convertToVariadicExpression) { |
3339 | #define EXPECT_CONVERT_IS_NOOP(TestExpr) \ |
3340 | do { \ |
3341 | const DIExpression *Variadic = \ |
3342 | DIExpression::convertToVariadicExpression(TestExpr); \ |
3343 | EXPECT_EQ(Variadic, TestExpr); \ |
3344 | } while (false) |
3345 | #define EXPECT_VARIADIC_OPS_EQUAL(TestExpr, Expected) \ |
3346 | do { \ |
3347 | const DIExpression *Variadic = \ |
3348 | DIExpression::convertToVariadicExpression(TestExpr); \ |
3349 | EXPECT_EQ(Variadic, Expected); \ |
3350 | } while (false) |
3351 | #define GET_EXPR(...) DIExpression::get(Context, {__VA_ARGS__}) |
3352 | |
3353 | // Expressions which are already variadic should be unaffected. |
3354 | EXPECT_CONVERT_IS_NOOP( |
3355 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_stack_value)); |
3356 | EXPECT_CONVERT_IS_NOOP(GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, |
3357 | dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_plus, |
3358 | dwarf::DW_OP_stack_value)); |
3359 | EXPECT_CONVERT_IS_NOOP(GET_EXPR(dwarf::DW_OP_constu, 5, dwarf::DW_OP_LLVM_arg, |
3360 | 0, dwarf::DW_OP_plus, |
3361 | dwarf::DW_OP_stack_value)); |
3362 | EXPECT_CONVERT_IS_NOOP(GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, |
3363 | dwarf::DW_OP_stack_value, |
3364 | dwarf::DW_OP_LLVM_fragment, 0, 32)); |
3365 | |
3366 | // Other expressions should receive a leading `LLVM_arg 0`. |
3367 | EXPECT_VARIADIC_OPS_EQUAL(GET_EXPR(), GET_EXPR(dwarf::DW_OP_LLVM_arg, 0)); |
3368 | EXPECT_VARIADIC_OPS_EQUAL( |
3369 | GET_EXPR(dwarf::DW_OP_plus_uconst, 4), |
3370 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_plus_uconst, 4)); |
3371 | EXPECT_VARIADIC_OPS_EQUAL( |
3372 | GET_EXPR(dwarf::DW_OP_plus_uconst, 4, dwarf::DW_OP_stack_value), |
3373 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_plus_uconst, 4, |
3374 | dwarf::DW_OP_stack_value)); |
3375 | EXPECT_VARIADIC_OPS_EQUAL( |
3376 | GET_EXPR(dwarf::DW_OP_plus_uconst, 6, dwarf::DW_OP_stack_value, |
3377 | dwarf::DW_OP_LLVM_fragment, 32, 32), |
3378 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_plus_uconst, 6, |
3379 | dwarf::DW_OP_stack_value, dwarf::DW_OP_LLVM_fragment, 32, 32)); |
3380 | EXPECT_VARIADIC_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_plus_uconst, 14, |
3381 | dwarf::DW_OP_LLVM_fragment, 32, 32), |
3382 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, |
3383 | dwarf::DW_OP_plus_uconst, 14, |
3384 | dwarf::DW_OP_LLVM_fragment, 32, 32)); |
3385 | |
3386 | #undef EXPECT_CONVERT_IS_NOOP |
3387 | #undef EXPECT_VARIADIC_OPS_EQUAL |
3388 | #undef GET_EXPR |
3389 | } |
3390 | |
3391 | TEST_F(DIExpressionTest, convertToNonVariadicExpression) { |
3392 | #define EXPECT_CONVERT_IS_NOOP(TestExpr) \ |
3393 | do { \ |
3394 | std::optional<const DIExpression *> NonVariadic = \ |
3395 | DIExpression::convertToNonVariadicExpression(TestExpr); \ |
3396 | EXPECT_TRUE(NonVariadic.has_value()); \ |
3397 | EXPECT_EQ(*NonVariadic, TestExpr); \ |
3398 | } while (false) |
3399 | #define EXPECT_NON_VARIADIC_OPS_EQUAL(TestExpr, Expected) \ |
3400 | do { \ |
3401 | std::optional<const DIExpression *> NonVariadic = \ |
3402 | DIExpression::convertToNonVariadicExpression(TestExpr); \ |
3403 | EXPECT_TRUE(NonVariadic.has_value()); \ |
3404 | EXPECT_EQ(*NonVariadic, Expected); \ |
3405 | } while (false) |
3406 | #define EXPECT_INVALID_CONVERSION(TestExpr) \ |
3407 | do { \ |
3408 | std::optional<const DIExpression *> NonVariadic = \ |
3409 | DIExpression::convertToNonVariadicExpression(TestExpr); \ |
3410 | EXPECT_FALSE(NonVariadic.has_value()); \ |
3411 | } while (false) |
3412 | #define GET_EXPR(...) DIExpression::get(Context, {__VA_ARGS__}) |
3413 | |
3414 | // Expressions which are already non-variadic should be unaffected. |
3415 | EXPECT_CONVERT_IS_NOOP(GET_EXPR()); |
3416 | EXPECT_CONVERT_IS_NOOP(GET_EXPR(dwarf::DW_OP_plus_uconst, 4)); |
3417 | EXPECT_CONVERT_IS_NOOP( |
3418 | GET_EXPR(dwarf::DW_OP_plus_uconst, 4, dwarf::DW_OP_stack_value)); |
3419 | EXPECT_CONVERT_IS_NOOP(GET_EXPR(dwarf::DW_OP_plus_uconst, 6, |
3420 | dwarf::DW_OP_stack_value, |
3421 | dwarf::DW_OP_LLVM_fragment, 32, 32)); |
3422 | EXPECT_CONVERT_IS_NOOP(GET_EXPR(dwarf::DW_OP_plus_uconst, 14, |
3423 | dwarf::DW_OP_LLVM_fragment, 32, 32)); |
3424 | |
3425 | // Variadic expressions with a single leading `LLVM_arg 0` and no other |
3426 | // LLVM_args should have the leading arg removed. |
3427 | EXPECT_NON_VARIADIC_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_LLVM_arg, 0), GET_EXPR()); |
3428 | EXPECT_NON_VARIADIC_OPS_EQUAL( |
3429 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_stack_value), |
3430 | GET_EXPR(dwarf::DW_OP_stack_value)); |
3431 | EXPECT_NON_VARIADIC_OPS_EQUAL( |
3432 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_fragment, 16, 32), |
3433 | GET_EXPR(dwarf::DW_OP_LLVM_fragment, 16, 32)); |
3434 | EXPECT_NON_VARIADIC_OPS_EQUAL( |
3435 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_stack_value, |
3436 | dwarf::DW_OP_LLVM_fragment, 24, 32), |
3437 | GET_EXPR(dwarf::DW_OP_stack_value, dwarf::DW_OP_LLVM_fragment, 24, 32)); |
3438 | EXPECT_NON_VARIADIC_OPS_EQUAL( |
3439 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_plus_uconst, 4), |
3440 | GET_EXPR(dwarf::DW_OP_plus_uconst, 4)); |
3441 | EXPECT_NON_VARIADIC_OPS_EQUAL( |
3442 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_plus_uconst, 4, |
3443 | dwarf::DW_OP_stack_value), |
3444 | GET_EXPR(dwarf::DW_OP_plus_uconst, 4, dwarf::DW_OP_stack_value)); |
3445 | EXPECT_NON_VARIADIC_OPS_EQUAL( |
3446 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_plus_uconst, 6, |
3447 | dwarf::DW_OP_stack_value, dwarf::DW_OP_LLVM_fragment, 32, 32), |
3448 | GET_EXPR(dwarf::DW_OP_plus_uconst, 6, dwarf::DW_OP_stack_value, |
3449 | dwarf::DW_OP_LLVM_fragment, 32, 32)); |
3450 | EXPECT_NON_VARIADIC_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, |
3451 | dwarf::DW_OP_plus_uconst, 14, |
3452 | dwarf::DW_OP_LLVM_fragment, 32, 32), |
3453 | GET_EXPR(dwarf::DW_OP_plus_uconst, 14, |
3454 | dwarf::DW_OP_LLVM_fragment, 32, 32)); |
3455 | |
3456 | // Variadic expressions that have any LLVM_args other than a leading |
3457 | // `LLVM_arg 0` cannot be converted and so should return std::nullopt. |
3458 | EXPECT_INVALID_CONVERSION(GET_EXPR( |
3459 | dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_mul)); |
3460 | EXPECT_INVALID_CONVERSION( |
3461 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg, 1, |
3462 | dwarf::DW_OP_plus, dwarf::DW_OP_stack_value)); |
3463 | EXPECT_INVALID_CONVERSION( |
3464 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg, 0, |
3465 | dwarf::DW_OP_minus, dwarf::DW_OP_stack_value)); |
3466 | EXPECT_INVALID_CONVERSION(GET_EXPR(dwarf::DW_OP_constu, 5, |
3467 | dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_div, |
3468 | dwarf::DW_OP_stack_value)); |
3469 | |
3470 | #undef EXPECT_CONVERT_IS_NOOP |
3471 | #undef EXPECT_NON_VARIADIC_OPS_EQUAL |
3472 | #undef EXPECT_INVALID_CONVERSION |
3473 | #undef GET_EXPR |
3474 | } |
3475 | |
3476 | TEST_F(DIExpressionTest, replaceArg) { |
3477 | #define EXPECT_REPLACE_ARG_EQ(Expr, OldArg, NewArg, ...) \ |
3478 | do { \ |
3479 | uint64_t Elements[] = {__VA_ARGS__}; \ |
3480 | ArrayRef<uint64_t> Expected = Elements; \ |
3481 | DIExpression *Expression = DIExpression::replaceArg(Expr, OldArg, NewArg); \ |
3482 | EXPECT_EQ(Expression->getElements(), Expected); \ |
3483 | } while (false) |
3484 | |
3485 | auto N = DIExpression::get( |
3486 | Context, Elements: {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg, 1, |
3487 | dwarf::DW_OP_plus, dwarf::DW_OP_LLVM_arg, 2, dwarf::DW_OP_mul}); |
3488 | EXPECT_REPLACE_ARG_EQ(N, 0, 1, dwarf::DW_OP_LLVM_arg, 0, |
3489 | dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_plus, |
3490 | dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_mul); |
3491 | EXPECT_REPLACE_ARG_EQ(N, 0, 2, dwarf::DW_OP_LLVM_arg, 1, |
3492 | dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_plus, |
3493 | dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_mul); |
3494 | EXPECT_REPLACE_ARG_EQ(N, 2, 0, dwarf::DW_OP_LLVM_arg, 0, |
3495 | dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_plus, |
3496 | dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_mul); |
3497 | EXPECT_REPLACE_ARG_EQ(N, 2, 1, dwarf::DW_OP_LLVM_arg, 0, |
3498 | dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_plus, |
3499 | dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_mul); |
3500 | |
3501 | #undef EXPECT_REPLACE_ARG_EQ |
3502 | } |
3503 | |
3504 | TEST_F(DIExpressionTest, isEqualExpression) { |
3505 | #define EXPECT_EQ_DEBUG_VALUE(ExprA, DirectA, ExprB, DirectB) \ |
3506 | EXPECT_TRUE(DIExpression::isEqualExpression(ExprA, DirectA, ExprB, DirectB)) |
3507 | #define EXPECT_NE_DEBUG_VALUE(ExprA, DirectA, ExprB, DirectB) \ |
3508 | EXPECT_FALSE(DIExpression::isEqualExpression(ExprA, DirectA, ExprB, DirectB)) |
3509 | #define GET_EXPR(...) DIExpression::get(Context, {__VA_ARGS__}) |
3510 | |
3511 | EXPECT_EQ_DEBUG_VALUE(GET_EXPR(), false, GET_EXPR(), false); |
3512 | EXPECT_NE_DEBUG_VALUE(GET_EXPR(), false, GET_EXPR(), true); |
3513 | EXPECT_EQ_DEBUG_VALUE( |
3514 | GET_EXPR(dwarf::DW_OP_plus_uconst, 32), true, |
3515 | GET_EXPR(dwarf::DW_OP_plus_uconst, 32, dwarf::DW_OP_deref), false); |
3516 | EXPECT_NE_DEBUG_VALUE( |
3517 | GET_EXPR(dwarf::DW_OP_plus_uconst, 16, dwarf::DW_OP_deref), true, |
3518 | GET_EXPR(dwarf::DW_OP_plus_uconst, 16, dwarf::DW_OP_deref), false); |
3519 | EXPECT_EQ_DEBUG_VALUE( |
3520 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_plus_uconst, 5), false, |
3521 | GET_EXPR(dwarf::DW_OP_plus_uconst, 5), false); |
3522 | EXPECT_NE_DEBUG_VALUE(GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_plus), |
3523 | false, |
3524 | GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, |
3525 | dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_plus), |
3526 | false); |
3527 | EXPECT_NE_DEBUG_VALUE(GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_constu, |
3528 | 8, dwarf::DW_OP_minus), |
3529 | false, |
3530 | GET_EXPR(dwarf::DW_OP_constu, 8, dwarf::DW_OP_LLVM_arg, |
3531 | 0, dwarf::DW_OP_minus), |
3532 | false); |
3533 | // These expressions are actually equivalent, but we do not currently identify |
3534 | // commutative operations with different operand orders as being equivalent. |
3535 | EXPECT_NE_DEBUG_VALUE(GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_constu, |
3536 | 8, dwarf::DW_OP_plus), |
3537 | false, |
3538 | GET_EXPR(dwarf::DW_OP_constu, 8, dwarf::DW_OP_LLVM_arg, |
3539 | 0, dwarf::DW_OP_plus), |
3540 | false); |
3541 | |
3542 | #undef EXPECT_EQ_DEBUG_VALUE |
3543 | #undef EXPECT_NE_DEBUG_VALUE |
3544 | #undef GET_EXPR |
3545 | } |
3546 | |
3547 | TEST_F(DIExpressionTest, foldConstant) { |
3548 | const ConstantInt *Int; |
3549 | const ConstantInt *NewInt; |
3550 | DIExpression *Expr; |
3551 | DIExpression *NewExpr; |
3552 | |
3553 | #define EXPECT_FOLD_CONST(StartWidth, StartValue, EndWidth, EndValue, NumElts) \ |
3554 | Int = ConstantInt::get(Context, APInt(StartWidth, StartValue)); \ |
3555 | std::tie(NewExpr, NewInt) = Expr->constantFold(Int); \ |
3556 | ASSERT_EQ(NewInt->getBitWidth(), EndWidth##u); \ |
3557 | EXPECT_EQ(NewInt->getValue(), APInt(EndWidth, EndValue)); \ |
3558 | EXPECT_EQ(NewExpr->getNumElements(), NumElts##u) |
3559 | |
3560 | // Unfoldable expression should return the original unmodified Int/Expr. |
3561 | Expr = DIExpression::get(Context, Elements: {dwarf::DW_OP_deref}); |
3562 | EXPECT_FOLD_CONST(32, 117, 32, 117, 1); |
3563 | EXPECT_EQ(NewExpr, Expr); |
3564 | EXPECT_EQ(NewInt, Int); |
3565 | EXPECT_TRUE(NewExpr->startsWithDeref()); |
3566 | |
3567 | // One unsigned bit-width conversion. |
3568 | Expr = DIExpression::get( |
3569 | Context, Elements: {dwarf::DW_OP_LLVM_convert, 72, dwarf::DW_ATE_unsigned}); |
3570 | EXPECT_FOLD_CONST(8, 12, 72, 12, 0); |
3571 | |
3572 | // Two unsigned bit-width conversions (mask truncation). |
3573 | Expr = DIExpression::get( |
3574 | Context, Elements: {dwarf::DW_OP_LLVM_convert, 8, dwarf::DW_ATE_unsigned, |
3575 | dwarf::DW_OP_LLVM_convert, 16, dwarf::DW_ATE_unsigned}); |
3576 | EXPECT_FOLD_CONST(32, -1, 16, 0xff, 0); |
3577 | |
3578 | // Sign extension. |
3579 | Expr = DIExpression::get( |
3580 | Context, Elements: {dwarf::DW_OP_LLVM_convert, 32, dwarf::DW_ATE_signed}); |
3581 | EXPECT_FOLD_CONST(16, -1, 32, -1, 0); |
3582 | |
3583 | // Get non-foldable operations back in the new Expr. |
3584 | uint64_t Elements[] = {dwarf::DW_OP_deref, dwarf::DW_OP_stack_value}; |
3585 | ArrayRef<uint64_t> Expected = Elements; |
3586 | Expr = DIExpression::get( |
3587 | Context, Elements: {dwarf::DW_OP_LLVM_convert, 32, dwarf::DW_ATE_signed}); |
3588 | Expr = DIExpression::append(Expr, Ops: Expected); |
3589 | ASSERT_EQ(Expr->getNumElements(), 5u); |
3590 | EXPECT_FOLD_CONST(16, -1, 32, -1, 2); |
3591 | EXPECT_EQ(NewExpr->getElements(), Expected); |
3592 | |
3593 | #undef EXPECT_FOLD_CONST |
3594 | } |
3595 | |
3596 | TEST_F(DIExpressionTest, appendToStackAssert) { |
3597 | DIExpression *Expr = DIExpression::get(Context, Elements: {}); |
3598 | |
3599 | // Verify that the DW_OP_LLVM_convert operands, which have the same values as |
3600 | // DW_OP_stack_value and DW_OP_LLVM_fragment, do not get interpreted as such |
3601 | // operations. This previously triggered an assert. |
3602 | uint64_t FromSize = dwarf::DW_OP_stack_value; |
3603 | uint64_t ToSize = dwarf::DW_OP_LLVM_fragment; |
3604 | uint64_t Ops[] = { |
3605 | dwarf::DW_OP_LLVM_convert, FromSize, dwarf::DW_ATE_signed, |
3606 | dwarf::DW_OP_LLVM_convert, ToSize, dwarf::DW_ATE_signed, |
3607 | }; |
3608 | Expr = DIExpression::appendToStack(Expr, Ops); |
3609 | |
3610 | uint64_t Expected[] = { |
3611 | dwarf::DW_OP_LLVM_convert, FromSize, dwarf::DW_ATE_signed, |
3612 | dwarf::DW_OP_LLVM_convert, ToSize, dwarf::DW_ATE_signed, |
3613 | dwarf::DW_OP_stack_value}; |
3614 | EXPECT_EQ(Expr->getElements(), ArrayRef<uint64_t>(Expected)); |
3615 | } |
3616 | |
3617 | typedef MetadataTest DIObjCPropertyTest; |
3618 | |
3619 | TEST_F(DIObjCPropertyTest, get) { |
3620 | StringRef Name = "name" ; |
3621 | DIFile *File = getFile(); |
3622 | unsigned Line = 5; |
3623 | StringRef GetterName = "getter" ; |
3624 | StringRef SetterName = "setter" ; |
3625 | unsigned Attributes = 7; |
3626 | DIType *Type = getBasicType(Name: "basic" ); |
3627 | |
3628 | auto *N = DIObjCProperty::get(Context, Name, File, Line, GetterName, |
3629 | SetterName, Attributes, Type); |
3630 | |
3631 | EXPECT_EQ(dwarf::DW_TAG_APPLE_property, N->getTag()); |
3632 | EXPECT_EQ(Name, N->getName()); |
3633 | EXPECT_EQ(File, N->getFile()); |
3634 | EXPECT_EQ(Line, N->getLine()); |
3635 | EXPECT_EQ(GetterName, N->getGetterName()); |
3636 | EXPECT_EQ(SetterName, N->getSetterName()); |
3637 | EXPECT_EQ(Attributes, N->getAttributes()); |
3638 | EXPECT_EQ(Type, N->getType()); |
3639 | EXPECT_EQ(N, DIObjCProperty::get(Context, Name, File, Line, GetterName, |
3640 | SetterName, Attributes, Type)); |
3641 | |
3642 | EXPECT_NE(N, DIObjCProperty::get(Context, "other" , File, Line, GetterName, |
3643 | SetterName, Attributes, Type)); |
3644 | EXPECT_NE(N, DIObjCProperty::get(Context, Name, getFile(), Line, GetterName, |
3645 | SetterName, Attributes, Type)); |
3646 | EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line + 1, GetterName, |
3647 | SetterName, Attributes, Type)); |
3648 | EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line, "other" , |
3649 | SetterName, Attributes, Type)); |
3650 | EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line, GetterName, |
3651 | "other" , Attributes, Type)); |
3652 | EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line, GetterName, |
3653 | SetterName, Attributes + 1, Type)); |
3654 | EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line, GetterName, |
3655 | SetterName, Attributes, |
3656 | getBasicType("other" ))); |
3657 | |
3658 | TempDIObjCProperty Temp = N->clone(); |
3659 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
3660 | } |
3661 | |
3662 | typedef MetadataTest DIImportedEntityTest; |
3663 | |
3664 | TEST_F(DIImportedEntityTest, get) { |
3665 | unsigned Tag = dwarf::DW_TAG_imported_module; |
3666 | DIScope *Scope = getSubprogram(); |
3667 | DINode *Entity = getCompositeType(); |
3668 | DIFile *File = getFile(); |
3669 | unsigned Line = 5; |
3670 | StringRef Name = "name" ; |
3671 | |
3672 | auto *N = |
3673 | DIImportedEntity::get(Context, Tag, Scope, Entity, File, Line, Name); |
3674 | |
3675 | EXPECT_EQ(Tag, N->getTag()); |
3676 | EXPECT_EQ(Scope, N->getScope()); |
3677 | EXPECT_EQ(Entity, N->getEntity()); |
3678 | EXPECT_EQ(File, N->getFile()); |
3679 | EXPECT_EQ(Line, N->getLine()); |
3680 | EXPECT_EQ(Name, N->getName()); |
3681 | EXPECT_EQ( |
3682 | N, DIImportedEntity::get(Context, Tag, Scope, Entity, File, Line, Name)); |
3683 | |
3684 | EXPECT_NE(N, |
3685 | DIImportedEntity::get(Context, dwarf::DW_TAG_imported_declaration, |
3686 | Scope, Entity, File, Line, Name)); |
3687 | EXPECT_NE(N, DIImportedEntity::get(Context, Tag, getSubprogram(), Entity, |
3688 | File, Line, Name)); |
3689 | EXPECT_NE(N, DIImportedEntity::get(Context, Tag, Scope, getCompositeType(), |
3690 | File, Line, Name)); |
3691 | EXPECT_NE(N, DIImportedEntity::get(Context, Tag, Scope, Entity, nullptr, Line, |
3692 | Name)); |
3693 | EXPECT_NE(N, DIImportedEntity::get(Context, Tag, Scope, Entity, File, |
3694 | Line + 1, Name)); |
3695 | EXPECT_NE(N, DIImportedEntity::get(Context, Tag, Scope, Entity, File, Line, |
3696 | "other" )); |
3697 | |
3698 | TempDIImportedEntity Temp = N->clone(); |
3699 | EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); |
3700 | |
3701 | MDTuple *Elements1 = getTuple(); |
3702 | MDTuple *Elements2 = getTuple(); |
3703 | auto *Ne = DIImportedEntity::get(Context, Tag, Scope, Entity, File, Line, |
3704 | Name, Elements: Elements1); |
3705 | |
3706 | EXPECT_EQ(Elements1, Ne->getElements().get()); |
3707 | |
3708 | EXPECT_EQ(Ne, DIImportedEntity::get(Context, Tag, Scope, Entity, File, Line, |
3709 | Name, Elements1)); |
3710 | EXPECT_NE(Ne, DIImportedEntity::get(Context, Tag, Scope, Entity, File, Line, |
3711 | "ModOther" , Elements1)); |
3712 | EXPECT_NE(Ne, DIImportedEntity::get(Context, Tag, Scope, Entity, File, Line, |
3713 | Name, Elements2)); |
3714 | EXPECT_NE( |
3715 | Ne, DIImportedEntity::get(Context, Tag, Scope, Entity, File, Line, Name)); |
3716 | |
3717 | TempDIImportedEntity Tempe = Ne->clone(); |
3718 | EXPECT_EQ(Ne, MDNode::replaceWithUniqued(std::move(Tempe))); |
3719 | } |
3720 | |
3721 | typedef MetadataTest MetadataAsValueTest; |
3722 | |
3723 | TEST_F(MetadataAsValueTest, MDNode) { |
3724 | MDNode *N = MDNode::get(Context, MDs: std::nullopt); |
3725 | auto *V = MetadataAsValue::get(Context, MD: N); |
3726 | EXPECT_TRUE(V->getType()->isMetadataTy()); |
3727 | EXPECT_EQ(N, V->getMetadata()); |
3728 | |
3729 | auto *V2 = MetadataAsValue::get(Context, MD: N); |
3730 | EXPECT_EQ(V, V2); |
3731 | } |
3732 | |
3733 | TEST_F(MetadataAsValueTest, MDNodeMDNode) { |
3734 | MDNode *N = MDNode::get(Context, MDs: std::nullopt); |
3735 | Metadata *Ops[] = {N}; |
3736 | MDNode *N2 = MDNode::get(Context, MDs: Ops); |
3737 | auto *V = MetadataAsValue::get(Context, MD: N2); |
3738 | EXPECT_TRUE(V->getType()->isMetadataTy()); |
3739 | EXPECT_EQ(N2, V->getMetadata()); |
3740 | |
3741 | auto *V2 = MetadataAsValue::get(Context, MD: N2); |
3742 | EXPECT_EQ(V, V2); |
3743 | |
3744 | auto *V3 = MetadataAsValue::get(Context, MD: N); |
3745 | EXPECT_TRUE(V3->getType()->isMetadataTy()); |
3746 | EXPECT_NE(V, V3); |
3747 | EXPECT_EQ(N, V3->getMetadata()); |
3748 | } |
3749 | |
3750 | TEST_F(MetadataAsValueTest, MDNodeConstant) { |
3751 | auto *C = ConstantInt::getTrue(Context); |
3752 | auto *MD = ConstantAsMetadata::get(C); |
3753 | Metadata *Ops[] = {MD}; |
3754 | auto *N = MDNode::get(Context, MDs: Ops); |
3755 | |
3756 | auto *V = MetadataAsValue::get(Context, MD); |
3757 | EXPECT_TRUE(V->getType()->isMetadataTy()); |
3758 | EXPECT_EQ(MD, V->getMetadata()); |
3759 | |
3760 | auto *V2 = MetadataAsValue::get(Context, MD: N); |
3761 | EXPECT_EQ(MD, V2->getMetadata()); |
3762 | EXPECT_EQ(V, V2); |
3763 | } |
3764 | |
3765 | typedef MetadataTest ValueAsMetadataTest; |
3766 | |
3767 | TEST_F(ValueAsMetadataTest, UpdatesOnRAUW) { |
3768 | Type *Ty = PointerType::getUnqual(C&: Context); |
3769 | std::unique_ptr<GlobalVariable> GV0( |
3770 | new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); |
3771 | auto *MD = ValueAsMetadata::get(V: GV0.get()); |
3772 | EXPECT_TRUE(MD->getValue() == GV0.get()); |
3773 | ASSERT_TRUE(GV0->use_empty()); |
3774 | |
3775 | std::unique_ptr<GlobalVariable> GV1( |
3776 | new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); |
3777 | GV0->replaceAllUsesWith(V: GV1.get()); |
3778 | EXPECT_TRUE(MD->getValue() == GV1.get()); |
3779 | } |
3780 | |
3781 | TEST_F(ValueAsMetadataTest, handleRAUWWithTypeChange) { |
3782 | // Test that handleRAUW supports type changes. |
3783 | // This is helpful in cases where poison values are used to encode |
3784 | // types in metadata, e.g. in type annotations. |
3785 | // Changing the type stored in metadata requires to change the type of |
3786 | // the stored poison value. |
3787 | auto *I32Poison = PoisonValue::get(T: Type::getInt32Ty(C&: Context)); |
3788 | auto *I64Poison = PoisonValue::get(T: Type::getInt64Ty(C&: Context)); |
3789 | auto *MD = ConstantAsMetadata::get(C: I32Poison); |
3790 | |
3791 | EXPECT_EQ(MD->getValue(), I32Poison); |
3792 | EXPECT_NE(MD->getValue(), I64Poison); |
3793 | |
3794 | ValueAsMetadata::handleRAUW(From: I32Poison, To: I64Poison); |
3795 | |
3796 | EXPECT_NE(MD->getValue(), I32Poison); |
3797 | EXPECT_EQ(MD->getValue(), I64Poison); |
3798 | } |
3799 | |
3800 | TEST_F(ValueAsMetadataTest, TempTempReplacement) { |
3801 | // Create a constant. |
3802 | ConstantAsMetadata *CI = |
3803 | ConstantAsMetadata::get(C: ConstantInt::get(Context, V: APInt(8, 0))); |
3804 | |
3805 | auto Temp1 = MDTuple::getTemporary(Context, MDs: std::nullopt); |
3806 | auto Temp2 = MDTuple::getTemporary(Context, MDs: {CI}); |
3807 | auto *N = MDTuple::get(Context, MDs: {Temp1.get()}); |
3808 | |
3809 | // Test replacing a temporary node with another temporary node. |
3810 | Temp1->replaceAllUsesWith(MD: Temp2.get()); |
3811 | EXPECT_EQ(N->getOperand(0), Temp2.get()); |
3812 | |
3813 | // Clean up Temp2 for teardown. |
3814 | Temp2->replaceAllUsesWith(MD: nullptr); |
3815 | } |
3816 | |
3817 | TEST_F(ValueAsMetadataTest, CollidingDoubleUpdates) { |
3818 | // Create a constant. |
3819 | ConstantAsMetadata *CI = |
3820 | ConstantAsMetadata::get(C: ConstantInt::get(Context, V: APInt(8, 0))); |
3821 | |
3822 | // Create a temporary to prevent nodes from resolving. |
3823 | auto Temp = MDTuple::getTemporary(Context, MDs: std::nullopt); |
3824 | |
3825 | // When the first operand of N1 gets reset to nullptr, it'll collide with N2. |
3826 | Metadata *Ops1[] = {CI, CI, Temp.get()}; |
3827 | Metadata *Ops2[] = {nullptr, CI, Temp.get()}; |
3828 | |
3829 | auto *N1 = MDTuple::get(Context, MDs: Ops1); |
3830 | auto *N2 = MDTuple::get(Context, MDs: Ops2); |
3831 | ASSERT_NE(N1, N2); |
3832 | |
3833 | // Tell metadata that the constant is getting deleted. |
3834 | // |
3835 | // After this, N1 will be invalid, so don't touch it. |
3836 | ValueAsMetadata::handleDeletion(V: CI->getValue()); |
3837 | EXPECT_EQ(nullptr, N2->getOperand(0)); |
3838 | EXPECT_EQ(nullptr, N2->getOperand(1)); |
3839 | EXPECT_EQ(Temp.get(), N2->getOperand(2)); |
3840 | |
3841 | // Clean up Temp for teardown. |
3842 | Temp->replaceAllUsesWith(MD: nullptr); |
3843 | } |
3844 | |
3845 | typedef MetadataTest DIArgListTest; |
3846 | |
3847 | TEST_F(DIArgListTest, get) { |
3848 | SmallVector<ValueAsMetadata *, 2> VMs; |
3849 | VMs.push_back( |
3850 | Elt: ConstantAsMetadata::get(C: ConstantInt::get(Context, V: APInt(8, 0)))); |
3851 | VMs.push_back( |
3852 | Elt: ConstantAsMetadata::get(C: ConstantInt::get(Context, V: APInt(2, 0)))); |
3853 | DIArgList *DV0 = DIArgList::get(Context, Args: VMs); |
3854 | DIArgList *DV1 = DIArgList::get(Context, Args: VMs); |
3855 | EXPECT_EQ(DV0, DV1); |
3856 | } |
3857 | |
3858 | TEST_F(DIArgListTest, UpdatesOnRAUW) { |
3859 | Type *Ty = PointerType::getUnqual(C&: Context); |
3860 | ConstantAsMetadata *CI = |
3861 | ConstantAsMetadata::get(C: ConstantInt::get(Context, V: APInt(8, 0))); |
3862 | std::unique_ptr<GlobalVariable> GV0( |
3863 | new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); |
3864 | auto *MD0 = ValueAsMetadata::get(V: GV0.get()); |
3865 | |
3866 | SmallVector<ValueAsMetadata *, 2> VMs; |
3867 | VMs.push_back(Elt: CI); |
3868 | VMs.push_back(Elt: MD0); |
3869 | auto *AL = DIArgList::get(Context, Args: VMs); |
3870 | EXPECT_EQ(AL->getArgs()[0], CI); |
3871 | EXPECT_EQ(AL->getArgs()[1], MD0); |
3872 | |
3873 | std::unique_ptr<GlobalVariable> GV1( |
3874 | new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); |
3875 | auto *MD1 = ValueAsMetadata::get(V: GV1.get()); |
3876 | GV0->replaceAllUsesWith(V: GV1.get()); |
3877 | EXPECT_EQ(AL->getArgs()[0], CI); |
3878 | EXPECT_EQ(AL->getArgs()[1], MD1); |
3879 | } |
3880 | |
3881 | typedef MetadataTest TrackingMDRefTest; |
3882 | |
3883 | TEST_F(TrackingMDRefTest, UpdatesOnRAUW) { |
3884 | Type *Ty = PointerType::getUnqual(C&: Context); |
3885 | std::unique_ptr<GlobalVariable> GV0( |
3886 | new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); |
3887 | TypedTrackingMDRef<ValueAsMetadata> MD(ValueAsMetadata::get(V: GV0.get())); |
3888 | EXPECT_TRUE(MD->getValue() == GV0.get()); |
3889 | ASSERT_TRUE(GV0->use_empty()); |
3890 | |
3891 | std::unique_ptr<GlobalVariable> GV1( |
3892 | new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); |
3893 | GV0->replaceAllUsesWith(V: GV1.get()); |
3894 | EXPECT_TRUE(MD->getValue() == GV1.get()); |
3895 | |
3896 | // Reset it, so we don't inadvertently test deletion. |
3897 | MD.reset(); |
3898 | } |
3899 | |
3900 | TEST_F(TrackingMDRefTest, UpdatesOnDeletion) { |
3901 | Type *Ty = PointerType::getUnqual(C&: Context); |
3902 | std::unique_ptr<GlobalVariable> GV( |
3903 | new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); |
3904 | TypedTrackingMDRef<ValueAsMetadata> MD(ValueAsMetadata::get(V: GV.get())); |
3905 | EXPECT_TRUE(MD->getValue() == GV.get()); |
3906 | ASSERT_TRUE(GV->use_empty()); |
3907 | |
3908 | GV.reset(); |
3909 | EXPECT_TRUE(!MD); |
3910 | } |
3911 | |
3912 | TEST(NamedMDNodeTest, Search) { |
3913 | LLVMContext Context; |
3914 | ConstantAsMetadata *C = |
3915 | ConstantAsMetadata::get(C: ConstantInt::get(Ty: Type::getInt32Ty(C&: Context), V: 1)); |
3916 | ConstantAsMetadata *C2 = |
3917 | ConstantAsMetadata::get(C: ConstantInt::get(Ty: Type::getInt32Ty(C&: Context), V: 2)); |
3918 | |
3919 | Metadata *const V = C; |
3920 | Metadata *const V2 = C2; |
3921 | MDNode *n = MDNode::get(Context, MDs: V); |
3922 | MDNode *n2 = MDNode::get(Context, MDs: V2); |
3923 | |
3924 | Module M("MyModule" , Context); |
3925 | const char *Name = "llvm.NMD1" ; |
3926 | NamedMDNode *NMD = M.getOrInsertNamedMetadata(Name); |
3927 | NMD->addOperand(M: n); |
3928 | NMD->addOperand(M: n2); |
3929 | |
3930 | std::string Str; |
3931 | raw_string_ostream oss(Str); |
3932 | NMD->print(ROS&: oss); |
3933 | EXPECT_STREQ("!llvm.NMD1 = !{!0, !1}\n" , |
3934 | oss.str().c_str()); |
3935 | } |
3936 | |
3937 | typedef MetadataTest FunctionAttachmentTest; |
3938 | TEST_F(FunctionAttachmentTest, setMetadata) { |
3939 | Function *F = getFunction(Name: "foo" ); |
3940 | ASSERT_FALSE(F->hasMetadata()); |
3941 | EXPECT_EQ(nullptr, F->getMetadata(LLVMContext::MD_dbg)); |
3942 | EXPECT_EQ(nullptr, F->getMetadata("dbg" )); |
3943 | EXPECT_EQ(nullptr, F->getMetadata("other" )); |
3944 | |
3945 | DISubprogram *SP1 = getSubprogram(); |
3946 | DISubprogram *SP2 = getSubprogram(); |
3947 | ASSERT_NE(SP1, SP2); |
3948 | |
3949 | F->setMetadata(Kind: "dbg" , Node: SP1); |
3950 | EXPECT_TRUE(F->hasMetadata()); |
3951 | EXPECT_EQ(SP1, F->getMetadata(LLVMContext::MD_dbg)); |
3952 | EXPECT_EQ(SP1, F->getMetadata("dbg" )); |
3953 | EXPECT_EQ(nullptr, F->getMetadata("other" )); |
3954 | |
3955 | F->setMetadata(KindID: LLVMContext::MD_dbg, Node: SP2); |
3956 | EXPECT_TRUE(F->hasMetadata()); |
3957 | EXPECT_EQ(SP2, F->getMetadata(LLVMContext::MD_dbg)); |
3958 | EXPECT_EQ(SP2, F->getMetadata("dbg" )); |
3959 | EXPECT_EQ(nullptr, F->getMetadata("other" )); |
3960 | |
3961 | F->setMetadata(Kind: "dbg" , Node: nullptr); |
3962 | EXPECT_FALSE(F->hasMetadata()); |
3963 | EXPECT_EQ(nullptr, F->getMetadata(LLVMContext::MD_dbg)); |
3964 | EXPECT_EQ(nullptr, F->getMetadata("dbg" )); |
3965 | EXPECT_EQ(nullptr, F->getMetadata("other" )); |
3966 | |
3967 | MDTuple *T1 = getTuple(); |
3968 | MDTuple *T2 = getTuple(); |
3969 | ASSERT_NE(T1, T2); |
3970 | |
3971 | F->setMetadata(Kind: "other1" , Node: T1); |
3972 | F->setMetadata(Kind: "other2" , Node: T2); |
3973 | EXPECT_TRUE(F->hasMetadata()); |
3974 | EXPECT_EQ(T1, F->getMetadata("other1" )); |
3975 | EXPECT_EQ(T2, F->getMetadata("other2" )); |
3976 | EXPECT_EQ(nullptr, F->getMetadata("dbg" )); |
3977 | |
3978 | F->setMetadata(Kind: "other1" , Node: T2); |
3979 | F->setMetadata(Kind: "other2" , Node: T1); |
3980 | EXPECT_EQ(T2, F->getMetadata("other1" )); |
3981 | EXPECT_EQ(T1, F->getMetadata("other2" )); |
3982 | |
3983 | F->setMetadata(Kind: "other1" , Node: nullptr); |
3984 | F->setMetadata(Kind: "other2" , Node: nullptr); |
3985 | EXPECT_FALSE(F->hasMetadata()); |
3986 | EXPECT_EQ(nullptr, F->getMetadata("other1" )); |
3987 | EXPECT_EQ(nullptr, F->getMetadata("other2" )); |
3988 | } |
3989 | |
3990 | TEST_F(FunctionAttachmentTest, getAll) { |
3991 | Function *F = getFunction(Name: "foo" ); |
3992 | |
3993 | MDTuple *T1 = getTuple(); |
3994 | MDTuple *T2 = getTuple(); |
3995 | MDTuple *P = getTuple(); |
3996 | DISubprogram *SP = getSubprogram(); |
3997 | |
3998 | F->setMetadata(Kind: "other1" , Node: T2); |
3999 | F->setMetadata(KindID: LLVMContext::MD_dbg, Node: SP); |
4000 | F->setMetadata(Kind: "other2" , Node: T1); |
4001 | F->setMetadata(KindID: LLVMContext::MD_prof, Node: P); |
4002 | F->setMetadata(Kind: "other2" , Node: T2); |
4003 | F->setMetadata(Kind: "other1" , Node: T1); |
4004 | |
4005 | SmallVector<std::pair<unsigned, MDNode *>, 4> MDs; |
4006 | F->getAllMetadata(MDs); |
4007 | ASSERT_EQ(4u, MDs.size()); |
4008 | EXPECT_EQ(LLVMContext::MD_dbg, MDs[0].first); |
4009 | EXPECT_EQ(LLVMContext::MD_prof, MDs[1].first); |
4010 | EXPECT_EQ(Context.getMDKindID("other1" ), MDs[2].first); |
4011 | EXPECT_EQ(Context.getMDKindID("other2" ), MDs[3].first); |
4012 | EXPECT_EQ(SP, MDs[0].second); |
4013 | EXPECT_EQ(P, MDs[1].second); |
4014 | EXPECT_EQ(T1, MDs[2].second); |
4015 | EXPECT_EQ(T2, MDs[3].second); |
4016 | } |
4017 | |
4018 | TEST_F(FunctionAttachmentTest, Verifier) { |
4019 | Function *F = getFunction(Name: "foo" ); |
4020 | F->setMetadata(Kind: "attach" , Node: getTuple()); |
4021 | F->setIsMaterializable(true); |
4022 | |
4023 | // Confirm this is materializable. |
4024 | ASSERT_TRUE(F->isMaterializable()); |
4025 | |
4026 | // Materializable functions cannot have metadata attachments. |
4027 | EXPECT_TRUE(verifyFunction(*F)); |
4028 | |
4029 | // Function declarations can. |
4030 | F->setIsMaterializable(false); |
4031 | EXPECT_FALSE(verifyModule(*F->getParent())); |
4032 | EXPECT_FALSE(verifyFunction(*F)); |
4033 | |
4034 | // So can definitions. |
4035 | (void)new UnreachableInst(Context, BasicBlock::Create(Context, Name: "bb" , Parent: F)); |
4036 | EXPECT_FALSE(verifyModule(*F->getParent())); |
4037 | EXPECT_FALSE(verifyFunction(*F)); |
4038 | } |
4039 | |
4040 | TEST_F(FunctionAttachmentTest, RealEntryCount) { |
4041 | Function *F = getFunction(Name: "foo" ); |
4042 | EXPECT_FALSE(F->getEntryCount().has_value()); |
4043 | F->setEntryCount(Count: 12304, Type: Function::PCT_Real); |
4044 | auto Count = F->getEntryCount(); |
4045 | EXPECT_TRUE(Count.has_value()); |
4046 | EXPECT_EQ(12304u, Count->getCount()); |
4047 | EXPECT_EQ(Function::PCT_Real, Count->getType()); |
4048 | } |
4049 | |
4050 | TEST_F(FunctionAttachmentTest, SyntheticEntryCount) { |
4051 | Function *F = getFunction(Name: "bar" ); |
4052 | EXPECT_FALSE(F->getEntryCount().has_value()); |
4053 | F->setEntryCount(Count: 123, Type: Function::PCT_Synthetic); |
4054 | auto Count = F->getEntryCount(AllowSynthetic: true /*allow synthetic*/); |
4055 | EXPECT_TRUE(Count.has_value()); |
4056 | EXPECT_EQ(123u, Count->getCount()); |
4057 | EXPECT_EQ(Function::PCT_Synthetic, Count->getType()); |
4058 | } |
4059 | |
4060 | TEST_F(FunctionAttachmentTest, SubprogramAttachment) { |
4061 | Function *F = getFunction(Name: "foo" ); |
4062 | DISubprogram *SP = getSubprogram(); |
4063 | F->setSubprogram(SP); |
4064 | |
4065 | // Note that the static_cast confirms that F->getSubprogram() actually |
4066 | // returns an DISubprogram. |
4067 | EXPECT_EQ(SP, static_cast<DISubprogram *>(F->getSubprogram())); |
4068 | EXPECT_EQ(SP, F->getMetadata("dbg" )); |
4069 | EXPECT_EQ(SP, F->getMetadata(LLVMContext::MD_dbg)); |
4070 | } |
4071 | |
4072 | typedef MetadataTest DistinctMDOperandPlaceholderTest; |
4073 | TEST_F(DistinctMDOperandPlaceholderTest, getID) { |
4074 | EXPECT_EQ(7u, DistinctMDOperandPlaceholder(7).getID()); |
4075 | } |
4076 | |
4077 | TEST_F(DistinctMDOperandPlaceholderTest, replaceUseWith) { |
4078 | // Set up some placeholders. |
4079 | DistinctMDOperandPlaceholder PH0(7); |
4080 | DistinctMDOperandPlaceholder PH1(3); |
4081 | DistinctMDOperandPlaceholder PH2(0); |
4082 | Metadata *Ops[] = {&PH0, &PH1, &PH2}; |
4083 | auto *D = MDTuple::getDistinct(Context, MDs: Ops); |
4084 | ASSERT_EQ(&PH0, D->getOperand(0)); |
4085 | ASSERT_EQ(&PH1, D->getOperand(1)); |
4086 | ASSERT_EQ(&PH2, D->getOperand(2)); |
4087 | |
4088 | // Replace them. |
4089 | auto *N0 = MDTuple::get(Context, MDs: std::nullopt); |
4090 | auto *N1 = MDTuple::get(Context, MDs: N0); |
4091 | PH0.replaceUseWith(MD: N0); |
4092 | PH1.replaceUseWith(MD: N1); |
4093 | PH2.replaceUseWith(MD: nullptr); |
4094 | EXPECT_EQ(N0, D->getOperand(0)); |
4095 | EXPECT_EQ(N1, D->getOperand(1)); |
4096 | EXPECT_EQ(nullptr, D->getOperand(2)); |
4097 | } |
4098 | |
4099 | TEST_F(DistinctMDOperandPlaceholderTest, replaceUseWithNoUser) { |
4100 | // There is no user, but we can still call replace. |
4101 | DistinctMDOperandPlaceholder(7).replaceUseWith( |
4102 | MD: MDTuple::get(Context, MDs: std::nullopt)); |
4103 | } |
4104 | |
4105 | // Test various assertions in metadata tracking. Don't run these tests if gtest |
4106 | // will use SEH to recover from them. Two of these tests get halfway through |
4107 | // inserting metadata into DenseMaps for tracking purposes, and then they |
4108 | // assert, and we attempt to destroy an LLVMContext with broken invariants, |
4109 | // leading to infinite loops. |
4110 | #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) && !defined(GTEST_HAS_SEH) |
4111 | TEST_F(DistinctMDOperandPlaceholderTest, MetadataAsValue) { |
4112 | // This shouldn't crash. |
4113 | DistinctMDOperandPlaceholder PH(7); |
4114 | EXPECT_DEATH(MetadataAsValue::get(Context, &PH), |
4115 | "Unexpected callback to owner" ); |
4116 | } |
4117 | |
4118 | TEST_F(DistinctMDOperandPlaceholderTest, UniquedMDNode) { |
4119 | // This shouldn't crash. |
4120 | DistinctMDOperandPlaceholder PH(7); |
4121 | EXPECT_DEATH(MDTuple::get(Context, &PH), "Unexpected callback to owner" ); |
4122 | } |
4123 | |
4124 | TEST_F(DistinctMDOperandPlaceholderTest, SecondDistinctMDNode) { |
4125 | // This shouldn't crash. |
4126 | DistinctMDOperandPlaceholder PH(7); |
4127 | MDTuple::getDistinct(Context, &PH); |
4128 | EXPECT_DEATH(MDTuple::getDistinct(Context, &PH), |
4129 | "Placeholders can only be used once" ); |
4130 | } |
4131 | |
4132 | TEST_F(DistinctMDOperandPlaceholderTest, TrackingMDRefAndDistinctMDNode) { |
4133 | // TrackingMDRef doesn't install an owner callback, so it can't be detected |
4134 | // as an invalid use. However, using a placeholder in a TrackingMDRef *and* |
4135 | // a distinct node isn't possible and we should assert. |
4136 | // |
4137 | // (There's no positive test for using TrackingMDRef because it's not a |
4138 | // useful thing to do.) |
4139 | { |
4140 | DistinctMDOperandPlaceholder PH(7); |
4141 | MDTuple::getDistinct(Context, &PH); |
4142 | EXPECT_DEATH(TrackingMDRef Ref(&PH), "Placeholders can only be used once" ); |
4143 | } |
4144 | { |
4145 | DistinctMDOperandPlaceholder PH(7); |
4146 | TrackingMDRef Ref(&PH); |
4147 | EXPECT_DEATH(MDTuple::getDistinct(Context, &PH), |
4148 | "Placeholders can only be used once" ); |
4149 | } |
4150 | } |
4151 | #endif |
4152 | |
4153 | typedef MetadataTest DebugVariableTest; |
4154 | TEST_F(DebugVariableTest, DenseMap) { |
4155 | DenseMap<DebugVariable, uint64_t> DebugVariableMap; |
4156 | |
4157 | DILocalScope *Scope = getSubprogram(); |
4158 | DIFile *File = getFile(); |
4159 | DIType *Type = getDerivedType(); |
4160 | DINode::DIFlags Flags = static_cast<DINode::DIFlags>(7); |
4161 | |
4162 | DILocation *InlinedLoc = DILocation::get(Context, Line: 2, Column: 7, Scope); |
4163 | |
4164 | DILocalVariable *VarA = |
4165 | DILocalVariable::get(Context, Scope, Name: "A" , File, Line: 5, Type, Arg: 2, Flags, AlignInBits: 8, Annotations: nullptr); |
4166 | DILocalVariable *VarB = |
4167 | DILocalVariable::get(Context, Scope, Name: "B" , File, Line: 7, Type, Arg: 3, Flags, AlignInBits: 8, Annotations: nullptr); |
4168 | |
4169 | DebugVariable DebugVariableA(VarA, std::nullopt, nullptr); |
4170 | DebugVariable DebugVariableInlineA(VarA, std::nullopt, InlinedLoc); |
4171 | DebugVariable DebugVariableB(VarB, std::nullopt, nullptr); |
4172 | DebugVariable DebugVariableFragB(VarB, {{16, 16}}, nullptr); |
4173 | |
4174 | DebugVariableMap.insert(KV: {DebugVariableA, 2}); |
4175 | DebugVariableMap.insert(KV: {DebugVariableInlineA, 3}); |
4176 | DebugVariableMap.insert(KV: {DebugVariableB, 6}); |
4177 | DebugVariableMap.insert(KV: {DebugVariableFragB, 12}); |
4178 | |
4179 | EXPECT_EQ(DebugVariableMap.count(DebugVariableA), 1u); |
4180 | EXPECT_EQ(DebugVariableMap.count(DebugVariableInlineA), 1u); |
4181 | EXPECT_EQ(DebugVariableMap.count(DebugVariableB), 1u); |
4182 | EXPECT_EQ(DebugVariableMap.count(DebugVariableFragB), 1u); |
4183 | |
4184 | EXPECT_EQ(DebugVariableMap.find(DebugVariableA)->second, 2u); |
4185 | EXPECT_EQ(DebugVariableMap.find(DebugVariableInlineA)->second, 3u); |
4186 | EXPECT_EQ(DebugVariableMap.find(DebugVariableB)->second, 6u); |
4187 | EXPECT_EQ(DebugVariableMap.find(DebugVariableFragB)->second, 12u); |
4188 | } |
4189 | |
4190 | typedef MetadataTest MDTupleAllocationTest; |
4191 | TEST_F(MDTupleAllocationTest, Tracking) { |
4192 | // Make sure that the move constructor and move assignment op |
4193 | // for MDOperand correctly adjust tracking information. |
4194 | auto *Value1 = getConstantAsMetadata(); |
4195 | MDTuple *A = MDTuple::getDistinct(Context, MDs: {Value1, Value1}); |
4196 | EXPECT_EQ(A->getOperand(0), Value1); |
4197 | EXPECT_EQ(A->getOperand(1), Value1); |
4198 | |
4199 | MDNode::op_range Ops = A->operands(); |
4200 | |
4201 | MDOperand NewOps1; |
4202 | // Move assignment operator. |
4203 | NewOps1 = std::move(*const_cast<MDOperand *>(Ops.begin())); |
4204 | // Move constructor. |
4205 | MDOperand NewOps2(std::move(*const_cast<MDOperand *>(Ops.begin() + 1))); |
4206 | |
4207 | EXPECT_EQ(NewOps1.get(), static_cast<Metadata *>(Value1)); |
4208 | EXPECT_EQ(NewOps2.get(), static_cast<Metadata *>(Value1)); |
4209 | |
4210 | auto *Value2 = getConstantAsMetadata(); |
4211 | Value *V1 = Value1->getValue(); |
4212 | Value *V2 = Value2->getValue(); |
4213 | ValueAsMetadata::handleRAUW(From: V1, To: V2); |
4214 | |
4215 | EXPECT_EQ(NewOps1.get(), static_cast<Metadata *>(Value2)); |
4216 | EXPECT_EQ(NewOps2.get(), static_cast<Metadata *>(Value2)); |
4217 | } |
4218 | |
4219 | TEST_F(MDTupleAllocationTest, Resize) { |
4220 | MDTuple *A = getTuple(); |
4221 | Metadata *Value1 = getConstantAsMetadata(); |
4222 | Metadata *Value2 = getConstantAsMetadata(); |
4223 | Metadata *Value3 = getConstantAsMetadata(); |
4224 | |
4225 | EXPECT_EQ(A->getNumOperands(), 0u); |
4226 | |
4227 | // Add a couple of elements to it, which resizes the node. |
4228 | A->push_back(MD: Value1); |
4229 | EXPECT_EQ(A->getNumOperands(), 1u); |
4230 | EXPECT_EQ(A->getOperand(0), Value1); |
4231 | |
4232 | A->push_back(MD: Value2); |
4233 | EXPECT_EQ(A->getNumOperands(), 2u); |
4234 | EXPECT_EQ(A->getOperand(0), Value1); |
4235 | EXPECT_EQ(A->getOperand(1), Value2); |
4236 | |
4237 | // Append another element, which should resize the node |
4238 | // to a "large" node, though not detectable by the user. |
4239 | A->push_back(MD: Value3); |
4240 | EXPECT_EQ(A->getNumOperands(), 3u); |
4241 | EXPECT_EQ(A->getOperand(0), Value1); |
4242 | EXPECT_EQ(A->getOperand(1), Value2); |
4243 | EXPECT_EQ(A->getOperand(2), Value3); |
4244 | |
4245 | // Remove the last element |
4246 | A->pop_back(); |
4247 | EXPECT_EQ(A->getNumOperands(), 2u); |
4248 | EXPECT_EQ(A->getOperand(1), Value2); |
4249 | |
4250 | // Allocate a node with 4 operands. |
4251 | Metadata *Value4 = getConstantAsMetadata(); |
4252 | Metadata *Value5 = getConstantAsMetadata(); |
4253 | |
4254 | Metadata *Ops[] = {Value1, Value2, Value3, Value4}; |
4255 | MDTuple *B = MDTuple::getDistinct(Context, MDs: Ops); |
4256 | |
4257 | EXPECT_EQ(B->getNumOperands(), 4u); |
4258 | B->pop_back(); |
4259 | EXPECT_EQ(B->getNumOperands(), 3u); |
4260 | B->push_back(MD: Value5); |
4261 | EXPECT_EQ(B->getNumOperands(), 4u); |
4262 | EXPECT_EQ(B->getOperand(0), Value1); |
4263 | EXPECT_EQ(B->getOperand(1), Value2); |
4264 | EXPECT_EQ(B->getOperand(2), Value3); |
4265 | EXPECT_EQ(B->getOperand(3), Value5); |
4266 | |
4267 | // Check that we can resize temporary nodes as well. |
4268 | auto Temp1 = MDTuple::getTemporary(Context, MDs: std::nullopt); |
4269 | EXPECT_EQ(Temp1->getNumOperands(), 0u); |
4270 | |
4271 | Temp1->push_back(MD: Value1); |
4272 | EXPECT_EQ(Temp1->getNumOperands(), 1u); |
4273 | EXPECT_EQ(Temp1->getOperand(0), Value1); |
4274 | |
4275 | for (int i = 0; i < 11; i++) |
4276 | Temp1->push_back(MD: Value2); |
4277 | EXPECT_EQ(Temp1->getNumOperands(), 12u); |
4278 | EXPECT_EQ(Temp1->getOperand(2), Value2); |
4279 | EXPECT_EQ(Temp1->getOperand(11), Value2); |
4280 | |
4281 | // Allocate a node that starts off as a large one. |
4282 | Metadata *OpsLarge[] = {Value1, Value2, Value3, Value4, |
4283 | Value1, Value2, Value3, Value4, |
4284 | Value1, Value2, Value3, Value4, |
4285 | Value1, Value2, Value3, Value4, |
4286 | Value1, Value2, Value3, Value4}; |
4287 | MDTuple *C = MDTuple::getDistinct(Context, MDs: OpsLarge); |
4288 | EXPECT_EQ(C->getNumOperands(), 20u); |
4289 | EXPECT_EQ(C->getOperand(7), Value4); |
4290 | EXPECT_EQ(C->getOperand(13), Value2); |
4291 | |
4292 | C->push_back(MD: Value1); |
4293 | C->push_back(MD: Value2); |
4294 | EXPECT_EQ(C->getNumOperands(), 22u); |
4295 | EXPECT_EQ(C->getOperand(21), Value2); |
4296 | C->pop_back(); |
4297 | EXPECT_EQ(C->getNumOperands(), 21u); |
4298 | EXPECT_EQ(C->getOperand(20), Value1); |
4299 | } |
4300 | |
4301 | TEST_F(MDTupleAllocationTest, Tracking2) { |
4302 | // Resize a tuple and check that we can still RAUW one of its operands. |
4303 | auto *Value1 = getConstantAsMetadata(); |
4304 | MDTuple *A = getTuple(); |
4305 | A->push_back(MD: Value1); |
4306 | A->push_back(MD: Value1); |
4307 | A->push_back(MD: Value1); // Causes a resize to large. |
4308 | EXPECT_EQ(A->getOperand(0), Value1); |
4309 | EXPECT_EQ(A->getOperand(1), Value1); |
4310 | EXPECT_EQ(A->getOperand(2), Value1); |
4311 | |
4312 | auto *Value2 = getConstantAsMetadata(); |
4313 | Value *V1 = Value1->getValue(); |
4314 | Value *V2 = Value2->getValue(); |
4315 | ValueAsMetadata::handleRAUW(From: V1, To: V2); |
4316 | |
4317 | EXPECT_EQ(A->getOperand(0), Value2); |
4318 | EXPECT_EQ(A->getOperand(1), Value2); |
4319 | EXPECT_EQ(A->getOperand(2), Value2); |
4320 | } |
4321 | |
4322 | #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) && !defined(GTEST_HAS_SEH) |
4323 | typedef MetadataTest MDTupleAllocationDeathTest; |
4324 | TEST_F(MDTupleAllocationDeathTest, ResizeRejected) { |
4325 | MDTuple *A = MDTuple::get(Context, std::nullopt); |
4326 | auto *Value1 = getConstantAsMetadata(); |
4327 | EXPECT_DEATH(A->push_back(Value1), |
4328 | "Resizing is not supported for uniqued nodes" ); |
4329 | |
4330 | // Check that a node, which has been allocated as a temporary, |
4331 | // cannot be resized after it has been uniqued. |
4332 | auto *Value2 = getConstantAsMetadata(); |
4333 | auto B = MDTuple::getTemporary(Context, {Value2}); |
4334 | B->push_back(Value2); |
4335 | MDTuple *BUniqued = MDNode::replaceWithUniqued(std::move(B)); |
4336 | EXPECT_EQ(BUniqued->getNumOperands(), 2u); |
4337 | EXPECT_EQ(BUniqued->getOperand(1), Value2); |
4338 | EXPECT_DEATH(BUniqued->push_back(Value2), |
4339 | "Resizing is not supported for uniqued nodes" ); |
4340 | } |
4341 | #endif |
4342 | |
4343 | } // end namespace |
4344 | |