1 | //===- llvm/unittest/IR/BasicBlockTest.cpp - BasicBlock 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/BasicBlock.h" |
10 | #include "llvm/ADT/STLExtras.h" |
11 | #include "llvm/AsmParser/Parser.h" |
12 | #include "llvm/IR/Function.h" |
13 | #include "llvm/IR/IRBuilder.h" |
14 | #include "llvm/IR/Instructions.h" |
15 | #include "llvm/IR/LLVMContext.h" |
16 | #include "llvm/IR/Module.h" |
17 | #include "llvm/IR/NoFolder.h" |
18 | #include "llvm/IR/Verifier.h" |
19 | #include "llvm/Support/SourceMgr.h" |
20 | #include "gmock/gmock-matchers.h" |
21 | #include "gtest/gtest.h" |
22 | #include <memory> |
23 | |
24 | namespace llvm { |
25 | namespace { |
26 | |
27 | TEST(BasicBlockTest, PhiRange) { |
28 | LLVMContext Context; |
29 | |
30 | // Create the main block. |
31 | std::unique_ptr<BasicBlock> BB(BasicBlock::Create(Context)); |
32 | |
33 | // Create some predecessors of it. |
34 | std::unique_ptr<BasicBlock> BB1(BasicBlock::Create(Context)); |
35 | BranchInst::Create(IfTrue: BB.get(), InsertAtEnd: BB1.get()); |
36 | std::unique_ptr<BasicBlock> BB2(BasicBlock::Create(Context)); |
37 | BranchInst::Create(IfTrue: BB.get(), InsertAtEnd: BB2.get()); |
38 | |
39 | // Make sure this doesn't crash if there are no phis. |
40 | int PhiCount = 0; |
41 | for (auto &PN : BB->phis()) { |
42 | (void)PN; |
43 | PhiCount++; |
44 | } |
45 | ASSERT_EQ(PhiCount, 0) << "empty block should have no phis" ; |
46 | |
47 | // Make it a cycle. |
48 | auto *BI = BranchInst::Create(IfTrue: BB.get(), InsertAtEnd: BB.get()); |
49 | |
50 | // Now insert some PHI nodes. |
51 | auto *Int32Ty = Type::getInt32Ty(C&: Context); |
52 | auto *P1 = PHINode::Create(Ty: Int32Ty, /*NumReservedValues*/ 3, NameStr: "phi.1" , InsertBefore: BI); |
53 | auto *P2 = PHINode::Create(Ty: Int32Ty, /*NumReservedValues*/ 3, NameStr: "phi.2" , InsertBefore: BI); |
54 | auto *P3 = PHINode::Create(Ty: Int32Ty, /*NumReservedValues*/ 3, NameStr: "phi.3" , InsertBefore: BI); |
55 | |
56 | // Some non-PHI nodes. |
57 | auto *Sum = BinaryOperator::CreateAdd(V1: P1, V2: P2, Name: "sum" , I: BI); |
58 | |
59 | // Now wire up the incoming values that are interesting. |
60 | P1->addIncoming(V: P2, BB: BB.get()); |
61 | P2->addIncoming(V: P1, BB: BB.get()); |
62 | P3->addIncoming(V: Sum, BB: BB.get()); |
63 | |
64 | // Finally, let's iterate them, which is the thing we're trying to test. |
65 | // We'll use this to wire up the rest of the incoming values. |
66 | for (auto &PN : BB->phis()) { |
67 | PN.addIncoming(V: UndefValue::get(T: Int32Ty), BB: BB1.get()); |
68 | PN.addIncoming(V: UndefValue::get(T: Int32Ty), BB: BB2.get()); |
69 | } |
70 | |
71 | // Test that we can use const iterators and generally that the iterators |
72 | // behave like iterators. |
73 | BasicBlock::const_phi_iterator CI; |
74 | CI = BB->phis().begin(); |
75 | EXPECT_NE(CI, BB->phis().end()); |
76 | |
77 | // Test that filtering iterators work with basic blocks. |
78 | auto isPhi = [](Instruction &I) { return isa<PHINode>(Val: &I); }; |
79 | auto Phis = make_filter_range(Range&: *BB, Pred: isPhi); |
80 | auto ReversedPhis = reverse(C: make_filter_range(Range&: *BB, Pred: isPhi)); |
81 | EXPECT_EQ(std::distance(Phis.begin(), Phis.end()), 3); |
82 | EXPECT_EQ(&*Phis.begin(), P1); |
83 | EXPECT_EQ(std::distance(ReversedPhis.begin(), ReversedPhis.end()), 3); |
84 | EXPECT_EQ(&*ReversedPhis.begin(), P3); |
85 | |
86 | // And iterate a const range. |
87 | for (const auto &PN : const_cast<const BasicBlock *>(BB.get())->phis()) { |
88 | EXPECT_EQ(BB.get(), PN.getIncomingBlock(0)); |
89 | EXPECT_EQ(BB1.get(), PN.getIncomingBlock(1)); |
90 | EXPECT_EQ(BB2.get(), PN.getIncomingBlock(2)); |
91 | } |
92 | } |
93 | |
94 | #define CHECK_ITERATORS(Range1, Range2) \ |
95 | EXPECT_EQ(std::distance(Range1.begin(), Range1.end()), \ |
96 | std::distance(Range2.begin(), Range2.end())); \ |
97 | for (auto Pair : zip(Range1, Range2)) \ |
98 | EXPECT_EQ(&std::get<0>(Pair), std::get<1>(Pair)); |
99 | |
100 | TEST(BasicBlockTest, TestInstructionsWithoutDebug) { |
101 | LLVMContext Ctx; |
102 | |
103 | Module *M = new Module("MyModule" , Ctx); |
104 | Type *ArgTy1[] = {PointerType::getUnqual(C&: Ctx)}; |
105 | FunctionType *FT = FunctionType::get(Result: Type::getVoidTy(C&: Ctx), Params: ArgTy1, isVarArg: false); |
106 | Argument *V = new Argument(Type::getInt32Ty(C&: Ctx)); |
107 | Function *F = Function::Create(Ty: FT, Linkage: Function::ExternalLinkage, N: "" , M); |
108 | |
109 | Function *DbgDeclare = Intrinsic::getDeclaration(M, Intrinsic::id: dbg_declare); |
110 | Function *DbgValue = Intrinsic::getDeclaration(M, Intrinsic::id: dbg_value); |
111 | Value *DIV = MetadataAsValue::get(Context&: Ctx, MD: (Metadata *)nullptr); |
112 | SmallVector<Value *, 3> Args = {DIV, DIV, DIV}; |
113 | |
114 | BasicBlock *BB1 = BasicBlock::Create(Context&: Ctx, Name: "" , Parent: F); |
115 | const BasicBlock *BBConst = BB1; |
116 | IRBuilder<> Builder1(BB1); |
117 | |
118 | AllocaInst *Var = Builder1.CreateAlloca(Ty: Builder1.getInt8Ty()); |
119 | Builder1.CreateCall(Callee: DbgValue, Args); |
120 | Instruction *AddInst = cast<Instruction>(Val: Builder1.CreateAdd(LHS: V, RHS: V)); |
121 | Instruction *MulInst = cast<Instruction>(Val: Builder1.CreateMul(LHS: AddInst, RHS: V)); |
122 | Builder1.CreateCall(Callee: DbgDeclare, Args); |
123 | Instruction *SubInst = cast<Instruction>(Val: Builder1.CreateSub(LHS: MulInst, RHS: V)); |
124 | |
125 | SmallVector<Instruction *, 4> Exp = {Var, AddInst, MulInst, SubInst}; |
126 | CHECK_ITERATORS(BB1->instructionsWithoutDebug(), Exp); |
127 | CHECK_ITERATORS(BBConst->instructionsWithoutDebug(), Exp); |
128 | |
129 | EXPECT_EQ(static_cast<size_t>(BB1->sizeWithoutDebug()), Exp.size()); |
130 | EXPECT_EQ(static_cast<size_t>(BBConst->sizeWithoutDebug()), Exp.size()); |
131 | |
132 | delete M; |
133 | delete V; |
134 | } |
135 | |
136 | TEST(BasicBlockTest, ComesBefore) { |
137 | const char *ModuleString = R"(define i32 @f(i32 %x) { |
138 | %add = add i32 %x, 42 |
139 | ret i32 %add |
140 | })" ; |
141 | LLVMContext Ctx; |
142 | SMDiagnostic Err; |
143 | auto M = parseAssemblyString(AsmString: ModuleString, Err, Context&: Ctx); |
144 | ASSERT_TRUE(M.get()); |
145 | |
146 | Function *F = M->getFunction(Name: "f" ); |
147 | BasicBlock &BB = F->front(); |
148 | BasicBlock::iterator I = BB.begin(); |
149 | Instruction *Add = &*I++; |
150 | Instruction *Ret = &*I++; |
151 | |
152 | // Intentionally duplicated to verify cached and uncached are the same. |
153 | EXPECT_FALSE(BB.isInstrOrderValid()); |
154 | EXPECT_FALSE(Add->comesBefore(Add)); |
155 | EXPECT_TRUE(BB.isInstrOrderValid()); |
156 | EXPECT_FALSE(Add->comesBefore(Add)); |
157 | BB.invalidateOrders(); |
158 | EXPECT_FALSE(BB.isInstrOrderValid()); |
159 | EXPECT_TRUE(Add->comesBefore(Ret)); |
160 | EXPECT_TRUE(BB.isInstrOrderValid()); |
161 | EXPECT_TRUE(Add->comesBefore(Ret)); |
162 | BB.invalidateOrders(); |
163 | EXPECT_FALSE(Ret->comesBefore(Add)); |
164 | EXPECT_FALSE(Ret->comesBefore(Add)); |
165 | BB.invalidateOrders(); |
166 | EXPECT_FALSE(Ret->comesBefore(Ret)); |
167 | EXPECT_FALSE(Ret->comesBefore(Ret)); |
168 | } |
169 | |
170 | class InstrOrderInvalidationTest : public ::testing::Test { |
171 | protected: |
172 | void SetUp() override { |
173 | M.reset(p: new Module("MyModule" , Ctx)); |
174 | Nop = Intrinsic::getDeclaration(M: M.get(), Intrinsic::id: donothing); |
175 | FunctionType *FT = FunctionType::get(Result: Type::getVoidTy(C&: Ctx), Params: {}, isVarArg: false); |
176 | Function *F = Function::Create(Ty: FT, Linkage: Function::ExternalLinkage, N: "foo" , M&: *M); |
177 | BB = BasicBlock::Create(Context&: Ctx, Name: "entry" , Parent: F); |
178 | |
179 | IRBuilder<> Builder(BB); |
180 | I1 = Builder.CreateCall(Callee: Nop); |
181 | I2 = Builder.CreateCall(Callee: Nop); |
182 | I3 = Builder.CreateCall(Callee: Nop); |
183 | Ret = Builder.CreateRetVoid(); |
184 | } |
185 | |
186 | LLVMContext Ctx; |
187 | std::unique_ptr<Module> M; |
188 | Function *Nop = nullptr; |
189 | BasicBlock *BB = nullptr; |
190 | Instruction *I1 = nullptr; |
191 | Instruction *I2 = nullptr; |
192 | Instruction *I3 = nullptr; |
193 | Instruction *Ret = nullptr; |
194 | }; |
195 | |
196 | TEST_F(InstrOrderInvalidationTest, InsertInvalidation) { |
197 | EXPECT_FALSE(BB->isInstrOrderValid()); |
198 | EXPECT_TRUE(I1->comesBefore(I2)); |
199 | EXPECT_TRUE(BB->isInstrOrderValid()); |
200 | EXPECT_TRUE(I2->comesBefore(I3)); |
201 | EXPECT_TRUE(I3->comesBefore(Ret)); |
202 | EXPECT_TRUE(BB->isInstrOrderValid()); |
203 | |
204 | // Invalidate orders. |
205 | IRBuilder<> Builder(BB, I2->getIterator()); |
206 | Instruction *I1a = Builder.CreateCall(Callee: Nop); |
207 | EXPECT_FALSE(BB->isInstrOrderValid()); |
208 | EXPECT_TRUE(I1->comesBefore(I1a)); |
209 | EXPECT_TRUE(BB->isInstrOrderValid()); |
210 | EXPECT_TRUE(I1a->comesBefore(I2)); |
211 | EXPECT_TRUE(I2->comesBefore(I3)); |
212 | EXPECT_TRUE(I3->comesBefore(Ret)); |
213 | EXPECT_TRUE(BB->isInstrOrderValid()); |
214 | } |
215 | |
216 | TEST_F(InstrOrderInvalidationTest, SpliceInvalidation) { |
217 | EXPECT_TRUE(I1->comesBefore(I2)); |
218 | EXPECT_TRUE(I2->comesBefore(I3)); |
219 | EXPECT_TRUE(I3->comesBefore(Ret)); |
220 | EXPECT_TRUE(BB->isInstrOrderValid()); |
221 | |
222 | // Use Instruction::moveBefore, which uses splice. |
223 | I2->moveBefore(MovePos: I1); |
224 | EXPECT_FALSE(BB->isInstrOrderValid()); |
225 | |
226 | EXPECT_TRUE(I2->comesBefore(I1)); |
227 | EXPECT_TRUE(I1->comesBefore(I3)); |
228 | EXPECT_TRUE(I3->comesBefore(Ret)); |
229 | EXPECT_TRUE(BB->isInstrOrderValid()); |
230 | } |
231 | |
232 | TEST_F(InstrOrderInvalidationTest, RemoveNoInvalidation) { |
233 | // Cache the instruction order. |
234 | EXPECT_FALSE(BB->isInstrOrderValid()); |
235 | EXPECT_TRUE(I1->comesBefore(I2)); |
236 | EXPECT_TRUE(BB->isInstrOrderValid()); |
237 | |
238 | // Removing does not invalidate instruction order. |
239 | I2->removeFromParent(); |
240 | I2->deleteValue(); |
241 | I2 = nullptr; |
242 | EXPECT_TRUE(BB->isInstrOrderValid()); |
243 | EXPECT_TRUE(I1->comesBefore(I3)); |
244 | EXPECT_EQ(std::next(I1->getIterator()), I3->getIterator()); |
245 | } |
246 | |
247 | TEST_F(InstrOrderInvalidationTest, EraseNoInvalidation) { |
248 | // Cache the instruction order. |
249 | EXPECT_FALSE(BB->isInstrOrderValid()); |
250 | EXPECT_TRUE(I1->comesBefore(I2)); |
251 | EXPECT_TRUE(BB->isInstrOrderValid()); |
252 | |
253 | // Removing does not invalidate instruction order. |
254 | I2->eraseFromParent(); |
255 | I2 = nullptr; |
256 | EXPECT_TRUE(BB->isInstrOrderValid()); |
257 | EXPECT_TRUE(I1->comesBefore(I3)); |
258 | EXPECT_EQ(std::next(I1->getIterator()), I3->getIterator()); |
259 | } |
260 | |
261 | static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { |
262 | SMDiagnostic Err; |
263 | std::unique_ptr<Module> Mod = parseAssemblyString(AsmString: IR, Err, Context&: C); |
264 | if (!Mod) |
265 | Err.print(__FILE__, S&: errs()); |
266 | return Mod; |
267 | } |
268 | |
269 | TEST(BasicBlockTest, SpliceFromBB) { |
270 | LLVMContext Ctx; |
271 | std::unique_ptr<Module> M = parseIR(C&: Ctx, IR: R"( |
272 | define void @f(i32 %a) { |
273 | from: |
274 | %fromInstr1 = add i32 %a, %a |
275 | %fromInstr2 = sub i32 %a, %a |
276 | br label %to |
277 | |
278 | to: |
279 | %toInstr1 = mul i32 %a, %a |
280 | %toInstr2 = sdiv i32 %a, %a |
281 | ret void |
282 | } |
283 | )" ); |
284 | Function *F = &*M->begin(); |
285 | auto BBIt = F->begin(); |
286 | BasicBlock *FromBB = &*BBIt++; |
287 | BasicBlock *ToBB = &*BBIt++; |
288 | |
289 | auto FromBBIt = FromBB->begin(); |
290 | Instruction *FromI1 = &*FromBBIt++; |
291 | Instruction *FromI2 = &*FromBBIt++; |
292 | Instruction *FromBr = &*FromBBIt++; |
293 | |
294 | auto ToBBIt = ToBB->begin(); |
295 | Instruction *ToI1 = &*ToBBIt++; |
296 | Instruction *ToI2 = &*ToBBIt++; |
297 | Instruction *ToRet = &*ToBBIt++; |
298 | ToBB->splice(ToIt: ToI1->getIterator(), FromBB); |
299 | |
300 | EXPECT_TRUE(FromBB->empty()); |
301 | |
302 | auto It = ToBB->begin(); |
303 | EXPECT_EQ(&*It++, FromI1); |
304 | EXPECT_EQ(&*It++, FromI2); |
305 | EXPECT_EQ(&*It++, FromBr); |
306 | EXPECT_EQ(&*It++, ToI1); |
307 | EXPECT_EQ(&*It++, ToI2); |
308 | EXPECT_EQ(&*It++, ToRet); |
309 | } |
310 | |
311 | TEST(BasicBlockTest, SpliceOneInstr) { |
312 | LLVMContext Ctx; |
313 | std::unique_ptr<Module> M = parseIR(C&: Ctx, IR: R"( |
314 | define void @f(i32 %a) { |
315 | from: |
316 | %fromInstr1 = add i32 %a, %a |
317 | %fromInstr2 = sub i32 %a, %a |
318 | br label %to |
319 | |
320 | to: |
321 | %toInstr1 = mul i32 %a, %a |
322 | %toInstr2 = sdiv i32 %a, %a |
323 | ret void |
324 | } |
325 | )" ); |
326 | Function *F = &*M->begin(); |
327 | auto BBIt = F->begin(); |
328 | BasicBlock *FromBB = &*BBIt++; |
329 | BasicBlock *ToBB = &*BBIt++; |
330 | |
331 | auto FromBBIt = FromBB->begin(); |
332 | Instruction *FromI1 = &*FromBBIt++; |
333 | Instruction *FromI2 = &*FromBBIt++; |
334 | Instruction *FromBr = &*FromBBIt++; |
335 | |
336 | auto ToBBIt = ToBB->begin(); |
337 | Instruction *ToI1 = &*ToBBIt++; |
338 | Instruction *ToI2 = &*ToBBIt++; |
339 | Instruction *ToRet = &*ToBBIt++; |
340 | ToBB->splice(ToIt: ToI1->getIterator(), FromBB, FromIt: FromI2->getIterator()); |
341 | |
342 | EXPECT_EQ(FromBB->size(), 2u); |
343 | EXPECT_EQ(ToBB->size(), 4u); |
344 | |
345 | auto It = FromBB->begin(); |
346 | EXPECT_EQ(&*It++, FromI1); |
347 | EXPECT_EQ(&*It++, FromBr); |
348 | |
349 | It = ToBB->begin(); |
350 | EXPECT_EQ(&*It++, FromI2); |
351 | EXPECT_EQ(&*It++, ToI1); |
352 | EXPECT_EQ(&*It++, ToI2); |
353 | EXPECT_EQ(&*It++, ToRet); |
354 | } |
355 | |
356 | TEST(BasicBlockTest, SpliceOneInstrWhenFromIsSameAsTo) { |
357 | LLVMContext Ctx; |
358 | std::unique_ptr<Module> M = parseIR(C&: Ctx, IR: R"( |
359 | define void @f(i32 %a) { |
360 | bb: |
361 | %instr1 = add i32 %a, %a |
362 | %instr2 = sub i32 %a, %a |
363 | ret void |
364 | } |
365 | )" ); |
366 | Function *F = &*M->begin(); |
367 | auto BBIt = F->begin(); |
368 | BasicBlock *BB = &*BBIt++; |
369 | |
370 | auto It = BB->begin(); |
371 | Instruction *Instr1 = &*It++; |
372 | Instruction *Instr2 = &*It++; |
373 | Instruction *Ret = &*It++; |
374 | |
375 | // According to ilist's splice() a single-element splice where dst == src |
376 | // should be a noop. |
377 | BB->splice(ToIt: Instr1->getIterator(), FromBB: BB, FromIt: Instr1->getIterator()); |
378 | |
379 | It = BB->begin(); |
380 | EXPECT_EQ(&*It++, Instr1); |
381 | EXPECT_EQ(&*It++, Instr2); |
382 | EXPECT_EQ(&*It++, Ret); |
383 | EXPECT_EQ(BB->size(), 3u); |
384 | } |
385 | |
386 | TEST(BasicBlockTest, SpliceLastInstr) { |
387 | LLVMContext Ctx; |
388 | std::unique_ptr<Module> M = parseIR(C&: Ctx, IR: R"( |
389 | define void @f(i32 %a) { |
390 | from: |
391 | %fromInstr1 = add i32 %a, %a |
392 | %fromInstr2 = sub i32 %a, %a |
393 | br label %to |
394 | |
395 | to: |
396 | %toInstr1 = mul i32 %a, %a |
397 | %toInstr2 = sdiv i32 %a, %a |
398 | ret void |
399 | } |
400 | )" ); |
401 | Function *F = &*M->begin(); |
402 | auto BBIt = F->begin(); |
403 | BasicBlock *FromBB = &*BBIt++; |
404 | BasicBlock *ToBB = &*BBIt++; |
405 | |
406 | auto FromBBIt = FromBB->begin(); |
407 | Instruction *FromI1 = &*FromBBIt++; |
408 | Instruction *FromI2 = &*FromBBIt++; |
409 | Instruction *FromBr = &*FromBBIt++; |
410 | |
411 | auto ToBBIt = ToBB->begin(); |
412 | Instruction *ToI1 = &*ToBBIt++; |
413 | Instruction *ToI2 = &*ToBBIt++; |
414 | Instruction *ToRet = &*ToBBIt++; |
415 | ToBB->splice(ToIt: ToI1->getIterator(), FromBB, FromBeginIt: FromI2->getIterator(), |
416 | FromEndIt: FromBr->getIterator()); |
417 | |
418 | EXPECT_EQ(FromBB->size(), 2u); |
419 | auto It = FromBB->begin(); |
420 | EXPECT_EQ(&*It++, FromI1); |
421 | EXPECT_EQ(&*It++, FromBr); |
422 | |
423 | EXPECT_EQ(ToBB->size(), 4u); |
424 | It = ToBB->begin(); |
425 | EXPECT_EQ(&*It++, FromI2); |
426 | EXPECT_EQ(&*It++, ToI1); |
427 | EXPECT_EQ(&*It++, ToI2); |
428 | EXPECT_EQ(&*It++, ToRet); |
429 | } |
430 | |
431 | TEST(BasicBlockTest, SpliceInstrRange) { |
432 | LLVMContext Ctx; |
433 | std::unique_ptr<Module> M = parseIR(C&: Ctx, IR: R"( |
434 | define void @f(i32 %a) { |
435 | from: |
436 | %fromInstr1 = add i32 %a, %a |
437 | %fromInstr2 = sub i32 %a, %a |
438 | br label %to |
439 | |
440 | to: |
441 | %toInstr1 = mul i32 %a, %a |
442 | %toInstr2 = sdiv i32 %a, %a |
443 | ret void |
444 | } |
445 | )" ); |
446 | Function *F = &*M->begin(); |
447 | auto BBIt = F->begin(); |
448 | BasicBlock *FromBB = &*BBIt++; |
449 | BasicBlock *ToBB = &*BBIt++; |
450 | |
451 | auto FromBBIt = FromBB->begin(); |
452 | Instruction *FromI1 = &*FromBBIt++; |
453 | Instruction *FromI2 = &*FromBBIt++; |
454 | Instruction *FromBr = &*FromBBIt++; |
455 | |
456 | auto ToBBIt = ToBB->begin(); |
457 | Instruction *ToI1 = &*ToBBIt++; |
458 | Instruction *ToI2 = &*ToBBIt++; |
459 | Instruction *ToRet = &*ToBBIt++; |
460 | ToBB->splice(ToIt: ToI2->getIterator(), FromBB, FromBeginIt: FromBB->begin(), FromEndIt: FromBB->end()); |
461 | |
462 | EXPECT_EQ(FromBB->size(), 0u); |
463 | |
464 | EXPECT_EQ(ToBB->size(), 6u); |
465 | auto It = ToBB->begin(); |
466 | EXPECT_EQ(&*It++, ToI1); |
467 | EXPECT_EQ(&*It++, FromI1); |
468 | EXPECT_EQ(&*It++, FromI2); |
469 | EXPECT_EQ(&*It++, FromBr); |
470 | EXPECT_EQ(&*It++, ToI2); |
471 | EXPECT_EQ(&*It++, ToRet); |
472 | } |
473 | |
474 | #ifdef EXPENSIVE_CHECKS |
475 | TEST(BasicBlockTest, SpliceEndBeforeBegin) { |
476 | LLVMContext Ctx; |
477 | std::unique_ptr<Module> M = parseIR(Ctx, R"( |
478 | define void @f(i32 %a) { |
479 | from: |
480 | %fromInstr1 = add i32 %a, %a |
481 | %fromInstr2 = sub i32 %a, %a |
482 | br label %to |
483 | |
484 | to: |
485 | %toInstr1 = mul i32 %a, %a |
486 | %toInstr2 = sdiv i32 %a, %a |
487 | ret void |
488 | } |
489 | )" ); |
490 | Function *F = &*M->begin(); |
491 | auto BBIt = F->begin(); |
492 | BasicBlock *FromBB = &*BBIt++; |
493 | BasicBlock *ToBB = &*BBIt++; |
494 | |
495 | auto FromBBIt = FromBB->begin(); |
496 | Instruction *FromI1 = &*FromBBIt++; |
497 | Instruction *FromI2 = &*FromBBIt++; |
498 | |
499 | auto ToBBIt = ToBB->begin(); |
500 | Instruction *ToI2 = &*ToBBIt++; |
501 | |
502 | EXPECT_DEATH(ToBB->splice(ToI2->getIterator(), FromBB, FromI2->getIterator(), |
503 | FromI1->getIterator()), |
504 | "FromBeginIt not before FromEndIt!" ); |
505 | } |
506 | #endif //EXPENSIVE_CHECKS |
507 | |
508 | TEST(BasicBlockTest, EraseRange) { |
509 | LLVMContext Ctx; |
510 | std::unique_ptr<Module> M = parseIR(C&: Ctx, IR: R"( |
511 | define void @f(i32 %a) { |
512 | bb0: |
513 | %instr1 = add i32 %a, %a |
514 | %instr2 = sub i32 %a, %a |
515 | ret void |
516 | } |
517 | )" ); |
518 | Function *F = &*M->begin(); |
519 | |
520 | auto BB0It = F->begin(); |
521 | BasicBlock *BB0 = &*BB0It; |
522 | |
523 | auto It = BB0->begin(); |
524 | Instruction *Instr1 = &*It++; |
525 | Instruction *Instr2 = &*It++; |
526 | |
527 | EXPECT_EQ(BB0->size(), 3u); |
528 | |
529 | // Erase no instruction |
530 | BB0->erase(FromIt: Instr1->getIterator(), ToIt: Instr1->getIterator()); |
531 | EXPECT_EQ(BB0->size(), 3u); |
532 | |
533 | // Erase %instr1 |
534 | BB0->erase(FromIt: Instr1->getIterator(), ToIt: Instr2->getIterator()); |
535 | EXPECT_EQ(BB0->size(), 2u); |
536 | EXPECT_EQ(&*BB0->begin(), Instr2); |
537 | |
538 | // Erase all instructions |
539 | BB0->erase(FromIt: BB0->begin(), ToIt: BB0->end()); |
540 | EXPECT_TRUE(BB0->empty()); |
541 | } |
542 | |
543 | TEST(BasicBlockTest, DiscardValueNames) { |
544 | const char *ModuleString = "declare void @f(i32 %dangling)" ; |
545 | SMDiagnostic Err; |
546 | LLVMContext Ctx; |
547 | { // Scope of M. |
548 | auto M = parseAssemblyString(AsmString: ModuleString, Err, Context&: Ctx); |
549 | ASSERT_TRUE(M.get()); |
550 | EXPECT_FALSE(Ctx.shouldDiscardValueNames()); |
551 | } |
552 | { // Scope of M. |
553 | auto M = parseAssemblyString(AsmString: ModuleString, Err, Context&: Ctx); |
554 | ASSERT_TRUE(M.get()); |
555 | Ctx.setDiscardValueNames(true); |
556 | } |
557 | } |
558 | |
559 | TEST(BasicBlockTest, DiscardValueNames2) { |
560 | SMDiagnostic Err; |
561 | LLVMContext Ctx; |
562 | Module M("Mod" , Ctx); |
563 | auto FTy = FunctionType::get(Result: Type::getVoidTy(C&: M.getContext()), |
564 | Params: {Type::getInt32Ty(C&: Ctx)}, /*isVarArg=*/false); |
565 | { // Scope of F. |
566 | Function *F = Function::Create(Ty: FTy, Linkage: Function::ExternalLinkage, N: "f" , M: &M); |
567 | F->getArg(i: 0)->setName("dangling" ); |
568 | F->removeFromParent(); |
569 | EXPECT_FALSE(Ctx.shouldDiscardValueNames()); |
570 | delete F; |
571 | } |
572 | { // Scope of F. |
573 | Function *F = Function::Create(Ty: FTy, Linkage: Function::ExternalLinkage, N: "f" , M: &M); |
574 | F->getArg(i: 0)->setName("dangling" ); |
575 | F->removeFromParent(); |
576 | Ctx.setDiscardValueNames(true); |
577 | delete F; |
578 | } |
579 | } |
580 | |
581 | } // End anonymous namespace. |
582 | } // End llvm namespace. |
583 | |