xref: /llvm-project/llvm/unittests/SandboxIR/TrackerTest.cpp (revision 3b8606be547acbc7ae93d943645e6d6c83f66983)
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 //===----------------------------------------------------------------------===//
8 
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"
19 
20 using namespace llvm;
21 
22 struct TrackerTest : public testing::Test {
23   LLVMContext C;
24   std::unique_ptr<Module> M;
25 
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());
31   }
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!");
37   }
38 };
39 
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
48 }
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);
67 
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);
72 }
73 
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
80 }
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++;
93 
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);
100 }
101 
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
111 }
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++);
126 
127   unsigned SuccIdx = 0;
128   SmallVector<sandboxir::BasicBlock *> ExpectedSuccs({BB2, BB1});
129   for (auto *Succ : Br->successors())
130     EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]);
131 
132   // This calls User::swapOperandsInternal() internally.
133   Br->swapSuccessors();
134 
135   SuccIdx = 0;
136   for (auto *Succ : reverse(Br->successors()))
137     EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]);
138 
139   Ctx.getTracker().revert();
140   SuccIdx = 0;
141   for (auto *Succ : Br->successors())
142     EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]);
143 }
144 
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
153 }
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);
170 
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);
178 
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);
188 
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);
198 
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);
207 
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);
214 
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);
221 }
222 
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
230 }
231 )IR");
232   Function &LLVMF = *M->getFunction("foo");
233   sandboxir::Context Ctx(C);
234 
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++;
241 
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);
250 
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);
259 
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());
273 }
274 
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
282 }
283 )IR");
284   Function &LLVMF = *M->getFunction("foo");
285   sandboxir::Context Ctx(C);
286 
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++;
294 
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);
306 
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);
315 
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());
330 }
331 
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
339 }
340 )IR");
341   Function &LLVMF = *M->getFunction("foo");
342   sandboxir::Context Ctx(C);
343 
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++;
350 
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());
366 
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());
381 
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());
397 
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());
413 
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());
429 
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());
445 }
446 
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
453 }
454 )IR");
455   Function &LLVMF = *M->getFunction("foo");
456   sandboxir::Context Ctx(C);
457 
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();
465 
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());
478 
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());
491 
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());
504 
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);
508 }
509 
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
516 }
517 )IR");
518   Function &LLVMF = *M->getFunction("foo");
519   sandboxir::Context Ctx(C);
520 
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++;
527 
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());
544 }
545 
546 TEST_F(TrackerTest, FenceInstSetters) {
547   parseIR(C, R"IR(
548 define void @foo() {
549   fence syncscope("singlethread") seq_cst
550   ret void
551 }
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++);
559 
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);
578 }
579 
580 TEST_F(TrackerTest, CallBaseSetters) {
581   parseIR(C, R"IR(
582 declare void @bar1(i8)
583 declare void @bar2(i8)
584 
585 define void @foo(i8 %arg0, i8 %arg1) {
586   call void @bar1(i8 %arg0)
587   ret void
588 }
589 )IR");
590   Function &LLVMF = *M->getFunction("foo");
591   sandboxir::Context Ctx(C);
592 
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++);
601 
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);
608 
609   auto *Bar1F = Call->getCalledFunction();
610   auto *Bar2F = Ctx.createFunction(M->getFunction("bar2"));
611 
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);
618 
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);
625 }
626 
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
639 }
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++);
654 
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);
661 
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);
668 
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);
675 
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);
681 }
682 
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
696 }
697 )IR");
698   Function &LLVMF = *M->getFunction("foo");
699 
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());
712 
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);
749 }
750 
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
761 bb:
762   ret void
763 }
764 )IR");
765   Function &LLVMF = *M->getFunction("foo");
766   auto *LLVMUnwind = getBasicBlockByName(LLVMF, "unwind");
767 
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++);
774 
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);
784 }
785 
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
799 }
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++);
805 
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());
815 
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);
834 }
835 
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
850 }
851 )IR");
852   Function &LLVMF = *M->getFunction("foo");
853   BasicBlock *LLVMCleanup = getBasicBlockByName(LLVMF, "cleanup");
854 
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());
866 
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);
885 }
886 
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
899 }
900 )IR");
901   Function &LLVMF = *M->getFunction("foo");
902   auto *LLVMEntry = getBasicBlockByName(LLVMF, "entry");
903 
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());
913 
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);
966 }
967 
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
983 }
984 )IR");
985   Function &LLVMF = *M->getFunction("foo");
986   auto *LLVMEntry = getBasicBlockByName(LLVMF, "entry");
987 
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());
998 
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);
1003 
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);
1018 
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);
1032 
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);
1048 }
1049 
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
1055 }
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++);
1065 
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);
1074 }
1075 
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
1081 }
1082 )IR");
1083   Function &LLVMF = *M->getFunction("foo");
1084   sandboxir::Context Ctx(C);
1085 
1086   auto *F = Ctx.createFunction(&LLVMF);
1087   auto *BB = &*F->begin();
1088   auto It = BB->begin();
1089   auto *SVI = cast<sandboxir::ShuffleVectorInst>(&*It++);
1090 
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));
1098 
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));
1111 }
1112 
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
1118 }
1119 )IR");
1120   Function &LLVMF = *M->getFunction("foo");
1121   sandboxir::Context Ctx(C);
1122 
1123   auto &F = *Ctx.createFunction(&LLVMF);
1124   auto *BB = &*F.begin();
1125   auto It = BB->begin();
1126   auto *PDI = cast<sandboxir::PossiblyDisjointInst>(&*It++);
1127 
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);
1137 }
1138 
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
1144 }
1145 )IR");
1146   Function &LLVMF = *M->getFunction("foo");
1147   sandboxir::Context Ctx(C);
1148 
1149   auto &F = *Ctx.createFunction(&LLVMF);
1150   auto *BB = &*F.begin();
1151   auto It = BB->begin();
1152   auto *PNNI = cast<sandboxir::PossiblyNonNegInst>(&*It++);
1153 
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);
1163 }
1164 
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
1170 }
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++);
1178 
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);
1188 
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);
1198 
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);
1208 
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);
1218 }
1219 
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
1225 }
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++);
1233 
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);
1243 
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);
1253 
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);
1263 
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);
1273 
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);
1283 
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);
1293 }
1294 
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
1300 }
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++);
1308 
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);
1318 
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);
1328 
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);
1338 }
1339 
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
1352 }
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);
1370 
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);
1378 }
1379 
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
1391 bb:
1392   ret void
1393 }
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());
1406 
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);
1418 
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);
1428   }
1429 }
1430 
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
1436 
1437 bb1:
1438   %phi = phi i8 [ %arg0, %bb0 ], [ %arg1, %bb1 ]
1439   br label %bb1
1440 
1441 bb2:
1442   ret void
1443 }
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());
1459 
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);
1472 
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);
1485 
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);
1499 
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);
1512 
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);
1525 
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);
1549 
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);
1562 }
1563 
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);
1572 
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);
1584 }
1585 
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
1592 
1593   ret void
1594 }
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);
1605 }
1606 
1607 TEST_F(TrackerTest, GlobalValueSetters) {
1608   parseIR(C, R"IR(
1609 define void @foo() {
1610   call void @foo()
1611   ret void
1612 }
1613 )IR");
1614   Function &LLVMF = *M->getFunction("foo");
1615   sandboxir::Context Ctx(C);
1616 
1617   auto &F = *Ctx.createFunction(&LLVMF);
1618   auto *BB = &*F.begin();
1619   auto *Call = cast<sandboxir::CallInst>(&*BB->begin());
1620 
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);
1631 
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);
1642 }
1643 
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
1652 }
1653 )IR");
1654   Function &LLVMF = *M->getFunction("foo");
1655   sandboxir::Context Ctx(C);
1656 
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);
1674 }
1675 
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
1684 }
1685 )IR");
1686   Function &LLVMF = *M->getFunction("foo");
1687   sandboxir::Context Ctx(C);
1688 
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);
1722 }
1723 
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
1732 }
1733 )IR");
1734   Function &LLVMF = *M->getFunction("foo");
1735   sandboxir::Context Ctx(C);
1736 
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);
1753 }
1754 
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
1761 }
1762 )IR");
1763   Function &LLVMF = *M->getFunction("foo");
1764   sandboxir::Context Ctx(C);
1765 
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++);
1771 
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());
1778 
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());
1785 }
1786 
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
1794 }
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++;
1804 
1805 #define CHECK_FLAG(I, GETTER, SETTER)                                          \
1806   {                                                                            \
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);                                          \
1814   }
1815 
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);
1827 
1828   // Check setFastMathFlags().
1829   FastMathFlags OrigFMF = FAdd->getFastMathFlags();
1830   FastMathFlags NewFMF;
1831   NewFMF.setAllowReassoc(true);
1832   EXPECT_TRUE(NewFMF != OrigFMF);
1833 
1834   Ctx.save();
1835   FAdd->setFastMathFlags(NewFMF);
1836   EXPECT_FALSE(FAdd->getFastMathFlags() != NewFMF);
1837   Ctx.revert();
1838   EXPECT_FALSE(FAdd->getFastMathFlags() != OrigFMF);
1839 
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);
1846 }
1847 
1848 // IRSnapshotChecker is only defined in debug mode.
1849 #ifndef NDEBUG
1850 
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
1856 }
1857 )IR");
1858   Function &LLVMF = *M->getFunction("foo");
1859   sandboxir::Context Ctx(C);
1860 
1861   [[maybe_unused]] auto *F = Ctx.createFunction(&LLVMF);
1862   sandboxir::IRSnapshotChecker Checker(Ctx);
1863   Checker.save();
1864   Checker.expectNoDiff();
1865 }
1866 
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
1873 }
1874 )IR");
1875   Function &LLVMF = *M->getFunction("foo");
1876   sandboxir::Context Ctx(C);
1877 
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");
1887 }
1888 
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
1895 }
1896 )IR");
1897   Function &LLVMF = *M->getFunction("foo");
1898   sandboxir::Context Ctx(C);
1899 
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();
1912 }
1913 
1914 #endif // NDEBUG
1915