1 | //===- llvm/unittest/IR/ValueTest.cpp - Value 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/Value.h" |
10 | #include "llvm/AsmParser/Parser.h" |
11 | #include "llvm/IR/Function.h" |
12 | #include "llvm/IR/IntrinsicInst.h" |
13 | #include "llvm/IR/LLVMContext.h" |
14 | #include "llvm/IR/Module.h" |
15 | #include "llvm/IR/ModuleSlotTracker.h" |
16 | #include "llvm/Support/SourceMgr.h" |
17 | #include "gtest/gtest.h" |
18 | using namespace llvm; |
19 | |
20 | extern cl::opt<bool> UseNewDbgInfoFormat; |
21 | |
22 | namespace { |
23 | |
24 | TEST(ValueTest, UsedInBasicBlock) { |
25 | LLVMContext C; |
26 | |
27 | const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n" |
28 | "bb0:\n" |
29 | " %y1 = add i32 %y, 1\n" |
30 | " %y2 = add i32 %y, 1\n" |
31 | " %y3 = add i32 %y, 1\n" |
32 | " %y4 = add i32 %y, 1\n" |
33 | " %y5 = add i32 %y, 1\n" |
34 | " %y6 = add i32 %y, 1\n" |
35 | " %y7 = add i32 %y, 1\n" |
36 | " %y8 = add i32 %x, 1\n" |
37 | " ret void\n" |
38 | "}\n" ; |
39 | SMDiagnostic Err; |
40 | std::unique_ptr<Module> M = parseAssemblyString(AsmString: ModuleString, Err, Context&: C); |
41 | |
42 | Function *F = M->getFunction(Name: "f" ); |
43 | |
44 | EXPECT_FALSE(F->isUsedInBasicBlock(&F->front())); |
45 | EXPECT_TRUE(std::next(F->arg_begin())->isUsedInBasicBlock(&F->front())); |
46 | EXPECT_TRUE(F->arg_begin()->isUsedInBasicBlock(&F->front())); |
47 | } |
48 | |
49 | TEST(GlobalTest, CreateAddressSpace) { |
50 | LLVMContext Ctx; |
51 | std::unique_ptr<Module> M(new Module("TestModule" , Ctx)); |
52 | Type *Int8Ty = Type::getInt8Ty(C&: Ctx); |
53 | Type *Int32Ty = Type::getInt32Ty(C&: Ctx); |
54 | |
55 | GlobalVariable *Dummy0 |
56 | = new GlobalVariable(*M, |
57 | Int32Ty, |
58 | true, |
59 | GlobalValue::ExternalLinkage, |
60 | Constant::getAllOnesValue(Ty: Int32Ty), |
61 | "dummy" , |
62 | nullptr, |
63 | GlobalVariable::NotThreadLocal, |
64 | 1); |
65 | |
66 | const Align kMaxAlignment(Value::MaximumAlignment); |
67 | EXPECT_TRUE(kMaxAlignment.value() == 4294967296ULL); |
68 | Dummy0->setAlignment(kMaxAlignment); |
69 | EXPECT_TRUE(Dummy0->getAlign()); |
70 | EXPECT_EQ(*Dummy0->getAlign(), kMaxAlignment); |
71 | |
72 | // Make sure the address space isn't dropped when returning this. |
73 | Constant *Dummy1 = M->getOrInsertGlobal(Name: "dummy" , Ty: Int32Ty); |
74 | EXPECT_EQ(Dummy0, Dummy1); |
75 | EXPECT_EQ(1u, Dummy1->getType()->getPointerAddressSpace()); |
76 | |
77 | |
78 | // This one requires a bitcast, but the address space must also stay the same. |
79 | GlobalVariable *DummyCast0 |
80 | = new GlobalVariable(*M, |
81 | Int32Ty, |
82 | true, |
83 | GlobalValue::ExternalLinkage, |
84 | Constant::getAllOnesValue(Ty: Int32Ty), |
85 | "dummy_cast" , |
86 | nullptr, |
87 | GlobalVariable::NotThreadLocal, |
88 | 1); |
89 | |
90 | // Make sure the address space isn't dropped when returning this. |
91 | Constant *DummyCast1 = M->getOrInsertGlobal(Name: "dummy_cast" , Ty: Int8Ty); |
92 | EXPECT_EQ(DummyCast0, DummyCast1); |
93 | EXPECT_EQ(1u, DummyCast1->getType()->getPointerAddressSpace()); |
94 | } |
95 | |
96 | #ifdef GTEST_HAS_DEATH_TEST |
97 | #ifndef NDEBUG |
98 | |
99 | TEST(GlobalTest, AlignDeath) { |
100 | LLVMContext Ctx; |
101 | std::unique_ptr<Module> M(new Module("TestModule" , Ctx)); |
102 | Type *Int32Ty = Type::getInt32Ty(C&: Ctx); |
103 | GlobalVariable *Var = |
104 | new GlobalVariable(*M, Int32Ty, true, GlobalValue::ExternalLinkage, |
105 | Constant::getAllOnesValue(Ty: Int32Ty), "var" , nullptr, |
106 | GlobalVariable::NotThreadLocal, 1); |
107 | |
108 | EXPECT_DEATH(Var->setAlignment(Align(8589934592ULL)), |
109 | "Alignment is greater than MaximumAlignment" ); |
110 | } |
111 | #endif |
112 | #endif |
113 | |
114 | TEST(ValueTest, printSlots) { |
115 | // Check that Value::print() and Value::printAsOperand() work with and |
116 | // without a slot tracker. |
117 | LLVMContext C; |
118 | |
119 | const char *ModuleString = "@g0 = external global %500\n" |
120 | "@g1 = external global %900\n" |
121 | "\n" |
122 | "%900 = type { i32, i32 }\n" |
123 | "%500 = type { i32 }\n" |
124 | "\n" |
125 | "define void @f(i32 %x, i32 %y) {\n" |
126 | "entry:\n" |
127 | " %0 = add i32 %y, 1\n" |
128 | " %1 = add i32 %y, 1\n" |
129 | " ret void\n" |
130 | "}\n" ; |
131 | SMDiagnostic Err; |
132 | std::unique_ptr<Module> M = parseAssemblyString(AsmString: ModuleString, Err, Context&: C); |
133 | |
134 | Function *F = M->getFunction(Name: "f" ); |
135 | ASSERT_TRUE(F); |
136 | ASSERT_FALSE(F->empty()); |
137 | BasicBlock &BB = F->getEntryBlock(); |
138 | ASSERT_EQ(3u, BB.size()); |
139 | |
140 | Instruction *I0 = &*BB.begin(); |
141 | ASSERT_TRUE(I0); |
142 | Instruction *I1 = &*++BB.begin(); |
143 | ASSERT_TRUE(I1); |
144 | |
145 | GlobalVariable *G0 = M->getGlobalVariable(Name: "g0" ); |
146 | ASSERT_TRUE(G0); |
147 | GlobalVariable *G1 = M->getGlobalVariable(Name: "g1" ); |
148 | ASSERT_TRUE(G1); |
149 | |
150 | ModuleSlotTracker MST(M.get()); |
151 | |
152 | #define CHECK_PRINT(INST, STR) \ |
153 | do { \ |
154 | { \ |
155 | std::string S; \ |
156 | raw_string_ostream OS(S); \ |
157 | INST->print(OS); \ |
158 | EXPECT_EQ(STR, OS.str()); \ |
159 | } \ |
160 | { \ |
161 | std::string S; \ |
162 | raw_string_ostream OS(S); \ |
163 | INST->print(OS, MST); \ |
164 | EXPECT_EQ(STR, OS.str()); \ |
165 | } \ |
166 | } while (false) |
167 | CHECK_PRINT(I0, " %0 = add i32 %y, 1" ); |
168 | CHECK_PRINT(I1, " %1 = add i32 %y, 1" ); |
169 | #undef CHECK_PRINT |
170 | |
171 | #define CHECK_PRINT_AS_OPERAND(INST, TYPE, STR) \ |
172 | do { \ |
173 | { \ |
174 | std::string S; \ |
175 | raw_string_ostream OS(S); \ |
176 | INST->printAsOperand(OS, TYPE); \ |
177 | EXPECT_EQ(StringRef(STR), StringRef(OS.str())); \ |
178 | } \ |
179 | { \ |
180 | std::string S; \ |
181 | raw_string_ostream OS(S); \ |
182 | INST->printAsOperand(OS, TYPE, MST); \ |
183 | EXPECT_EQ(StringRef(STR), StringRef(OS.str())); \ |
184 | } \ |
185 | } while (false) |
186 | CHECK_PRINT_AS_OPERAND(I0, false, "%0" ); |
187 | CHECK_PRINT_AS_OPERAND(I1, false, "%1" ); |
188 | CHECK_PRINT_AS_OPERAND(I0, true, "i32 %0" ); |
189 | CHECK_PRINT_AS_OPERAND(I1, true, "i32 %1" ); |
190 | CHECK_PRINT_AS_OPERAND(G0, true, "ptr @g0" ); |
191 | CHECK_PRINT_AS_OPERAND(G1, true, "ptr @g1" ); |
192 | #undef CHECK_PRINT_AS_OPERAND |
193 | } |
194 | |
195 | TEST(ValueTest, getLocalSlots) { |
196 | // Verify that the getLocalSlot method returns the correct slot numbers. |
197 | LLVMContext C; |
198 | const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n" |
199 | "entry:\n" |
200 | " %0 = add i32 %y, 1\n" |
201 | " %1 = add i32 %y, 1\n" |
202 | " br label %2\n" |
203 | "\n" |
204 | " ret void\n" |
205 | "}\n" ; |
206 | SMDiagnostic Err; |
207 | std::unique_ptr<Module> M = parseAssemblyString(AsmString: ModuleString, Err, Context&: C); |
208 | |
209 | Function *F = M->getFunction(Name: "f" ); |
210 | ASSERT_TRUE(F); |
211 | ASSERT_FALSE(F->empty()); |
212 | BasicBlock &EntryBB = F->getEntryBlock(); |
213 | ASSERT_EQ(3u, EntryBB.size()); |
214 | BasicBlock *BB2 = &*++F->begin(); |
215 | ASSERT_TRUE(BB2); |
216 | |
217 | Instruction *I0 = &*EntryBB.begin(); |
218 | ASSERT_TRUE(I0); |
219 | Instruction *I1 = &*++EntryBB.begin(); |
220 | ASSERT_TRUE(I1); |
221 | |
222 | ModuleSlotTracker MST(M.get()); |
223 | MST.incorporateFunction(F: *F); |
224 | EXPECT_EQ(MST.getLocalSlot(I0), 0); |
225 | EXPECT_EQ(MST.getLocalSlot(I1), 1); |
226 | EXPECT_EQ(MST.getLocalSlot(&EntryBB), -1); |
227 | EXPECT_EQ(MST.getLocalSlot(BB2), 2); |
228 | } |
229 | |
230 | #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) |
231 | TEST(ValueTest, getLocalSlotDeath) { |
232 | LLVMContext C; |
233 | const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n" |
234 | "entry:\n" |
235 | " %0 = add i32 %y, 1\n" |
236 | " %1 = add i32 %y, 1\n" |
237 | " br label %2\n" |
238 | "\n" |
239 | " ret void\n" |
240 | "}\n" ; |
241 | SMDiagnostic Err; |
242 | std::unique_ptr<Module> M = parseAssemblyString(AsmString: ModuleString, Err, Context&: C); |
243 | |
244 | Function *F = M->getFunction(Name: "f" ); |
245 | ASSERT_TRUE(F); |
246 | ASSERT_FALSE(F->empty()); |
247 | BasicBlock *BB2 = &*++F->begin(); |
248 | ASSERT_TRUE(BB2); |
249 | |
250 | ModuleSlotTracker MST(M.get()); |
251 | EXPECT_DEATH(MST.getLocalSlot(BB2), "No function incorporated" ); |
252 | } |
253 | #endif |
254 | |
255 | TEST(ValueTest, replaceUsesOutsideBlock) { |
256 | // Check that Value::replaceUsesOutsideBlock(New, BB) replaces uses outside |
257 | // BB, including dbg.* uses of MetadataAsValue(ValueAsMetadata(this)). |
258 | const auto *IR = R"( |
259 | define i32 @f() !dbg !6 { |
260 | entry: |
261 | %a = add i32 0, 1, !dbg !15 |
262 | %b = add i32 0, 2, !dbg !15 |
263 | %c = add i32 %a, 2, !dbg !15 |
264 | call void @llvm.dbg.value(metadata i32 %a, metadata !9, metadata !DIExpression()), !dbg !15 |
265 | br label %exit, !dbg !15 |
266 | |
267 | exit: |
268 | call void @llvm.dbg.value(metadata i32 %a, metadata !11, metadata !DIExpression()), !dbg !16 |
269 | ret i32 %a, !dbg !16 |
270 | } |
271 | |
272 | declare void @llvm.dbg.value(metadata, metadata, metadata) |
273 | |
274 | !llvm.dbg.cu = !{!0} |
275 | !llvm.module.flags = !{!5} |
276 | |
277 | !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
278 | !1 = !DIFile(filename: "test.ll", directory: "/") |
279 | !2 = !{} |
280 | !5 = !{i32 2, !"Debug Info Version", i32 3} |
281 | !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !8) |
282 | !7 = !DISubroutineType(types: !2) |
283 | !8 = !{!9, !11} |
284 | !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) |
285 | !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_signed) |
286 | !11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !12) |
287 | !12 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_signed) |
288 | !15 = !DILocation(line: 1, column: 1, scope: !6) |
289 | !16 = !DILocation(line: 5, column: 1, scope: !6) |
290 | )" ; |
291 | LLVMContext Ctx; |
292 | SMDiagnostic Err; |
293 | std::unique_ptr<Module> M = parseAssemblyString(AsmString: IR, Err, Context&: Ctx); |
294 | if (!M) |
295 | Err.print(ProgName: "ValueTest" , S&: errs()); |
296 | |
297 | auto GetNext = [](auto *I) { return &*++I->getIterator(); }; |
298 | |
299 | Function *F = M->getFunction(Name: "f" ); |
300 | // Entry. |
301 | BasicBlock *Entry = &F->front(); |
302 | Instruction *A = &Entry->front(); |
303 | Instruction *B = GetNext(A); |
304 | Instruction *C = GetNext(B); |
305 | auto *EntryDbg = cast<DbgValueInst>(Val: GetNext(C)); |
306 | // Exit. |
307 | BasicBlock *Exit = GetNext(Entry); |
308 | auto *ExitDbg = cast<DbgValueInst>(Val: &Exit->front()); |
309 | Instruction *Ret = GetNext(ExitDbg); |
310 | |
311 | A->replaceUsesOutsideBlock(V: B, BB: Entry); |
312 | // These users are in Entry so shouldn't be changed. |
313 | ASSERT_TRUE(C->getOperand(0) == cast<Value>(A)); |
314 | ASSERT_TRUE(EntryDbg->getValue(0) == cast<Value>(A)); |
315 | // These users are outside Entry so should be changed. |
316 | ASSERT_TRUE(ExitDbg->getValue(0) == cast<Value>(B)); |
317 | ASSERT_TRUE(Ret->getOperand(0) == cast<Value>(B)); |
318 | } |
319 | |
320 | TEST(ValueTest, replaceUsesOutsideBlockDbgVariableRecord) { |
321 | // Check that Value::replaceUsesOutsideBlock(New, BB) replaces uses outside |
322 | // BB, including DbgVariableRecords. |
323 | const auto *IR = R"( |
324 | define i32 @f() !dbg !6 { |
325 | entry: |
326 | %a = add i32 0, 1, !dbg !15 |
327 | %b = add i32 0, 2, !dbg !15 |
328 | %c = add i32 %a, 2, !dbg !15 |
329 | call void @llvm.dbg.value(metadata i32 %a, metadata !9, metadata !DIExpression()), !dbg !15 |
330 | br label %exit, !dbg !15 |
331 | |
332 | exit: |
333 | call void @llvm.dbg.value(metadata i32 %a, metadata !11, metadata !DIExpression()), !dbg !16 |
334 | ret i32 %a, !dbg !16 |
335 | } |
336 | |
337 | declare void @llvm.dbg.value(metadata, metadata, metadata) |
338 | |
339 | !llvm.dbg.cu = !{!0} |
340 | !llvm.module.flags = !{!5} |
341 | |
342 | !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) |
343 | !1 = !DIFile(filename: "test.ll", directory: "/") |
344 | !2 = !{} |
345 | !5 = !{i32 2, !"Debug Info Version", i32 3} |
346 | !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !8) |
347 | !7 = !DISubroutineType(types: !2) |
348 | !8 = !{!9, !11} |
349 | !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) |
350 | !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_signed) |
351 | !11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !12) |
352 | !12 = !DIBasicType(name: "ty64", size: 64, encoding: DW_ATE_signed) |
353 | !15 = !DILocation(line: 1, column: 1, scope: !6) |
354 | !16 = !DILocation(line: 5, column: 1, scope: !6) |
355 | )" ; |
356 | LLVMContext Ctx; |
357 | SMDiagnostic Err; |
358 | std::unique_ptr<Module> M = parseAssemblyString(AsmString: IR, Err, Context&: Ctx); |
359 | if (!M) |
360 | Err.print(ProgName: "ValueTest" , S&: errs()); |
361 | |
362 | bool OldDbgValueMode = UseNewDbgInfoFormat; |
363 | UseNewDbgInfoFormat = true; |
364 | M->convertToNewDbgValues(); |
365 | |
366 | auto GetNext = [](auto *I) { return &*++I->getIterator(); }; |
367 | |
368 | Function *F = M->getFunction(Name: "f" ); |
369 | // Entry. |
370 | BasicBlock *Entry = &F->front(); |
371 | Instruction *A = &Entry->front(); |
372 | Instruction *B = GetNext(A); |
373 | Instruction *C = GetNext(B); |
374 | Instruction *Branch = GetNext(C); |
375 | // Exit. |
376 | BasicBlock *Exit = GetNext(Entry); |
377 | Instruction *Ret = &Exit->front(); |
378 | |
379 | EXPECT_TRUE(Branch->hasDbgRecords()); |
380 | EXPECT_TRUE(Ret->hasDbgRecords()); |
381 | |
382 | DbgVariableRecord *DVR1 = |
383 | cast<DbgVariableRecord>(Val: &*Branch->getDbgRecordRange().begin()); |
384 | DbgVariableRecord *DVR2 = |
385 | cast<DbgVariableRecord>(Val: &*Ret->getDbgRecordRange().begin()); |
386 | |
387 | A->replaceUsesOutsideBlock(V: B, BB: Entry); |
388 | // These users are in Entry so shouldn't be changed. |
389 | EXPECT_TRUE(DVR1->getVariableLocationOp(0) == cast<Value>(A)); |
390 | // These users are outside Entry so should be changed. |
391 | EXPECT_TRUE(DVR2->getVariableLocationOp(0) == cast<Value>(B)); |
392 | UseNewDbgInfoFormat = OldDbgValueMode; |
393 | } |
394 | |
395 | } // end anonymous namespace |
396 | |