[AArch64] Fix SDNode type mismatches between *.td files and ISel (#116523)
[llvm-project.git] / llvm / unittests / SandboxIR / TrackerTest.cpp
blob4eedab124bfa04790078d2486483ea7852f934bf
1 //===- TrackerTest.cpp ----------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
9 #include "llvm/AsmParser/Parser.h"
10 #include "llvm/IR/BasicBlock.h"
11 #include "llvm/IR/Function.h"
12 #include "llvm/IR/Instruction.h"
13 #include "llvm/IR/Module.h"
14 #include "llvm/SandboxIR/Function.h"
15 #include "llvm/SandboxIR/Instruction.h"
16 #include "llvm/Support/SourceMgr.h"
17 #include "gmock/gmock-matchers.h"
18 #include "gtest/gtest.h"
20 using namespace llvm;
22 struct TrackerTest : public testing::Test {
23 LLVMContext C;
24 std::unique_ptr<Module> M;
26 void parseIR(LLVMContext &C, const char *IR) {
27 SMDiagnostic Err;
28 M = parseAssemblyString(IR, Err, C);
29 if (!M)
30 Err.print("TrackerTest", errs());
32 BasicBlock *getBasicBlockByName(Function &F, StringRef Name) {
33 for (BasicBlock &BB : F)
34 if (BB.getName() == Name)
35 return &BB;
36 llvm_unreachable("Expected to find basic block!");
40 TEST_F(TrackerTest, SetOperand) {
41 parseIR(C, R"IR(
42 define void @foo(ptr %ptr) {
43 %gep0 = getelementptr float, ptr %ptr, i32 0
44 %gep1 = getelementptr float, ptr %ptr, i32 1
45 %ld0 = load float, ptr %gep0
46 store float undef, ptr %gep0
47 ret void
49 )IR");
50 Function &LLVMF = *M->getFunction("foo");
51 sandboxir::Context Ctx(C);
52 auto *F = Ctx.createFunction(&LLVMF);
53 auto *BB = &*F->begin();
54 auto &Tracker = Ctx.getTracker();
55 Tracker.save();
56 auto It = BB->begin();
57 auto *Gep0 = &*It++;
58 auto *Gep1 = &*It++;
59 auto *Ld = &*It++;
60 auto *St = &*It++;
61 St->setOperand(0, Ld);
62 St->setOperand(1, Gep1);
63 Ld->setOperand(0, Gep1);
64 EXPECT_EQ(St->getOperand(0), Ld);
65 EXPECT_EQ(St->getOperand(1), Gep1);
66 EXPECT_EQ(Ld->getOperand(0), Gep1);
68 Ctx.getTracker().revert();
69 EXPECT_NE(St->getOperand(0), Ld);
70 EXPECT_EQ(St->getOperand(1), Gep0);
71 EXPECT_EQ(Ld->getOperand(0), Gep0);
74 TEST_F(TrackerTest, SetUse) {
75 parseIR(C, R"IR(
76 define void @foo(ptr %ptr, i8 %arg) {
77 %ld = load i8, ptr %ptr
78 %add = add i8 %ld, %arg
79 ret void
81 )IR");
82 Function &LLVMF = *M->getFunction("foo");
83 sandboxir::Context Ctx(C);
84 auto *F = Ctx.createFunction(&LLVMF);
85 unsigned ArgIdx = 0;
86 auto *Arg0 = F->getArg(ArgIdx++);
87 auto *BB = &*F->begin();
88 auto &Tracker = Ctx.getTracker();
89 Tracker.save();
90 auto It = BB->begin();
91 auto *Ld = &*It++;
92 auto *Add = &*It++;
94 Ctx.save();
95 sandboxir::Use Use = Add->getOperandUse(0);
96 Use.set(Arg0);
97 EXPECT_EQ(Add->getOperand(0), Arg0);
98 Ctx.revert();
99 EXPECT_EQ(Add->getOperand(0), Ld);
102 TEST_F(TrackerTest, SwapOperands) {
103 parseIR(C, R"IR(
104 define void @foo(i1 %cond) {
105 bb0:
106 br i1 %cond, label %bb1, label %bb2
107 bb1:
108 ret void
109 bb2:
110 ret void
112 )IR");
113 Function &LLVMF = *M->getFunction("foo");
114 sandboxir::Context Ctx(C);
115 Ctx.createFunction(&LLVMF);
116 auto *BB0 = cast<sandboxir::BasicBlock>(
117 Ctx.getValue(getBasicBlockByName(LLVMF, "bb0")));
118 auto *BB1 = cast<sandboxir::BasicBlock>(
119 Ctx.getValue(getBasicBlockByName(LLVMF, "bb1")));
120 auto *BB2 = cast<sandboxir::BasicBlock>(
121 Ctx.getValue(getBasicBlockByName(LLVMF, "bb2")));
122 auto &Tracker = Ctx.getTracker();
123 Tracker.save();
124 auto It = BB0->begin();
125 auto *Br = cast<sandboxir::BranchInst>(&*It++);
127 unsigned SuccIdx = 0;
128 SmallVector<sandboxir::BasicBlock *> ExpectedSuccs({BB2, BB1});
129 for (auto *Succ : Br->successors())
130 EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]);
132 // This calls User::swapOperandsInternal() internally.
133 Br->swapSuccessors();
135 SuccIdx = 0;
136 for (auto *Succ : reverse(Br->successors()))
137 EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]);
139 Ctx.getTracker().revert();
140 SuccIdx = 0;
141 for (auto *Succ : Br->successors())
142 EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]);
145 TEST_F(TrackerTest, RUWIf_RAUW_RUOW) {
146 parseIR(C, R"IR(
147 define void @foo(ptr %ptr) {
148 %ld0 = load float, ptr %ptr
149 %ld1 = load float, ptr %ptr
150 store float %ld0, ptr %ptr
151 store float %ld0, ptr %ptr
152 ret void
154 )IR");
155 llvm::Function &LLVMF = *M->getFunction("foo");
156 sandboxir::Context Ctx(C);
157 llvm::BasicBlock *LLVMBB = &*LLVMF.begin();
158 Ctx.createFunction(&LLVMF);
159 auto *BB = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMBB));
160 auto It = BB->begin();
161 sandboxir::Instruction *Ld0 = &*It++;
162 sandboxir::Instruction *Ld1 = &*It++;
163 sandboxir::Instruction *St0 = &*It++;
164 sandboxir::Instruction *St1 = &*It++;
165 Ctx.save();
166 // Check RUWIf when the lambda returns false.
167 Ld0->replaceUsesWithIf(Ld1, [](const sandboxir::Use &Use) { return false; });
168 EXPECT_EQ(St0->getOperand(0), Ld0);
169 EXPECT_EQ(St1->getOperand(0), Ld0);
171 // Check RUWIf when the lambda returns true.
172 Ld0->replaceUsesWithIf(Ld1, [](const sandboxir::Use &Use) { return true; });
173 EXPECT_EQ(St0->getOperand(0), Ld1);
174 EXPECT_EQ(St1->getOperand(0), Ld1);
175 Ctx.revert();
176 EXPECT_EQ(St0->getOperand(0), Ld0);
177 EXPECT_EQ(St1->getOperand(0), Ld0);
179 // Check RUWIf user == St0.
180 Ctx.save();
181 Ld0->replaceUsesWithIf(
182 Ld1, [St0](const sandboxir::Use &Use) { return Use.getUser() == St0; });
183 EXPECT_EQ(St0->getOperand(0), Ld1);
184 EXPECT_EQ(St1->getOperand(0), Ld0);
185 Ctx.revert();
186 EXPECT_EQ(St0->getOperand(0), Ld0);
187 EXPECT_EQ(St1->getOperand(0), Ld0);
189 // Check RUWIf user == St1.
190 Ctx.save();
191 Ld0->replaceUsesWithIf(
192 Ld1, [St1](const sandboxir::Use &Use) { return Use.getUser() == St1; });
193 EXPECT_EQ(St0->getOperand(0), Ld0);
194 EXPECT_EQ(St1->getOperand(0), Ld1);
195 Ctx.revert();
196 EXPECT_EQ(St0->getOperand(0), Ld0);
197 EXPECT_EQ(St1->getOperand(0), Ld0);
199 // Check RAUW.
200 Ctx.save();
201 Ld1->replaceAllUsesWith(Ld0);
202 EXPECT_EQ(St0->getOperand(0), Ld0);
203 EXPECT_EQ(St1->getOperand(0), Ld0);
204 Ctx.revert();
205 EXPECT_EQ(St0->getOperand(0), Ld0);
206 EXPECT_EQ(St1->getOperand(0), Ld0);
208 // Check RUOW.
209 Ctx.save();
210 St0->replaceUsesOfWith(Ld0, Ld1);
211 EXPECT_EQ(St0->getOperand(0), Ld1);
212 Ctx.revert();
213 EXPECT_EQ(St0->getOperand(0), Ld0);
215 // Check accept().
216 Ctx.save();
217 St0->replaceUsesOfWith(Ld0, Ld1);
218 EXPECT_EQ(St0->getOperand(0), Ld1);
219 Ctx.accept();
220 EXPECT_EQ(St0->getOperand(0), Ld1);
223 // TODO: Test multi-instruction patterns.
224 TEST_F(TrackerTest, EraseFromParent) {
225 parseIR(C, R"IR(
226 define void @foo(i32 %v1) {
227 %add0 = add i32 %v1, %v1
228 %add1 = add i32 %add0, %v1
229 ret void
231 )IR");
232 Function &LLVMF = *M->getFunction("foo");
233 sandboxir::Context Ctx(C);
235 auto *F = Ctx.createFunction(&LLVMF);
236 auto *BB = &*F->begin();
237 auto It = BB->begin();
238 sandboxir::Instruction *Add0 = &*It++;
239 sandboxir::Instruction *Add1 = &*It++;
240 sandboxir::Instruction *Ret = &*It++;
242 Ctx.save();
243 // Check erase.
244 Add1->eraseFromParent();
245 It = BB->begin();
246 EXPECT_EQ(&*It++, Add0);
247 EXPECT_EQ(&*It++, Ret);
248 EXPECT_EQ(It, BB->end());
249 EXPECT_EQ(Add0->getNumUses(), 0u);
251 // Check revert().
252 Ctx.revert();
253 It = BB->begin();
254 EXPECT_EQ(&*It++, Add0);
255 EXPECT_EQ(&*It++, Add1);
256 EXPECT_EQ(&*It++, Ret);
257 EXPECT_EQ(It, BB->end());
258 EXPECT_EQ(Add1->getOperand(0), Add0);
260 // Same for the last instruction in the block.
261 Ctx.save();
262 Ret->eraseFromParent();
263 It = BB->begin();
264 EXPECT_EQ(&*It++, Add0);
265 EXPECT_EQ(&*It++, Add1);
266 EXPECT_EQ(It, BB->end());
267 Ctx.revert();
268 It = BB->begin();
269 EXPECT_EQ(&*It++, Add0);
270 EXPECT_EQ(&*It++, Add1);
271 EXPECT_EQ(&*It++, Ret);
272 EXPECT_EQ(It, BB->end());
275 // TODO: Test multi-instruction patterns.
276 TEST_F(TrackerTest, RemoveFromParent) {
277 parseIR(C, R"IR(
278 define i32 @foo(i32 %arg) {
279 %add0 = add i32 %arg, %arg
280 %add1 = add i32 %add0, %arg
281 ret i32 %add1
283 )IR");
284 Function &LLVMF = *M->getFunction("foo");
285 sandboxir::Context Ctx(C);
287 auto *F = Ctx.createFunction(&LLVMF);
288 auto *Arg = F->getArg(0);
289 auto *BB = &*F->begin();
290 auto It = BB->begin();
291 sandboxir::Instruction *Add0 = &*It++;
292 sandboxir::Instruction *Add1 = &*It++;
293 sandboxir::Instruction *Ret = &*It++;
295 Ctx.save();
296 // Check removeFromParent().
297 Add1->removeFromParent();
298 It = BB->begin();
299 EXPECT_EQ(&*It++, Add0);
300 EXPECT_EQ(&*It++, Ret);
301 EXPECT_EQ(It, BB->end());
302 // Removed instruction still be connected to operands and users.
303 EXPECT_EQ(Add1->getOperand(0), Add0);
304 EXPECT_EQ(Add1->getOperand(1), Arg);
305 EXPECT_EQ(Add0->getNumUses(), 1u);
307 // Check revert().
308 Ctx.revert();
309 It = BB->begin();
310 EXPECT_EQ(&*It++, Add0);
311 EXPECT_EQ(&*It++, Add1);
312 EXPECT_EQ(&*It++, Ret);
313 EXPECT_EQ(It, BB->end());
314 EXPECT_EQ(Add1->getOperand(0), Add0);
316 // Same for the last instruction in the block.
317 Ctx.save();
318 Ret->removeFromParent();
319 It = BB->begin();
320 EXPECT_EQ(&*It++, Add0);
321 EXPECT_EQ(&*It++, Add1);
322 EXPECT_EQ(It, BB->end());
323 EXPECT_EQ(Ret->getOperand(0), Add1);
324 Ctx.revert();
325 It = BB->begin();
326 EXPECT_EQ(&*It++, Add0);
327 EXPECT_EQ(&*It++, Add1);
328 EXPECT_EQ(&*It++, Ret);
329 EXPECT_EQ(It, BB->end());
332 // TODO: Test multi-instruction patterns.
333 TEST_F(TrackerTest, MoveInstr) {
334 parseIR(C, R"IR(
335 define i32 @foo(i32 %arg) {
336 %add0 = add i32 %arg, %arg
337 %add1 = add i32 %add0, %arg
338 ret i32 %add1
340 )IR");
341 Function &LLVMF = *M->getFunction("foo");
342 sandboxir::Context Ctx(C);
344 auto *F = Ctx.createFunction(&LLVMF);
345 auto *BB = &*F->begin();
346 auto It = BB->begin();
347 sandboxir::Instruction *Add0 = &*It++;
348 sandboxir::Instruction *Add1 = &*It++;
349 sandboxir::Instruction *Ret = &*It++;
351 // Check moveBefore(Instruction *) with tracking enabled.
352 Ctx.save();
353 Add1->moveBefore(Add0);
354 It = BB->begin();
355 EXPECT_EQ(&*It++, Add1);
356 EXPECT_EQ(&*It++, Add0);
357 EXPECT_EQ(&*It++, Ret);
358 EXPECT_EQ(It, BB->end());
359 // Check revert().
360 Ctx.revert();
361 It = BB->begin();
362 EXPECT_EQ(&*It++, Add0);
363 EXPECT_EQ(&*It++, Add1);
364 EXPECT_EQ(&*It++, Ret);
365 EXPECT_EQ(It, BB->end());
367 // Same for the last instruction in the block.
368 Ctx.save();
369 Ret->moveBefore(Add0);
370 It = BB->begin();
371 EXPECT_EQ(&*It++, Ret);
372 EXPECT_EQ(&*It++, Add0);
373 EXPECT_EQ(&*It++, Add1);
374 EXPECT_EQ(It, BB->end());
375 Ctx.revert();
376 It = BB->begin();
377 EXPECT_EQ(&*It++, Add0);
378 EXPECT_EQ(&*It++, Add1);
379 EXPECT_EQ(&*It++, Ret);
380 EXPECT_EQ(It, BB->end());
382 // Check moveBefore(BasicBlock &, BasicBlock::iterator) with tracking enabled.
383 Ctx.save();
384 Add1->moveBefore(*BB, Add0->getIterator());
385 It = BB->begin();
386 EXPECT_EQ(&*It++, Add1);
387 EXPECT_EQ(&*It++, Add0);
388 EXPECT_EQ(&*It++, Ret);
389 EXPECT_EQ(It, BB->end());
390 // Check revert().
391 Ctx.revert();
392 It = BB->begin();
393 EXPECT_EQ(&*It++, Add0);
394 EXPECT_EQ(&*It++, Add1);
395 EXPECT_EQ(&*It++, Ret);
396 EXPECT_EQ(It, BB->end());
398 // Same for the last instruction in the block.
399 Ctx.save();
400 Ret->moveBefore(*BB, Add0->getIterator());
401 It = BB->begin();
402 EXPECT_EQ(&*It++, Ret);
403 EXPECT_EQ(&*It++, Add0);
404 EXPECT_EQ(&*It++, Add1);
405 EXPECT_EQ(It, BB->end());
406 // Check revert().
407 Ctx.revert();
408 It = BB->begin();
409 EXPECT_EQ(&*It++, Add0);
410 EXPECT_EQ(&*It++, Add1);
411 EXPECT_EQ(&*It++, Ret);
412 EXPECT_EQ(It, BB->end());
414 // Check moveAfter(Instruction *) with tracking enabled.
415 Ctx.save();
416 Add0->moveAfter(Add1);
417 It = BB->begin();
418 EXPECT_EQ(&*It++, Add1);
419 EXPECT_EQ(&*It++, Add0);
420 EXPECT_EQ(&*It++, Ret);
421 EXPECT_EQ(It, BB->end());
422 // Check revert().
423 Ctx.revert();
424 It = BB->begin();
425 EXPECT_EQ(&*It++, Add0);
426 EXPECT_EQ(&*It++, Add1);
427 EXPECT_EQ(&*It++, Ret);
428 EXPECT_EQ(It, BB->end());
430 // Same for the last instruction in the block.
431 Ctx.save();
432 Ret->moveAfter(Add0);
433 It = BB->begin();
434 EXPECT_EQ(&*It++, Add0);
435 EXPECT_EQ(&*It++, Ret);
436 EXPECT_EQ(&*It++, Add1);
437 EXPECT_EQ(It, BB->end());
438 // Check revert().
439 Ctx.revert();
440 It = BB->begin();
441 EXPECT_EQ(&*It++, Add0);
442 EXPECT_EQ(&*It++, Add1);
443 EXPECT_EQ(&*It++, Ret);
444 EXPECT_EQ(It, BB->end());
447 // TODO: Test multi-instruction patterns.
448 TEST_F(TrackerTest, InsertIntoBB) {
449 parseIR(C, R"IR(
450 define void @foo(i32 %arg) {
451 %add0 = add i32 %arg, %arg
452 ret void
454 )IR");
455 Function &LLVMF = *M->getFunction("foo");
456 sandboxir::Context Ctx(C);
458 auto *F = Ctx.createFunction(&LLVMF);
459 auto *BB = &*F->begin();
460 auto It = BB->begin();
461 sandboxir::Instruction *Add0 = &*It++;
462 sandboxir::Instruction *Ret = &*It++;
463 // Detach `Add0` before we save.
464 Add0->removeFromParent();
466 // Check insertBefore(Instruction *) with tracking enabled.
467 Ctx.save();
468 Add0->insertBefore(Ret);
469 It = BB->begin();
470 EXPECT_EQ(&*It++, Add0);
471 EXPECT_EQ(&*It++, Ret);
472 EXPECT_EQ(It, BB->end());
473 // Check revert().
474 Ctx.revert();
475 It = BB->begin();
476 EXPECT_EQ(&*It++, Ret);
477 EXPECT_EQ(It, BB->end());
479 // Check insertAfter(Instruction *) with tracking enabled.
480 Ctx.save();
481 Add0->insertAfter(Ret);
482 It = BB->begin();
483 EXPECT_EQ(&*It++, Ret);
484 EXPECT_EQ(&*It++, Add0);
485 EXPECT_EQ(It, BB->end());
486 // Check revert().
487 Ctx.revert();
488 It = BB->begin();
489 EXPECT_EQ(&*It++, Ret);
490 EXPECT_EQ(It, BB->end());
492 // Check insertInto(BasicBlock *, BasicBlock::iterator) with tracking enabled.
493 Ctx.save();
494 Add0->insertInto(BB, Ret->getIterator());
495 It = BB->begin();
496 EXPECT_EQ(&*It++, Add0);
497 EXPECT_EQ(&*It++, Ret);
498 EXPECT_EQ(It, BB->end());
499 // Check revert().
500 Ctx.revert();
501 It = BB->begin();
502 EXPECT_EQ(&*It++, Ret);
503 EXPECT_EQ(It, BB->end());
505 // To make sure we don't leak memory insert `Add0` back into the BB before the
506 // end of the test.
507 Add0->insertBefore(Ret);
510 // TODO: Test multi-instruction patterns.
511 TEST_F(TrackerTest, CreateAndInsertInst) {
512 parseIR(C, R"IR(
513 define void @foo(ptr %ptr) {
514 %ld = load i8, ptr %ptr, align 64
515 ret void
517 )IR");
518 Function &LLVMF = *M->getFunction("foo");
519 sandboxir::Context Ctx(C);
521 auto *F = Ctx.createFunction(&LLVMF);
522 auto *Ptr = F->getArg(0);
523 auto *BB = &*F->begin();
524 auto It = BB->begin();
525 auto *Ld = cast<sandboxir::LoadInst>(&*It++);
526 auto *Ret = &*It++;
528 Ctx.save();
529 // Check create(InsertBefore) with tracking enabled.
530 sandboxir::LoadInst *NewLd = sandboxir::LoadInst::create(
531 Ld->getType(), Ptr, Align(8),
532 /*InsertBefore=*/Ld->getIterator(), Ctx, "NewLd");
533 It = BB->begin();
534 EXPECT_EQ(&*It++, NewLd);
535 EXPECT_EQ(&*It++, Ld);
536 EXPECT_EQ(&*It++, Ret);
537 EXPECT_EQ(It, BB->end());
538 // Check revert().
539 Ctx.revert();
540 It = BB->begin();
541 EXPECT_EQ(&*It++, Ld);
542 EXPECT_EQ(&*It++, Ret);
543 EXPECT_EQ(It, BB->end());
546 TEST_F(TrackerTest, FenceInstSetters) {
547 parseIR(C, R"IR(
548 define void @foo() {
549 fence syncscope("singlethread") seq_cst
550 ret void
552 )IR");
553 llvm::Function *LLVMF = &*M->getFunction("foo");
554 sandboxir::Context Ctx(C);
555 sandboxir::Function *F = Ctx.createFunction(LLVMF);
556 auto *BB = &*F->begin();
557 auto It = BB->begin();
558 auto *Fence = cast<sandboxir::FenceInst>(&*It++);
560 // Check setOrdering().
561 auto OrigOrdering = Fence->getOrdering();
562 auto NewOrdering = AtomicOrdering::Release;
563 EXPECT_NE(NewOrdering, OrigOrdering);
564 Ctx.save();
565 Fence->setOrdering(NewOrdering);
566 EXPECT_EQ(Fence->getOrdering(), NewOrdering);
567 Ctx.revert();
568 EXPECT_EQ(Fence->getOrdering(), OrigOrdering);
569 // Check setSyncScopeID().
570 auto OrigSSID = Fence->getSyncScopeID();
571 auto NewSSID = SyncScope::System;
572 EXPECT_NE(NewSSID, OrigSSID);
573 Ctx.save();
574 Fence->setSyncScopeID(NewSSID);
575 EXPECT_EQ(Fence->getSyncScopeID(), NewSSID);
576 Ctx.revert();
577 EXPECT_EQ(Fence->getSyncScopeID(), OrigSSID);
580 TEST_F(TrackerTest, CallBaseSetters) {
581 parseIR(C, R"IR(
582 declare void @bar1(i8)
583 declare void @bar2(i8)
585 define void @foo(i8 %arg0, i8 %arg1) {
586 call void @bar1(i8 %arg0)
587 ret void
589 )IR");
590 Function &LLVMF = *M->getFunction("foo");
591 sandboxir::Context Ctx(C);
593 auto *F = Ctx.createFunction(&LLVMF);
594 unsigned ArgIdx = 0;
595 auto *Arg0 = F->getArg(ArgIdx++);
596 auto *Arg1 = F->getArg(ArgIdx++);
597 auto *BB = &*F->begin();
598 auto It = BB->begin();
599 auto *Call = cast<sandboxir::CallBase>(&*It++);
600 [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
602 // Check setArgOperand().
603 Ctx.save();
604 Call->setArgOperand(0, Arg1);
605 EXPECT_EQ(Call->getArgOperand(0), Arg1);
606 Ctx.revert();
607 EXPECT_EQ(Call->getArgOperand(0), Arg0);
609 auto *Bar1F = Call->getCalledFunction();
610 auto *Bar2F = Ctx.createFunction(M->getFunction("bar2"));
612 // Check setCalledOperand().
613 Ctx.save();
614 Call->setCalledOperand(Bar2F);
615 EXPECT_EQ(Call->getCalledOperand(), Bar2F);
616 Ctx.revert();
617 EXPECT_EQ(Call->getCalledOperand(), Bar1F);
619 // Check setCalledFunction().
620 Ctx.save();
621 Call->setCalledFunction(Bar2F);
622 EXPECT_EQ(Call->getCalledFunction(), Bar2F);
623 Ctx.revert();
624 EXPECT_EQ(Call->getCalledFunction(), Bar1F);
627 TEST_F(TrackerTest, InvokeSetters) {
628 parseIR(C, R"IR(
629 define void @foo(i8 %arg) {
630 bb0:
631 invoke i8 @foo(i8 %arg) to label %normal_bb
632 unwind label %exception_bb
633 normal_bb:
634 ret void
635 exception_bb:
636 ret void
637 other_bb:
638 ret void
640 )IR");
641 Function &LLVMF = *M->getFunction("foo");
642 sandboxir::Context Ctx(C);
643 [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF);
644 auto *BB0 = cast<sandboxir::BasicBlock>(
645 Ctx.getValue(getBasicBlockByName(LLVMF, "bb0")));
646 auto *NormalBB = cast<sandboxir::BasicBlock>(
647 Ctx.getValue(getBasicBlockByName(LLVMF, "normal_bb")));
648 auto *ExceptionBB = cast<sandboxir::BasicBlock>(
649 Ctx.getValue(getBasicBlockByName(LLVMF, "exception_bb")));
650 auto *OtherBB = cast<sandboxir::BasicBlock>(
651 Ctx.getValue(getBasicBlockByName(LLVMF, "other_bb")));
652 auto It = BB0->begin();
653 auto *Invoke = cast<sandboxir::InvokeInst>(&*It++);
655 // Check setNormalDest().
656 Ctx.save();
657 Invoke->setNormalDest(OtherBB);
658 EXPECT_EQ(Invoke->getNormalDest(), OtherBB);
659 Ctx.revert();
660 EXPECT_EQ(Invoke->getNormalDest(), NormalBB);
662 // Check setUnwindDest().
663 Ctx.save();
664 Invoke->setUnwindDest(OtherBB);
665 EXPECT_EQ(Invoke->getUnwindDest(), OtherBB);
666 Ctx.revert();
667 EXPECT_EQ(Invoke->getUnwindDest(), ExceptionBB);
669 // Check setSuccessor().
670 Ctx.save();
671 Invoke->setSuccessor(0, OtherBB);
672 EXPECT_EQ(Invoke->getSuccessor(0), OtherBB);
673 Ctx.revert();
674 EXPECT_EQ(Invoke->getSuccessor(0), NormalBB);
676 Ctx.save();
677 Invoke->setSuccessor(1, OtherBB);
678 EXPECT_EQ(Invoke->getSuccessor(1), OtherBB);
679 Ctx.revert();
680 EXPECT_EQ(Invoke->getSuccessor(1), ExceptionBB);
683 TEST_F(TrackerTest, CatchSwitchInst) {
684 parseIR(C, R"IR(
685 define void @foo(i32 %cond0, i32 %cond1) {
686 bb0:
687 %cs0 = catchswitch within none [label %handler0, label %handler1] unwind to caller
688 bb1:
689 %cs1 = catchswitch within %cs0 [label %handler0, label %handler1] unwind label %cleanup
690 handler0:
691 ret void
692 handler1:
693 ret void
694 cleanup:
695 ret void
697 )IR");
698 Function &LLVMF = *M->getFunction("foo");
700 sandboxir::Context Ctx(C);
701 [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF);
702 auto *BB0 = cast<sandboxir::BasicBlock>(
703 Ctx.getValue(getBasicBlockByName(LLVMF, "bb0")));
704 auto *BB1 = cast<sandboxir::BasicBlock>(
705 Ctx.getValue(getBasicBlockByName(LLVMF, "bb1")));
706 auto *Handler0 = cast<sandboxir::BasicBlock>(
707 Ctx.getValue(getBasicBlockByName(LLVMF, "handler0")));
708 auto *Handler1 = cast<sandboxir::BasicBlock>(
709 Ctx.getValue(getBasicBlockByName(LLVMF, "handler1")));
710 auto *CS0 = cast<sandboxir::CatchSwitchInst>(&*BB0->begin());
711 auto *CS1 = cast<sandboxir::CatchSwitchInst>(&*BB1->begin());
713 // Check setParentPad().
714 auto *OrigPad = CS0->getParentPad();
715 auto *NewPad = CS1;
716 EXPECT_NE(NewPad, OrigPad);
717 Ctx.save();
718 CS0->setParentPad(NewPad);
719 EXPECT_EQ(CS0->getParentPad(), NewPad);
720 Ctx.revert();
721 EXPECT_EQ(CS0->getParentPad(), OrigPad);
722 // Check setUnwindDest().
723 auto *OrigUnwindDest = CS1->getUnwindDest();
724 auto *NewUnwindDest = BB0;
725 EXPECT_NE(NewUnwindDest, OrigUnwindDest);
726 Ctx.save();
727 CS1->setUnwindDest(NewUnwindDest);
728 EXPECT_EQ(CS1->getUnwindDest(), NewUnwindDest);
729 Ctx.revert();
730 EXPECT_EQ(CS1->getUnwindDest(), OrigUnwindDest);
731 // Check setSuccessor().
732 auto *OrigSuccessor = CS0->getSuccessor(0);
733 auto *NewSuccessor = BB0;
734 EXPECT_NE(NewSuccessor, OrigSuccessor);
735 Ctx.save();
736 CS0->setSuccessor(0, NewSuccessor);
737 EXPECT_EQ(CS0->getSuccessor(0), NewSuccessor);
738 Ctx.revert();
739 EXPECT_EQ(CS0->getSuccessor(0), OrigSuccessor);
740 // Check addHandler().
741 Ctx.save();
742 CS0->addHandler(BB0);
743 EXPECT_EQ(CS0->getNumHandlers(), 3u);
744 Ctx.revert();
745 EXPECT_EQ(CS0->getNumHandlers(), 2u);
746 auto HIt = CS0->handler_begin();
747 EXPECT_EQ(*HIt++, Handler0);
748 EXPECT_EQ(*HIt++, Handler1);
751 TEST_F(TrackerTest, LandingPadInstSetters) {
752 parseIR(C, R"IR(
753 define void @foo() {
754 entry:
755 invoke void @foo()
756 to label %bb unwind label %unwind
757 unwind:
758 %lpad = landingpad { ptr, i32 }
759 catch ptr null
760 ret void
762 ret void
764 )IR");
765 Function &LLVMF = *M->getFunction("foo");
766 auto *LLVMUnwind = getBasicBlockByName(LLVMF, "unwind");
768 sandboxir::Context Ctx(C);
769 [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF);
770 auto *Unwind = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMUnwind));
771 auto It = Unwind->begin();
772 auto *LPad = cast<sandboxir::LandingPadInst>(&*It++);
773 [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
775 // Check setCleanup().
776 auto OrigIsCleanup = LPad->isCleanup();
777 auto NewIsCleanup = true;
778 EXPECT_NE(NewIsCleanup, OrigIsCleanup);
779 Ctx.save();
780 LPad->setCleanup(NewIsCleanup);
781 EXPECT_EQ(LPad->isCleanup(), NewIsCleanup);
782 Ctx.revert();
783 EXPECT_EQ(LPad->isCleanup(), OrigIsCleanup);
786 TEST_F(TrackerTest, CatchReturnInstSetters) {
787 parseIR(C, R"IR(
788 define void @foo() {
789 dispatch:
790 %cs = catchswitch within none [label %catch] unwind to caller
791 catch:
792 %catchpad = catchpad within %cs [ptr @foo]
793 catchret from %catchpad to label %continue
794 continue:
795 ret void
796 catch2:
797 %catchpad2 = catchpad within %cs [ptr @foo]
798 ret void
800 )IR");
801 Function &LLVMF = *M->getFunction("foo");
802 BasicBlock *LLVMCatch = getBasicBlockByName(LLVMF, "catch");
803 auto LLVMIt = LLVMCatch->begin();
804 [[maybe_unused]] auto *LLVMCP = cast<llvm::CatchPadInst>(&*LLVMIt++);
806 sandboxir::Context Ctx(C);
807 [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF);
808 auto *Catch = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMCatch));
809 auto *Catch2 = cast<sandboxir::BasicBlock>(
810 Ctx.getValue(getBasicBlockByName(LLVMF, "catch2")));
811 auto It = Catch->begin();
812 [[maybe_unused]] auto *CP = cast<sandboxir::CatchPadInst>(&*It++);
813 auto *CR = cast<sandboxir::CatchReturnInst>(&*It++);
814 auto *CP2 = cast<sandboxir::CatchPadInst>(&*Catch2->begin());
816 // Check setCatchPad().
817 auto *OrigCP = CR->getCatchPad();
818 auto *NewCP = CP2;
819 EXPECT_NE(NewCP, OrigCP);
820 Ctx.save();
821 CR->setCatchPad(NewCP);
822 EXPECT_EQ(CR->getCatchPad(), NewCP);
823 Ctx.revert();
824 EXPECT_EQ(CR->getCatchPad(), OrigCP);
825 // Check setSuccessor().
826 auto *OrigSucc = CR->getSuccessor();
827 auto *NewSucc = Catch;
828 EXPECT_NE(NewSucc, OrigSucc);
829 Ctx.save();
830 CR->setSuccessor(NewSucc);
831 EXPECT_EQ(CR->getSuccessor(), NewSucc);
832 Ctx.revert();
833 EXPECT_EQ(CR->getSuccessor(), OrigSucc);
836 TEST_F(TrackerTest, CleanupReturnInstSetters) {
837 parseIR(C, R"IR(
838 define void @foo() {
839 dispatch:
840 invoke void @foo()
841 to label %throw unwind label %cleanup
842 throw:
843 ret void
844 cleanup:
845 %cleanuppad = cleanuppad within none []
846 cleanupret from %cleanuppad unwind label %cleanup2
847 cleanup2:
848 %cleanuppad2 = cleanuppad within none []
849 ret void
851 )IR");
852 Function &LLVMF = *M->getFunction("foo");
853 BasicBlock *LLVMCleanup = getBasicBlockByName(LLVMF, "cleanup");
855 sandboxir::Context Ctx(C);
856 [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF);
857 auto *Throw = cast<sandboxir::BasicBlock>(
858 Ctx.getValue(getBasicBlockByName(LLVMF, "throw")));
859 auto *Cleanup = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMCleanup));
860 auto *Cleanup2 = cast<sandboxir::BasicBlock>(
861 Ctx.getValue(getBasicBlockByName(LLVMF, "cleanup2")));
862 auto It = Cleanup->begin();
863 [[maybe_unused]] auto *CP = cast<sandboxir::CleanupPadInst>(&*It++);
864 auto *CRI = cast<sandboxir::CleanupReturnInst>(&*It++);
865 auto *CP2 = cast<sandboxir::CleanupPadInst>(&*Cleanup2->begin());
867 // Check setCleanupPad().
868 auto *OrigCleanupPad = CRI->getCleanupPad();
869 auto *NewCleanupPad = CP2;
870 EXPECT_NE(NewCleanupPad, OrigCleanupPad);
871 Ctx.save();
872 CRI->setCleanupPad(NewCleanupPad);
873 EXPECT_EQ(CRI->getCleanupPad(), NewCleanupPad);
874 Ctx.revert();
875 EXPECT_EQ(CRI->getCleanupPad(), OrigCleanupPad);
876 // Check setUnwindDest().
877 auto *OrigUnwindDest = CRI->getUnwindDest();
878 auto *NewUnwindDest = Throw;
879 EXPECT_NE(NewUnwindDest, OrigUnwindDest);
880 Ctx.save();
881 CRI->setUnwindDest(NewUnwindDest);
882 EXPECT_EQ(CRI->getUnwindDest(), NewUnwindDest);
883 Ctx.revert();
884 EXPECT_EQ(CRI->getUnwindDest(), OrigUnwindDest);
887 TEST_F(TrackerTest, SwitchInstSetters) {
888 parseIR(C, R"IR(
889 define void @foo(i32 %cond0, i32 %cond1) {
890 entry:
891 switch i32 %cond0, label %default [ i32 0, label %bb0
892 i32 1, label %bb1 ]
893 bb0:
894 ret void
895 bb1:
896 ret void
897 default:
898 ret void
900 )IR");
901 Function &LLVMF = *M->getFunction("foo");
902 auto *LLVMEntry = getBasicBlockByName(LLVMF, "entry");
904 sandboxir::Context Ctx(C);
905 auto &F = *Ctx.createFunction(&LLVMF);
906 auto *Cond1 = F.getArg(1);
907 auto *Entry = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMEntry));
908 auto *BB0 = cast<sandboxir::BasicBlock>(
909 Ctx.getValue(getBasicBlockByName(LLVMF, "bb0")));
910 auto *BB1 = cast<sandboxir::BasicBlock>(
911 Ctx.getValue(getBasicBlockByName(LLVMF, "bb1")));
912 auto *Switch = cast<sandboxir::SwitchInst>(&*Entry->begin());
914 // Check setCondition().
915 auto *OrigCond = Switch->getCondition();
916 auto *NewCond = Cond1;
917 EXPECT_NE(NewCond, OrigCond);
918 Ctx.save();
919 Switch->setCondition(NewCond);
920 EXPECT_EQ(Switch->getCondition(), NewCond);
921 Ctx.revert();
922 EXPECT_EQ(Switch->getCondition(), OrigCond);
923 // Check setDefaultDest().
924 auto *OrigDefaultDest = Switch->getDefaultDest();
925 auto *NewDefaultDest = Entry;
926 EXPECT_NE(NewDefaultDest, OrigDefaultDest);
927 Ctx.save();
928 Switch->setDefaultDest(NewDefaultDest);
929 EXPECT_EQ(Switch->getDefaultDest(), NewDefaultDest);
930 Ctx.revert();
931 EXPECT_EQ(Switch->getDefaultDest(), OrigDefaultDest);
932 // Check setSuccessor().
933 auto *OrigSucc = Switch->getSuccessor(0);
934 auto *NewSucc = Entry;
935 EXPECT_NE(NewSucc, OrigSucc);
936 Ctx.save();
937 Switch->setSuccessor(0, NewSucc);
938 EXPECT_EQ(Switch->getSuccessor(0), NewSucc);
939 Ctx.revert();
940 EXPECT_EQ(Switch->getSuccessor(0), OrigSucc);
941 // Check addCase().
942 auto *Zero = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 0);
943 auto *One = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 1);
944 auto *FortyTwo =
945 sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 42);
946 Ctx.save();
947 Switch->addCase(FortyTwo, Entry);
948 EXPECT_EQ(Switch->getNumCases(), 3u);
949 EXPECT_EQ(Switch->findCaseDest(Entry), FortyTwo);
950 EXPECT_EQ(Switch->findCaseValue(FortyTwo)->getCaseSuccessor(), Entry);
951 EXPECT_EQ(Switch->findCaseDest(BB0), Zero);
952 EXPECT_EQ(Switch->findCaseDest(BB1), One);
953 Ctx.revert();
954 EXPECT_EQ(Switch->getNumCases(), 2u);
955 EXPECT_EQ(Switch->findCaseDest(BB0), Zero);
956 EXPECT_EQ(Switch->findCaseDest(BB1), One);
957 // Check removeCase().
958 Ctx.save();
959 Switch->removeCase(Switch->findCaseValue(Zero));
960 EXPECT_EQ(Switch->getNumCases(), 1u);
961 EXPECT_EQ(Switch->findCaseDest(BB1), One);
962 Ctx.revert();
963 EXPECT_EQ(Switch->getNumCases(), 2u);
964 EXPECT_EQ(Switch->findCaseDest(BB0), Zero);
965 EXPECT_EQ(Switch->findCaseDest(BB1), One);
968 TEST_F(TrackerTest, SwitchInstPreservesSuccesorOrder) {
969 parseIR(C, R"IR(
970 define void @foo(i32 %cond0) {
971 entry:
972 switch i32 %cond0, label %default [ i32 0, label %bb0
973 i32 1, label %bb1
974 i32 2, label %bb2 ]
975 bb0:
976 ret void
977 bb1:
978 ret void
979 bb2:
980 ret void
981 default:
982 ret void
984 )IR");
985 Function &LLVMF = *M->getFunction("foo");
986 auto *LLVMEntry = getBasicBlockByName(LLVMF, "entry");
988 sandboxir::Context Ctx(C);
989 [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF);
990 auto *Entry = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMEntry));
991 auto *BB0 = cast<sandboxir::BasicBlock>(
992 Ctx.getValue(getBasicBlockByName(LLVMF, "bb0")));
993 auto *BB1 = cast<sandboxir::BasicBlock>(
994 Ctx.getValue(getBasicBlockByName(LLVMF, "bb1")));
995 auto *BB2 = cast<sandboxir::BasicBlock>(
996 Ctx.getValue(getBasicBlockByName(LLVMF, "bb2")));
997 auto *Switch = cast<sandboxir::SwitchInst>(&*Entry->begin());
999 auto *DefaultDest = Switch->getDefaultDest();
1000 auto *Zero = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 0);
1001 auto *One = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 1);
1002 auto *Two = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 2);
1004 // Check that we can properly revert a removeCase multiple positions apart
1005 // from the end of the operand list.
1006 Ctx.save();
1007 Switch->removeCase(Switch->findCaseValue(Zero));
1008 EXPECT_EQ(Switch->getNumCases(), 2u);
1009 Ctx.revert();
1010 EXPECT_EQ(Switch->getNumCases(), 3u);
1011 EXPECT_EQ(Switch->findCaseDest(BB0), Zero);
1012 EXPECT_EQ(Switch->findCaseDest(BB1), One);
1013 EXPECT_EQ(Switch->findCaseDest(BB2), Two);
1014 EXPECT_EQ(Switch->getSuccessor(0), DefaultDest);
1015 EXPECT_EQ(Switch->getSuccessor(1), BB0);
1016 EXPECT_EQ(Switch->getSuccessor(2), BB1);
1017 EXPECT_EQ(Switch->getSuccessor(3), BB2);
1019 // Check that we can properly revert a removeCase of the last case.
1020 Ctx.save();
1021 Switch->removeCase(Switch->findCaseValue(Two));
1022 EXPECT_EQ(Switch->getNumCases(), 2u);
1023 Ctx.revert();
1024 EXPECT_EQ(Switch->getNumCases(), 3u);
1025 EXPECT_EQ(Switch->findCaseDest(BB0), Zero);
1026 EXPECT_EQ(Switch->findCaseDest(BB1), One);
1027 EXPECT_EQ(Switch->findCaseDest(BB2), Two);
1028 EXPECT_EQ(Switch->getSuccessor(0), DefaultDest);
1029 EXPECT_EQ(Switch->getSuccessor(1), BB0);
1030 EXPECT_EQ(Switch->getSuccessor(2), BB1);
1031 EXPECT_EQ(Switch->getSuccessor(3), BB2);
1033 // Check order is preserved after reverting multiple removeCase invocations.
1034 Ctx.save();
1035 Switch->removeCase(Switch->findCaseValue(One));
1036 Switch->removeCase(Switch->findCaseValue(Zero));
1037 Switch->removeCase(Switch->findCaseValue(Two));
1038 EXPECT_EQ(Switch->getNumCases(), 0u);
1039 Ctx.revert();
1040 EXPECT_EQ(Switch->getNumCases(), 3u);
1041 EXPECT_EQ(Switch->findCaseDest(BB0), Zero);
1042 EXPECT_EQ(Switch->findCaseDest(BB1), One);
1043 EXPECT_EQ(Switch->findCaseDest(BB2), Two);
1044 EXPECT_EQ(Switch->getSuccessor(0), DefaultDest);
1045 EXPECT_EQ(Switch->getSuccessor(1), BB0);
1046 EXPECT_EQ(Switch->getSuccessor(2), BB1);
1047 EXPECT_EQ(Switch->getSuccessor(3), BB2);
1050 TEST_F(TrackerTest, SelectInst) {
1051 parseIR(C, R"IR(
1052 define void @foo(i1 %c0, i8 %v0, i8 %v1) {
1053 %sel = select i1 %c0, i8 %v0, i8 %v1
1054 ret void
1056 )IR");
1057 llvm::Function *LLVMF = &*M->getFunction("foo");
1058 sandboxir::Context Ctx(C);
1059 sandboxir::Function *F = Ctx.createFunction(LLVMF);
1060 auto *V0 = F->getArg(1);
1061 auto *V1 = F->getArg(2);
1062 auto *BB = &*F->begin();
1063 auto It = BB->begin();
1064 auto *Select = cast<sandboxir::SelectInst>(&*It++);
1066 // Check tracking for swapValues.
1067 Ctx.save();
1068 Select->swapValues();
1069 EXPECT_EQ(Select->getTrueValue(), V1);
1070 EXPECT_EQ(Select->getFalseValue(), V0);
1071 Ctx.revert();
1072 EXPECT_EQ(Select->getTrueValue(), V0);
1073 EXPECT_EQ(Select->getFalseValue(), V1);
1076 TEST_F(TrackerTest, ShuffleVectorInst) {
1077 parseIR(C, R"IR(
1078 define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
1079 %shuf = shufflevector <2 x i8> %v1, <2 x i8> %v2, <2 x i32> <i32 1, i32 2>
1080 ret void
1082 )IR");
1083 Function &LLVMF = *M->getFunction("foo");
1084 sandboxir::Context Ctx(C);
1086 auto *F = Ctx.createFunction(&LLVMF);
1087 auto *BB = &*F->begin();
1088 auto It = BB->begin();
1089 auto *SVI = cast<sandboxir::ShuffleVectorInst>(&*It++);
1091 // Check setShuffleMask.
1092 SmallVector<int, 2> OrigMask(SVI->getShuffleMask());
1093 Ctx.save();
1094 SVI->setShuffleMask(ArrayRef<int>({0, 0}));
1095 EXPECT_NE(SVI->getShuffleMask(), ArrayRef<int>(OrigMask));
1096 Ctx.revert();
1097 EXPECT_EQ(SVI->getShuffleMask(), ArrayRef<int>(OrigMask));
1099 // Check commute.
1100 auto *Op0 = SVI->getOperand(0);
1101 auto *Op1 = SVI->getOperand(1);
1102 Ctx.save();
1103 SVI->commute();
1104 EXPECT_EQ(SVI->getOperand(0), Op1);
1105 EXPECT_EQ(SVI->getOperand(1), Op0);
1106 EXPECT_NE(SVI->getShuffleMask(), ArrayRef<int>(OrigMask));
1107 Ctx.revert();
1108 EXPECT_EQ(SVI->getOperand(0), Op0);
1109 EXPECT_EQ(SVI->getOperand(1), Op1);
1110 EXPECT_EQ(SVI->getShuffleMask(), ArrayRef<int>(OrigMask));
1113 TEST_F(TrackerTest, PossiblyDisjointInstSetters) {
1114 parseIR(C, R"IR(
1115 define void @foo(i8 %arg0, i8 %arg1) {
1116 %or = or i8 %arg0, %arg1
1117 ret void
1119 )IR");
1120 Function &LLVMF = *M->getFunction("foo");
1121 sandboxir::Context Ctx(C);
1123 auto &F = *Ctx.createFunction(&LLVMF);
1124 auto *BB = &*F.begin();
1125 auto It = BB->begin();
1126 auto *PDI = cast<sandboxir::PossiblyDisjointInst>(&*It++);
1128 // Check setIsDisjoint().
1129 auto OrigIsDisjoint = PDI->isDisjoint();
1130 auto NewIsDisjoint = true;
1131 EXPECT_NE(NewIsDisjoint, OrigIsDisjoint);
1132 Ctx.save();
1133 PDI->setIsDisjoint(NewIsDisjoint);
1134 EXPECT_EQ(PDI->isDisjoint(), NewIsDisjoint);
1135 Ctx.revert();
1136 EXPECT_EQ(PDI->isDisjoint(), OrigIsDisjoint);
1139 TEST_F(TrackerTest, PossiblyNonNegInstSetters) {
1140 parseIR(C, R"IR(
1141 define void @foo(i32 %arg) {
1142 %zext = zext i32 %arg to i64
1143 ret void
1145 )IR");
1146 Function &LLVMF = *M->getFunction("foo");
1147 sandboxir::Context Ctx(C);
1149 auto &F = *Ctx.createFunction(&LLVMF);
1150 auto *BB = &*F.begin();
1151 auto It = BB->begin();
1152 auto *PNNI = cast<sandboxir::PossiblyNonNegInst>(&*It++);
1154 // Check setNonNeg().
1155 auto OrigNonNeg = PNNI->hasNonNeg();
1156 auto NewNonNeg = true;
1157 EXPECT_NE(NewNonNeg, OrigNonNeg);
1158 Ctx.save();
1159 PNNI->setNonNeg(NewNonNeg);
1160 EXPECT_EQ(PNNI->hasNonNeg(), NewNonNeg);
1161 Ctx.revert();
1162 EXPECT_EQ(PNNI->hasNonNeg(), OrigNonNeg);
1165 TEST_F(TrackerTest, AtomicRMWSetters) {
1166 parseIR(C, R"IR(
1167 define void @foo(ptr %ptr, i8 %arg) {
1168 %atomicrmw = atomicrmw add ptr %ptr, i8 %arg acquire, align 128
1169 ret void
1171 )IR");
1172 Function &LLVMF = *M->getFunction("foo");
1173 sandboxir::Context Ctx(C);
1174 auto &F = *Ctx.createFunction(&LLVMF);
1175 auto *BB = &*F.begin();
1176 auto It = BB->begin();
1177 auto *RMW = cast<sandboxir::AtomicRMWInst>(&*It++);
1179 // Check setAlignment().
1180 Ctx.save();
1181 auto OrigAlign = RMW->getAlign();
1182 Align NewAlign(1024);
1183 EXPECT_NE(NewAlign, OrigAlign);
1184 RMW->setAlignment(NewAlign);
1185 EXPECT_EQ(RMW->getAlign(), NewAlign);
1186 Ctx.revert();
1187 EXPECT_EQ(RMW->getAlign(), OrigAlign);
1189 // Check setVolatile().
1190 Ctx.save();
1191 auto OrigIsVolatile = RMW->isVolatile();
1192 bool NewIsVolatile = true;
1193 EXPECT_NE(NewIsVolatile, OrigIsVolatile);
1194 RMW->setVolatile(NewIsVolatile);
1195 EXPECT_EQ(RMW->isVolatile(), NewIsVolatile);
1196 Ctx.revert();
1197 EXPECT_EQ(RMW->isVolatile(), OrigIsVolatile);
1199 // Check setOrdering().
1200 Ctx.save();
1201 auto OrigOrdering = RMW->getOrdering();
1202 auto NewOrdering = AtomicOrdering::SequentiallyConsistent;
1203 EXPECT_NE(NewOrdering, OrigOrdering);
1204 RMW->setOrdering(NewOrdering);
1205 EXPECT_EQ(RMW->getOrdering(), NewOrdering);
1206 Ctx.revert();
1207 EXPECT_EQ(RMW->getOrdering(), OrigOrdering);
1209 // Check setSyncScopeID().
1210 Ctx.save();
1211 auto OrigSSID = RMW->getSyncScopeID();
1212 auto NewSSID = SyncScope::SingleThread;
1213 EXPECT_NE(NewSSID, OrigSSID);
1214 RMW->setSyncScopeID(NewSSID);
1215 EXPECT_EQ(RMW->getSyncScopeID(), NewSSID);
1216 Ctx.revert();
1217 EXPECT_EQ(RMW->getSyncScopeID(), OrigSSID);
1220 TEST_F(TrackerTest, AtomicCmpXchgSetters) {
1221 parseIR(C, R"IR(
1222 define void @foo(ptr %ptr, i8 %cmp, i8 %new) {
1223 %cmpxchg = cmpxchg ptr %ptr, i8 %cmp, i8 %new monotonic monotonic, align 128
1224 ret void
1226 )IR");
1227 Function &LLVMF = *M->getFunction("foo");
1228 sandboxir::Context Ctx(C);
1229 auto &F = *Ctx.createFunction(&LLVMF);
1230 auto *BB = &*F.begin();
1231 auto It = BB->begin();
1232 auto *CmpXchg = cast<sandboxir::AtomicCmpXchgInst>(&*It++);
1234 // Check setAlignment().
1235 Ctx.save();
1236 auto OrigAlign = CmpXchg->getAlign();
1237 Align NewAlign(1024);
1238 EXPECT_NE(NewAlign, OrigAlign);
1239 CmpXchg->setAlignment(NewAlign);
1240 EXPECT_EQ(CmpXchg->getAlign(), NewAlign);
1241 Ctx.revert();
1242 EXPECT_EQ(CmpXchg->getAlign(), OrigAlign);
1244 // Check setVolatile().
1245 Ctx.save();
1246 auto OrigIsVolatile = CmpXchg->isVolatile();
1247 bool NewIsVolatile = true;
1248 EXPECT_NE(NewIsVolatile, OrigIsVolatile);
1249 CmpXchg->setVolatile(NewIsVolatile);
1250 EXPECT_EQ(CmpXchg->isVolatile(), NewIsVolatile);
1251 Ctx.revert();
1252 EXPECT_EQ(CmpXchg->isVolatile(), OrigIsVolatile);
1254 // Check setWeak().
1255 Ctx.save();
1256 auto OrigIsWeak = CmpXchg->isWeak();
1257 bool NewIsWeak = true;
1258 EXPECT_NE(NewIsWeak, OrigIsWeak);
1259 CmpXchg->setWeak(NewIsWeak);
1260 EXPECT_EQ(CmpXchg->isWeak(), NewIsWeak);
1261 Ctx.revert();
1262 EXPECT_EQ(CmpXchg->isWeak(), OrigIsWeak);
1264 // Check setSuccessOrdering().
1265 Ctx.save();
1266 auto OrigSuccessOrdering = CmpXchg->getSuccessOrdering();
1267 auto NewSuccessOrdering = AtomicOrdering::SequentiallyConsistent;
1268 EXPECT_NE(NewSuccessOrdering, OrigSuccessOrdering);
1269 CmpXchg->setSuccessOrdering(NewSuccessOrdering);
1270 EXPECT_EQ(CmpXchg->getSuccessOrdering(), NewSuccessOrdering);
1271 Ctx.revert();
1272 EXPECT_EQ(CmpXchg->getSuccessOrdering(), OrigSuccessOrdering);
1274 // Check setFailureOrdering().
1275 Ctx.save();
1276 auto OrigFailureOrdering = CmpXchg->getFailureOrdering();
1277 auto NewFailureOrdering = AtomicOrdering::SequentiallyConsistent;
1278 EXPECT_NE(NewFailureOrdering, OrigFailureOrdering);
1279 CmpXchg->setFailureOrdering(NewFailureOrdering);
1280 EXPECT_EQ(CmpXchg->getFailureOrdering(), NewFailureOrdering);
1281 Ctx.revert();
1282 EXPECT_EQ(CmpXchg->getFailureOrdering(), OrigFailureOrdering);
1284 // Check setSyncScopeID().
1285 Ctx.save();
1286 auto OrigSSID = CmpXchg->getSyncScopeID();
1287 auto NewSSID = SyncScope::SingleThread;
1288 EXPECT_NE(NewSSID, OrigSSID);
1289 CmpXchg->setSyncScopeID(NewSSID);
1290 EXPECT_EQ(CmpXchg->getSyncScopeID(), NewSSID);
1291 Ctx.revert();
1292 EXPECT_EQ(CmpXchg->getSyncScopeID(), OrigSSID);
1295 TEST_F(TrackerTest, AllocaInstSetters) {
1296 parseIR(C, R"IR(
1297 define void @foo(i8 %arg) {
1298 %alloca = alloca i32, align 64
1299 ret void
1301 )IR");
1302 Function &LLVMF = *M->getFunction("foo");
1303 sandboxir::Context Ctx(C);
1304 auto &F = *Ctx.createFunction(&LLVMF);
1305 auto *BB = &*F.begin();
1306 auto It = BB->begin();
1307 auto *Alloca = cast<sandboxir::AllocaInst>(&*It++);
1309 // Check setAllocatedType().
1310 Ctx.save();
1311 auto *OrigTy = Alloca->getAllocatedType();
1312 auto *NewTy = sandboxir::Type::getInt64Ty(Ctx);
1313 EXPECT_NE(NewTy, OrigTy);
1314 Alloca->setAllocatedType(NewTy);
1315 EXPECT_EQ(Alloca->getAllocatedType(), NewTy);
1316 Ctx.revert();
1317 EXPECT_EQ(Alloca->getAllocatedType(), OrigTy);
1319 // Check setAlignment().
1320 Ctx.save();
1321 auto OrigAlign = Alloca->getAlign();
1322 Align NewAlign(128);
1323 EXPECT_NE(NewAlign, OrigAlign);
1324 Alloca->setAlignment(NewAlign);
1325 EXPECT_EQ(Alloca->getAlign(), NewAlign);
1326 Ctx.revert();
1327 EXPECT_EQ(Alloca->getAlign(), OrigAlign);
1329 // Check setUsedWithInAlloca().
1330 Ctx.save();
1331 auto OrigWIA = Alloca->isUsedWithInAlloca();
1332 bool NewWIA = true;
1333 EXPECT_NE(NewWIA, OrigWIA);
1334 Alloca->setUsedWithInAlloca(NewWIA);
1335 EXPECT_EQ(Alloca->isUsedWithInAlloca(), NewWIA);
1336 Ctx.revert();
1337 EXPECT_EQ(Alloca->isUsedWithInAlloca(), OrigWIA);
1340 TEST_F(TrackerTest, CallBrSetters) {
1341 parseIR(C, R"IR(
1342 define void @foo(i8 %arg) {
1343 bb0:
1344 callbr void @foo(i8 %arg)
1345 to label %bb1 [label %bb2]
1346 bb1:
1347 ret void
1348 bb2:
1349 ret void
1350 other_bb:
1351 ret void
1353 )IR");
1354 Function &LLVMF = *M->getFunction("foo");
1355 sandboxir::Context Ctx(C);
1356 [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF);
1357 auto *BB0 = cast<sandboxir::BasicBlock>(
1358 Ctx.getValue(getBasicBlockByName(LLVMF, "bb0")));
1359 auto *OtherBB = cast<sandboxir::BasicBlock>(
1360 Ctx.getValue(getBasicBlockByName(LLVMF, "other_bb")));
1361 auto It = BB0->begin();
1362 auto *CallBr = cast<sandboxir::CallBrInst>(&*It++);
1363 // Check setDefaultDest().
1364 Ctx.save();
1365 auto *OrigDefaultDest = CallBr->getDefaultDest();
1366 CallBr->setDefaultDest(OtherBB);
1367 EXPECT_EQ(CallBr->getDefaultDest(), OtherBB);
1368 Ctx.revert();
1369 EXPECT_EQ(CallBr->getDefaultDest(), OrigDefaultDest);
1371 // Check setIndirectDest().
1372 Ctx.save();
1373 auto *OrigIndirectDest = CallBr->getIndirectDest(0);
1374 CallBr->setIndirectDest(0, OtherBB);
1375 EXPECT_EQ(CallBr->getIndirectDest(0), OtherBB);
1376 Ctx.revert();
1377 EXPECT_EQ(CallBr->getIndirectDest(0), OrigIndirectDest);
1380 TEST_F(TrackerTest, FuncletPadInstSetters) {
1381 parseIR(C, R"IR(
1382 define void @foo() {
1383 dispatch:
1384 %cs = catchswitch within none [label %handler0] unwind to caller
1385 handler0:
1386 %catchpad = catchpad within %cs [ptr @foo]
1387 ret void
1388 handler1:
1389 %cleanuppad = cleanuppad within %cs [ptr @foo]
1390 ret void
1392 ret void
1394 )IR");
1395 Function &LLVMF = *M->getFunction("foo");
1396 sandboxir::Context Ctx(C);
1397 [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF);
1398 auto *Dispatch = cast<sandboxir::BasicBlock>(
1399 Ctx.getValue(getBasicBlockByName(LLVMF, "dispatch")));
1400 auto *Handler0 = cast<sandboxir::BasicBlock>(
1401 Ctx.getValue(getBasicBlockByName(LLVMF, "handler0")));
1402 auto *Handler1 = cast<sandboxir::BasicBlock>(
1403 Ctx.getValue(getBasicBlockByName(LLVMF, "handler1")));
1404 auto *CP = cast<sandboxir::CatchPadInst>(&*Handler0->begin());
1405 auto *CLP = cast<sandboxir::CleanupPadInst>(&*Handler1->begin());
1407 for (auto *FPI : {static_cast<sandboxir::FuncletPadInst *>(CP),
1408 static_cast<sandboxir::FuncletPadInst *>(CLP)}) {
1409 // Check setParentPad().
1410 auto *OrigParentPad = FPI->getParentPad();
1411 auto *NewParentPad = Dispatch;
1412 EXPECT_NE(NewParentPad, OrigParentPad);
1413 Ctx.save();
1414 FPI->setParentPad(NewParentPad);
1415 EXPECT_EQ(FPI->getParentPad(), NewParentPad);
1416 Ctx.revert();
1417 EXPECT_EQ(FPI->getParentPad(), OrigParentPad);
1419 // Check setArgOperand().
1420 auto *OrigArgOperand = FPI->getArgOperand(0);
1421 auto *NewArgOperand = Dispatch;
1422 EXPECT_NE(NewArgOperand, OrigArgOperand);
1423 Ctx.save();
1424 FPI->setArgOperand(0, NewArgOperand);
1425 EXPECT_EQ(FPI->getArgOperand(0), NewArgOperand);
1426 Ctx.revert();
1427 EXPECT_EQ(FPI->getArgOperand(0), OrigArgOperand);
1431 TEST_F(TrackerTest, PHINodeSetters) {
1432 parseIR(C, R"IR(
1433 define void @foo(i8 %arg0, i8 %arg1, i8 %arg2) {
1434 bb0:
1435 br label %bb2
1437 bb1:
1438 %phi = phi i8 [ %arg0, %bb0 ], [ %arg1, %bb1 ]
1439 br label %bb1
1441 bb2:
1442 ret void
1444 )IR");
1445 Function &LLVMF = *M->getFunction("foo");
1446 sandboxir::Context Ctx(C);
1447 auto &F = *Ctx.createFunction(&LLVMF);
1448 unsigned ArgIdx = 0;
1449 auto *Arg0 = F.getArg(ArgIdx++);
1450 auto *Arg1 = F.getArg(ArgIdx++);
1451 auto *Arg2 = F.getArg(ArgIdx++);
1452 auto *BB0 = cast<sandboxir::BasicBlock>(
1453 Ctx.getValue(getBasicBlockByName(LLVMF, "bb0")));
1454 auto *BB1 = cast<sandboxir::BasicBlock>(
1455 Ctx.getValue(getBasicBlockByName(LLVMF, "bb1")));
1456 auto *BB2 = cast<sandboxir::BasicBlock>(
1457 Ctx.getValue(getBasicBlockByName(LLVMF, "bb2")));
1458 auto *PHI = cast<sandboxir::PHINode>(&*BB1->begin());
1460 // Check setIncomingValue().
1461 Ctx.save();
1462 EXPECT_EQ(PHI->getIncomingValue(0), Arg0);
1463 PHI->setIncomingValue(0, Arg2);
1464 EXPECT_EQ(PHI->getIncomingValue(0), Arg2);
1465 Ctx.revert();
1466 EXPECT_EQ(PHI->getIncomingValue(0), Arg0);
1467 EXPECT_EQ(PHI->getNumIncomingValues(), 2u);
1468 EXPECT_EQ(PHI->getIncomingBlock(0), BB0);
1469 EXPECT_EQ(PHI->getIncomingValue(0), Arg0);
1470 EXPECT_EQ(PHI->getIncomingBlock(1), BB1);
1471 EXPECT_EQ(PHI->getIncomingValue(1), Arg1);
1473 // Check setIncomingBlock().
1474 Ctx.save();
1475 EXPECT_EQ(PHI->getIncomingBlock(0), BB0);
1476 PHI->setIncomingBlock(0, BB2);
1477 EXPECT_EQ(PHI->getIncomingBlock(0), BB2);
1478 Ctx.revert();
1479 EXPECT_EQ(PHI->getIncomingBlock(0), BB0);
1480 EXPECT_EQ(PHI->getNumIncomingValues(), 2u);
1481 EXPECT_EQ(PHI->getIncomingBlock(0), BB0);
1482 EXPECT_EQ(PHI->getIncomingValue(0), Arg0);
1483 EXPECT_EQ(PHI->getIncomingBlock(1), BB1);
1484 EXPECT_EQ(PHI->getIncomingValue(1), Arg1);
1486 // Check addIncoming().
1487 Ctx.save();
1488 EXPECT_EQ(PHI->getNumIncomingValues(), 2u);
1489 PHI->addIncoming(Arg1, BB2);
1490 EXPECT_EQ(PHI->getNumIncomingValues(), 3u);
1491 EXPECT_EQ(PHI->getIncomingBlock(2), BB2);
1492 EXPECT_EQ(PHI->getIncomingValue(2), Arg1);
1493 Ctx.revert();
1494 EXPECT_EQ(PHI->getNumIncomingValues(), 2u);
1495 EXPECT_EQ(PHI->getIncomingBlock(0), BB0);
1496 EXPECT_EQ(PHI->getIncomingValue(0), Arg0);
1497 EXPECT_EQ(PHI->getIncomingBlock(1), BB1);
1498 EXPECT_EQ(PHI->getIncomingValue(1), Arg1);
1500 // Check removeIncomingValue(1).
1501 Ctx.save();
1502 PHI->removeIncomingValue(1);
1503 EXPECT_EQ(PHI->getNumIncomingValues(), 1u);
1504 EXPECT_EQ(PHI->getIncomingBlock(0), BB0);
1505 EXPECT_EQ(PHI->getIncomingValue(0), Arg0);
1506 Ctx.revert();
1507 EXPECT_EQ(PHI->getNumIncomingValues(), 2u);
1508 EXPECT_EQ(PHI->getIncomingBlock(0), BB0);
1509 EXPECT_EQ(PHI->getIncomingValue(0), Arg0);
1510 EXPECT_EQ(PHI->getIncomingBlock(1), BB1);
1511 EXPECT_EQ(PHI->getIncomingValue(1), Arg1);
1513 // Check removeIncomingValue(0).
1514 Ctx.save();
1515 PHI->removeIncomingValue(0u);
1516 EXPECT_EQ(PHI->getNumIncomingValues(), 1u);
1517 EXPECT_EQ(PHI->getIncomingBlock(0), BB1);
1518 EXPECT_EQ(PHI->getIncomingValue(0), Arg1);
1519 Ctx.revert();
1520 EXPECT_EQ(PHI->getNumIncomingValues(), 2u);
1521 EXPECT_EQ(PHI->getIncomingBlock(0), BB0);
1522 EXPECT_EQ(PHI->getIncomingValue(0), Arg0);
1523 EXPECT_EQ(PHI->getIncomingBlock(1), BB1);
1524 EXPECT_EQ(PHI->getIncomingValue(1), Arg1);
1526 // Check removeIncomingValueIf(FromBB1).
1527 Ctx.save();
1528 PHI->removeIncomingValueIf(
1529 [&](unsigned Idx) { return PHI->getIncomingBlock(Idx) == BB1; });
1530 EXPECT_EQ(PHI->getNumIncomingValues(), 1u);
1531 Ctx.revert();
1532 EXPECT_EQ(PHI->getNumIncomingValues(), 2u);
1533 EXPECT_EQ(PHI->getIncomingBlock(0), BB0);
1534 EXPECT_EQ(PHI->getIncomingBlock(1), BB1);
1535 // Check removeIncomingValue() remove all.
1536 Ctx.save();
1537 PHI->removeIncomingValue(0u);
1538 EXPECT_EQ(PHI->getNumIncomingValues(), 1u);
1539 EXPECT_EQ(PHI->getIncomingBlock(0), BB1);
1540 EXPECT_EQ(PHI->getIncomingValue(0), Arg1);
1541 PHI->removeIncomingValue(0u);
1542 EXPECT_EQ(PHI->getNumIncomingValues(), 0u);
1543 Ctx.revert();
1544 EXPECT_EQ(PHI->getNumIncomingValues(), 2u);
1545 EXPECT_EQ(PHI->getIncomingBlock(0), BB0);
1546 EXPECT_EQ(PHI->getIncomingValue(0), Arg0);
1547 EXPECT_EQ(PHI->getIncomingBlock(1), BB1);
1548 EXPECT_EQ(PHI->getIncomingValue(1), Arg1);
1550 // Check removeIncomingValue(BasicBlock *).
1551 Ctx.save();
1552 PHI->removeIncomingValue(BB1);
1553 EXPECT_EQ(PHI->getNumIncomingValues(), 1u);
1554 EXPECT_EQ(PHI->getIncomingBlock(0), BB0);
1555 EXPECT_EQ(PHI->getIncomingValue(0), Arg0);
1556 Ctx.revert();
1557 EXPECT_EQ(PHI->getNumIncomingValues(), 2u);
1558 EXPECT_EQ(PHI->getIncomingBlock(0), BB0);
1559 EXPECT_EQ(PHI->getIncomingValue(0), Arg0);
1560 EXPECT_EQ(PHI->getIncomingBlock(1), BB1);
1561 EXPECT_EQ(PHI->getIncomingValue(1), Arg1);
1564 void checkCmpInst(sandboxir::Context &Ctx, sandboxir::CmpInst *Cmp) {
1565 Ctx.save();
1566 auto OrigP = Cmp->getPredicate();
1567 auto NewP = Cmp->getSwappedPredicate();
1568 Cmp->setPredicate(NewP);
1569 EXPECT_EQ(Cmp->getPredicate(), NewP);
1570 Ctx.revert();
1571 EXPECT_EQ(Cmp->getPredicate(), OrigP);
1573 Ctx.save();
1574 auto OrigOp0 = Cmp->getOperand(0);
1575 auto OrigOp1 = Cmp->getOperand(1);
1576 Cmp->swapOperands();
1577 EXPECT_EQ(Cmp->getPredicate(), NewP);
1578 EXPECT_EQ(Cmp->getOperand(0), OrigOp1);
1579 EXPECT_EQ(Cmp->getOperand(1), OrigOp0);
1580 Ctx.revert();
1581 EXPECT_EQ(Cmp->getPredicate(), OrigP);
1582 EXPECT_EQ(Cmp->getOperand(0), OrigOp0);
1583 EXPECT_EQ(Cmp->getOperand(1), OrigOp1);
1586 TEST_F(TrackerTest, CmpInst) {
1587 SCOPED_TRACE("TrackerTest sandboxir::CmpInst tests");
1588 parseIR(C, R"IR(
1589 define void @foo(i64 %i0, i64 %i1, float %f0, float %f1) {
1590 %foeq = fcmp ogt float %f0, %f1
1591 %ioeq = icmp uge i64 %i0, %i1
1593 ret void
1595 )IR");
1596 Function &LLVMF = *M->getFunction("foo");
1597 sandboxir::Context Ctx(C);
1598 auto &F = *Ctx.createFunction(&LLVMF);
1599 auto *BB = &*F.begin();
1600 auto It = BB->begin();
1601 auto *FCmp = cast<sandboxir::CmpInst>(&*It++);
1602 checkCmpInst(Ctx, FCmp);
1603 auto *ICmp = cast<sandboxir::CmpInst>(&*It++);
1604 checkCmpInst(Ctx, ICmp);
1607 TEST_F(TrackerTest, GlobalValueSetters) {
1608 parseIR(C, R"IR(
1609 define void @foo() {
1610 call void @foo()
1611 ret void
1613 )IR");
1614 Function &LLVMF = *M->getFunction("foo");
1615 sandboxir::Context Ctx(C);
1617 auto &F = *Ctx.createFunction(&LLVMF);
1618 auto *BB = &*F.begin();
1619 auto *Call = cast<sandboxir::CallInst>(&*BB->begin());
1621 auto *GV = cast<sandboxir::GlobalValue>(Call->getCalledOperand());
1622 // Check setUnnamedAddr().
1623 auto OrigUnnamedAddr = GV->getUnnamedAddr();
1624 auto NewUnnamedAddr = sandboxir::GlobalValue::UnnamedAddr::Global;
1625 EXPECT_NE(NewUnnamedAddr, OrigUnnamedAddr);
1626 Ctx.save();
1627 GV->setUnnamedAddr(NewUnnamedAddr);
1628 EXPECT_EQ(GV->getUnnamedAddr(), NewUnnamedAddr);
1629 Ctx.revert();
1630 EXPECT_EQ(GV->getUnnamedAddr(), OrigUnnamedAddr);
1632 // Check setVisibility().
1633 auto OrigVisibility = GV->getVisibility();
1634 auto NewVisibility =
1635 sandboxir::GlobalValue::VisibilityTypes::ProtectedVisibility;
1636 EXPECT_NE(NewVisibility, OrigVisibility);
1637 Ctx.save();
1638 GV->setVisibility(NewVisibility);
1639 EXPECT_EQ(GV->getVisibility(), NewVisibility);
1640 Ctx.revert();
1641 EXPECT_EQ(GV->getVisibility(), OrigVisibility);
1644 TEST_F(TrackerTest, GlobalIFuncSetters) {
1645 parseIR(C, R"IR(
1646 declare external void @bar()
1647 @ifunc = ifunc void(), ptr @foo
1648 define void @foo() {
1649 call void @ifunc()
1650 call void @bar()
1651 ret void
1653 )IR");
1654 Function &LLVMF = *M->getFunction("foo");
1655 sandboxir::Context Ctx(C);
1657 auto &F = *Ctx.createFunction(&LLVMF);
1658 auto *BB = &*F.begin();
1659 auto It = BB->begin();
1660 auto *Call0 = cast<sandboxir::CallInst>(&*It++);
1661 auto *Call1 = cast<sandboxir::CallInst>(&*It++);
1662 // Check classof(), creation.
1663 auto *IFunc = cast<sandboxir::GlobalIFunc>(Call0->getCalledOperand());
1664 auto *Bar = cast<sandboxir::Function>(Call1->getCalledOperand());
1665 // Check setResolver().
1666 auto *OrigResolver = IFunc->getResolver();
1667 auto *NewResolver = Bar;
1668 EXPECT_NE(NewResolver, OrigResolver);
1669 Ctx.save();
1670 IFunc->setResolver(NewResolver);
1671 EXPECT_EQ(IFunc->getResolver(), NewResolver);
1672 Ctx.revert();
1673 EXPECT_EQ(IFunc->getResolver(), OrigResolver);
1676 TEST_F(TrackerTest, GlobalVariableSetters) {
1677 parseIR(C, R"IR(
1678 @glob0 = global i32 42
1679 @glob1 = global i32 43
1680 define void @foo() {
1681 %ld0 = load i32, ptr @glob0
1682 %ld1 = load i32, ptr @glob1
1683 ret void
1685 )IR");
1686 Function &LLVMF = *M->getFunction("foo");
1687 sandboxir::Context Ctx(C);
1689 auto &F = *Ctx.createFunction(&LLVMF);
1690 auto *BB = &*F.begin();
1691 auto It = BB->begin();
1692 auto *Ld0 = cast<sandboxir::LoadInst>(&*It++);
1693 auto *Ld1 = cast<sandboxir::LoadInst>(&*It++);
1694 // Check classof(), creation.
1695 auto *GV0 = cast<sandboxir::GlobalVariable>(Ld0->getPointerOperand());
1696 auto *GV1 = cast<sandboxir::GlobalVariable>(Ld1->getPointerOperand());
1697 // Check setInitializer().
1698 auto *OrigInitializer = GV0->getInitializer();
1699 auto *NewInitializer = GV1->getInitializer();
1700 EXPECT_NE(NewInitializer, OrigInitializer);
1701 Ctx.save();
1702 GV0->setInitializer(NewInitializer);
1703 EXPECT_EQ(GV0->getInitializer(), NewInitializer);
1704 Ctx.revert();
1705 EXPECT_EQ(GV0->getInitializer(), OrigInitializer);
1706 // Check setConstant().
1707 bool OrigIsConstant = GV0->isConstant();
1708 bool NewIsConstant = !OrigIsConstant;
1709 Ctx.save();
1710 GV0->setConstant(NewIsConstant);
1711 EXPECT_EQ(GV0->isConstant(), NewIsConstant);
1712 Ctx.revert();
1713 EXPECT_EQ(GV0->isConstant(), OrigIsConstant);
1714 // Check setExternallyInitialized().
1715 bool OrigIsExtInit = GV0->isExternallyInitialized();
1716 bool NewIsExtInit = !OrigIsExtInit;
1717 Ctx.save();
1718 GV0->setExternallyInitialized(NewIsExtInit);
1719 EXPECT_EQ(GV0->isExternallyInitialized(), NewIsExtInit);
1720 Ctx.revert();
1721 EXPECT_EQ(GV0->isExternallyInitialized(), OrigIsExtInit);
1724 TEST_F(TrackerTest, GlobalAliasSetters) {
1725 parseIR(C, R"IR(
1726 @alias = dso_local alias void(), ptr @foo
1727 declare void @bar();
1728 define void @foo() {
1729 call void @alias()
1730 call void @bar()
1731 ret void
1733 )IR");
1734 Function &LLVMF = *M->getFunction("foo");
1735 sandboxir::Context Ctx(C);
1737 auto &F = *Ctx.createFunction(&LLVMF);
1738 auto *BB = &*F.begin();
1739 auto It = BB->begin();
1740 auto *Call0 = cast<sandboxir::CallInst>(&*It++);
1741 auto *Call1 = cast<sandboxir::CallInst>(&*It++);
1742 auto *Callee1 = cast<sandboxir::Constant>(Call1->getCalledOperand());
1743 auto *Alias = cast<sandboxir::GlobalAlias>(Call0->getCalledOperand());
1744 // Check setAliasee().
1745 auto *OrigAliasee = Alias->getAliasee();
1746 auto *NewAliasee = Callee1;
1747 EXPECT_NE(NewAliasee, OrigAliasee);
1748 Ctx.save();
1749 Alias->setAliasee(NewAliasee);
1750 EXPECT_EQ(Alias->getAliasee(), NewAliasee);
1751 Ctx.revert();
1752 EXPECT_EQ(Alias->getAliasee(), OrigAliasee);
1755 TEST_F(TrackerTest, SetVolatile) {
1756 parseIR(C, R"IR(
1757 define void @foo(ptr %arg0, i8 %val) {
1758 %ld = load i8, ptr %arg0, align 64
1759 store i8 %val, ptr %arg0, align 64
1760 ret void
1762 )IR");
1763 Function &LLVMF = *M->getFunction("foo");
1764 sandboxir::Context Ctx(C);
1766 auto *F = Ctx.createFunction(&LLVMF);
1767 auto *BB = &*F->begin();
1768 auto It = BB->begin();
1769 auto *Load = cast<sandboxir::LoadInst>(&*It++);
1770 auto *Store = cast<sandboxir::StoreInst>(&*It++);
1772 EXPECT_FALSE(Load->isVolatile());
1773 Ctx.save();
1774 Load->setVolatile(true);
1775 EXPECT_TRUE(Load->isVolatile());
1776 Ctx.revert();
1777 EXPECT_FALSE(Load->isVolatile());
1779 EXPECT_FALSE(Store->isVolatile());
1780 Ctx.save();
1781 Store->setVolatile(true);
1782 EXPECT_TRUE(Store->isVolatile());
1783 Ctx.revert();
1784 EXPECT_FALSE(Store->isVolatile());
1787 TEST_F(TrackerTest, Flags) {
1788 parseIR(C, R"IR(
1789 define void @foo(i32 %arg, float %farg) {
1790 %add = add i32 %arg, %arg
1791 %fadd = fadd float %farg, %farg
1792 %udiv = udiv i32 %arg, %arg
1793 ret void
1795 )IR");
1796 Function &LLVMF = *M->getFunction("foo");
1797 sandboxir::Context Ctx(C);
1798 auto &F = *Ctx.createFunction(&LLVMF);
1799 auto *BB = &*F.begin();
1800 auto It = BB->begin();
1801 auto *Add = &*It++;
1802 auto *FAdd = &*It++;
1803 auto *UDiv = &*It++;
1805 #define CHECK_FLAG(I, GETTER, SETTER) \
1807 Ctx.save(); \
1808 bool OrigFlag = I->GETTER(); \
1809 bool NewFlag = !OrigFlag; \
1810 I->SETTER(NewFlag); \
1811 EXPECT_EQ(I->GETTER(), NewFlag); \
1812 Ctx.revert(); \
1813 EXPECT_EQ(I->GETTER(), OrigFlag); \
1816 CHECK_FLAG(Add, hasNoUnsignedWrap, setHasNoUnsignedWrap);
1817 CHECK_FLAG(Add, hasNoSignedWrap, setHasNoSignedWrap);
1818 CHECK_FLAG(FAdd, isFast, setFast);
1819 CHECK_FLAG(FAdd, hasAllowReassoc, setHasAllowReassoc);
1820 CHECK_FLAG(UDiv, isExact, setIsExact);
1821 CHECK_FLAG(FAdd, hasNoNaNs, setHasNoNaNs);
1822 CHECK_FLAG(FAdd, hasNoInfs, setHasNoInfs);
1823 CHECK_FLAG(FAdd, hasNoSignedZeros, setHasNoSignedZeros);
1824 CHECK_FLAG(FAdd, hasAllowReciprocal, setHasAllowReciprocal);
1825 CHECK_FLAG(FAdd, hasAllowContract, setHasAllowContract);
1826 CHECK_FLAG(FAdd, hasApproxFunc, setHasApproxFunc);
1828 // Check setFastMathFlags().
1829 FastMathFlags OrigFMF = FAdd->getFastMathFlags();
1830 FastMathFlags NewFMF;
1831 NewFMF.setAllowReassoc(true);
1832 EXPECT_TRUE(NewFMF != OrigFMF);
1834 Ctx.save();
1835 FAdd->setFastMathFlags(NewFMF);
1836 EXPECT_FALSE(FAdd->getFastMathFlags() != NewFMF);
1837 Ctx.revert();
1838 EXPECT_FALSE(FAdd->getFastMathFlags() != OrigFMF);
1840 // Check copyFastMathFlags().
1841 Ctx.save();
1842 FAdd->copyFastMathFlags(NewFMF);
1843 EXPECT_FALSE(FAdd->getFastMathFlags() != NewFMF);
1844 Ctx.revert();
1845 EXPECT_FALSE(FAdd->getFastMathFlags() != OrigFMF);
1848 // IRSnapshotChecker is only defined in debug mode.
1849 #ifndef NDEBUG
1851 TEST_F(TrackerTest, IRSnapshotCheckerNoChanges) {
1852 parseIR(C, R"IR(
1853 define i32 @foo(i32 %arg) {
1854 %add0 = add i32 %arg, %arg
1855 ret i32 %add0
1857 )IR");
1858 Function &LLVMF = *M->getFunction("foo");
1859 sandboxir::Context Ctx(C);
1861 [[maybe_unused]] auto *F = Ctx.createFunction(&LLVMF);
1862 sandboxir::IRSnapshotChecker Checker(Ctx);
1863 Checker.save();
1864 Checker.expectNoDiff();
1867 TEST_F(TrackerTest, IRSnapshotCheckerDiesWithUnexpectedChanges) {
1868 parseIR(C, R"IR(
1869 define i32 @foo(i32 %arg) {
1870 %add0 = add i32 %arg, %arg
1871 %add1 = add i32 %add0, %arg
1872 ret i32 %add1
1874 )IR");
1875 Function &LLVMF = *M->getFunction("foo");
1876 sandboxir::Context Ctx(C);
1878 auto *F = Ctx.createFunction(&LLVMF);
1879 auto *BB = &*F->begin();
1880 auto It = BB->begin();
1881 sandboxir::Instruction *Add0 = &*It++;
1882 sandboxir::Instruction *Add1 = &*It++;
1883 sandboxir::IRSnapshotChecker Checker(Ctx);
1884 Checker.save();
1885 Add1->setOperand(1, Add0);
1886 EXPECT_DEATH(Checker.expectNoDiff(), "Found IR difference");
1889 TEST_F(TrackerTest, IRSnapshotCheckerSaveMultipleTimes) {
1890 parseIR(C, R"IR(
1891 define i32 @foo(i32 %arg) {
1892 %add0 = add i32 %arg, %arg
1893 %add1 = add i32 %add0, %arg
1894 ret i32 %add1
1896 )IR");
1897 Function &LLVMF = *M->getFunction("foo");
1898 sandboxir::Context Ctx(C);
1900 auto *F = Ctx.createFunction(&LLVMF);
1901 auto *BB = &*F->begin();
1902 auto It = BB->begin();
1903 sandboxir::Instruction *Add0 = &*It++;
1904 sandboxir::Instruction *Add1 = &*It++;
1905 sandboxir::IRSnapshotChecker Checker(Ctx);
1906 Checker.save();
1907 Add1->setOperand(1, Add0);
1908 // Now IR differs from the last snapshot. Let's take a new snapshot.
1909 Checker.save();
1910 // The new snapshot should have replaced the old one, so this should succeed.
1911 Checker.expectNoDiff();
1914 #endif // NDEBUG