15338bd3cSvporpo //===- TrackerTest.cpp ----------------------------------------------------===// 25338bd3cSvporpo // 35338bd3cSvporpo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45338bd3cSvporpo // See https://llvm.org/LICENSE.txt for license information. 55338bd3cSvporpo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65338bd3cSvporpo // 75338bd3cSvporpo //===----------------------------------------------------------------------===// 85338bd3cSvporpo 95338bd3cSvporpo #include "llvm/AsmParser/Parser.h" 105338bd3cSvporpo #include "llvm/IR/BasicBlock.h" 115338bd3cSvporpo #include "llvm/IR/Function.h" 125338bd3cSvporpo #include "llvm/IR/Instruction.h" 135338bd3cSvporpo #include "llvm/IR/Module.h" 14e22b07e7Svporpo #include "llvm/SandboxIR/Function.h" 15eba106d4Svporpo #include "llvm/SandboxIR/Instruction.h" 165338bd3cSvporpo #include "llvm/Support/SourceMgr.h" 17b5ba7265SJorge Gorbe Moya #include "gmock/gmock-matchers.h" 185338bd3cSvporpo #include "gtest/gtest.h" 195338bd3cSvporpo 205338bd3cSvporpo using namespace llvm; 215338bd3cSvporpo 225338bd3cSvporpo struct TrackerTest : public testing::Test { 235338bd3cSvporpo LLVMContext C; 245338bd3cSvporpo std::unique_ptr<Module> M; 255338bd3cSvporpo 265338bd3cSvporpo void parseIR(LLVMContext &C, const char *IR) { 275338bd3cSvporpo SMDiagnostic Err; 285338bd3cSvporpo M = parseAssemblyString(IR, Err, C); 295338bd3cSvporpo if (!M) 305338bd3cSvporpo Err.print("TrackerTest", errs()); 315338bd3cSvporpo } 325338bd3cSvporpo BasicBlock *getBasicBlockByName(Function &F, StringRef Name) { 335338bd3cSvporpo for (BasicBlock &BB : F) 345338bd3cSvporpo if (BB.getName() == Name) 355338bd3cSvporpo return &BB; 365338bd3cSvporpo llvm_unreachable("Expected to find basic block!"); 375338bd3cSvporpo } 385338bd3cSvporpo }; 395338bd3cSvporpo 405338bd3cSvporpo TEST_F(TrackerTest, SetOperand) { 415338bd3cSvporpo parseIR(C, R"IR( 425338bd3cSvporpo define void @foo(ptr %ptr) { 435338bd3cSvporpo %gep0 = getelementptr float, ptr %ptr, i32 0 445338bd3cSvporpo %gep1 = getelementptr float, ptr %ptr, i32 1 455338bd3cSvporpo %ld0 = load float, ptr %gep0 465338bd3cSvporpo store float undef, ptr %gep0 475338bd3cSvporpo ret void 485338bd3cSvporpo } 495338bd3cSvporpo )IR"); 505338bd3cSvporpo Function &LLVMF = *M->getFunction("foo"); 515338bd3cSvporpo sandboxir::Context Ctx(C); 525338bd3cSvporpo auto *F = Ctx.createFunction(&LLVMF); 535338bd3cSvporpo auto *BB = &*F->begin(); 545338bd3cSvporpo auto &Tracker = Ctx.getTracker(); 555338bd3cSvporpo Tracker.save(); 565338bd3cSvporpo auto It = BB->begin(); 575338bd3cSvporpo auto *Gep0 = &*It++; 585338bd3cSvporpo auto *Gep1 = &*It++; 595338bd3cSvporpo auto *Ld = &*It++; 605338bd3cSvporpo auto *St = &*It++; 615338bd3cSvporpo St->setOperand(0, Ld); 625338bd3cSvporpo St->setOperand(1, Gep1); 635338bd3cSvporpo Ld->setOperand(0, Gep1); 645338bd3cSvporpo EXPECT_EQ(St->getOperand(0), Ld); 655338bd3cSvporpo EXPECT_EQ(St->getOperand(1), Gep1); 665338bd3cSvporpo EXPECT_EQ(Ld->getOperand(0), Gep1); 675338bd3cSvporpo 685338bd3cSvporpo Ctx.getTracker().revert(); 695338bd3cSvporpo EXPECT_NE(St->getOperand(0), Ld); 705338bd3cSvporpo EXPECT_EQ(St->getOperand(1), Gep0); 715338bd3cSvporpo EXPECT_EQ(Ld->getOperand(0), Gep0); 725338bd3cSvporpo } 735338bd3cSvporpo 74372a6beaSvporpo TEST_F(TrackerTest, SetUse) { 75372a6beaSvporpo parseIR(C, R"IR( 76372a6beaSvporpo define void @foo(ptr %ptr, i8 %arg) { 77372a6beaSvporpo %ld = load i8, ptr %ptr 78372a6beaSvporpo %add = add i8 %ld, %arg 79372a6beaSvporpo ret void 80372a6beaSvporpo } 81372a6beaSvporpo )IR"); 82372a6beaSvporpo Function &LLVMF = *M->getFunction("foo"); 83372a6beaSvporpo sandboxir::Context Ctx(C); 84372a6beaSvporpo auto *F = Ctx.createFunction(&LLVMF); 85372a6beaSvporpo unsigned ArgIdx = 0; 86372a6beaSvporpo auto *Arg0 = F->getArg(ArgIdx++); 87372a6beaSvporpo auto *BB = &*F->begin(); 88372a6beaSvporpo auto &Tracker = Ctx.getTracker(); 89372a6beaSvporpo Tracker.save(); 90372a6beaSvporpo auto It = BB->begin(); 91372a6beaSvporpo auto *Ld = &*It++; 92372a6beaSvporpo auto *Add = &*It++; 93372a6beaSvporpo 94372a6beaSvporpo Ctx.save(); 95372a6beaSvporpo sandboxir::Use Use = Add->getOperandUse(0); 96372a6beaSvporpo Use.set(Arg0); 97372a6beaSvporpo EXPECT_EQ(Add->getOperand(0), Arg0); 98372a6beaSvporpo Ctx.revert(); 99372a6beaSvporpo EXPECT_EQ(Add->getOperand(0), Ld); 100372a6beaSvporpo } 101372a6beaSvporpo 102c444548bSVasileios Porpodas TEST_F(TrackerTest, SwapOperands) { 103c444548bSVasileios Porpodas parseIR(C, R"IR( 104c444548bSVasileios Porpodas define void @foo(i1 %cond) { 105c444548bSVasileios Porpodas bb0: 106c444548bSVasileios Porpodas br i1 %cond, label %bb1, label %bb2 107c444548bSVasileios Porpodas bb1: 108c444548bSVasileios Porpodas ret void 109c444548bSVasileios Porpodas bb2: 110c444548bSVasileios Porpodas ret void 111c444548bSVasileios Porpodas } 112c444548bSVasileios Porpodas )IR"); 113c444548bSVasileios Porpodas Function &LLVMF = *M->getFunction("foo"); 114c444548bSVasileios Porpodas sandboxir::Context Ctx(C); 115c444548bSVasileios Porpodas Ctx.createFunction(&LLVMF); 116c444548bSVasileios Porpodas auto *BB0 = cast<sandboxir::BasicBlock>( 117c444548bSVasileios Porpodas Ctx.getValue(getBasicBlockByName(LLVMF, "bb0"))); 118c444548bSVasileios Porpodas auto *BB1 = cast<sandboxir::BasicBlock>( 119c444548bSVasileios Porpodas Ctx.getValue(getBasicBlockByName(LLVMF, "bb1"))); 120c444548bSVasileios Porpodas auto *BB2 = cast<sandboxir::BasicBlock>( 121c444548bSVasileios Porpodas Ctx.getValue(getBasicBlockByName(LLVMF, "bb2"))); 122c444548bSVasileios Porpodas auto &Tracker = Ctx.getTracker(); 123c444548bSVasileios Porpodas Tracker.save(); 124c444548bSVasileios Porpodas auto It = BB0->begin(); 125c444548bSVasileios Porpodas auto *Br = cast<sandboxir::BranchInst>(&*It++); 126c444548bSVasileios Porpodas 127c444548bSVasileios Porpodas unsigned SuccIdx = 0; 128c444548bSVasileios Porpodas SmallVector<sandboxir::BasicBlock *> ExpectedSuccs({BB2, BB1}); 129c444548bSVasileios Porpodas for (auto *Succ : Br->successors()) 130c444548bSVasileios Porpodas EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]); 131c444548bSVasileios Porpodas 132c444548bSVasileios Porpodas // This calls User::swapOperandsInternal() internally. 133c444548bSVasileios Porpodas Br->swapSuccessors(); 134c444548bSVasileios Porpodas 135c444548bSVasileios Porpodas SuccIdx = 0; 136c444548bSVasileios Porpodas for (auto *Succ : reverse(Br->successors())) 137c444548bSVasileios Porpodas EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]); 138c444548bSVasileios Porpodas 139c444548bSVasileios Porpodas Ctx.getTracker().revert(); 140c444548bSVasileios Porpodas SuccIdx = 0; 141c444548bSVasileios Porpodas for (auto *Succ : Br->successors()) 142c444548bSVasileios Porpodas EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]); 143c444548bSVasileios Porpodas } 144c444548bSVasileios Porpodas 1455338bd3cSvporpo TEST_F(TrackerTest, RUWIf_RAUW_RUOW) { 1465338bd3cSvporpo parseIR(C, R"IR( 1475338bd3cSvporpo define void @foo(ptr %ptr) { 1485338bd3cSvporpo %ld0 = load float, ptr %ptr 1495338bd3cSvporpo %ld1 = load float, ptr %ptr 1505338bd3cSvporpo store float %ld0, ptr %ptr 1515338bd3cSvporpo store float %ld0, ptr %ptr 1525338bd3cSvporpo ret void 1535338bd3cSvporpo } 1545338bd3cSvporpo )IR"); 1555338bd3cSvporpo llvm::Function &LLVMF = *M->getFunction("foo"); 1565338bd3cSvporpo sandboxir::Context Ctx(C); 1575338bd3cSvporpo llvm::BasicBlock *LLVMBB = &*LLVMF.begin(); 1585338bd3cSvporpo Ctx.createFunction(&LLVMF); 1595338bd3cSvporpo auto *BB = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMBB)); 1605338bd3cSvporpo auto It = BB->begin(); 1615338bd3cSvporpo sandboxir::Instruction *Ld0 = &*It++; 1625338bd3cSvporpo sandboxir::Instruction *Ld1 = &*It++; 1635338bd3cSvporpo sandboxir::Instruction *St0 = &*It++; 1645338bd3cSvporpo sandboxir::Instruction *St1 = &*It++; 1655338bd3cSvporpo Ctx.save(); 1665338bd3cSvporpo // Check RUWIf when the lambda returns false. 1675338bd3cSvporpo Ld0->replaceUsesWithIf(Ld1, [](const sandboxir::Use &Use) { return false; }); 1685338bd3cSvporpo EXPECT_EQ(St0->getOperand(0), Ld0); 1695338bd3cSvporpo EXPECT_EQ(St1->getOperand(0), Ld0); 1705338bd3cSvporpo 1715338bd3cSvporpo // Check RUWIf when the lambda returns true. 1725338bd3cSvporpo Ld0->replaceUsesWithIf(Ld1, [](const sandboxir::Use &Use) { return true; }); 1735338bd3cSvporpo EXPECT_EQ(St0->getOperand(0), Ld1); 1745338bd3cSvporpo EXPECT_EQ(St1->getOperand(0), Ld1); 1755338bd3cSvporpo Ctx.revert(); 1765338bd3cSvporpo EXPECT_EQ(St0->getOperand(0), Ld0); 1775338bd3cSvporpo EXPECT_EQ(St1->getOperand(0), Ld0); 1785338bd3cSvporpo 1795338bd3cSvporpo // Check RUWIf user == St0. 1805338bd3cSvporpo Ctx.save(); 1815338bd3cSvporpo Ld0->replaceUsesWithIf( 1825338bd3cSvporpo Ld1, [St0](const sandboxir::Use &Use) { return Use.getUser() == St0; }); 1835338bd3cSvporpo EXPECT_EQ(St0->getOperand(0), Ld1); 1845338bd3cSvporpo EXPECT_EQ(St1->getOperand(0), Ld0); 1855338bd3cSvporpo Ctx.revert(); 1865338bd3cSvporpo EXPECT_EQ(St0->getOperand(0), Ld0); 1875338bd3cSvporpo EXPECT_EQ(St1->getOperand(0), Ld0); 1885338bd3cSvporpo 1895338bd3cSvporpo // Check RUWIf user == St1. 1905338bd3cSvporpo Ctx.save(); 1915338bd3cSvporpo Ld0->replaceUsesWithIf( 1925338bd3cSvporpo Ld1, [St1](const sandboxir::Use &Use) { return Use.getUser() == St1; }); 1935338bd3cSvporpo EXPECT_EQ(St0->getOperand(0), Ld0); 1945338bd3cSvporpo EXPECT_EQ(St1->getOperand(0), Ld1); 1955338bd3cSvporpo Ctx.revert(); 1965338bd3cSvporpo EXPECT_EQ(St0->getOperand(0), Ld0); 1975338bd3cSvporpo EXPECT_EQ(St1->getOperand(0), Ld0); 1985338bd3cSvporpo 1995338bd3cSvporpo // Check RAUW. 2005338bd3cSvporpo Ctx.save(); 2015338bd3cSvporpo Ld1->replaceAllUsesWith(Ld0); 2025338bd3cSvporpo EXPECT_EQ(St0->getOperand(0), Ld0); 2035338bd3cSvporpo EXPECT_EQ(St1->getOperand(0), Ld0); 2045338bd3cSvporpo Ctx.revert(); 2055338bd3cSvporpo EXPECT_EQ(St0->getOperand(0), Ld0); 2065338bd3cSvporpo EXPECT_EQ(St1->getOperand(0), Ld0); 2075338bd3cSvporpo 2085338bd3cSvporpo // Check RUOW. 2095338bd3cSvporpo Ctx.save(); 2105338bd3cSvporpo St0->replaceUsesOfWith(Ld0, Ld1); 2115338bd3cSvporpo EXPECT_EQ(St0->getOperand(0), Ld1); 2125338bd3cSvporpo Ctx.revert(); 2135338bd3cSvporpo EXPECT_EQ(St0->getOperand(0), Ld0); 2145338bd3cSvporpo 2155338bd3cSvporpo // Check accept(). 2165338bd3cSvporpo Ctx.save(); 2175338bd3cSvporpo St0->replaceUsesOfWith(Ld0, Ld1); 2185338bd3cSvporpo EXPECT_EQ(St0->getOperand(0), Ld1); 2195338bd3cSvporpo Ctx.accept(); 2205338bd3cSvporpo EXPECT_EQ(St0->getOperand(0), Ld1); 2215338bd3cSvporpo } 222c5432d31Svporpo 223c5432d31Svporpo // TODO: Test multi-instruction patterns. 224c5432d31Svporpo TEST_F(TrackerTest, EraseFromParent) { 225c5432d31Svporpo parseIR(C, R"IR( 226c5432d31Svporpo define void @foo(i32 %v1) { 227c5432d31Svporpo %add0 = add i32 %v1, %v1 228c5432d31Svporpo %add1 = add i32 %add0, %v1 229c5432d31Svporpo ret void 230c5432d31Svporpo } 231c5432d31Svporpo )IR"); 232c5432d31Svporpo Function &LLVMF = *M->getFunction("foo"); 233c5432d31Svporpo sandboxir::Context Ctx(C); 234c5432d31Svporpo 235c5432d31Svporpo auto *F = Ctx.createFunction(&LLVMF); 236c5432d31Svporpo auto *BB = &*F->begin(); 237c5432d31Svporpo auto It = BB->begin(); 238c5432d31Svporpo sandboxir::Instruction *Add0 = &*It++; 239c5432d31Svporpo sandboxir::Instruction *Add1 = &*It++; 240c5432d31Svporpo sandboxir::Instruction *Ret = &*It++; 241c5432d31Svporpo 242c5432d31Svporpo Ctx.save(); 243c5432d31Svporpo // Check erase. 244c5432d31Svporpo Add1->eraseFromParent(); 245c5432d31Svporpo It = BB->begin(); 246c5432d31Svporpo EXPECT_EQ(&*It++, Add0); 247c5432d31Svporpo EXPECT_EQ(&*It++, Ret); 248c5432d31Svporpo EXPECT_EQ(It, BB->end()); 249c5432d31Svporpo EXPECT_EQ(Add0->getNumUses(), 0u); 250c5432d31Svporpo 251c5432d31Svporpo // Check revert(). 252c5432d31Svporpo Ctx.revert(); 253c5432d31Svporpo It = BB->begin(); 254c5432d31Svporpo EXPECT_EQ(&*It++, Add0); 255c5432d31Svporpo EXPECT_EQ(&*It++, Add1); 256c5432d31Svporpo EXPECT_EQ(&*It++, Ret); 257c5432d31Svporpo EXPECT_EQ(It, BB->end()); 258c5432d31Svporpo EXPECT_EQ(Add1->getOperand(0), Add0); 259c5432d31Svporpo 260c5432d31Svporpo // Same for the last instruction in the block. 261c5432d31Svporpo Ctx.save(); 262c5432d31Svporpo Ret->eraseFromParent(); 263c5432d31Svporpo It = BB->begin(); 264c5432d31Svporpo EXPECT_EQ(&*It++, Add0); 265c5432d31Svporpo EXPECT_EQ(&*It++, Add1); 266c5432d31Svporpo EXPECT_EQ(It, BB->end()); 267c5432d31Svporpo Ctx.revert(); 268c5432d31Svporpo It = BB->begin(); 269c5432d31Svporpo EXPECT_EQ(&*It++, Add0); 270c5432d31Svporpo EXPECT_EQ(&*It++, Add1); 271c5432d31Svporpo EXPECT_EQ(&*It++, Ret); 272c5432d31Svporpo EXPECT_EQ(It, BB->end()); 273c5432d31Svporpo } 2744f786c68Svporpo 2754f786c68Svporpo // TODO: Test multi-instruction patterns. 2764f786c68Svporpo TEST_F(TrackerTest, RemoveFromParent) { 2774f786c68Svporpo parseIR(C, R"IR( 2784f786c68Svporpo define i32 @foo(i32 %arg) { 2794f786c68Svporpo %add0 = add i32 %arg, %arg 2804f786c68Svporpo %add1 = add i32 %add0, %arg 2814f786c68Svporpo ret i32 %add1 2824f786c68Svporpo } 2834f786c68Svporpo )IR"); 2844f786c68Svporpo Function &LLVMF = *M->getFunction("foo"); 2854f786c68Svporpo sandboxir::Context Ctx(C); 2864f786c68Svporpo 2874f786c68Svporpo auto *F = Ctx.createFunction(&LLVMF); 2884f786c68Svporpo auto *Arg = F->getArg(0); 2894f786c68Svporpo auto *BB = &*F->begin(); 2904f786c68Svporpo auto It = BB->begin(); 2914f786c68Svporpo sandboxir::Instruction *Add0 = &*It++; 2924f786c68Svporpo sandboxir::Instruction *Add1 = &*It++; 2934f786c68Svporpo sandboxir::Instruction *Ret = &*It++; 2944f786c68Svporpo 2954f786c68Svporpo Ctx.save(); 2964f786c68Svporpo // Check removeFromParent(). 2974f786c68Svporpo Add1->removeFromParent(); 2984f786c68Svporpo It = BB->begin(); 2994f786c68Svporpo EXPECT_EQ(&*It++, Add0); 3004f786c68Svporpo EXPECT_EQ(&*It++, Ret); 3014f786c68Svporpo EXPECT_EQ(It, BB->end()); 3024f786c68Svporpo // Removed instruction still be connected to operands and users. 3034f786c68Svporpo EXPECT_EQ(Add1->getOperand(0), Add0); 3044f786c68Svporpo EXPECT_EQ(Add1->getOperand(1), Arg); 3054f786c68Svporpo EXPECT_EQ(Add0->getNumUses(), 1u); 3064f786c68Svporpo 3074f786c68Svporpo // Check revert(). 3084f786c68Svporpo Ctx.revert(); 3094f786c68Svporpo It = BB->begin(); 3104f786c68Svporpo EXPECT_EQ(&*It++, Add0); 3114f786c68Svporpo EXPECT_EQ(&*It++, Add1); 3124f786c68Svporpo EXPECT_EQ(&*It++, Ret); 3134f786c68Svporpo EXPECT_EQ(It, BB->end()); 3144f786c68Svporpo EXPECT_EQ(Add1->getOperand(0), Add0); 3154f786c68Svporpo 3164f786c68Svporpo // Same for the last instruction in the block. 3174f786c68Svporpo Ctx.save(); 3184f786c68Svporpo Ret->removeFromParent(); 3194f786c68Svporpo It = BB->begin(); 3204f786c68Svporpo EXPECT_EQ(&*It++, Add0); 3214f786c68Svporpo EXPECT_EQ(&*It++, Add1); 3224f786c68Svporpo EXPECT_EQ(It, BB->end()); 3234f786c68Svporpo EXPECT_EQ(Ret->getOperand(0), Add1); 3244f786c68Svporpo Ctx.revert(); 3254f786c68Svporpo It = BB->begin(); 3264f786c68Svporpo EXPECT_EQ(&*It++, Add0); 3274f786c68Svporpo EXPECT_EQ(&*It++, Add1); 3284f786c68Svporpo EXPECT_EQ(&*It++, Ret); 3294f786c68Svporpo EXPECT_EQ(It, BB->end()); 3304f786c68Svporpo } 331cbbd1532Svporpo 332cbbd1532Svporpo // TODO: Test multi-instruction patterns. 333cbbd1532Svporpo TEST_F(TrackerTest, MoveInstr) { 334cbbd1532Svporpo parseIR(C, R"IR( 335cbbd1532Svporpo define i32 @foo(i32 %arg) { 336cbbd1532Svporpo %add0 = add i32 %arg, %arg 337cbbd1532Svporpo %add1 = add i32 %add0, %arg 338cbbd1532Svporpo ret i32 %add1 339cbbd1532Svporpo } 340cbbd1532Svporpo )IR"); 341cbbd1532Svporpo Function &LLVMF = *M->getFunction("foo"); 342cbbd1532Svporpo sandboxir::Context Ctx(C); 343cbbd1532Svporpo 344cbbd1532Svporpo auto *F = Ctx.createFunction(&LLVMF); 345cbbd1532Svporpo auto *BB = &*F->begin(); 346cbbd1532Svporpo auto It = BB->begin(); 347cbbd1532Svporpo sandboxir::Instruction *Add0 = &*It++; 348cbbd1532Svporpo sandboxir::Instruction *Add1 = &*It++; 349cbbd1532Svporpo sandboxir::Instruction *Ret = &*It++; 350cbbd1532Svporpo 351cbbd1532Svporpo // Check moveBefore(Instruction *) with tracking enabled. 352cbbd1532Svporpo Ctx.save(); 353cbbd1532Svporpo Add1->moveBefore(Add0); 354cbbd1532Svporpo It = BB->begin(); 355cbbd1532Svporpo EXPECT_EQ(&*It++, Add1); 356cbbd1532Svporpo EXPECT_EQ(&*It++, Add0); 357cbbd1532Svporpo EXPECT_EQ(&*It++, Ret); 358cbbd1532Svporpo EXPECT_EQ(It, BB->end()); 359cbbd1532Svporpo // Check revert(). 360cbbd1532Svporpo Ctx.revert(); 361cbbd1532Svporpo It = BB->begin(); 362cbbd1532Svporpo EXPECT_EQ(&*It++, Add0); 363cbbd1532Svporpo EXPECT_EQ(&*It++, Add1); 364cbbd1532Svporpo EXPECT_EQ(&*It++, Ret); 365cbbd1532Svporpo EXPECT_EQ(It, BB->end()); 366cbbd1532Svporpo 367cbbd1532Svporpo // Same for the last instruction in the block. 368cbbd1532Svporpo Ctx.save(); 369cbbd1532Svporpo Ret->moveBefore(Add0); 370cbbd1532Svporpo It = BB->begin(); 371cbbd1532Svporpo EXPECT_EQ(&*It++, Ret); 372cbbd1532Svporpo EXPECT_EQ(&*It++, Add0); 373cbbd1532Svporpo EXPECT_EQ(&*It++, Add1); 374cbbd1532Svporpo EXPECT_EQ(It, BB->end()); 375cbbd1532Svporpo Ctx.revert(); 376cbbd1532Svporpo It = BB->begin(); 377cbbd1532Svporpo EXPECT_EQ(&*It++, Add0); 378cbbd1532Svporpo EXPECT_EQ(&*It++, Add1); 379cbbd1532Svporpo EXPECT_EQ(&*It++, Ret); 380cbbd1532Svporpo EXPECT_EQ(It, BB->end()); 381cbbd1532Svporpo 382cbbd1532Svporpo // Check moveBefore(BasicBlock &, BasicBlock::iterator) with tracking enabled. 383cbbd1532Svporpo Ctx.save(); 384cbbd1532Svporpo Add1->moveBefore(*BB, Add0->getIterator()); 385cbbd1532Svporpo It = BB->begin(); 386cbbd1532Svporpo EXPECT_EQ(&*It++, Add1); 387cbbd1532Svporpo EXPECT_EQ(&*It++, Add0); 388cbbd1532Svporpo EXPECT_EQ(&*It++, Ret); 389cbbd1532Svporpo EXPECT_EQ(It, BB->end()); 390cbbd1532Svporpo // Check revert(). 391cbbd1532Svporpo Ctx.revert(); 392cbbd1532Svporpo It = BB->begin(); 393cbbd1532Svporpo EXPECT_EQ(&*It++, Add0); 394cbbd1532Svporpo EXPECT_EQ(&*It++, Add1); 395cbbd1532Svporpo EXPECT_EQ(&*It++, Ret); 396cbbd1532Svporpo EXPECT_EQ(It, BB->end()); 397cbbd1532Svporpo 398cbbd1532Svporpo // Same for the last instruction in the block. 399cbbd1532Svporpo Ctx.save(); 400cbbd1532Svporpo Ret->moveBefore(*BB, Add0->getIterator()); 401cbbd1532Svporpo It = BB->begin(); 402cbbd1532Svporpo EXPECT_EQ(&*It++, Ret); 403cbbd1532Svporpo EXPECT_EQ(&*It++, Add0); 404cbbd1532Svporpo EXPECT_EQ(&*It++, Add1); 405cbbd1532Svporpo EXPECT_EQ(It, BB->end()); 406cbbd1532Svporpo // Check revert(). 407cbbd1532Svporpo Ctx.revert(); 408cbbd1532Svporpo It = BB->begin(); 409cbbd1532Svporpo EXPECT_EQ(&*It++, Add0); 410cbbd1532Svporpo EXPECT_EQ(&*It++, Add1); 411cbbd1532Svporpo EXPECT_EQ(&*It++, Ret); 412cbbd1532Svporpo EXPECT_EQ(It, BB->end()); 413cbbd1532Svporpo 414cbbd1532Svporpo // Check moveAfter(Instruction *) with tracking enabled. 415cbbd1532Svporpo Ctx.save(); 416cbbd1532Svporpo Add0->moveAfter(Add1); 417cbbd1532Svporpo It = BB->begin(); 418cbbd1532Svporpo EXPECT_EQ(&*It++, Add1); 419cbbd1532Svporpo EXPECT_EQ(&*It++, Add0); 420cbbd1532Svporpo EXPECT_EQ(&*It++, Ret); 421cbbd1532Svporpo EXPECT_EQ(It, BB->end()); 422cbbd1532Svporpo // Check revert(). 423cbbd1532Svporpo Ctx.revert(); 424cbbd1532Svporpo It = BB->begin(); 425cbbd1532Svporpo EXPECT_EQ(&*It++, Add0); 426cbbd1532Svporpo EXPECT_EQ(&*It++, Add1); 427cbbd1532Svporpo EXPECT_EQ(&*It++, Ret); 428cbbd1532Svporpo EXPECT_EQ(It, BB->end()); 429cbbd1532Svporpo 430cbbd1532Svporpo // Same for the last instruction in the block. 431cbbd1532Svporpo Ctx.save(); 432cbbd1532Svporpo Ret->moveAfter(Add0); 433cbbd1532Svporpo It = BB->begin(); 434cbbd1532Svporpo EXPECT_EQ(&*It++, Add0); 435cbbd1532Svporpo EXPECT_EQ(&*It++, Ret); 436cbbd1532Svporpo EXPECT_EQ(&*It++, Add1); 437cbbd1532Svporpo EXPECT_EQ(It, BB->end()); 438cbbd1532Svporpo // Check revert(). 439cbbd1532Svporpo Ctx.revert(); 440cbbd1532Svporpo It = BB->begin(); 441cbbd1532Svporpo EXPECT_EQ(&*It++, Add0); 442cbbd1532Svporpo EXPECT_EQ(&*It++, Add1); 443cbbd1532Svporpo EXPECT_EQ(&*It++, Ret); 444cbbd1532Svporpo EXPECT_EQ(It, BB->end()); 445cbbd1532Svporpo } 446372a6beaSvporpo 44785da9611Svporpo // TODO: Test multi-instruction patterns. 44885da9611Svporpo TEST_F(TrackerTest, InsertIntoBB) { 44985da9611Svporpo parseIR(C, R"IR( 45085da9611Svporpo define void @foo(i32 %arg) { 45185da9611Svporpo %add0 = add i32 %arg, %arg 45285da9611Svporpo ret void 45385da9611Svporpo } 45485da9611Svporpo )IR"); 45585da9611Svporpo Function &LLVMF = *M->getFunction("foo"); 45685da9611Svporpo sandboxir::Context Ctx(C); 45785da9611Svporpo 45885da9611Svporpo auto *F = Ctx.createFunction(&LLVMF); 45985da9611Svporpo auto *BB = &*F->begin(); 46085da9611Svporpo auto It = BB->begin(); 46185da9611Svporpo sandboxir::Instruction *Add0 = &*It++; 46285da9611Svporpo sandboxir::Instruction *Ret = &*It++; 46385da9611Svporpo // Detach `Add0` before we save. 46485da9611Svporpo Add0->removeFromParent(); 46585da9611Svporpo 46685da9611Svporpo // Check insertBefore(Instruction *) with tracking enabled. 46785da9611Svporpo Ctx.save(); 46885da9611Svporpo Add0->insertBefore(Ret); 46985da9611Svporpo It = BB->begin(); 47085da9611Svporpo EXPECT_EQ(&*It++, Add0); 47185da9611Svporpo EXPECT_EQ(&*It++, Ret); 47285da9611Svporpo EXPECT_EQ(It, BB->end()); 47385da9611Svporpo // Check revert(). 47485da9611Svporpo Ctx.revert(); 47585da9611Svporpo It = BB->begin(); 47685da9611Svporpo EXPECT_EQ(&*It++, Ret); 47785da9611Svporpo EXPECT_EQ(It, BB->end()); 47885da9611Svporpo 47985da9611Svporpo // Check insertAfter(Instruction *) with tracking enabled. 48085da9611Svporpo Ctx.save(); 48185da9611Svporpo Add0->insertAfter(Ret); 48285da9611Svporpo It = BB->begin(); 48385da9611Svporpo EXPECT_EQ(&*It++, Ret); 48485da9611Svporpo EXPECT_EQ(&*It++, Add0); 48585da9611Svporpo EXPECT_EQ(It, BB->end()); 48685da9611Svporpo // Check revert(). 48785da9611Svporpo Ctx.revert(); 48885da9611Svporpo It = BB->begin(); 48985da9611Svporpo EXPECT_EQ(&*It++, Ret); 49085da9611Svporpo EXPECT_EQ(It, BB->end()); 49185da9611Svporpo 49285da9611Svporpo // Check insertInto(BasicBlock *, BasicBlock::iterator) with tracking enabled. 49385da9611Svporpo Ctx.save(); 49485da9611Svporpo Add0->insertInto(BB, Ret->getIterator()); 49585da9611Svporpo It = BB->begin(); 49685da9611Svporpo EXPECT_EQ(&*It++, Add0); 49785da9611Svporpo EXPECT_EQ(&*It++, Ret); 49885da9611Svporpo EXPECT_EQ(It, BB->end()); 49985da9611Svporpo // Check revert(). 50085da9611Svporpo Ctx.revert(); 50185da9611Svporpo It = BB->begin(); 50285da9611Svporpo EXPECT_EQ(&*It++, Ret); 50385da9611Svporpo EXPECT_EQ(It, BB->end()); 50485da9611Svporpo 50585da9611Svporpo // To make sure we don't leak memory insert `Add0` back into the BB before the 50685da9611Svporpo // end of the test. 50785da9611Svporpo Add0->insertBefore(Ret); 50885da9611Svporpo } 50985da9611Svporpo 5100959e58fSvporpo // TODO: Test multi-instruction patterns. 5110959e58fSvporpo TEST_F(TrackerTest, CreateAndInsertInst) { 5120959e58fSvporpo parseIR(C, R"IR( 5130959e58fSvporpo define void @foo(ptr %ptr) { 5140959e58fSvporpo %ld = load i8, ptr %ptr, align 64 5150959e58fSvporpo ret void 5160959e58fSvporpo } 5170959e58fSvporpo )IR"); 5180959e58fSvporpo Function &LLVMF = *M->getFunction("foo"); 5190959e58fSvporpo sandboxir::Context Ctx(C); 5200959e58fSvporpo 5210959e58fSvporpo auto *F = Ctx.createFunction(&LLVMF); 5220959e58fSvporpo auto *Ptr = F->getArg(0); 5230959e58fSvporpo auto *BB = &*F->begin(); 5240959e58fSvporpo auto It = BB->begin(); 5250959e58fSvporpo auto *Ld = cast<sandboxir::LoadInst>(&*It++); 5260959e58fSvporpo auto *Ret = &*It++; 5270959e58fSvporpo 5280959e58fSvporpo Ctx.save(); 5290959e58fSvporpo // Check create(InsertBefore) with tracking enabled. 530e1434a87Svporpo sandboxir::LoadInst *NewLd = sandboxir::LoadInst::create( 531e1434a87Svporpo Ld->getType(), Ptr, Align(8), 532e1434a87Svporpo /*InsertBefore=*/Ld->getIterator(), Ctx, "NewLd"); 5330959e58fSvporpo It = BB->begin(); 5340959e58fSvporpo EXPECT_EQ(&*It++, NewLd); 5350959e58fSvporpo EXPECT_EQ(&*It++, Ld); 5360959e58fSvporpo EXPECT_EQ(&*It++, Ret); 5370959e58fSvporpo EXPECT_EQ(It, BB->end()); 5380959e58fSvporpo // Check revert(). 5390959e58fSvporpo Ctx.revert(); 5400959e58fSvporpo It = BB->begin(); 5410959e58fSvporpo EXPECT_EQ(&*It++, Ld); 5420959e58fSvporpo EXPECT_EQ(&*It++, Ret); 5430959e58fSvporpo EXPECT_EQ(It, BB->end()); 5440959e58fSvporpo } 5450959e58fSvporpo 546d88876e7Svporpo TEST_F(TrackerTest, FenceInstSetters) { 547d88876e7Svporpo parseIR(C, R"IR( 548d88876e7Svporpo define void @foo() { 549d88876e7Svporpo fence syncscope("singlethread") seq_cst 550d88876e7Svporpo ret void 551d88876e7Svporpo } 552d88876e7Svporpo )IR"); 553d88876e7Svporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 554d88876e7Svporpo sandboxir::Context Ctx(C); 555d88876e7Svporpo sandboxir::Function *F = Ctx.createFunction(LLVMF); 556d88876e7Svporpo auto *BB = &*F->begin(); 557d88876e7Svporpo auto It = BB->begin(); 558d88876e7Svporpo auto *Fence = cast<sandboxir::FenceInst>(&*It++); 559d88876e7Svporpo 560d88876e7Svporpo // Check setOrdering(). 561d88876e7Svporpo auto OrigOrdering = Fence->getOrdering(); 562d88876e7Svporpo auto NewOrdering = AtomicOrdering::Release; 563d88876e7Svporpo EXPECT_NE(NewOrdering, OrigOrdering); 564d88876e7Svporpo Ctx.save(); 565d88876e7Svporpo Fence->setOrdering(NewOrdering); 566d88876e7Svporpo EXPECT_EQ(Fence->getOrdering(), NewOrdering); 567d88876e7Svporpo Ctx.revert(); 568d88876e7Svporpo EXPECT_EQ(Fence->getOrdering(), OrigOrdering); 569d88876e7Svporpo // Check setSyncScopeID(). 570d88876e7Svporpo auto OrigSSID = Fence->getSyncScopeID(); 571d88876e7Svporpo auto NewSSID = SyncScope::System; 572d88876e7Svporpo EXPECT_NE(NewSSID, OrigSSID); 573d88876e7Svporpo Ctx.save(); 574d88876e7Svporpo Fence->setSyncScopeID(NewSSID); 575d88876e7Svporpo EXPECT_EQ(Fence->getSyncScopeID(), NewSSID); 576d88876e7Svporpo Ctx.revert(); 577d88876e7Svporpo EXPECT_EQ(Fence->getSyncScopeID(), OrigSSID); 578d88876e7Svporpo } 579d88876e7Svporpo 580372a6beaSvporpo TEST_F(TrackerTest, CallBaseSetters) { 581372a6beaSvporpo parseIR(C, R"IR( 582372a6beaSvporpo declare void @bar1(i8) 583372a6beaSvporpo declare void @bar2(i8) 584372a6beaSvporpo 585372a6beaSvporpo define void @foo(i8 %arg0, i8 %arg1) { 586372a6beaSvporpo call void @bar1(i8 %arg0) 587372a6beaSvporpo ret void 588372a6beaSvporpo } 589372a6beaSvporpo )IR"); 590372a6beaSvporpo Function &LLVMF = *M->getFunction("foo"); 591372a6beaSvporpo sandboxir::Context Ctx(C); 592372a6beaSvporpo 593372a6beaSvporpo auto *F = Ctx.createFunction(&LLVMF); 594372a6beaSvporpo unsigned ArgIdx = 0; 595372a6beaSvporpo auto *Arg0 = F->getArg(ArgIdx++); 596372a6beaSvporpo auto *Arg1 = F->getArg(ArgIdx++); 597372a6beaSvporpo auto *BB = &*F->begin(); 598372a6beaSvporpo auto It = BB->begin(); 599372a6beaSvporpo auto *Call = cast<sandboxir::CallBase>(&*It++); 600372a6beaSvporpo [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 601372a6beaSvporpo 602372a6beaSvporpo // Check setArgOperand(). 603372a6beaSvporpo Ctx.save(); 604372a6beaSvporpo Call->setArgOperand(0, Arg1); 605372a6beaSvporpo EXPECT_EQ(Call->getArgOperand(0), Arg1); 606372a6beaSvporpo Ctx.revert(); 607372a6beaSvporpo EXPECT_EQ(Call->getArgOperand(0), Arg0); 608372a6beaSvporpo 609372a6beaSvporpo auto *Bar1F = Call->getCalledFunction(); 610372a6beaSvporpo auto *Bar2F = Ctx.createFunction(M->getFunction("bar2")); 611372a6beaSvporpo 612372a6beaSvporpo // Check setCalledOperand(). 613372a6beaSvporpo Ctx.save(); 614372a6beaSvporpo Call->setCalledOperand(Bar2F); 615372a6beaSvporpo EXPECT_EQ(Call->getCalledOperand(), Bar2F); 616372a6beaSvporpo Ctx.revert(); 617372a6beaSvporpo EXPECT_EQ(Call->getCalledOperand(), Bar1F); 618372a6beaSvporpo 619372a6beaSvporpo // Check setCalledFunction(). 620372a6beaSvporpo Ctx.save(); 621372a6beaSvporpo Call->setCalledFunction(Bar2F); 622372a6beaSvporpo EXPECT_EQ(Call->getCalledFunction(), Bar2F); 623372a6beaSvporpo Ctx.revert(); 624372a6beaSvporpo EXPECT_EQ(Call->getCalledFunction(), Bar1F); 625372a6beaSvporpo } 626db2aa50eSvporpo 627db2aa50eSvporpo TEST_F(TrackerTest, InvokeSetters) { 628db2aa50eSvporpo parseIR(C, R"IR( 629db2aa50eSvporpo define void @foo(i8 %arg) { 630db2aa50eSvporpo bb0: 631db2aa50eSvporpo invoke i8 @foo(i8 %arg) to label %normal_bb 632db2aa50eSvporpo unwind label %exception_bb 633db2aa50eSvporpo normal_bb: 634db2aa50eSvporpo ret void 635db2aa50eSvporpo exception_bb: 636db2aa50eSvporpo ret void 637db2aa50eSvporpo other_bb: 638db2aa50eSvporpo ret void 639db2aa50eSvporpo } 640db2aa50eSvporpo )IR"); 641db2aa50eSvporpo Function &LLVMF = *M->getFunction("foo"); 642db2aa50eSvporpo sandboxir::Context Ctx(C); 643db2aa50eSvporpo [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); 644db2aa50eSvporpo auto *BB0 = cast<sandboxir::BasicBlock>( 645db2aa50eSvporpo Ctx.getValue(getBasicBlockByName(LLVMF, "bb0"))); 646db2aa50eSvporpo auto *NormalBB = cast<sandboxir::BasicBlock>( 647db2aa50eSvporpo Ctx.getValue(getBasicBlockByName(LLVMF, "normal_bb"))); 648db2aa50eSvporpo auto *ExceptionBB = cast<sandboxir::BasicBlock>( 649db2aa50eSvporpo Ctx.getValue(getBasicBlockByName(LLVMF, "exception_bb"))); 650db2aa50eSvporpo auto *OtherBB = cast<sandboxir::BasicBlock>( 651db2aa50eSvporpo Ctx.getValue(getBasicBlockByName(LLVMF, "other_bb"))); 652db2aa50eSvporpo auto It = BB0->begin(); 653db2aa50eSvporpo auto *Invoke = cast<sandboxir::InvokeInst>(&*It++); 654db2aa50eSvporpo 655db2aa50eSvporpo // Check setNormalDest(). 656db2aa50eSvporpo Ctx.save(); 657db2aa50eSvporpo Invoke->setNormalDest(OtherBB); 658db2aa50eSvporpo EXPECT_EQ(Invoke->getNormalDest(), OtherBB); 659db2aa50eSvporpo Ctx.revert(); 660db2aa50eSvporpo EXPECT_EQ(Invoke->getNormalDest(), NormalBB); 661db2aa50eSvporpo 662db2aa50eSvporpo // Check setUnwindDest(). 663db2aa50eSvporpo Ctx.save(); 664db2aa50eSvporpo Invoke->setUnwindDest(OtherBB); 665db2aa50eSvporpo EXPECT_EQ(Invoke->getUnwindDest(), OtherBB); 666db2aa50eSvporpo Ctx.revert(); 667db2aa50eSvporpo EXPECT_EQ(Invoke->getUnwindDest(), ExceptionBB); 668db2aa50eSvporpo 669db2aa50eSvporpo // Check setSuccessor(). 670db2aa50eSvporpo Ctx.save(); 671db2aa50eSvporpo Invoke->setSuccessor(0, OtherBB); 672db2aa50eSvporpo EXPECT_EQ(Invoke->getSuccessor(0), OtherBB); 673db2aa50eSvporpo Ctx.revert(); 674db2aa50eSvporpo EXPECT_EQ(Invoke->getSuccessor(0), NormalBB); 675db2aa50eSvporpo 676db2aa50eSvporpo Ctx.save(); 677db2aa50eSvporpo Invoke->setSuccessor(1, OtherBB); 678db2aa50eSvporpo EXPECT_EQ(Invoke->getSuccessor(1), OtherBB); 679db2aa50eSvporpo Ctx.revert(); 680db2aa50eSvporpo EXPECT_EQ(Invoke->getSuccessor(1), ExceptionBB); 681db2aa50eSvporpo } 682cfb92be0Svporpo 6836e8c9703Svporpo TEST_F(TrackerTest, CatchSwitchInst) { 6846e8c9703Svporpo parseIR(C, R"IR( 6856e8c9703Svporpo define void @foo(i32 %cond0, i32 %cond1) { 6866e8c9703Svporpo bb0: 6876e8c9703Svporpo %cs0 = catchswitch within none [label %handler0, label %handler1] unwind to caller 6886e8c9703Svporpo bb1: 6896e8c9703Svporpo %cs1 = catchswitch within %cs0 [label %handler0, label %handler1] unwind label %cleanup 6906e8c9703Svporpo handler0: 6916e8c9703Svporpo ret void 6926e8c9703Svporpo handler1: 6936e8c9703Svporpo ret void 6946e8c9703Svporpo cleanup: 6956e8c9703Svporpo ret void 6966e8c9703Svporpo } 6976e8c9703Svporpo )IR"); 6986e8c9703Svporpo Function &LLVMF = *M->getFunction("foo"); 6996e8c9703Svporpo 7006e8c9703Svporpo sandboxir::Context Ctx(C); 7016e8c9703Svporpo [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); 7026e8c9703Svporpo auto *BB0 = cast<sandboxir::BasicBlock>( 7036e8c9703Svporpo Ctx.getValue(getBasicBlockByName(LLVMF, "bb0"))); 7046e8c9703Svporpo auto *BB1 = cast<sandboxir::BasicBlock>( 7056e8c9703Svporpo Ctx.getValue(getBasicBlockByName(LLVMF, "bb1"))); 7066e8c9703Svporpo auto *Handler0 = cast<sandboxir::BasicBlock>( 7076e8c9703Svporpo Ctx.getValue(getBasicBlockByName(LLVMF, "handler0"))); 7086e8c9703Svporpo auto *Handler1 = cast<sandboxir::BasicBlock>( 7096e8c9703Svporpo Ctx.getValue(getBasicBlockByName(LLVMF, "handler1"))); 7106e8c9703Svporpo auto *CS0 = cast<sandboxir::CatchSwitchInst>(&*BB0->begin()); 7116e8c9703Svporpo auto *CS1 = cast<sandboxir::CatchSwitchInst>(&*BB1->begin()); 7126e8c9703Svporpo 7136e8c9703Svporpo // Check setParentPad(). 7146e8c9703Svporpo auto *OrigPad = CS0->getParentPad(); 7156e8c9703Svporpo auto *NewPad = CS1; 7166e8c9703Svporpo EXPECT_NE(NewPad, OrigPad); 7176e8c9703Svporpo Ctx.save(); 7186e8c9703Svporpo CS0->setParentPad(NewPad); 7196e8c9703Svporpo EXPECT_EQ(CS0->getParentPad(), NewPad); 7206e8c9703Svporpo Ctx.revert(); 7216e8c9703Svporpo EXPECT_EQ(CS0->getParentPad(), OrigPad); 7226e8c9703Svporpo // Check setUnwindDest(). 7236e8c9703Svporpo auto *OrigUnwindDest = CS1->getUnwindDest(); 7246e8c9703Svporpo auto *NewUnwindDest = BB0; 7256e8c9703Svporpo EXPECT_NE(NewUnwindDest, OrigUnwindDest); 7266e8c9703Svporpo Ctx.save(); 7276e8c9703Svporpo CS1->setUnwindDest(NewUnwindDest); 7286e8c9703Svporpo EXPECT_EQ(CS1->getUnwindDest(), NewUnwindDest); 7296e8c9703Svporpo Ctx.revert(); 7306e8c9703Svporpo EXPECT_EQ(CS1->getUnwindDest(), OrigUnwindDest); 7316e8c9703Svporpo // Check setSuccessor(). 7326e8c9703Svporpo auto *OrigSuccessor = CS0->getSuccessor(0); 7336e8c9703Svporpo auto *NewSuccessor = BB0; 7346e8c9703Svporpo EXPECT_NE(NewSuccessor, OrigSuccessor); 7356e8c9703Svporpo Ctx.save(); 7366e8c9703Svporpo CS0->setSuccessor(0, NewSuccessor); 7376e8c9703Svporpo EXPECT_EQ(CS0->getSuccessor(0), NewSuccessor); 7386e8c9703Svporpo Ctx.revert(); 7396e8c9703Svporpo EXPECT_EQ(CS0->getSuccessor(0), OrigSuccessor); 7406e8c9703Svporpo // Check addHandler(). 7416e8c9703Svporpo Ctx.save(); 7426e8c9703Svporpo CS0->addHandler(BB0); 7436e8c9703Svporpo EXPECT_EQ(CS0->getNumHandlers(), 3u); 7446e8c9703Svporpo Ctx.revert(); 7456e8c9703Svporpo EXPECT_EQ(CS0->getNumHandlers(), 2u); 7466e8c9703Svporpo auto HIt = CS0->handler_begin(); 7476e8c9703Svporpo EXPECT_EQ(*HIt++, Handler0); 7486e8c9703Svporpo EXPECT_EQ(*HIt++, Handler1); 7496e8c9703Svporpo } 7506e8c9703Svporpo 751e8b93ce2Svporpo TEST_F(TrackerTest, LandingPadInstSetters) { 752e8b93ce2Svporpo parseIR(C, R"IR( 753e8b93ce2Svporpo define void @foo() { 754e8b93ce2Svporpo entry: 755e8b93ce2Svporpo invoke void @foo() 756e8b93ce2Svporpo to label %bb unwind label %unwind 757e8b93ce2Svporpo unwind: 758e8b93ce2Svporpo %lpad = landingpad { ptr, i32 } 759e8b93ce2Svporpo catch ptr null 760e8b93ce2Svporpo ret void 761e8b93ce2Svporpo bb: 762e8b93ce2Svporpo ret void 763e8b93ce2Svporpo } 764e8b93ce2Svporpo )IR"); 765e8b93ce2Svporpo Function &LLVMF = *M->getFunction("foo"); 766e8b93ce2Svporpo auto *LLVMUnwind = getBasicBlockByName(LLVMF, "unwind"); 767e8b93ce2Svporpo 768e8b93ce2Svporpo sandboxir::Context Ctx(C); 769e8b93ce2Svporpo [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); 770e8b93ce2Svporpo auto *Unwind = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMUnwind)); 771e8b93ce2Svporpo auto It = Unwind->begin(); 772e8b93ce2Svporpo auto *LPad = cast<sandboxir::LandingPadInst>(&*It++); 773e8b93ce2Svporpo [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 774e8b93ce2Svporpo 775e8b93ce2Svporpo // Check setCleanup(). 776e8b93ce2Svporpo auto OrigIsCleanup = LPad->isCleanup(); 777e8b93ce2Svporpo auto NewIsCleanup = true; 778e8b93ce2Svporpo EXPECT_NE(NewIsCleanup, OrigIsCleanup); 779e8b93ce2Svporpo Ctx.save(); 780e8b93ce2Svporpo LPad->setCleanup(NewIsCleanup); 781e8b93ce2Svporpo EXPECT_EQ(LPad->isCleanup(), NewIsCleanup); 782e8b93ce2Svporpo Ctx.revert(); 783e8b93ce2Svporpo EXPECT_EQ(LPad->isCleanup(), OrigIsCleanup); 784e8b93ce2Svporpo } 785e8b93ce2Svporpo 7860d21c2b3Svporpo TEST_F(TrackerTest, CatchReturnInstSetters) { 7870d21c2b3Svporpo parseIR(C, R"IR( 7880d21c2b3Svporpo define void @foo() { 7890d21c2b3Svporpo dispatch: 7900d21c2b3Svporpo %cs = catchswitch within none [label %catch] unwind to caller 7910d21c2b3Svporpo catch: 7920d21c2b3Svporpo %catchpad = catchpad within %cs [ptr @foo] 7930d21c2b3Svporpo catchret from %catchpad to label %continue 7940d21c2b3Svporpo continue: 7950d21c2b3Svporpo ret void 7960d21c2b3Svporpo catch2: 7970d21c2b3Svporpo %catchpad2 = catchpad within %cs [ptr @foo] 7980d21c2b3Svporpo ret void 7990d21c2b3Svporpo } 8000d21c2b3Svporpo )IR"); 8010d21c2b3Svporpo Function &LLVMF = *M->getFunction("foo"); 8020d21c2b3Svporpo BasicBlock *LLVMCatch = getBasicBlockByName(LLVMF, "catch"); 8030d21c2b3Svporpo auto LLVMIt = LLVMCatch->begin(); 8040d21c2b3Svporpo [[maybe_unused]] auto *LLVMCP = cast<llvm::CatchPadInst>(&*LLVMIt++); 8050d21c2b3Svporpo 8060d21c2b3Svporpo sandboxir::Context Ctx(C); 8070d21c2b3Svporpo [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); 8080d21c2b3Svporpo auto *Catch = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMCatch)); 8090d21c2b3Svporpo auto *Catch2 = cast<sandboxir::BasicBlock>( 8100d21c2b3Svporpo Ctx.getValue(getBasicBlockByName(LLVMF, "catch2"))); 8110d21c2b3Svporpo auto It = Catch->begin(); 8120d21c2b3Svporpo [[maybe_unused]] auto *CP = cast<sandboxir::CatchPadInst>(&*It++); 8130d21c2b3Svporpo auto *CR = cast<sandboxir::CatchReturnInst>(&*It++); 8140d21c2b3Svporpo auto *CP2 = cast<sandboxir::CatchPadInst>(&*Catch2->begin()); 8150d21c2b3Svporpo 8160d21c2b3Svporpo // Check setCatchPad(). 8170d21c2b3Svporpo auto *OrigCP = CR->getCatchPad(); 8180d21c2b3Svporpo auto *NewCP = CP2; 8190d21c2b3Svporpo EXPECT_NE(NewCP, OrigCP); 8200d21c2b3Svporpo Ctx.save(); 8210d21c2b3Svporpo CR->setCatchPad(NewCP); 8220d21c2b3Svporpo EXPECT_EQ(CR->getCatchPad(), NewCP); 8230d21c2b3Svporpo Ctx.revert(); 8240d21c2b3Svporpo EXPECT_EQ(CR->getCatchPad(), OrigCP); 8250d21c2b3Svporpo // Check setSuccessor(). 8260d21c2b3Svporpo auto *OrigSucc = CR->getSuccessor(); 8270d21c2b3Svporpo auto *NewSucc = Catch; 8280d21c2b3Svporpo EXPECT_NE(NewSucc, OrigSucc); 8290d21c2b3Svporpo Ctx.save(); 8300d21c2b3Svporpo CR->setSuccessor(NewSucc); 8310d21c2b3Svporpo EXPECT_EQ(CR->getSuccessor(), NewSucc); 8320d21c2b3Svporpo Ctx.revert(); 8330d21c2b3Svporpo EXPECT_EQ(CR->getSuccessor(), OrigSucc); 8340d21c2b3Svporpo } 8350d21c2b3Svporpo 836d0213216Svporpo TEST_F(TrackerTest, CleanupReturnInstSetters) { 837d0213216Svporpo parseIR(C, R"IR( 838d0213216Svporpo define void @foo() { 839d0213216Svporpo dispatch: 840d0213216Svporpo invoke void @foo() 841d0213216Svporpo to label %throw unwind label %cleanup 842d0213216Svporpo throw: 843d0213216Svporpo ret void 844d0213216Svporpo cleanup: 845d0213216Svporpo %cleanuppad = cleanuppad within none [] 846d0213216Svporpo cleanupret from %cleanuppad unwind label %cleanup2 847d0213216Svporpo cleanup2: 848d0213216Svporpo %cleanuppad2 = cleanuppad within none [] 849d0213216Svporpo ret void 850d0213216Svporpo } 851d0213216Svporpo )IR"); 852d0213216Svporpo Function &LLVMF = *M->getFunction("foo"); 853d0213216Svporpo BasicBlock *LLVMCleanup = getBasicBlockByName(LLVMF, "cleanup"); 854d0213216Svporpo 855d0213216Svporpo sandboxir::Context Ctx(C); 856d0213216Svporpo [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); 857d0213216Svporpo auto *Throw = cast<sandboxir::BasicBlock>( 858d0213216Svporpo Ctx.getValue(getBasicBlockByName(LLVMF, "throw"))); 859d0213216Svporpo auto *Cleanup = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMCleanup)); 860d0213216Svporpo auto *Cleanup2 = cast<sandboxir::BasicBlock>( 861d0213216Svporpo Ctx.getValue(getBasicBlockByName(LLVMF, "cleanup2"))); 862d0213216Svporpo auto It = Cleanup->begin(); 863d0213216Svporpo [[maybe_unused]] auto *CP = cast<sandboxir::CleanupPadInst>(&*It++); 864d0213216Svporpo auto *CRI = cast<sandboxir::CleanupReturnInst>(&*It++); 865d0213216Svporpo auto *CP2 = cast<sandboxir::CleanupPadInst>(&*Cleanup2->begin()); 866d0213216Svporpo 867d0213216Svporpo // Check setCleanupPad(). 868d0213216Svporpo auto *OrigCleanupPad = CRI->getCleanupPad(); 869d0213216Svporpo auto *NewCleanupPad = CP2; 870d0213216Svporpo EXPECT_NE(NewCleanupPad, OrigCleanupPad); 871d0213216Svporpo Ctx.save(); 872d0213216Svporpo CRI->setCleanupPad(NewCleanupPad); 873d0213216Svporpo EXPECT_EQ(CRI->getCleanupPad(), NewCleanupPad); 874d0213216Svporpo Ctx.revert(); 875d0213216Svporpo EXPECT_EQ(CRI->getCleanupPad(), OrigCleanupPad); 876d0213216Svporpo // Check setUnwindDest(). 877d0213216Svporpo auto *OrigUnwindDest = CRI->getUnwindDest(); 878d0213216Svporpo auto *NewUnwindDest = Throw; 879d0213216Svporpo EXPECT_NE(NewUnwindDest, OrigUnwindDest); 880d0213216Svporpo Ctx.save(); 881d0213216Svporpo CRI->setUnwindDest(NewUnwindDest); 882d0213216Svporpo EXPECT_EQ(CRI->getUnwindDest(), NewUnwindDest); 883d0213216Svporpo Ctx.revert(); 884d0213216Svporpo EXPECT_EQ(CRI->getUnwindDest(), OrigUnwindDest); 885d0213216Svporpo } 886d0213216Svporpo 887516c1a0eSvporpo TEST_F(TrackerTest, SwitchInstSetters) { 888516c1a0eSvporpo parseIR(C, R"IR( 889516c1a0eSvporpo define void @foo(i32 %cond0, i32 %cond1) { 890516c1a0eSvporpo entry: 891516c1a0eSvporpo switch i32 %cond0, label %default [ i32 0, label %bb0 892516c1a0eSvporpo i32 1, label %bb1 ] 893516c1a0eSvporpo bb0: 894516c1a0eSvporpo ret void 895516c1a0eSvporpo bb1: 896516c1a0eSvporpo ret void 897516c1a0eSvporpo default: 898516c1a0eSvporpo ret void 899516c1a0eSvporpo } 900516c1a0eSvporpo )IR"); 901516c1a0eSvporpo Function &LLVMF = *M->getFunction("foo"); 902516c1a0eSvporpo auto *LLVMEntry = getBasicBlockByName(LLVMF, "entry"); 903516c1a0eSvporpo 904516c1a0eSvporpo sandboxir::Context Ctx(C); 905516c1a0eSvporpo auto &F = *Ctx.createFunction(&LLVMF); 906516c1a0eSvporpo auto *Cond1 = F.getArg(1); 907516c1a0eSvporpo auto *Entry = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMEntry)); 908516c1a0eSvporpo auto *BB0 = cast<sandboxir::BasicBlock>( 909516c1a0eSvporpo Ctx.getValue(getBasicBlockByName(LLVMF, "bb0"))); 910516c1a0eSvporpo auto *BB1 = cast<sandboxir::BasicBlock>( 911516c1a0eSvporpo Ctx.getValue(getBasicBlockByName(LLVMF, "bb1"))); 912516c1a0eSvporpo auto *Switch = cast<sandboxir::SwitchInst>(&*Entry->begin()); 913516c1a0eSvporpo 914516c1a0eSvporpo // Check setCondition(). 915516c1a0eSvporpo auto *OrigCond = Switch->getCondition(); 916516c1a0eSvporpo auto *NewCond = Cond1; 917516c1a0eSvporpo EXPECT_NE(NewCond, OrigCond); 918516c1a0eSvporpo Ctx.save(); 919516c1a0eSvporpo Switch->setCondition(NewCond); 920516c1a0eSvporpo EXPECT_EQ(Switch->getCondition(), NewCond); 921516c1a0eSvporpo Ctx.revert(); 922516c1a0eSvporpo EXPECT_EQ(Switch->getCondition(), OrigCond); 923516c1a0eSvporpo // Check setDefaultDest(). 924516c1a0eSvporpo auto *OrigDefaultDest = Switch->getDefaultDest(); 925516c1a0eSvporpo auto *NewDefaultDest = Entry; 926516c1a0eSvporpo EXPECT_NE(NewDefaultDest, OrigDefaultDest); 927516c1a0eSvporpo Ctx.save(); 928516c1a0eSvporpo Switch->setDefaultDest(NewDefaultDest); 929516c1a0eSvporpo EXPECT_EQ(Switch->getDefaultDest(), NewDefaultDest); 930516c1a0eSvporpo Ctx.revert(); 931516c1a0eSvporpo EXPECT_EQ(Switch->getDefaultDest(), OrigDefaultDest); 932516c1a0eSvporpo // Check setSuccessor(). 933516c1a0eSvporpo auto *OrigSucc = Switch->getSuccessor(0); 934516c1a0eSvporpo auto *NewSucc = Entry; 935516c1a0eSvporpo EXPECT_NE(NewSucc, OrigSucc); 936516c1a0eSvporpo Ctx.save(); 937516c1a0eSvporpo Switch->setSuccessor(0, NewSucc); 938516c1a0eSvporpo EXPECT_EQ(Switch->getSuccessor(0), NewSucc); 939516c1a0eSvporpo Ctx.revert(); 940516c1a0eSvporpo EXPECT_EQ(Switch->getSuccessor(0), OrigSucc); 941516c1a0eSvporpo // Check addCase(). 942034f2b38Svporpo auto *Zero = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 0); 943034f2b38Svporpo auto *One = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 1); 944034f2b38Svporpo auto *FortyTwo = 945034f2b38Svporpo sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 42); 946516c1a0eSvporpo Ctx.save(); 947516c1a0eSvporpo Switch->addCase(FortyTwo, Entry); 948516c1a0eSvporpo EXPECT_EQ(Switch->getNumCases(), 3u); 949516c1a0eSvporpo EXPECT_EQ(Switch->findCaseDest(Entry), FortyTwo); 950516c1a0eSvporpo EXPECT_EQ(Switch->findCaseValue(FortyTwo)->getCaseSuccessor(), Entry); 951516c1a0eSvporpo EXPECT_EQ(Switch->findCaseDest(BB0), Zero); 952516c1a0eSvporpo EXPECT_EQ(Switch->findCaseDest(BB1), One); 953516c1a0eSvporpo Ctx.revert(); 954516c1a0eSvporpo EXPECT_EQ(Switch->getNumCases(), 2u); 955516c1a0eSvporpo EXPECT_EQ(Switch->findCaseDest(BB0), Zero); 956516c1a0eSvporpo EXPECT_EQ(Switch->findCaseDest(BB1), One); 957516c1a0eSvporpo // Check removeCase(). 958516c1a0eSvporpo Ctx.save(); 959516c1a0eSvporpo Switch->removeCase(Switch->findCaseValue(Zero)); 960516c1a0eSvporpo EXPECT_EQ(Switch->getNumCases(), 1u); 961516c1a0eSvporpo EXPECT_EQ(Switch->findCaseDest(BB1), One); 962516c1a0eSvporpo Ctx.revert(); 963516c1a0eSvporpo EXPECT_EQ(Switch->getNumCases(), 2u); 964516c1a0eSvporpo EXPECT_EQ(Switch->findCaseDest(BB0), Zero); 965516c1a0eSvporpo EXPECT_EQ(Switch->findCaseDest(BB1), One); 966516c1a0eSvporpo } 967516c1a0eSvporpo 9689d85ba57SJorge Gorbe Moya TEST_F(TrackerTest, SwitchInstPreservesSuccesorOrder) { 9699d85ba57SJorge Gorbe Moya parseIR(C, R"IR( 9709d85ba57SJorge Gorbe Moya define void @foo(i32 %cond0) { 9719d85ba57SJorge Gorbe Moya entry: 9729d85ba57SJorge Gorbe Moya switch i32 %cond0, label %default [ i32 0, label %bb0 9739d85ba57SJorge Gorbe Moya i32 1, label %bb1 9749d85ba57SJorge Gorbe Moya i32 2, label %bb2 ] 9759d85ba57SJorge Gorbe Moya bb0: 9769d85ba57SJorge Gorbe Moya ret void 9779d85ba57SJorge Gorbe Moya bb1: 9789d85ba57SJorge Gorbe Moya ret void 9799d85ba57SJorge Gorbe Moya bb2: 9809d85ba57SJorge Gorbe Moya ret void 9819d85ba57SJorge Gorbe Moya default: 9829d85ba57SJorge Gorbe Moya ret void 9839d85ba57SJorge Gorbe Moya } 9849d85ba57SJorge Gorbe Moya )IR"); 9859d85ba57SJorge Gorbe Moya Function &LLVMF = *M->getFunction("foo"); 9869d85ba57SJorge Gorbe Moya auto *LLVMEntry = getBasicBlockByName(LLVMF, "entry"); 9879d85ba57SJorge Gorbe Moya 9889d85ba57SJorge Gorbe Moya sandboxir::Context Ctx(C); 9899d85ba57SJorge Gorbe Moya [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); 9909d85ba57SJorge Gorbe Moya auto *Entry = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMEntry)); 9919d85ba57SJorge Gorbe Moya auto *BB0 = cast<sandboxir::BasicBlock>( 9929d85ba57SJorge Gorbe Moya Ctx.getValue(getBasicBlockByName(LLVMF, "bb0"))); 9939d85ba57SJorge Gorbe Moya auto *BB1 = cast<sandboxir::BasicBlock>( 9949d85ba57SJorge Gorbe Moya Ctx.getValue(getBasicBlockByName(LLVMF, "bb1"))); 9959d85ba57SJorge Gorbe Moya auto *BB2 = cast<sandboxir::BasicBlock>( 9969d85ba57SJorge Gorbe Moya Ctx.getValue(getBasicBlockByName(LLVMF, "bb2"))); 9979d85ba57SJorge Gorbe Moya auto *Switch = cast<sandboxir::SwitchInst>(&*Entry->begin()); 9989d85ba57SJorge Gorbe Moya 9999d85ba57SJorge Gorbe Moya auto *DefaultDest = Switch->getDefaultDest(); 10009d85ba57SJorge Gorbe Moya auto *Zero = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 0); 10019d85ba57SJorge Gorbe Moya auto *One = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 1); 10029d85ba57SJorge Gorbe Moya auto *Two = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 2); 10039d85ba57SJorge Gorbe Moya 10049d85ba57SJorge Gorbe Moya // Check that we can properly revert a removeCase multiple positions apart 10059d85ba57SJorge Gorbe Moya // from the end of the operand list. 10069d85ba57SJorge Gorbe Moya Ctx.save(); 10079d85ba57SJorge Gorbe Moya Switch->removeCase(Switch->findCaseValue(Zero)); 10089d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getNumCases(), 2u); 10099d85ba57SJorge Gorbe Moya Ctx.revert(); 10109d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getNumCases(), 3u); 10119d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->findCaseDest(BB0), Zero); 10129d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->findCaseDest(BB1), One); 10139d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->findCaseDest(BB2), Two); 10149d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getSuccessor(0), DefaultDest); 10159d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getSuccessor(1), BB0); 10169d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getSuccessor(2), BB1); 10179d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getSuccessor(3), BB2); 10189d85ba57SJorge Gorbe Moya 10199d85ba57SJorge Gorbe Moya // Check that we can properly revert a removeCase of the last case. 10209d85ba57SJorge Gorbe Moya Ctx.save(); 10219d85ba57SJorge Gorbe Moya Switch->removeCase(Switch->findCaseValue(Two)); 10229d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getNumCases(), 2u); 10239d85ba57SJorge Gorbe Moya Ctx.revert(); 10249d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getNumCases(), 3u); 10259d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->findCaseDest(BB0), Zero); 10269d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->findCaseDest(BB1), One); 10279d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->findCaseDest(BB2), Two); 10289d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getSuccessor(0), DefaultDest); 10299d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getSuccessor(1), BB0); 10309d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getSuccessor(2), BB1); 10319d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getSuccessor(3), BB2); 10329d85ba57SJorge Gorbe Moya 10339d85ba57SJorge Gorbe Moya // Check order is preserved after reverting multiple removeCase invocations. 10349d85ba57SJorge Gorbe Moya Ctx.save(); 10359d85ba57SJorge Gorbe Moya Switch->removeCase(Switch->findCaseValue(One)); 10369d85ba57SJorge Gorbe Moya Switch->removeCase(Switch->findCaseValue(Zero)); 10379d85ba57SJorge Gorbe Moya Switch->removeCase(Switch->findCaseValue(Two)); 10389d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getNumCases(), 0u); 10399d85ba57SJorge Gorbe Moya Ctx.revert(); 10409d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getNumCases(), 3u); 10419d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->findCaseDest(BB0), Zero); 10429d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->findCaseDest(BB1), One); 10439d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->findCaseDest(BB2), Two); 10449d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getSuccessor(0), DefaultDest); 10459d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getSuccessor(1), BB0); 10469d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getSuccessor(2), BB1); 10479d85ba57SJorge Gorbe Moya EXPECT_EQ(Switch->getSuccessor(3), BB2); 10489d85ba57SJorge Gorbe Moya } 10499d85ba57SJorge Gorbe Moya 1050956591beSJorge Gorbe Moya TEST_F(TrackerTest, SelectInst) { 1051956591beSJorge Gorbe Moya parseIR(C, R"IR( 1052956591beSJorge Gorbe Moya define void @foo(i1 %c0, i8 %v0, i8 %v1) { 1053956591beSJorge Gorbe Moya %sel = select i1 %c0, i8 %v0, i8 %v1 1054956591beSJorge Gorbe Moya ret void 1055956591beSJorge Gorbe Moya } 1056956591beSJorge Gorbe Moya )IR"); 1057956591beSJorge Gorbe Moya llvm::Function *LLVMF = &*M->getFunction("foo"); 1058956591beSJorge Gorbe Moya sandboxir::Context Ctx(C); 1059956591beSJorge Gorbe Moya sandboxir::Function *F = Ctx.createFunction(LLVMF); 1060956591beSJorge Gorbe Moya auto *V0 = F->getArg(1); 1061956591beSJorge Gorbe Moya auto *V1 = F->getArg(2); 1062956591beSJorge Gorbe Moya auto *BB = &*F->begin(); 1063956591beSJorge Gorbe Moya auto It = BB->begin(); 1064956591beSJorge Gorbe Moya auto *Select = cast<sandboxir::SelectInst>(&*It++); 1065956591beSJorge Gorbe Moya 1066956591beSJorge Gorbe Moya // Check tracking for swapValues. 1067956591beSJorge Gorbe Moya Ctx.save(); 1068956591beSJorge Gorbe Moya Select->swapValues(); 1069956591beSJorge Gorbe Moya EXPECT_EQ(Select->getTrueValue(), V1); 1070956591beSJorge Gorbe Moya EXPECT_EQ(Select->getFalseValue(), V0); 1071956591beSJorge Gorbe Moya Ctx.revert(); 1072956591beSJorge Gorbe Moya EXPECT_EQ(Select->getTrueValue(), V0); 1073956591beSJorge Gorbe Moya EXPECT_EQ(Select->getFalseValue(), V1); 1074956591beSJorge Gorbe Moya } 1075956591beSJorge Gorbe Moya 1076e89bcfc0SJorge Gorbe Moya TEST_F(TrackerTest, ShuffleVectorInst) { 1077b5ba7265SJorge Gorbe Moya parseIR(C, R"IR( 1078b5ba7265SJorge Gorbe Moya define void @foo(<2 x i8> %v1, <2 x i8> %v2) { 1079b5ba7265SJorge Gorbe Moya %shuf = shufflevector <2 x i8> %v1, <2 x i8> %v2, <2 x i32> <i32 1, i32 2> 1080b5ba7265SJorge Gorbe Moya ret void 1081b5ba7265SJorge Gorbe Moya } 1082b5ba7265SJorge Gorbe Moya )IR"); 1083b5ba7265SJorge Gorbe Moya Function &LLVMF = *M->getFunction("foo"); 1084b5ba7265SJorge Gorbe Moya sandboxir::Context Ctx(C); 1085b5ba7265SJorge Gorbe Moya 1086b5ba7265SJorge Gorbe Moya auto *F = Ctx.createFunction(&LLVMF); 1087b5ba7265SJorge Gorbe Moya auto *BB = &*F->begin(); 1088b5ba7265SJorge Gorbe Moya auto It = BB->begin(); 1089b5ba7265SJorge Gorbe Moya auto *SVI = cast<sandboxir::ShuffleVectorInst>(&*It++); 1090b5ba7265SJorge Gorbe Moya 1091b5ba7265SJorge Gorbe Moya // Check setShuffleMask. 1092b5ba7265SJorge Gorbe Moya SmallVector<int, 2> OrigMask(SVI->getShuffleMask()); 1093b5ba7265SJorge Gorbe Moya Ctx.save(); 1094b5ba7265SJorge Gorbe Moya SVI->setShuffleMask(ArrayRef<int>({0, 0})); 1095e89bcfc0SJorge Gorbe Moya EXPECT_NE(SVI->getShuffleMask(), ArrayRef<int>(OrigMask)); 1096b5ba7265SJorge Gorbe Moya Ctx.revert(); 1097e89bcfc0SJorge Gorbe Moya EXPECT_EQ(SVI->getShuffleMask(), ArrayRef<int>(OrigMask)); 1098e89bcfc0SJorge Gorbe Moya 1099e89bcfc0SJorge Gorbe Moya // Check commute. 1100e89bcfc0SJorge Gorbe Moya auto *Op0 = SVI->getOperand(0); 1101e89bcfc0SJorge Gorbe Moya auto *Op1 = SVI->getOperand(1); 1102e89bcfc0SJorge Gorbe Moya Ctx.save(); 1103e89bcfc0SJorge Gorbe Moya SVI->commute(); 1104e89bcfc0SJorge Gorbe Moya EXPECT_EQ(SVI->getOperand(0), Op1); 1105e89bcfc0SJorge Gorbe Moya EXPECT_EQ(SVI->getOperand(1), Op0); 1106e89bcfc0SJorge Gorbe Moya EXPECT_NE(SVI->getShuffleMask(), ArrayRef<int>(OrigMask)); 1107e89bcfc0SJorge Gorbe Moya Ctx.revert(); 1108e89bcfc0SJorge Gorbe Moya EXPECT_EQ(SVI->getOperand(0), Op0); 1109e89bcfc0SJorge Gorbe Moya EXPECT_EQ(SVI->getOperand(1), Op1); 1110e89bcfc0SJorge Gorbe Moya EXPECT_EQ(SVI->getShuffleMask(), ArrayRef<int>(OrigMask)); 1111b5ba7265SJorge Gorbe Moya } 1112b5ba7265SJorge Gorbe Moya 11133b0a1ecbSvporpo TEST_F(TrackerTest, PossiblyDisjointInstSetters) { 11143b0a1ecbSvporpo parseIR(C, R"IR( 11153b0a1ecbSvporpo define void @foo(i8 %arg0, i8 %arg1) { 11163b0a1ecbSvporpo %or = or i8 %arg0, %arg1 11173b0a1ecbSvporpo ret void 11183b0a1ecbSvporpo } 11193b0a1ecbSvporpo )IR"); 11203b0a1ecbSvporpo Function &LLVMF = *M->getFunction("foo"); 11213b0a1ecbSvporpo sandboxir::Context Ctx(C); 11223b0a1ecbSvporpo 11233b0a1ecbSvporpo auto &F = *Ctx.createFunction(&LLVMF); 11243b0a1ecbSvporpo auto *BB = &*F.begin(); 11253b0a1ecbSvporpo auto It = BB->begin(); 11263b0a1ecbSvporpo auto *PDI = cast<sandboxir::PossiblyDisjointInst>(&*It++); 11273b0a1ecbSvporpo 11283b0a1ecbSvporpo // Check setIsDisjoint(). 11293b0a1ecbSvporpo auto OrigIsDisjoint = PDI->isDisjoint(); 11303b0a1ecbSvporpo auto NewIsDisjoint = true; 11313b0a1ecbSvporpo EXPECT_NE(NewIsDisjoint, OrigIsDisjoint); 11323b0a1ecbSvporpo Ctx.save(); 11333b0a1ecbSvporpo PDI->setIsDisjoint(NewIsDisjoint); 11343b0a1ecbSvporpo EXPECT_EQ(PDI->isDisjoint(), NewIsDisjoint); 11353b0a1ecbSvporpo Ctx.revert(); 11363b0a1ecbSvporpo EXPECT_EQ(PDI->isDisjoint(), OrigIsDisjoint); 11373b0a1ecbSvporpo } 11383b0a1ecbSvporpo 1139af4a82e4Svporpo TEST_F(TrackerTest, PossiblyNonNegInstSetters) { 1140af4a82e4Svporpo parseIR(C, R"IR( 1141af4a82e4Svporpo define void @foo(i32 %arg) { 1142af4a82e4Svporpo %zext = zext i32 %arg to i64 1143af4a82e4Svporpo ret void 1144af4a82e4Svporpo } 1145af4a82e4Svporpo )IR"); 1146af4a82e4Svporpo Function &LLVMF = *M->getFunction("foo"); 1147af4a82e4Svporpo sandboxir::Context Ctx(C); 1148af4a82e4Svporpo 1149af4a82e4Svporpo auto &F = *Ctx.createFunction(&LLVMF); 1150af4a82e4Svporpo auto *BB = &*F.begin(); 1151af4a82e4Svporpo auto It = BB->begin(); 1152af4a82e4Svporpo auto *PNNI = cast<sandboxir::PossiblyNonNegInst>(&*It++); 1153af4a82e4Svporpo 1154af4a82e4Svporpo // Check setNonNeg(). 1155af4a82e4Svporpo auto OrigNonNeg = PNNI->hasNonNeg(); 1156af4a82e4Svporpo auto NewNonNeg = true; 1157af4a82e4Svporpo EXPECT_NE(NewNonNeg, OrigNonNeg); 1158af4a82e4Svporpo Ctx.save(); 1159af4a82e4Svporpo PNNI->setNonNeg(NewNonNeg); 1160af4a82e4Svporpo EXPECT_EQ(PNNI->hasNonNeg(), NewNonNeg); 1161af4a82e4Svporpo Ctx.revert(); 1162af4a82e4Svporpo EXPECT_EQ(PNNI->hasNonNeg(), OrigNonNeg); 1163af4a82e4Svporpo } 1164af4a82e4Svporpo 1165ab5102d6Svporpo TEST_F(TrackerTest, AtomicRMWSetters) { 1166ab5102d6Svporpo parseIR(C, R"IR( 1167ab5102d6Svporpo define void @foo(ptr %ptr, i8 %arg) { 1168ab5102d6Svporpo %atomicrmw = atomicrmw add ptr %ptr, i8 %arg acquire, align 128 1169ab5102d6Svporpo ret void 1170ab5102d6Svporpo } 1171ab5102d6Svporpo )IR"); 1172ab5102d6Svporpo Function &LLVMF = *M->getFunction("foo"); 1173ab5102d6Svporpo sandboxir::Context Ctx(C); 1174ab5102d6Svporpo auto &F = *Ctx.createFunction(&LLVMF); 1175ab5102d6Svporpo auto *BB = &*F.begin(); 1176ab5102d6Svporpo auto It = BB->begin(); 1177ab5102d6Svporpo auto *RMW = cast<sandboxir::AtomicRMWInst>(&*It++); 1178ab5102d6Svporpo 1179ab5102d6Svporpo // Check setAlignment(). 1180ab5102d6Svporpo Ctx.save(); 1181ab5102d6Svporpo auto OrigAlign = RMW->getAlign(); 1182ab5102d6Svporpo Align NewAlign(1024); 1183ab5102d6Svporpo EXPECT_NE(NewAlign, OrigAlign); 1184ab5102d6Svporpo RMW->setAlignment(NewAlign); 1185ab5102d6Svporpo EXPECT_EQ(RMW->getAlign(), NewAlign); 1186ab5102d6Svporpo Ctx.revert(); 1187ab5102d6Svporpo EXPECT_EQ(RMW->getAlign(), OrigAlign); 1188ab5102d6Svporpo 1189ab5102d6Svporpo // Check setVolatile(). 1190ab5102d6Svporpo Ctx.save(); 1191ab5102d6Svporpo auto OrigIsVolatile = RMW->isVolatile(); 1192ab5102d6Svporpo bool NewIsVolatile = true; 1193ab5102d6Svporpo EXPECT_NE(NewIsVolatile, OrigIsVolatile); 1194ab5102d6Svporpo RMW->setVolatile(NewIsVolatile); 1195ab5102d6Svporpo EXPECT_EQ(RMW->isVolatile(), NewIsVolatile); 1196ab5102d6Svporpo Ctx.revert(); 1197ab5102d6Svporpo EXPECT_EQ(RMW->isVolatile(), OrigIsVolatile); 1198ab5102d6Svporpo 1199ab5102d6Svporpo // Check setOrdering(). 1200ab5102d6Svporpo Ctx.save(); 1201ab5102d6Svporpo auto OrigOrdering = RMW->getOrdering(); 1202ab5102d6Svporpo auto NewOrdering = AtomicOrdering::SequentiallyConsistent; 1203ab5102d6Svporpo EXPECT_NE(NewOrdering, OrigOrdering); 1204ab5102d6Svporpo RMW->setOrdering(NewOrdering); 1205ab5102d6Svporpo EXPECT_EQ(RMW->getOrdering(), NewOrdering); 1206ab5102d6Svporpo Ctx.revert(); 1207ab5102d6Svporpo EXPECT_EQ(RMW->getOrdering(), OrigOrdering); 1208ab5102d6Svporpo 1209ab5102d6Svporpo // Check setSyncScopeID(). 1210ab5102d6Svporpo Ctx.save(); 1211ab5102d6Svporpo auto OrigSSID = RMW->getSyncScopeID(); 1212ab5102d6Svporpo auto NewSSID = SyncScope::SingleThread; 1213ab5102d6Svporpo EXPECT_NE(NewSSID, OrigSSID); 1214ab5102d6Svporpo RMW->setSyncScopeID(NewSSID); 1215ab5102d6Svporpo EXPECT_EQ(RMW->getSyncScopeID(), NewSSID); 1216ab5102d6Svporpo Ctx.revert(); 1217ab5102d6Svporpo EXPECT_EQ(RMW->getSyncScopeID(), OrigSSID); 1218ab5102d6Svporpo } 1219ab5102d6Svporpo 122000a40422Svporpo TEST_F(TrackerTest, AtomicCmpXchgSetters) { 122100a40422Svporpo parseIR(C, R"IR( 122200a40422Svporpo define void @foo(ptr %ptr, i8 %cmp, i8 %new) { 122300a40422Svporpo %cmpxchg = cmpxchg ptr %ptr, i8 %cmp, i8 %new monotonic monotonic, align 128 122400a40422Svporpo ret void 122500a40422Svporpo } 122600a40422Svporpo )IR"); 122700a40422Svporpo Function &LLVMF = *M->getFunction("foo"); 122800a40422Svporpo sandboxir::Context Ctx(C); 122900a40422Svporpo auto &F = *Ctx.createFunction(&LLVMF); 123000a40422Svporpo auto *BB = &*F.begin(); 123100a40422Svporpo auto It = BB->begin(); 123200a40422Svporpo auto *CmpXchg = cast<sandboxir::AtomicCmpXchgInst>(&*It++); 123300a40422Svporpo 123400a40422Svporpo // Check setAlignment(). 123500a40422Svporpo Ctx.save(); 123600a40422Svporpo auto OrigAlign = CmpXchg->getAlign(); 123700a40422Svporpo Align NewAlign(1024); 123800a40422Svporpo EXPECT_NE(NewAlign, OrigAlign); 123900a40422Svporpo CmpXchg->setAlignment(NewAlign); 124000a40422Svporpo EXPECT_EQ(CmpXchg->getAlign(), NewAlign); 124100a40422Svporpo Ctx.revert(); 124200a40422Svporpo EXPECT_EQ(CmpXchg->getAlign(), OrigAlign); 124300a40422Svporpo 124400a40422Svporpo // Check setVolatile(). 124500a40422Svporpo Ctx.save(); 124600a40422Svporpo auto OrigIsVolatile = CmpXchg->isVolatile(); 124700a40422Svporpo bool NewIsVolatile = true; 124800a40422Svporpo EXPECT_NE(NewIsVolatile, OrigIsVolatile); 124900a40422Svporpo CmpXchg->setVolatile(NewIsVolatile); 125000a40422Svporpo EXPECT_EQ(CmpXchg->isVolatile(), NewIsVolatile); 125100a40422Svporpo Ctx.revert(); 125200a40422Svporpo EXPECT_EQ(CmpXchg->isVolatile(), OrigIsVolatile); 125300a40422Svporpo 125400a40422Svporpo // Check setWeak(). 125500a40422Svporpo Ctx.save(); 125600a40422Svporpo auto OrigIsWeak = CmpXchg->isWeak(); 125700a40422Svporpo bool NewIsWeak = true; 125800a40422Svporpo EXPECT_NE(NewIsWeak, OrigIsWeak); 125900a40422Svporpo CmpXchg->setWeak(NewIsWeak); 126000a40422Svporpo EXPECT_EQ(CmpXchg->isWeak(), NewIsWeak); 126100a40422Svporpo Ctx.revert(); 126200a40422Svporpo EXPECT_EQ(CmpXchg->isWeak(), OrigIsWeak); 126300a40422Svporpo 126400a40422Svporpo // Check setSuccessOrdering(). 126500a40422Svporpo Ctx.save(); 126600a40422Svporpo auto OrigSuccessOrdering = CmpXchg->getSuccessOrdering(); 126700a40422Svporpo auto NewSuccessOrdering = AtomicOrdering::SequentiallyConsistent; 126800a40422Svporpo EXPECT_NE(NewSuccessOrdering, OrigSuccessOrdering); 126900a40422Svporpo CmpXchg->setSuccessOrdering(NewSuccessOrdering); 127000a40422Svporpo EXPECT_EQ(CmpXchg->getSuccessOrdering(), NewSuccessOrdering); 127100a40422Svporpo Ctx.revert(); 127200a40422Svporpo EXPECT_EQ(CmpXchg->getSuccessOrdering(), OrigSuccessOrdering); 127300a40422Svporpo 127400a40422Svporpo // Check setFailureOrdering(). 127500a40422Svporpo Ctx.save(); 127600a40422Svporpo auto OrigFailureOrdering = CmpXchg->getFailureOrdering(); 127700a40422Svporpo auto NewFailureOrdering = AtomicOrdering::SequentiallyConsistent; 127800a40422Svporpo EXPECT_NE(NewFailureOrdering, OrigFailureOrdering); 127900a40422Svporpo CmpXchg->setFailureOrdering(NewFailureOrdering); 128000a40422Svporpo EXPECT_EQ(CmpXchg->getFailureOrdering(), NewFailureOrdering); 128100a40422Svporpo Ctx.revert(); 128200a40422Svporpo EXPECT_EQ(CmpXchg->getFailureOrdering(), OrigFailureOrdering); 128300a40422Svporpo 128400a40422Svporpo // Check setSyncScopeID(). 128500a40422Svporpo Ctx.save(); 128600a40422Svporpo auto OrigSSID = CmpXchg->getSyncScopeID(); 128700a40422Svporpo auto NewSSID = SyncScope::SingleThread; 128800a40422Svporpo EXPECT_NE(NewSSID, OrigSSID); 128900a40422Svporpo CmpXchg->setSyncScopeID(NewSSID); 129000a40422Svporpo EXPECT_EQ(CmpXchg->getSyncScopeID(), NewSSID); 129100a40422Svporpo Ctx.revert(); 129200a40422Svporpo EXPECT_EQ(CmpXchg->getSyncScopeID(), OrigSSID); 129300a40422Svporpo } 129400a40422Svporpo 129536f0d648Svporpo TEST_F(TrackerTest, AllocaInstSetters) { 129636f0d648Svporpo parseIR(C, R"IR( 129736f0d648Svporpo define void @foo(i8 %arg) { 129836f0d648Svporpo %alloca = alloca i32, align 64 129936f0d648Svporpo ret void 130036f0d648Svporpo } 130136f0d648Svporpo )IR"); 130236f0d648Svporpo Function &LLVMF = *M->getFunction("foo"); 130336f0d648Svporpo sandboxir::Context Ctx(C); 130436f0d648Svporpo auto &F = *Ctx.createFunction(&LLVMF); 130536f0d648Svporpo auto *BB = &*F.begin(); 130636f0d648Svporpo auto It = BB->begin(); 130736f0d648Svporpo auto *Alloca = cast<sandboxir::AllocaInst>(&*It++); 130836f0d648Svporpo 130936f0d648Svporpo // Check setAllocatedType(). 131036f0d648Svporpo Ctx.save(); 131136f0d648Svporpo auto *OrigTy = Alloca->getAllocatedType(); 1312034f2b38Svporpo auto *NewTy = sandboxir::Type::getInt64Ty(Ctx); 131336f0d648Svporpo EXPECT_NE(NewTy, OrigTy); 131436f0d648Svporpo Alloca->setAllocatedType(NewTy); 131536f0d648Svporpo EXPECT_EQ(Alloca->getAllocatedType(), NewTy); 131636f0d648Svporpo Ctx.revert(); 131736f0d648Svporpo EXPECT_EQ(Alloca->getAllocatedType(), OrigTy); 131836f0d648Svporpo 131936f0d648Svporpo // Check setAlignment(). 132036f0d648Svporpo Ctx.save(); 132136f0d648Svporpo auto OrigAlign = Alloca->getAlign(); 132236f0d648Svporpo Align NewAlign(128); 132336f0d648Svporpo EXPECT_NE(NewAlign, OrigAlign); 132436f0d648Svporpo Alloca->setAlignment(NewAlign); 132536f0d648Svporpo EXPECT_EQ(Alloca->getAlign(), NewAlign); 132636f0d648Svporpo Ctx.revert(); 132736f0d648Svporpo EXPECT_EQ(Alloca->getAlign(), OrigAlign); 132836f0d648Svporpo 132936f0d648Svporpo // Check setUsedWithInAlloca(). 133036f0d648Svporpo Ctx.save(); 133136f0d648Svporpo auto OrigWIA = Alloca->isUsedWithInAlloca(); 133236f0d648Svporpo bool NewWIA = true; 133336f0d648Svporpo EXPECT_NE(NewWIA, OrigWIA); 133436f0d648Svporpo Alloca->setUsedWithInAlloca(NewWIA); 133536f0d648Svporpo EXPECT_EQ(Alloca->isUsedWithInAlloca(), NewWIA); 133636f0d648Svporpo Ctx.revert(); 133736f0d648Svporpo EXPECT_EQ(Alloca->isUsedWithInAlloca(), OrigWIA); 133836f0d648Svporpo } 133936f0d648Svporpo 1340cfb92be0Svporpo TEST_F(TrackerTest, CallBrSetters) { 1341cfb92be0Svporpo parseIR(C, R"IR( 1342cfb92be0Svporpo define void @foo(i8 %arg) { 1343cfb92be0Svporpo bb0: 1344cfb92be0Svporpo callbr void @foo(i8 %arg) 1345cfb92be0Svporpo to label %bb1 [label %bb2] 1346cfb92be0Svporpo bb1: 1347cfb92be0Svporpo ret void 1348cfb92be0Svporpo bb2: 1349cfb92be0Svporpo ret void 1350cfb92be0Svporpo other_bb: 1351cfb92be0Svporpo ret void 1352cfb92be0Svporpo } 1353cfb92be0Svporpo )IR"); 1354cfb92be0Svporpo Function &LLVMF = *M->getFunction("foo"); 1355cfb92be0Svporpo sandboxir::Context Ctx(C); 1356cfb92be0Svporpo [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); 1357cfb92be0Svporpo auto *BB0 = cast<sandboxir::BasicBlock>( 1358cfb92be0Svporpo Ctx.getValue(getBasicBlockByName(LLVMF, "bb0"))); 1359cfb92be0Svporpo auto *OtherBB = cast<sandboxir::BasicBlock>( 1360cfb92be0Svporpo Ctx.getValue(getBasicBlockByName(LLVMF, "other_bb"))); 1361cfb92be0Svporpo auto It = BB0->begin(); 1362cfb92be0Svporpo auto *CallBr = cast<sandboxir::CallBrInst>(&*It++); 1363cfb92be0Svporpo // Check setDefaultDest(). 1364cfb92be0Svporpo Ctx.save(); 1365cfb92be0Svporpo auto *OrigDefaultDest = CallBr->getDefaultDest(); 1366cfb92be0Svporpo CallBr->setDefaultDest(OtherBB); 1367cfb92be0Svporpo EXPECT_EQ(CallBr->getDefaultDest(), OtherBB); 1368cfb92be0Svporpo Ctx.revert(); 1369cfb92be0Svporpo EXPECT_EQ(CallBr->getDefaultDest(), OrigDefaultDest); 1370cfb92be0Svporpo 1371cfb92be0Svporpo // Check setIndirectDest(). 1372cfb92be0Svporpo Ctx.save(); 1373cfb92be0Svporpo auto *OrigIndirectDest = CallBr->getIndirectDest(0); 1374cfb92be0Svporpo CallBr->setIndirectDest(0, OtherBB); 1375cfb92be0Svporpo EXPECT_EQ(CallBr->getIndirectDest(0), OtherBB); 1376cfb92be0Svporpo Ctx.revert(); 1377cfb92be0Svporpo EXPECT_EQ(CallBr->getIndirectDest(0), OrigIndirectDest); 1378cfb92be0Svporpo } 13793403b593SSterling-Augustine 13807854b16dSvporpo TEST_F(TrackerTest, FuncletPadInstSetters) { 13817854b16dSvporpo parseIR(C, R"IR( 13827854b16dSvporpo define void @foo() { 13837854b16dSvporpo dispatch: 13847854b16dSvporpo %cs = catchswitch within none [label %handler0] unwind to caller 13857854b16dSvporpo handler0: 13867854b16dSvporpo %catchpad = catchpad within %cs [ptr @foo] 13877854b16dSvporpo ret void 13887854b16dSvporpo handler1: 13897854b16dSvporpo %cleanuppad = cleanuppad within %cs [ptr @foo] 13907854b16dSvporpo ret void 13917854b16dSvporpo bb: 13927854b16dSvporpo ret void 13937854b16dSvporpo } 13947854b16dSvporpo )IR"); 13957854b16dSvporpo Function &LLVMF = *M->getFunction("foo"); 13967854b16dSvporpo sandboxir::Context Ctx(C); 13977854b16dSvporpo [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); 13987854b16dSvporpo auto *Dispatch = cast<sandboxir::BasicBlock>( 13997854b16dSvporpo Ctx.getValue(getBasicBlockByName(LLVMF, "dispatch"))); 14007854b16dSvporpo auto *Handler0 = cast<sandboxir::BasicBlock>( 14017854b16dSvporpo Ctx.getValue(getBasicBlockByName(LLVMF, "handler0"))); 14027854b16dSvporpo auto *Handler1 = cast<sandboxir::BasicBlock>( 14037854b16dSvporpo Ctx.getValue(getBasicBlockByName(LLVMF, "handler1"))); 14047854b16dSvporpo auto *CP = cast<sandboxir::CatchPadInst>(&*Handler0->begin()); 14057854b16dSvporpo auto *CLP = cast<sandboxir::CleanupPadInst>(&*Handler1->begin()); 14067854b16dSvporpo 14077854b16dSvporpo for (auto *FPI : {static_cast<sandboxir::FuncletPadInst *>(CP), 14087854b16dSvporpo static_cast<sandboxir::FuncletPadInst *>(CLP)}) { 14097854b16dSvporpo // Check setParentPad(). 14107854b16dSvporpo auto *OrigParentPad = FPI->getParentPad(); 14117854b16dSvporpo auto *NewParentPad = Dispatch; 14127854b16dSvporpo EXPECT_NE(NewParentPad, OrigParentPad); 14137854b16dSvporpo Ctx.save(); 14147854b16dSvporpo FPI->setParentPad(NewParentPad); 14157854b16dSvporpo EXPECT_EQ(FPI->getParentPad(), NewParentPad); 14167854b16dSvporpo Ctx.revert(); 14177854b16dSvporpo EXPECT_EQ(FPI->getParentPad(), OrigParentPad); 14187854b16dSvporpo 14197854b16dSvporpo // Check setArgOperand(). 14207854b16dSvporpo auto *OrigArgOperand = FPI->getArgOperand(0); 14217854b16dSvporpo auto *NewArgOperand = Dispatch; 14227854b16dSvporpo EXPECT_NE(NewArgOperand, OrigArgOperand); 14237854b16dSvporpo Ctx.save(); 14247854b16dSvporpo FPI->setArgOperand(0, NewArgOperand); 14257854b16dSvporpo EXPECT_EQ(FPI->getArgOperand(0), NewArgOperand); 14267854b16dSvporpo Ctx.revert(); 14277854b16dSvporpo EXPECT_EQ(FPI->getArgOperand(0), OrigArgOperand); 14287854b16dSvporpo } 14297854b16dSvporpo } 14307854b16dSvporpo 14313403b593SSterling-Augustine TEST_F(TrackerTest, PHINodeSetters) { 14323403b593SSterling-Augustine parseIR(C, R"IR( 14333403b593SSterling-Augustine define void @foo(i8 %arg0, i8 %arg1, i8 %arg2) { 14343403b593SSterling-Augustine bb0: 14353403b593SSterling-Augustine br label %bb2 14363403b593SSterling-Augustine 14373403b593SSterling-Augustine bb1: 14383403b593SSterling-Augustine %phi = phi i8 [ %arg0, %bb0 ], [ %arg1, %bb1 ] 14393403b593SSterling-Augustine br label %bb1 14403403b593SSterling-Augustine 14413403b593SSterling-Augustine bb2: 14423403b593SSterling-Augustine ret void 14433403b593SSterling-Augustine } 14443403b593SSterling-Augustine )IR"); 14453403b593SSterling-Augustine Function &LLVMF = *M->getFunction("foo"); 14463403b593SSterling-Augustine sandboxir::Context Ctx(C); 14473403b593SSterling-Augustine auto &F = *Ctx.createFunction(&LLVMF); 14483403b593SSterling-Augustine unsigned ArgIdx = 0; 14493403b593SSterling-Augustine auto *Arg0 = F.getArg(ArgIdx++); 14503403b593SSterling-Augustine auto *Arg1 = F.getArg(ArgIdx++); 14513403b593SSterling-Augustine auto *Arg2 = F.getArg(ArgIdx++); 14523403b593SSterling-Augustine auto *BB0 = cast<sandboxir::BasicBlock>( 14533403b593SSterling-Augustine Ctx.getValue(getBasicBlockByName(LLVMF, "bb0"))); 14543403b593SSterling-Augustine auto *BB1 = cast<sandboxir::BasicBlock>( 14553403b593SSterling-Augustine Ctx.getValue(getBasicBlockByName(LLVMF, "bb1"))); 14563403b593SSterling-Augustine auto *BB2 = cast<sandboxir::BasicBlock>( 14573403b593SSterling-Augustine Ctx.getValue(getBasicBlockByName(LLVMF, "bb2"))); 14583403b593SSterling-Augustine auto *PHI = cast<sandboxir::PHINode>(&*BB1->begin()); 14593403b593SSterling-Augustine 14603403b593SSterling-Augustine // Check setIncomingValue(). 14613403b593SSterling-Augustine Ctx.save(); 14623403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg0); 14633403b593SSterling-Augustine PHI->setIncomingValue(0, Arg2); 14643403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg2); 14653403b593SSterling-Augustine Ctx.revert(); 14663403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg0); 14673403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 2u); 14683403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB0); 14693403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg0); 14703403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(1), BB1); 14713403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(1), Arg1); 14723403b593SSterling-Augustine 14733403b593SSterling-Augustine // Check setIncomingBlock(). 14743403b593SSterling-Augustine Ctx.save(); 14753403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB0); 14763403b593SSterling-Augustine PHI->setIncomingBlock(0, BB2); 14773403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB2); 14783403b593SSterling-Augustine Ctx.revert(); 14793403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB0); 14803403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 2u); 14813403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB0); 14823403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg0); 14833403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(1), BB1); 14843403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(1), Arg1); 14853403b593SSterling-Augustine 14863403b593SSterling-Augustine // Check addIncoming(). 14873403b593SSterling-Augustine Ctx.save(); 14883403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 2u); 14893403b593SSterling-Augustine PHI->addIncoming(Arg1, BB2); 14903403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 3u); 14913403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(2), BB2); 14923403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(2), Arg1); 14933403b593SSterling-Augustine Ctx.revert(); 14943403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 2u); 14953403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB0); 14963403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg0); 14973403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(1), BB1); 14983403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(1), Arg1); 14993403b593SSterling-Augustine 15003403b593SSterling-Augustine // Check removeIncomingValue(1). 15013403b593SSterling-Augustine Ctx.save(); 15023403b593SSterling-Augustine PHI->removeIncomingValue(1); 15033403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 1u); 15043403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB0); 15053403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg0); 15063403b593SSterling-Augustine Ctx.revert(); 15073403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 2u); 15083403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB0); 15093403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg0); 15103403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(1), BB1); 15113403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(1), Arg1); 15123403b593SSterling-Augustine 15133403b593SSterling-Augustine // Check removeIncomingValue(0). 15143403b593SSterling-Augustine Ctx.save(); 15153403b593SSterling-Augustine PHI->removeIncomingValue(0u); 15163403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 1u); 15173403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB1); 15183403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg1); 15193403b593SSterling-Augustine Ctx.revert(); 15203403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 2u); 15213403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB0); 15223403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg0); 15233403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(1), BB1); 15243403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(1), Arg1); 15253403b593SSterling-Augustine 152666f4e3f8SSterling-Augustine // Check removeIncomingValueIf(FromBB1). 152766f4e3f8SSterling-Augustine Ctx.save(); 152866f4e3f8SSterling-Augustine PHI->removeIncomingValueIf( 152966f4e3f8SSterling-Augustine [&](unsigned Idx) { return PHI->getIncomingBlock(Idx) == BB1; }); 153066f4e3f8SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 1u); 153166f4e3f8SSterling-Augustine Ctx.revert(); 153266f4e3f8SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 2u); 153366f4e3f8SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB0); 153466f4e3f8SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(1), BB1); 15353403b593SSterling-Augustine // Check removeIncomingValue() remove all. 15363403b593SSterling-Augustine Ctx.save(); 15373403b593SSterling-Augustine PHI->removeIncomingValue(0u); 15383403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 1u); 15393403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB1); 15403403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg1); 15413403b593SSterling-Augustine PHI->removeIncomingValue(0u); 15423403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 0u); 15433403b593SSterling-Augustine Ctx.revert(); 15443403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 2u); 15453403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB0); 15463403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg0); 15473403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(1), BB1); 15483403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(1), Arg1); 15493403b593SSterling-Augustine 15503403b593SSterling-Augustine // Check removeIncomingValue(BasicBlock *). 15513403b593SSterling-Augustine Ctx.save(); 15523403b593SSterling-Augustine PHI->removeIncomingValue(BB1); 15533403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 1u); 15543403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB0); 15553403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg0); 15563403b593SSterling-Augustine Ctx.revert(); 15573403b593SSterling-Augustine EXPECT_EQ(PHI->getNumIncomingValues(), 2u); 15583403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(0), BB0); 15593403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(0), Arg0); 15603403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingBlock(1), BB1); 15613403b593SSterling-Augustine EXPECT_EQ(PHI->getIncomingValue(1), Arg1); 15623403b593SSterling-Augustine } 156395b366caSJulius Alexandre 1564840da2e8SSterling-Augustine void checkCmpInst(sandboxir::Context &Ctx, sandboxir::CmpInst *Cmp) { 1565840da2e8SSterling-Augustine Ctx.save(); 1566840da2e8SSterling-Augustine auto OrigP = Cmp->getPredicate(); 1567840da2e8SSterling-Augustine auto NewP = Cmp->getSwappedPredicate(); 1568840da2e8SSterling-Augustine Cmp->setPredicate(NewP); 1569840da2e8SSterling-Augustine EXPECT_EQ(Cmp->getPredicate(), NewP); 1570840da2e8SSterling-Augustine Ctx.revert(); 1571840da2e8SSterling-Augustine EXPECT_EQ(Cmp->getPredicate(), OrigP); 1572840da2e8SSterling-Augustine 1573840da2e8SSterling-Augustine Ctx.save(); 1574840da2e8SSterling-Augustine auto OrigOp0 = Cmp->getOperand(0); 1575840da2e8SSterling-Augustine auto OrigOp1 = Cmp->getOperand(1); 1576840da2e8SSterling-Augustine Cmp->swapOperands(); 1577840da2e8SSterling-Augustine EXPECT_EQ(Cmp->getPredicate(), NewP); 1578840da2e8SSterling-Augustine EXPECT_EQ(Cmp->getOperand(0), OrigOp1); 1579840da2e8SSterling-Augustine EXPECT_EQ(Cmp->getOperand(1), OrigOp0); 1580840da2e8SSterling-Augustine Ctx.revert(); 1581840da2e8SSterling-Augustine EXPECT_EQ(Cmp->getPredicate(), OrigP); 1582840da2e8SSterling-Augustine EXPECT_EQ(Cmp->getOperand(0), OrigOp0); 1583840da2e8SSterling-Augustine EXPECT_EQ(Cmp->getOperand(1), OrigOp1); 1584840da2e8SSterling-Augustine } 1585840da2e8SSterling-Augustine 1586840da2e8SSterling-Augustine TEST_F(TrackerTest, CmpInst) { 1587840da2e8SSterling-Augustine SCOPED_TRACE("TrackerTest sandboxir::CmpInst tests"); 1588840da2e8SSterling-Augustine parseIR(C, R"IR( 1589840da2e8SSterling-Augustine define void @foo(i64 %i0, i64 %i1, float %f0, float %f1) { 1590840da2e8SSterling-Augustine %foeq = fcmp ogt float %f0, %f1 1591840da2e8SSterling-Augustine %ioeq = icmp uge i64 %i0, %i1 1592840da2e8SSterling-Augustine 1593840da2e8SSterling-Augustine ret void 1594840da2e8SSterling-Augustine } 1595840da2e8SSterling-Augustine )IR"); 1596840da2e8SSterling-Augustine Function &LLVMF = *M->getFunction("foo"); 1597840da2e8SSterling-Augustine sandboxir::Context Ctx(C); 1598840da2e8SSterling-Augustine auto &F = *Ctx.createFunction(&LLVMF); 1599840da2e8SSterling-Augustine auto *BB = &*F.begin(); 1600840da2e8SSterling-Augustine auto It = BB->begin(); 1601840da2e8SSterling-Augustine auto *FCmp = cast<sandboxir::CmpInst>(&*It++); 1602840da2e8SSterling-Augustine checkCmpInst(Ctx, FCmp); 1603840da2e8SSterling-Augustine auto *ICmp = cast<sandboxir::CmpInst>(&*It++); 1604840da2e8SSterling-Augustine checkCmpInst(Ctx, ICmp); 1605840da2e8SSterling-Augustine } 1606840da2e8SSterling-Augustine 16076d859c17Svporpo TEST_F(TrackerTest, GlobalValueSetters) { 16086d859c17Svporpo parseIR(C, R"IR( 16096d859c17Svporpo define void @foo() { 16106d859c17Svporpo call void @foo() 16116d859c17Svporpo ret void 16126d859c17Svporpo } 16136d859c17Svporpo )IR"); 16146d859c17Svporpo Function &LLVMF = *M->getFunction("foo"); 16156d859c17Svporpo sandboxir::Context Ctx(C); 16166d859c17Svporpo 16176d859c17Svporpo auto &F = *Ctx.createFunction(&LLVMF); 16186d859c17Svporpo auto *BB = &*F.begin(); 16196d859c17Svporpo auto *Call = cast<sandboxir::CallInst>(&*BB->begin()); 16206d859c17Svporpo 16216d859c17Svporpo auto *GV = cast<sandboxir::GlobalValue>(Call->getCalledOperand()); 16226d859c17Svporpo // Check setUnnamedAddr(). 16236d859c17Svporpo auto OrigUnnamedAddr = GV->getUnnamedAddr(); 16246d859c17Svporpo auto NewUnnamedAddr = sandboxir::GlobalValue::UnnamedAddr::Global; 16256d859c17Svporpo EXPECT_NE(NewUnnamedAddr, OrigUnnamedAddr); 16266d859c17Svporpo Ctx.save(); 16276d859c17Svporpo GV->setUnnamedAddr(NewUnnamedAddr); 16286d859c17Svporpo EXPECT_EQ(GV->getUnnamedAddr(), NewUnnamedAddr); 16296d859c17Svporpo Ctx.revert(); 16306d859c17Svporpo EXPECT_EQ(GV->getUnnamedAddr(), OrigUnnamedAddr); 16316d859c17Svporpo 16326d859c17Svporpo // Check setVisibility(). 16336d859c17Svporpo auto OrigVisibility = GV->getVisibility(); 16346d859c17Svporpo auto NewVisibility = 16356d859c17Svporpo sandboxir::GlobalValue::VisibilityTypes::ProtectedVisibility; 16366d859c17Svporpo EXPECT_NE(NewVisibility, OrigVisibility); 16376d859c17Svporpo Ctx.save(); 16386d859c17Svporpo GV->setVisibility(NewVisibility); 16396d859c17Svporpo EXPECT_EQ(GV->getVisibility(), NewVisibility); 16406d859c17Svporpo Ctx.revert(); 16416d859c17Svporpo EXPECT_EQ(GV->getVisibility(), OrigVisibility); 16426d859c17Svporpo } 16436d859c17Svporpo 1644ae3e8258Svporpo TEST_F(TrackerTest, GlobalIFuncSetters) { 1645ae3e8258Svporpo parseIR(C, R"IR( 1646ae3e8258Svporpo declare external void @bar() 1647ae3e8258Svporpo @ifunc = ifunc void(), ptr @foo 1648ae3e8258Svporpo define void @foo() { 1649ae3e8258Svporpo call void @ifunc() 1650ae3e8258Svporpo call void @bar() 1651ae3e8258Svporpo ret void 1652ae3e8258Svporpo } 1653ae3e8258Svporpo )IR"); 1654ae3e8258Svporpo Function &LLVMF = *M->getFunction("foo"); 1655ae3e8258Svporpo sandboxir::Context Ctx(C); 1656ae3e8258Svporpo 1657ae3e8258Svporpo auto &F = *Ctx.createFunction(&LLVMF); 1658ae3e8258Svporpo auto *BB = &*F.begin(); 1659ae3e8258Svporpo auto It = BB->begin(); 1660ae3e8258Svporpo auto *Call0 = cast<sandboxir::CallInst>(&*It++); 1661ae3e8258Svporpo auto *Call1 = cast<sandboxir::CallInst>(&*It++); 1662ae3e8258Svporpo // Check classof(), creation. 1663ae3e8258Svporpo auto *IFunc = cast<sandboxir::GlobalIFunc>(Call0->getCalledOperand()); 1664ae3e8258Svporpo auto *Bar = cast<sandboxir::Function>(Call1->getCalledOperand()); 1665ae3e8258Svporpo // Check setResolver(). 1666ae3e8258Svporpo auto *OrigResolver = IFunc->getResolver(); 1667ae3e8258Svporpo auto *NewResolver = Bar; 1668ae3e8258Svporpo EXPECT_NE(NewResolver, OrigResolver); 1669ae3e8258Svporpo Ctx.save(); 1670ae3e8258Svporpo IFunc->setResolver(NewResolver); 1671ae3e8258Svporpo EXPECT_EQ(IFunc->getResolver(), NewResolver); 1672ae3e8258Svporpo Ctx.revert(); 1673ae3e8258Svporpo EXPECT_EQ(IFunc->getResolver(), OrigResolver); 1674ae3e8258Svporpo } 1675ae3e8258Svporpo 1676b9bf831eSvporpo TEST_F(TrackerTest, GlobalVariableSetters) { 1677b9bf831eSvporpo parseIR(C, R"IR( 1678b9bf831eSvporpo @glob0 = global i32 42 1679b9bf831eSvporpo @glob1 = global i32 43 1680b9bf831eSvporpo define void @foo() { 1681b9bf831eSvporpo %ld0 = load i32, ptr @glob0 1682b9bf831eSvporpo %ld1 = load i32, ptr @glob1 1683b9bf831eSvporpo ret void 1684b9bf831eSvporpo } 1685b9bf831eSvporpo )IR"); 1686b9bf831eSvporpo Function &LLVMF = *M->getFunction("foo"); 1687b9bf831eSvporpo sandboxir::Context Ctx(C); 1688b9bf831eSvporpo 1689b9bf831eSvporpo auto &F = *Ctx.createFunction(&LLVMF); 1690b9bf831eSvporpo auto *BB = &*F.begin(); 1691b9bf831eSvporpo auto It = BB->begin(); 1692b9bf831eSvporpo auto *Ld0 = cast<sandboxir::LoadInst>(&*It++); 1693b9bf831eSvporpo auto *Ld1 = cast<sandboxir::LoadInst>(&*It++); 1694b9bf831eSvporpo // Check classof(), creation. 1695b9bf831eSvporpo auto *GV0 = cast<sandboxir::GlobalVariable>(Ld0->getPointerOperand()); 1696b9bf831eSvporpo auto *GV1 = cast<sandboxir::GlobalVariable>(Ld1->getPointerOperand()); 1697b9bf831eSvporpo // Check setInitializer(). 1698b9bf831eSvporpo auto *OrigInitializer = GV0->getInitializer(); 1699b9bf831eSvporpo auto *NewInitializer = GV1->getInitializer(); 1700b9bf831eSvporpo EXPECT_NE(NewInitializer, OrigInitializer); 1701b9bf831eSvporpo Ctx.save(); 1702b9bf831eSvporpo GV0->setInitializer(NewInitializer); 1703b9bf831eSvporpo EXPECT_EQ(GV0->getInitializer(), NewInitializer); 1704b9bf831eSvporpo Ctx.revert(); 1705b9bf831eSvporpo EXPECT_EQ(GV0->getInitializer(), OrigInitializer); 1706b9bf831eSvporpo // Check setConstant(). 1707b9bf831eSvporpo bool OrigIsConstant = GV0->isConstant(); 1708b9bf831eSvporpo bool NewIsConstant = !OrigIsConstant; 1709b9bf831eSvporpo Ctx.save(); 1710b9bf831eSvporpo GV0->setConstant(NewIsConstant); 1711b9bf831eSvporpo EXPECT_EQ(GV0->isConstant(), NewIsConstant); 1712b9bf831eSvporpo Ctx.revert(); 1713b9bf831eSvporpo EXPECT_EQ(GV0->isConstant(), OrigIsConstant); 1714b9bf831eSvporpo // Check setExternallyInitialized(). 1715b9bf831eSvporpo bool OrigIsExtInit = GV0->isExternallyInitialized(); 1716b9bf831eSvporpo bool NewIsExtInit = !OrigIsExtInit; 1717b9bf831eSvporpo Ctx.save(); 1718b9bf831eSvporpo GV0->setExternallyInitialized(NewIsExtInit); 1719b9bf831eSvporpo EXPECT_EQ(GV0->isExternallyInitialized(), NewIsExtInit); 1720b9bf831eSvporpo Ctx.revert(); 1721b9bf831eSvporpo EXPECT_EQ(GV0->isExternallyInitialized(), OrigIsExtInit); 1722b9bf831eSvporpo } 1723b9bf831eSvporpo 17249a312d47Svporpo TEST_F(TrackerTest, GlobalAliasSetters) { 17259a312d47Svporpo parseIR(C, R"IR( 17269a312d47Svporpo @alias = dso_local alias void(), ptr @foo 17279a312d47Svporpo declare void @bar(); 17289a312d47Svporpo define void @foo() { 17299a312d47Svporpo call void @alias() 17309a312d47Svporpo call void @bar() 17319a312d47Svporpo ret void 17329a312d47Svporpo } 17339a312d47Svporpo )IR"); 17349a312d47Svporpo Function &LLVMF = *M->getFunction("foo"); 17359a312d47Svporpo sandboxir::Context Ctx(C); 17369a312d47Svporpo 17379a312d47Svporpo auto &F = *Ctx.createFunction(&LLVMF); 17389a312d47Svporpo auto *BB = &*F.begin(); 17399a312d47Svporpo auto It = BB->begin(); 17409a312d47Svporpo auto *Call0 = cast<sandboxir::CallInst>(&*It++); 17419a312d47Svporpo auto *Call1 = cast<sandboxir::CallInst>(&*It++); 17429a312d47Svporpo auto *Callee1 = cast<sandboxir::Constant>(Call1->getCalledOperand()); 17439a312d47Svporpo auto *Alias = cast<sandboxir::GlobalAlias>(Call0->getCalledOperand()); 17449a312d47Svporpo // Check setAliasee(). 17459a312d47Svporpo auto *OrigAliasee = Alias->getAliasee(); 17469a312d47Svporpo auto *NewAliasee = Callee1; 17479a312d47Svporpo EXPECT_NE(NewAliasee, OrigAliasee); 17489a312d47Svporpo Ctx.save(); 17499a312d47Svporpo Alias->setAliasee(NewAliasee); 17509a312d47Svporpo EXPECT_EQ(Alias->getAliasee(), NewAliasee); 17519a312d47Svporpo Ctx.revert(); 17529a312d47Svporpo EXPECT_EQ(Alias->getAliasee(), OrigAliasee); 17539a312d47Svporpo } 17549a312d47Svporpo 175595b366caSJulius Alexandre TEST_F(TrackerTest, SetVolatile) { 175695b366caSJulius Alexandre parseIR(C, R"IR( 175795b366caSJulius Alexandre define void @foo(ptr %arg0, i8 %val) { 175895b366caSJulius Alexandre %ld = load i8, ptr %arg0, align 64 175995b366caSJulius Alexandre store i8 %val, ptr %arg0, align 64 176095b366caSJulius Alexandre ret void 176195b366caSJulius Alexandre } 176295b366caSJulius Alexandre )IR"); 176395b366caSJulius Alexandre Function &LLVMF = *M->getFunction("foo"); 176495b366caSJulius Alexandre sandboxir::Context Ctx(C); 176595b366caSJulius Alexandre 176695b366caSJulius Alexandre auto *F = Ctx.createFunction(&LLVMF); 176795b366caSJulius Alexandre auto *BB = &*F->begin(); 176895b366caSJulius Alexandre auto It = BB->begin(); 176995b366caSJulius Alexandre auto *Load = cast<sandboxir::LoadInst>(&*It++); 177095b366caSJulius Alexandre auto *Store = cast<sandboxir::StoreInst>(&*It++); 177195b366caSJulius Alexandre 177295b366caSJulius Alexandre EXPECT_FALSE(Load->isVolatile()); 177395b366caSJulius Alexandre Ctx.save(); 177495b366caSJulius Alexandre Load->setVolatile(true); 177595b366caSJulius Alexandre EXPECT_TRUE(Load->isVolatile()); 177695b366caSJulius Alexandre Ctx.revert(); 177795b366caSJulius Alexandre EXPECT_FALSE(Load->isVolatile()); 177895b366caSJulius Alexandre 177995b366caSJulius Alexandre EXPECT_FALSE(Store->isVolatile()); 178095b366caSJulius Alexandre Ctx.save(); 178195b366caSJulius Alexandre Store->setVolatile(true); 178295b366caSJulius Alexandre EXPECT_TRUE(Store->isVolatile()); 178395b366caSJulius Alexandre Ctx.revert(); 178495b366caSJulius Alexandre EXPECT_FALSE(Store->isVolatile()); 178595b366caSJulius Alexandre } 1786c4ae8b15Svporpo 1787c4ae8b15Svporpo TEST_F(TrackerTest, Flags) { 1788c4ae8b15Svporpo parseIR(C, R"IR( 1789c4ae8b15Svporpo define void @foo(i32 %arg, float %farg) { 1790c4ae8b15Svporpo %add = add i32 %arg, %arg 1791c4ae8b15Svporpo %fadd = fadd float %farg, %farg 1792c4ae8b15Svporpo %udiv = udiv i32 %arg, %arg 1793c4ae8b15Svporpo ret void 1794c4ae8b15Svporpo } 1795c4ae8b15Svporpo )IR"); 1796c4ae8b15Svporpo Function &LLVMF = *M->getFunction("foo"); 1797c4ae8b15Svporpo sandboxir::Context Ctx(C); 1798c4ae8b15Svporpo auto &F = *Ctx.createFunction(&LLVMF); 1799c4ae8b15Svporpo auto *BB = &*F.begin(); 1800c4ae8b15Svporpo auto It = BB->begin(); 1801c4ae8b15Svporpo auto *Add = &*It++; 1802c4ae8b15Svporpo auto *FAdd = &*It++; 1803c4ae8b15Svporpo auto *UDiv = &*It++; 1804c4ae8b15Svporpo 1805c4ae8b15Svporpo #define CHECK_FLAG(I, GETTER, SETTER) \ 1806c4ae8b15Svporpo { \ 1807c4ae8b15Svporpo Ctx.save(); \ 1808c4ae8b15Svporpo bool OrigFlag = I->GETTER(); \ 1809c4ae8b15Svporpo bool NewFlag = !OrigFlag; \ 1810c4ae8b15Svporpo I->SETTER(NewFlag); \ 1811c4ae8b15Svporpo EXPECT_EQ(I->GETTER(), NewFlag); \ 1812c4ae8b15Svporpo Ctx.revert(); \ 1813c4ae8b15Svporpo EXPECT_EQ(I->GETTER(), OrigFlag); \ 1814c4ae8b15Svporpo } 1815c4ae8b15Svporpo 1816c4ae8b15Svporpo CHECK_FLAG(Add, hasNoUnsignedWrap, setHasNoUnsignedWrap); 1817c4ae8b15Svporpo CHECK_FLAG(Add, hasNoSignedWrap, setHasNoSignedWrap); 1818c4ae8b15Svporpo CHECK_FLAG(FAdd, isFast, setFast); 1819c4ae8b15Svporpo CHECK_FLAG(FAdd, hasAllowReassoc, setHasAllowReassoc); 1820c4ae8b15Svporpo CHECK_FLAG(UDiv, isExact, setIsExact); 1821c4ae8b15Svporpo CHECK_FLAG(FAdd, hasNoNaNs, setHasNoNaNs); 1822c4ae8b15Svporpo CHECK_FLAG(FAdd, hasNoInfs, setHasNoInfs); 1823c4ae8b15Svporpo CHECK_FLAG(FAdd, hasNoSignedZeros, setHasNoSignedZeros); 1824c4ae8b15Svporpo CHECK_FLAG(FAdd, hasAllowReciprocal, setHasAllowReciprocal); 1825c4ae8b15Svporpo CHECK_FLAG(FAdd, hasAllowContract, setHasAllowContract); 1826c4ae8b15Svporpo CHECK_FLAG(FAdd, hasApproxFunc, setHasApproxFunc); 1827c4ae8b15Svporpo 1828c4ae8b15Svporpo // Check setFastMathFlags(). 1829c4ae8b15Svporpo FastMathFlags OrigFMF = FAdd->getFastMathFlags(); 1830c4ae8b15Svporpo FastMathFlags NewFMF; 1831c4ae8b15Svporpo NewFMF.setAllowReassoc(true); 1832c4ae8b15Svporpo EXPECT_TRUE(NewFMF != OrigFMF); 1833c4ae8b15Svporpo 1834c4ae8b15Svporpo Ctx.save(); 1835c4ae8b15Svporpo FAdd->setFastMathFlags(NewFMF); 1836c4ae8b15Svporpo EXPECT_FALSE(FAdd->getFastMathFlags() != NewFMF); 1837c4ae8b15Svporpo Ctx.revert(); 1838c4ae8b15Svporpo EXPECT_FALSE(FAdd->getFastMathFlags() != OrigFMF); 1839c4ae8b15Svporpo 1840c4ae8b15Svporpo // Check copyFastMathFlags(). 1841c4ae8b15Svporpo Ctx.save(); 1842c4ae8b15Svporpo FAdd->copyFastMathFlags(NewFMF); 1843c4ae8b15Svporpo EXPECT_FALSE(FAdd->getFastMathFlags() != NewFMF); 1844c4ae8b15Svporpo Ctx.revert(); 1845c4ae8b15Svporpo EXPECT_FALSE(FAdd->getFastMathFlags() != OrigFMF); 1846c4ae8b15Svporpo } 1847*3b8606beSJorge Gorbe Moya 1848*3b8606beSJorge Gorbe Moya // IRSnapshotChecker is only defined in debug mode. 1849*3b8606beSJorge Gorbe Moya #ifndef NDEBUG 1850*3b8606beSJorge Gorbe Moya 1851*3b8606beSJorge Gorbe Moya TEST_F(TrackerTest, IRSnapshotCheckerNoChanges) { 1852*3b8606beSJorge Gorbe Moya parseIR(C, R"IR( 1853*3b8606beSJorge Gorbe Moya define i32 @foo(i32 %arg) { 1854*3b8606beSJorge Gorbe Moya %add0 = add i32 %arg, %arg 1855*3b8606beSJorge Gorbe Moya ret i32 %add0 1856*3b8606beSJorge Gorbe Moya } 1857*3b8606beSJorge Gorbe Moya )IR"); 1858*3b8606beSJorge Gorbe Moya Function &LLVMF = *M->getFunction("foo"); 1859*3b8606beSJorge Gorbe Moya sandboxir::Context Ctx(C); 1860*3b8606beSJorge Gorbe Moya 1861*3b8606beSJorge Gorbe Moya [[maybe_unused]] auto *F = Ctx.createFunction(&LLVMF); 1862*3b8606beSJorge Gorbe Moya sandboxir::IRSnapshotChecker Checker(Ctx); 1863*3b8606beSJorge Gorbe Moya Checker.save(); 1864*3b8606beSJorge Gorbe Moya Checker.expectNoDiff(); 1865*3b8606beSJorge Gorbe Moya } 1866*3b8606beSJorge Gorbe Moya 1867*3b8606beSJorge Gorbe Moya TEST_F(TrackerTest, IRSnapshotCheckerDiesWithUnexpectedChanges) { 1868*3b8606beSJorge Gorbe Moya parseIR(C, R"IR( 1869*3b8606beSJorge Gorbe Moya define i32 @foo(i32 %arg) { 1870*3b8606beSJorge Gorbe Moya %add0 = add i32 %arg, %arg 1871*3b8606beSJorge Gorbe Moya %add1 = add i32 %add0, %arg 1872*3b8606beSJorge Gorbe Moya ret i32 %add1 1873*3b8606beSJorge Gorbe Moya } 1874*3b8606beSJorge Gorbe Moya )IR"); 1875*3b8606beSJorge Gorbe Moya Function &LLVMF = *M->getFunction("foo"); 1876*3b8606beSJorge Gorbe Moya sandboxir::Context Ctx(C); 1877*3b8606beSJorge Gorbe Moya 1878*3b8606beSJorge Gorbe Moya auto *F = Ctx.createFunction(&LLVMF); 1879*3b8606beSJorge Gorbe Moya auto *BB = &*F->begin(); 1880*3b8606beSJorge Gorbe Moya auto It = BB->begin(); 1881*3b8606beSJorge Gorbe Moya sandboxir::Instruction *Add0 = &*It++; 1882*3b8606beSJorge Gorbe Moya sandboxir::Instruction *Add1 = &*It++; 1883*3b8606beSJorge Gorbe Moya sandboxir::IRSnapshotChecker Checker(Ctx); 1884*3b8606beSJorge Gorbe Moya Checker.save(); 1885*3b8606beSJorge Gorbe Moya Add1->setOperand(1, Add0); 1886*3b8606beSJorge Gorbe Moya EXPECT_DEATH(Checker.expectNoDiff(), "Found IR difference"); 1887*3b8606beSJorge Gorbe Moya } 1888*3b8606beSJorge Gorbe Moya 1889*3b8606beSJorge Gorbe Moya TEST_F(TrackerTest, IRSnapshotCheckerSaveMultipleTimes) { 1890*3b8606beSJorge Gorbe Moya parseIR(C, R"IR( 1891*3b8606beSJorge Gorbe Moya define i32 @foo(i32 %arg) { 1892*3b8606beSJorge Gorbe Moya %add0 = add i32 %arg, %arg 1893*3b8606beSJorge Gorbe Moya %add1 = add i32 %add0, %arg 1894*3b8606beSJorge Gorbe Moya ret i32 %add1 1895*3b8606beSJorge Gorbe Moya } 1896*3b8606beSJorge Gorbe Moya )IR"); 1897*3b8606beSJorge Gorbe Moya Function &LLVMF = *M->getFunction("foo"); 1898*3b8606beSJorge Gorbe Moya sandboxir::Context Ctx(C); 1899*3b8606beSJorge Gorbe Moya 1900*3b8606beSJorge Gorbe Moya auto *F = Ctx.createFunction(&LLVMF); 1901*3b8606beSJorge Gorbe Moya auto *BB = &*F->begin(); 1902*3b8606beSJorge Gorbe Moya auto It = BB->begin(); 1903*3b8606beSJorge Gorbe Moya sandboxir::Instruction *Add0 = &*It++; 1904*3b8606beSJorge Gorbe Moya sandboxir::Instruction *Add1 = &*It++; 1905*3b8606beSJorge Gorbe Moya sandboxir::IRSnapshotChecker Checker(Ctx); 1906*3b8606beSJorge Gorbe Moya Checker.save(); 1907*3b8606beSJorge Gorbe Moya Add1->setOperand(1, Add0); 1908*3b8606beSJorge Gorbe Moya // Now IR differs from the last snapshot. Let's take a new snapshot. 1909*3b8606beSJorge Gorbe Moya Checker.save(); 1910*3b8606beSJorge Gorbe Moya // The new snapshot should have replaced the old one, so this should succeed. 1911*3b8606beSJorge Gorbe Moya Checker.expectNoDiff(); 1912*3b8606beSJorge Gorbe Moya } 1913*3b8606beSJorge Gorbe Moya 1914*3b8606beSJorge Gorbe Moya #endif // NDEBUG 1915