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