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