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"
18using namespace llvm;
19
20extern cl::opt<bool> UseNewDbgInfoFormat;
21
22namespace {
23
24TEST(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
49TEST(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
99TEST(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
114TEST(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
195TEST(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)
231TEST(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
255TEST(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
320TEST(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

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