| //===- SandboxIRTest.cpp --------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/SandboxIR/SandboxIR.h" |
| #include "llvm/AsmParser/Parser.h" |
| #include "llvm/IR/BasicBlock.h" |
| #include "llvm/IR/DataLayout.h" |
| #include "llvm/IR/Function.h" |
| #include "llvm/IR/Instruction.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/Support/SourceMgr.h" |
| #include "gtest/gtest.h" |
| |
| using namespace llvm; |
| |
| struct SandboxIRTest : public testing::Test { |
| LLVMContext C; |
| std::unique_ptr<Module> M; |
| |
| void parseIR(LLVMContext &C, const char *IR) { |
| SMDiagnostic Err; |
| M = parseAssemblyString(IR, Err, C); |
| if (!M) |
| Err.print("SandboxIRTest", errs()); |
| } |
| BasicBlock *getBasicBlockByName(Function &F, StringRef Name) { |
| for (BasicBlock &BB : F) |
| if (BB.getName() == Name) |
| return &BB; |
| llvm_unreachable("Expected to find basic block!"); |
| } |
| }; |
| |
| TEST_F(SandboxIRTest, ClassID) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %v1) { |
| %add = add i32 %v1, 42 |
| ret void |
| } |
| )IR"); |
| llvm::Function *LLVMF = &*M->getFunction("foo"); |
| llvm::BasicBlock *LLVMBB = &*LLVMF->begin(); |
| llvm::Instruction *LLVMAdd = &*LLVMBB->begin(); |
| auto *LLVMC = cast<llvm::Constant>(LLVMAdd->getOperand(1)); |
| |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(LLVMF); |
| sandboxir::Argument *Arg0 = F->getArg(0); |
| sandboxir::BasicBlock *BB = &*F->begin(); |
| sandboxir::Instruction *AddI = &*BB->begin(); |
| sandboxir::OpaqueInst *OpaqueI = cast<sandboxir::OpaqueInst>(AddI); |
| sandboxir::Constant *Const0 = cast<sandboxir::Constant>(Ctx.getValue(LLVMC)); |
| |
| EXPECT_TRUE(isa<sandboxir::Function>(F)); |
| EXPECT_FALSE(isa<sandboxir::Function>(Arg0)); |
| EXPECT_FALSE(isa<sandboxir::Function>(BB)); |
| EXPECT_FALSE(isa<sandboxir::Function>(AddI)); |
| EXPECT_FALSE(isa<sandboxir::Function>(Const0)); |
| EXPECT_FALSE(isa<sandboxir::Function>(OpaqueI)); |
| |
| EXPECT_FALSE(isa<sandboxir::Argument>(F)); |
| EXPECT_TRUE(isa<sandboxir::Argument>(Arg0)); |
| EXPECT_FALSE(isa<sandboxir::Argument>(BB)); |
| EXPECT_FALSE(isa<sandboxir::Argument>(AddI)); |
| EXPECT_FALSE(isa<sandboxir::Argument>(Const0)); |
| EXPECT_FALSE(isa<sandboxir::Argument>(OpaqueI)); |
| |
| EXPECT_TRUE(isa<sandboxir::Constant>(F)); |
| EXPECT_FALSE(isa<sandboxir::Constant>(Arg0)); |
| EXPECT_FALSE(isa<sandboxir::Constant>(BB)); |
| EXPECT_FALSE(isa<sandboxir::Constant>(AddI)); |
| EXPECT_TRUE(isa<sandboxir::Constant>(Const0)); |
| EXPECT_FALSE(isa<sandboxir::Constant>(OpaqueI)); |
| |
| EXPECT_FALSE(isa<sandboxir::OpaqueInst>(F)); |
| EXPECT_FALSE(isa<sandboxir::OpaqueInst>(Arg0)); |
| EXPECT_FALSE(isa<sandboxir::OpaqueInst>(BB)); |
| EXPECT_TRUE(isa<sandboxir::OpaqueInst>(AddI)); |
| EXPECT_FALSE(isa<sandboxir::OpaqueInst>(Const0)); |
| EXPECT_TRUE(isa<sandboxir::OpaqueInst>(OpaqueI)); |
| |
| EXPECT_FALSE(isa<sandboxir::Instruction>(F)); |
| EXPECT_FALSE(isa<sandboxir::Instruction>(Arg0)); |
| EXPECT_FALSE(isa<sandboxir::Instruction>(BB)); |
| EXPECT_TRUE(isa<sandboxir::Instruction>(AddI)); |
| EXPECT_FALSE(isa<sandboxir::Instruction>(Const0)); |
| EXPECT_TRUE(isa<sandboxir::Instruction>(OpaqueI)); |
| |
| EXPECT_TRUE(isa<sandboxir::User>(F)); |
| EXPECT_FALSE(isa<sandboxir::User>(Arg0)); |
| EXPECT_FALSE(isa<sandboxir::User>(BB)); |
| EXPECT_TRUE(isa<sandboxir::User>(AddI)); |
| EXPECT_TRUE(isa<sandboxir::User>(Const0)); |
| EXPECT_TRUE(isa<sandboxir::User>(OpaqueI)); |
| |
| #ifndef NDEBUG |
| std::string Buff; |
| raw_string_ostream BS(Buff); |
| F->dump(BS); |
| Arg0->dump(BS); |
| BB->dump(BS); |
| AddI->dump(BS); |
| Const0->dump(BS); |
| OpaqueI->dump(BS); |
| #endif |
| } |
| |
| TEST_F(SandboxIRTest, Use) { |
| parseIR(C, R"IR( |
| define i32 @foo(i32 %v0, i32 %v1) { |
| %add0 = add i32 %v0, %v1 |
| ret i32 %add0 |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| |
| BasicBlock *LLVMBB = &*LLVMF.begin(); |
| auto LLVMBBIt = LLVMBB->begin(); |
| Instruction *LLVMI0 = &*LLVMBBIt++; |
| Instruction *LLVMRet = &*LLVMBBIt++; |
| Argument *LLVMArg0 = LLVMF.getArg(0); |
| Argument *LLVMArg1 = LLVMF.getArg(1); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto &BB = *F.begin(); |
| auto *Arg0 = F.getArg(0); |
| auto *Arg1 = F.getArg(1); |
| auto It = BB.begin(); |
| auto *I0 = &*It++; |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| SmallVector<sandboxir::Argument *> Args{Arg0, Arg1}; |
| unsigned OpIdx = 0; |
| for (sandboxir::Use Use : I0->operands()) { |
| // Check Use.getOperandNo(). |
| EXPECT_EQ(Use.getOperandNo(), OpIdx); |
| // Check Use.getUser(). |
| EXPECT_EQ(Use.getUser(), I0); |
| // Check Use.getContext(). |
| EXPECT_EQ(Use.getContext(), &Ctx); |
| // Check Use.get(). |
| sandboxir::Value *Op = Use.get(); |
| EXPECT_EQ(Op, Ctx.getValue(LLVMI0->getOperand(OpIdx))); |
| // Check Use.getUser(). |
| EXPECT_EQ(Use.getUser(), I0); |
| // Check implicit cast to Value. |
| sandboxir::Value *Cast = Use; |
| EXPECT_EQ(Cast, Op); |
| // Check that Use points to the correct operand. |
| EXPECT_EQ(Op, Args[OpIdx]); |
| // Check getOperand(). |
| EXPECT_EQ(Op, I0->getOperand(OpIdx)); |
| // Check getOperandUse(). |
| EXPECT_EQ(Use, I0->getOperandUse(OpIdx)); |
| ++OpIdx; |
| } |
| EXPECT_EQ(OpIdx, 2u); |
| |
| // Check Use.operator==() and Use.operator!=(). |
| sandboxir::Use UseA = I0->getOperandUse(0); |
| sandboxir::Use UseB = I0->getOperandUse(0); |
| EXPECT_TRUE(UseA == UseB); |
| EXPECT_FALSE(UseA != UseB); |
| |
| // Check getNumOperands(). |
| EXPECT_EQ(I0->getNumOperands(), 2u); |
| EXPECT_EQ(Ret->getNumOperands(), 1u); |
| |
| EXPECT_EQ(Ret->getOperand(0), I0); |
| |
| #ifndef NDEBUG |
| // Check Use.dump() |
| std::string Buff; |
| raw_string_ostream BS(Buff); |
| BS << "\n"; |
| I0->getOperandUse(0).dump(BS); |
| EXPECT_EQ(Buff, R"IR( |
| Def: i32 %v0 ; SB2. (Argument) |
| User: %add0 = add i32 %v0, %v1 ; SB5. (Opaque) |
| OperandNo: 0 |
| )IR"); |
| #endif // NDEBUG |
| |
| // Check Value.user_begin(). |
| sandboxir::Value::user_iterator UIt = I0->user_begin(); |
| sandboxir::User *U = *UIt; |
| EXPECT_EQ(U, Ret); |
| // Check Value.uses(). |
| EXPECT_EQ(range_size(I0->uses()), 1u); |
| EXPECT_EQ((*I0->uses().begin()).getUser(), Ret); |
| // Check Value.users(). |
| EXPECT_EQ(range_size(I0->users()), 1u); |
| EXPECT_EQ(*I0->users().begin(), Ret); |
| // Check Value.getNumUses(). |
| EXPECT_EQ(I0->getNumUses(), 1u); |
| // Check Value.hasNUsesOrMore(). |
| EXPECT_TRUE(I0->hasNUsesOrMore(0u)); |
| EXPECT_TRUE(I0->hasNUsesOrMore(1u)); |
| EXPECT_FALSE(I0->hasNUsesOrMore(2u)); |
| // Check Value.hasNUses(). |
| EXPECT_FALSE(I0->hasNUses(0u)); |
| EXPECT_TRUE(I0->hasNUses(1u)); |
| EXPECT_FALSE(I0->hasNUses(2u)); |
| |
| // Check User.setOperand(). |
| Ret->setOperand(0, Arg0); |
| EXPECT_EQ(Ret->getOperand(0), Arg0); |
| EXPECT_EQ(Ret->getOperandUse(0).get(), Arg0); |
| EXPECT_EQ(LLVMRet->getOperand(0), LLVMArg0); |
| |
| Ret->setOperand(0, Arg1); |
| EXPECT_EQ(Ret->getOperand(0), Arg1); |
| EXPECT_EQ(Ret->getOperandUse(0).get(), Arg1); |
| EXPECT_EQ(LLVMRet->getOperand(0), LLVMArg1); |
| } |
| |
| TEST_F(SandboxIRTest, RUOW) { |
| parseIR(C, R"IR( |
| declare void @bar0() |
| declare void @bar1() |
| |
| @glob0 = global ptr @bar0 |
| @glob1 = global ptr @bar1 |
| |
| define i32 @foo(i32 %arg0, i32 %arg1) { |
| %add0 = add i32 %arg0, %arg1 |
| %gep1 = getelementptr i8, ptr @glob0, i32 1 |
| %gep2 = getelementptr i8, ptr @glob1, i32 1 |
| ret i32 %add0 |
| } |
| )IR"); |
| llvm::Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto &BB = *F.begin(); |
| auto *Arg0 = F.getArg(0); |
| auto *Arg1 = F.getArg(1); |
| auto It = BB.begin(); |
| auto *I0 = &*It++; |
| auto *I1 = &*It++; |
| auto *I2 = &*It++; |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| bool Replaced; |
| // Try to replace an operand that doesn't match. |
| Replaced = I0->replaceUsesOfWith(Ret, Arg1); |
| EXPECT_FALSE(Replaced); |
| EXPECT_EQ(I0->getOperand(0), Arg0); |
| EXPECT_EQ(I0->getOperand(1), Arg1); |
| |
| // Replace I0 operands when operands differ. |
| Replaced = I0->replaceUsesOfWith(Arg0, Arg1); |
| EXPECT_TRUE(Replaced); |
| EXPECT_EQ(I0->getOperand(0), Arg1); |
| EXPECT_EQ(I0->getOperand(1), Arg1); |
| |
| // Replace I0 operands when operands are the same. |
| Replaced = I0->replaceUsesOfWith(Arg1, Arg0); |
| EXPECT_TRUE(Replaced); |
| EXPECT_EQ(I0->getOperand(0), Arg0); |
| EXPECT_EQ(I0->getOperand(1), Arg0); |
| |
| // Replace Ret operand. |
| Replaced = Ret->replaceUsesOfWith(I0, Arg0); |
| EXPECT_TRUE(Replaced); |
| EXPECT_EQ(Ret->getOperand(0), Arg0); |
| |
| // Check RAUW on constant. |
| auto *Glob0 = cast<sandboxir::Constant>(I1->getOperand(0)); |
| auto *Glob1 = cast<sandboxir::Constant>(I2->getOperand(0)); |
| auto *Glob0Op = Glob0->getOperand(0); |
| Glob0->replaceUsesOfWith(Glob0Op, Glob1); |
| EXPECT_EQ(Glob0->getOperand(0), Glob1); |
| } |
| |
| TEST_F(SandboxIRTest, RAUW_RUWIf) { |
| parseIR(C, R"IR( |
| define void @foo(ptr %ptr) { |
| %ld0 = load float, ptr %ptr |
| %ld1 = load float, ptr %ptr |
| store float %ld0, ptr %ptr |
| store float %ld0, ptr %ptr |
| ret void |
| } |
| )IR"); |
| llvm::Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| llvm::BasicBlock *LLVMBB = &*LLVMF.begin(); |
| |
| Ctx.createFunction(&LLVMF); |
| auto *BB = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMBB)); |
| auto It = BB->begin(); |
| sandboxir::Instruction *Ld0 = &*It++; |
| sandboxir::Instruction *Ld1 = &*It++; |
| sandboxir::Instruction *St0 = &*It++; |
| sandboxir::Instruction *St1 = &*It++; |
| // Check RUWIf when the lambda returns false. |
| Ld0->replaceUsesWithIf(Ld1, [](const sandboxir::Use &Use) { return false; }); |
| EXPECT_EQ(St0->getOperand(0), Ld0); |
| EXPECT_EQ(St1->getOperand(0), Ld0); |
| // Check RUWIf when the lambda returns true. |
| Ld0->replaceUsesWithIf(Ld1, [](const sandboxir::Use &Use) { return true; }); |
| EXPECT_EQ(St0->getOperand(0), Ld1); |
| EXPECT_EQ(St1->getOperand(0), Ld1); |
| St0->setOperand(0, Ld0); |
| St1->setOperand(0, Ld0); |
| // Check RUWIf user == St0. |
| Ld0->replaceUsesWithIf( |
| Ld1, [St0](const sandboxir::Use &Use) { return Use.getUser() == St0; }); |
| EXPECT_EQ(St0->getOperand(0), Ld1); |
| EXPECT_EQ(St1->getOperand(0), Ld0); |
| St0->setOperand(0, Ld0); |
| // Check RUWIf user == St1. |
| Ld0->replaceUsesWithIf( |
| Ld1, [St1](const sandboxir::Use &Use) { return Use.getUser() == St1; }); |
| EXPECT_EQ(St0->getOperand(0), Ld0); |
| EXPECT_EQ(St1->getOperand(0), Ld1); |
| St1->setOperand(0, Ld0); |
| // Check RAUW. |
| Ld1->replaceAllUsesWith(Ld0); |
| EXPECT_EQ(St0->getOperand(0), Ld0); |
| EXPECT_EQ(St1->getOperand(0), Ld0); |
| } |
| |
| // Check that the operands/users are counted correctly. |
| // I1 |
| // / \ |
| // \ / |
| // I2 |
| TEST_F(SandboxIRTest, DuplicateUses) { |
| parseIR(C, R"IR( |
| define void @foo(i8 %v) { |
| %I1 = add i8 %v, %v |
| %I2 = add i8 %I1, %I1 |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| auto *F = Ctx.createFunction(&LLVMF); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| auto *I1 = &*It++; |
| auto *I2 = &*It++; |
| EXPECT_EQ(range_size(I1->users()), 2u); |
| EXPECT_EQ(range_size(I2->operands()), 2u); |
| } |
| |
| TEST_F(SandboxIRTest, Function) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %arg0, i32 %arg1) { |
| bb0: |
| br label %bb1 |
| bb1: |
| ret void |
| } |
| )IR"); |
| llvm::Function *LLVMF = &*M->getFunction("foo"); |
| llvm::Argument *LLVMArg0 = LLVMF->getArg(0); |
| llvm::Argument *LLVMArg1 = LLVMF->getArg(1); |
| |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(LLVMF); |
| |
| // Check F arguments |
| EXPECT_EQ(F->arg_size(), 2u); |
| EXPECT_FALSE(F->arg_empty()); |
| EXPECT_EQ(F->getArg(0), Ctx.getValue(LLVMArg0)); |
| EXPECT_EQ(F->getArg(1), Ctx.getValue(LLVMArg1)); |
| |
| // Check F.begin(), F.end(), Function::iterator |
| llvm::BasicBlock *LLVMBB = &*LLVMF->begin(); |
| for (sandboxir::BasicBlock &BB : *F) { |
| EXPECT_EQ(&BB, Ctx.getValue(LLVMBB)); |
| LLVMBB = LLVMBB->getNextNode(); |
| } |
| |
| #ifndef NDEBUG |
| { |
| // Check F.dumpNameAndArgs() |
| std::string Buff; |
| raw_string_ostream BS(Buff); |
| F->dumpNameAndArgs(BS); |
| EXPECT_EQ(Buff, "void @foo(i32 %arg0, i32 %arg1)"); |
| } |
| { |
| // Check F.dump() |
| std::string Buff; |
| raw_string_ostream BS(Buff); |
| BS << "\n"; |
| F->dump(BS); |
| EXPECT_EQ(Buff, R"IR( |
| void @foo(i32 %arg0, i32 %arg1) { |
| bb0: |
| br label %bb1 ; SB4. (Br) |
| |
| bb1: |
| ret void ; SB6. (Ret) |
| } |
| )IR"); |
| } |
| #endif // NDEBUG |
| } |
| |
| TEST_F(SandboxIRTest, BasicBlock) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %v1) { |
| bb0: |
| br label %bb1 |
| bb1: |
| ret void |
| } |
| )IR"); |
| llvm::Function *LLVMF = &*M->getFunction("foo"); |
| llvm::BasicBlock *LLVMBB0 = getBasicBlockByName(*LLVMF, "bb0"); |
| llvm::BasicBlock *LLVMBB1 = getBasicBlockByName(*LLVMF, "bb1"); |
| |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(LLVMF); |
| auto &BB0 = cast<sandboxir::BasicBlock>(*Ctx.getValue(LLVMBB0)); |
| auto &BB1 = cast<sandboxir::BasicBlock>(*Ctx.getValue(LLVMBB1)); |
| |
| // Check BB::classof() |
| EXPECT_TRUE(isa<sandboxir::Value>(BB0)); |
| EXPECT_FALSE(isa<sandboxir::User>(BB0)); |
| EXPECT_FALSE(isa<sandboxir::Instruction>(BB0)); |
| EXPECT_FALSE(isa<sandboxir::Constant>(BB0)); |
| EXPECT_FALSE(isa<sandboxir::Argument>(BB0)); |
| |
| // Check BB.getParent() |
| EXPECT_EQ(BB0.getParent(), F); |
| EXPECT_EQ(BB1.getParent(), F); |
| |
| // Check BBIterator, BB.begin(), BB.end(). |
| llvm::Instruction *LLVMI = &*LLVMBB0->begin(); |
| for (sandboxir::Instruction &I : BB0) { |
| EXPECT_EQ(&I, Ctx.getValue(LLVMI)); |
| LLVMI = LLVMI->getNextNode(); |
| } |
| LLVMI = &*LLVMBB1->begin(); |
| for (sandboxir::Instruction &I : BB1) { |
| EXPECT_EQ(&I, Ctx.getValue(LLVMI)); |
| LLVMI = LLVMI->getNextNode(); |
| } |
| |
| // Check BB.getTerminator() |
| EXPECT_EQ(BB0.getTerminator(), Ctx.getValue(LLVMBB0->getTerminator())); |
| EXPECT_EQ(BB1.getTerminator(), Ctx.getValue(LLVMBB1->getTerminator())); |
| |
| // Check BB.rbegin(), BB.rend() |
| EXPECT_EQ(&*BB0.rbegin(), BB0.getTerminator()); |
| EXPECT_EQ(&*std::prev(BB0.rend()), &*BB0.begin()); |
| |
| #ifndef NDEBUG |
| { |
| // Check BB.dump() |
| std::string Buff; |
| raw_string_ostream BS(Buff); |
| BS << "\n"; |
| BB0.dump(BS); |
| EXPECT_EQ(Buff, R"IR( |
| bb0: |
| br label %bb1 ; SB3. (Br) |
| )IR"); |
| } |
| #endif // NDEBUG |
| } |
| |
| TEST_F(SandboxIRTest, Instruction) { |
| parseIR(C, R"IR( |
| define void @foo(i8 %v1) { |
| %add0 = add i8 %v1, %v1 |
| %sub1 = sub i8 %add0, %v1 |
| ret void |
| } |
| )IR"); |
| llvm::Function *LLVMF = &*M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(LLVMF); |
| auto *Arg = F->getArg(0); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| auto *I0 = &*It++; |
| auto *I1 = &*It++; |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| // Check getPrevNode(). |
| EXPECT_EQ(Ret->getPrevNode(), I1); |
| EXPECT_EQ(I1->getPrevNode(), I0); |
| EXPECT_EQ(I0->getPrevNode(), nullptr); |
| |
| // Check getNextNode(). |
| EXPECT_EQ(I0->getNextNode(), I1); |
| EXPECT_EQ(I1->getNextNode(), Ret); |
| EXPECT_EQ(Ret->getNextNode(), nullptr); |
| |
| // Check getIterator(). |
| EXPECT_EQ(I0->getIterator(), std::next(BB->begin(), 0)); |
| EXPECT_EQ(I1->getIterator(), std::next(BB->begin(), 1)); |
| EXPECT_EQ(Ret->getIterator(), std::next(BB->begin(), 2)); |
| |
| // Check getOpcode(). |
| EXPECT_EQ(I0->getOpcode(), sandboxir::Instruction::Opcode::Opaque); |
| EXPECT_EQ(I1->getOpcode(), sandboxir::Instruction::Opcode::Opaque); |
| EXPECT_EQ(Ret->getOpcode(), sandboxir::Instruction::Opcode::Ret); |
| |
| // Check moveBefore(I). |
| I1->moveBefore(I0); |
| EXPECT_EQ(I0->getPrevNode(), I1); |
| EXPECT_EQ(I1->getNextNode(), I0); |
| |
| // Check moveAfter(I). |
| I1->moveAfter(I0); |
| EXPECT_EQ(I0->getNextNode(), I1); |
| EXPECT_EQ(I1->getPrevNode(), I0); |
| |
| // Check moveBefore(BB, It). |
| I1->moveBefore(*BB, BB->begin()); |
| EXPECT_EQ(I1->getPrevNode(), nullptr); |
| EXPECT_EQ(I1->getNextNode(), I0); |
| I1->moveBefore(*BB, BB->end()); |
| EXPECT_EQ(I1->getNextNode(), nullptr); |
| EXPECT_EQ(Ret->getNextNode(), I1); |
| I1->moveBefore(*BB, std::next(BB->begin())); |
| EXPECT_EQ(I0->getNextNode(), I1); |
| EXPECT_EQ(I1->getNextNode(), Ret); |
| |
| // Check removeFromParent(). |
| I0->removeFromParent(); |
| #ifndef NDEBUG |
| EXPECT_DEATH(I0->getPrevNode(), ".*Detached.*"); |
| EXPECT_DEATH(I0->getNextNode(), ".*Detached.*"); |
| #endif // NDEBUG |
| EXPECT_EQ(I0->getParent(), nullptr); |
| EXPECT_EQ(I1->getPrevNode(), nullptr); |
| EXPECT_EQ(I0->getOperand(0), Arg); |
| |
| // Check insertBefore(). |
| I0->insertBefore(I1); |
| EXPECT_EQ(I1->getPrevNode(), I0); |
| |
| // Check insertInto(). |
| I0->removeFromParent(); |
| I0->insertInto(BB, BB->end()); |
| EXPECT_EQ(Ret->getNextNode(), I0); |
| I0->moveBefore(I1); |
| EXPECT_EQ(I0->getNextNode(), I1); |
| |
| // Check eraseFromParent(). |
| #ifndef NDEBUG |
| EXPECT_DEATH(I0->eraseFromParent(), "Still connected to users.*"); |
| #endif |
| I1->eraseFromParent(); |
| EXPECT_EQ(I0->getNumUses(), 0u); |
| EXPECT_EQ(I0->getNextNode(), Ret); |
| } |
| |
| TEST_F(SandboxIRTest, SelectInst) { |
| parseIR(C, R"IR( |
| define void @foo(i1 %c0, i8 %v0, i8 %v1, i1 %c1) { |
| %sel = select i1 %c0, i8 %v0, i8 %v1 |
| ret void |
| } |
| )IR"); |
| llvm::Function *LLVMF = &*M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(LLVMF); |
| auto *Cond0 = F->getArg(0); |
| auto *V0 = F->getArg(1); |
| auto *V1 = F->getArg(2); |
| auto *Cond1 = F->getArg(3); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| auto *Select = cast<sandboxir::SelectInst>(&*It++); |
| auto *Ret = &*It++; |
| |
| // Check getCondition(). |
| EXPECT_EQ(Select->getCondition(), Cond0); |
| // Check getTrueValue(). |
| EXPECT_EQ(Select->getTrueValue(), V0); |
| // Check getFalseValue(). |
| EXPECT_EQ(Select->getFalseValue(), V1); |
| // Check setCondition(). |
| Select->setCondition(Cond1); |
| EXPECT_EQ(Select->getCondition(), Cond1); |
| // Check setTrueValue(). |
| Select->setTrueValue(V1); |
| EXPECT_EQ(Select->getTrueValue(), V1); |
| // Check setFalseValue(). |
| Select->setFalseValue(V0); |
| EXPECT_EQ(Select->getFalseValue(), V0); |
| |
| { |
| // Check SelectInst::create() InsertBefore. |
| auto *NewSel = cast<sandboxir::SelectInst>(sandboxir::SelectInst::create( |
| Cond0, V0, V1, /*InsertBefore=*/Ret, Ctx)); |
| EXPECT_EQ(NewSel->getCondition(), Cond0); |
| EXPECT_EQ(NewSel->getTrueValue(), V0); |
| EXPECT_EQ(NewSel->getFalseValue(), V1); |
| EXPECT_EQ(NewSel->getNextNode(), Ret); |
| } |
| { |
| // Check SelectInst::create() InsertAtEnd. |
| auto *NewSel = cast<sandboxir::SelectInst>( |
| sandboxir::SelectInst::create(Cond0, V0, V1, /*InsertAtEnd=*/BB, Ctx)); |
| EXPECT_EQ(NewSel->getCondition(), Cond0); |
| EXPECT_EQ(NewSel->getTrueValue(), V0); |
| EXPECT_EQ(NewSel->getFalseValue(), V1); |
| EXPECT_EQ(NewSel->getPrevNode(), Ret); |
| } |
| { |
| // Check SelectInst::create() Folded. |
| auto *False = |
| sandboxir::Constant::createInt(llvm::Type::getInt1Ty(C), 0, Ctx, |
| /*IsSigned=*/false); |
| auto *FortyTwo = |
| sandboxir::Constant::createInt(llvm::Type::getInt1Ty(C), 42, Ctx, |
| /*IsSigned=*/false); |
| auto *NewSel = |
| sandboxir::SelectInst::create(False, FortyTwo, FortyTwo, Ret, Ctx); |
| EXPECT_TRUE(isa<sandboxir::Constant>(NewSel)); |
| EXPECT_EQ(NewSel, FortyTwo); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, BranchInst) { |
| parseIR(C, R"IR( |
| define void @foo(i1 %cond0, i1 %cond2) { |
| bb0: |
| br i1 %cond0, label %bb1, label %bb2 |
| bb1: |
| ret void |
| bb2: |
| ret void |
| } |
| )IR"); |
| llvm::Function *LLVMF = &*M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(LLVMF); |
| auto *Cond0 = F->getArg(0); |
| auto *Cond1 = F->getArg(1); |
| auto *BB0 = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(*LLVMF, "bb0"))); |
| auto *BB1 = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(*LLVMF, "bb1"))); |
| auto *Ret1 = BB1->getTerminator(); |
| auto *BB2 = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(*LLVMF, "bb2"))); |
| auto *Ret2 = BB2->getTerminator(); |
| auto It = BB0->begin(); |
| auto *Br0 = cast<sandboxir::BranchInst>(&*It++); |
| // Check isUnconditional(). |
| EXPECT_FALSE(Br0->isUnconditional()); |
| // Check isConditional(). |
| EXPECT_TRUE(Br0->isConditional()); |
| // Check getCondition(). |
| EXPECT_EQ(Br0->getCondition(), Cond0); |
| // Check setCondition(). |
| Br0->setCondition(Cond1); |
| EXPECT_EQ(Br0->getCondition(), Cond1); |
| // Check getNumSuccessors(). |
| EXPECT_EQ(Br0->getNumSuccessors(), 2u); |
| // Check getSuccessor(). |
| EXPECT_EQ(Br0->getSuccessor(0), BB1); |
| EXPECT_EQ(Br0->getSuccessor(1), BB2); |
| // Check swapSuccessors(). |
| Br0->swapSuccessors(); |
| EXPECT_EQ(Br0->getSuccessor(0), BB2); |
| EXPECT_EQ(Br0->getSuccessor(1), BB1); |
| // Check successors(). |
| EXPECT_EQ(range_size(Br0->successors()), 2u); |
| unsigned SuccIdx = 0; |
| SmallVector<sandboxir::BasicBlock *> ExpectedSuccs({BB1, BB2}); |
| for (sandboxir::BasicBlock *Succ : Br0->successors()) |
| EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]); |
| |
| { |
| // Check unconditional BranchInst::create() InsertBefore. |
| auto *Br = sandboxir::BranchInst::create(BB1, /*InsertBefore=*/Ret1, Ctx); |
| EXPECT_FALSE(Br->isConditional()); |
| EXPECT_TRUE(Br->isUnconditional()); |
| #ifndef NDEBUG |
| EXPECT_DEATH(Br->getCondition(), ".*condition.*"); |
| #endif // NDEBUG |
| unsigned SuccIdx = 0; |
| SmallVector<sandboxir::BasicBlock *> ExpectedSuccs({BB1}); |
| for (sandboxir::BasicBlock *Succ : Br->successors()) |
| EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]); |
| EXPECT_EQ(Br->getNextNode(), Ret1); |
| } |
| { |
| // Check unconditional BranchInst::create() InsertAtEnd. |
| auto *Br = sandboxir::BranchInst::create(BB1, /*InsertAtEnd=*/BB1, Ctx); |
| EXPECT_FALSE(Br->isConditional()); |
| EXPECT_TRUE(Br->isUnconditional()); |
| #ifndef NDEBUG |
| EXPECT_DEATH(Br->getCondition(), ".*condition.*"); |
| #endif // NDEBUG |
| unsigned SuccIdx = 0; |
| SmallVector<sandboxir::BasicBlock *> ExpectedSuccs({BB1}); |
| for (sandboxir::BasicBlock *Succ : Br->successors()) |
| EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]); |
| EXPECT_EQ(Br->getPrevNode(), Ret1); |
| } |
| { |
| // Check conditional BranchInst::create() InsertBefore. |
| auto *Br = sandboxir::BranchInst::create(BB1, BB2, Cond0, |
| /*InsertBefore=*/Ret1, Ctx); |
| EXPECT_TRUE(Br->isConditional()); |
| EXPECT_EQ(Br->getCondition(), Cond0); |
| unsigned SuccIdx = 0; |
| SmallVector<sandboxir::BasicBlock *> ExpectedSuccs({BB2, BB1}); |
| for (sandboxir::BasicBlock *Succ : Br->successors()) |
| EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]); |
| EXPECT_EQ(Br->getNextNode(), Ret1); |
| } |
| { |
| // Check conditional BranchInst::create() InsertAtEnd. |
| auto *Br = sandboxir::BranchInst::create(BB1, BB2, Cond0, |
| /*InsertAtEnd=*/BB2, Ctx); |
| EXPECT_TRUE(Br->isConditional()); |
| EXPECT_EQ(Br->getCondition(), Cond0); |
| unsigned SuccIdx = 0; |
| SmallVector<sandboxir::BasicBlock *> ExpectedSuccs({BB2, BB1}); |
| for (sandboxir::BasicBlock *Succ : Br->successors()) |
| EXPECT_EQ(Succ, ExpectedSuccs[SuccIdx++]); |
| EXPECT_EQ(Br->getPrevNode(), Ret2); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, LoadInst) { |
| parseIR(C, R"IR( |
| define void @foo(ptr %arg0, ptr %arg1) { |
| %ld = load i8, ptr %arg0, align 64 |
| %vld = load volatile i8, ptr %arg0, align 64 |
| ret void |
| } |
| )IR"); |
| llvm::Function *LLVMF = &*M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(LLVMF); |
| auto *Arg0 = F->getArg(0); |
| auto *Arg1 = F->getArg(1); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| auto *Ld = cast<sandboxir::LoadInst>(&*It++); |
| auto *VLd = cast<sandboxir::LoadInst>(&*It++); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| // Check isVolatile() |
| EXPECT_FALSE(Ld->isVolatile()); |
| // Check isVolatile() |
| EXPECT_TRUE(VLd->isVolatile()); |
| // Check getPointerOperand() |
| EXPECT_EQ(Ld->getPointerOperand(), Arg0); |
| // Check getAlign() |
| EXPECT_EQ(Ld->getAlign(), 64); |
| // Check create(InsertBefore) |
| sandboxir::LoadInst *NewLd = |
| sandboxir::LoadInst::create(Ld->getType(), Arg1, Align(8), |
| /*InsertBefore=*/Ret, Ctx, "NewLd"); |
| EXPECT_FALSE(NewLd->isVolatile()); |
| EXPECT_EQ(NewLd->getType(), Ld->getType()); |
| EXPECT_EQ(NewLd->getPointerOperand(), Arg1); |
| EXPECT_EQ(NewLd->getAlign(), 8); |
| EXPECT_EQ(NewLd->getName(), "NewLd"); |
| // Check create(InsertBefore, IsVolatile=true) |
| sandboxir::LoadInst *NewVLd = |
| sandboxir::LoadInst::create(VLd->getType(), Arg1, Align(8), |
| /*InsertBefore=*/Ret, |
| /*IsVolatile=*/true, Ctx, "NewVLd"); |
| |
| EXPECT_TRUE(NewVLd->isVolatile()); |
| EXPECT_EQ(NewVLd->getName(), "NewVLd"); |
| // Check create(InsertAtEnd) |
| sandboxir::LoadInst *NewLdEnd = |
| sandboxir::LoadInst::create(Ld->getType(), Arg1, Align(8), |
| /*InsertAtEnd=*/BB, Ctx, "NewLdEnd"); |
| EXPECT_FALSE(NewLdEnd->isVolatile()); |
| EXPECT_EQ(NewLdEnd->getName(), "NewLdEnd"); |
| EXPECT_EQ(NewLdEnd->getType(), Ld->getType()); |
| EXPECT_EQ(NewLdEnd->getPointerOperand(), Arg1); |
| EXPECT_EQ(NewLdEnd->getAlign(), 8); |
| EXPECT_EQ(NewLdEnd->getParent(), BB); |
| EXPECT_EQ(NewLdEnd->getNextNode(), nullptr); |
| // Check create(InsertAtEnd, IsVolatile=true) |
| sandboxir::LoadInst *NewVLdEnd = |
| sandboxir::LoadInst::create(VLd->getType(), Arg1, Align(8), |
| /*InsertAtEnd=*/BB, |
| /*IsVolatile=*/true, Ctx, "NewVLdEnd"); |
| EXPECT_TRUE(NewVLdEnd->isVolatile()); |
| EXPECT_EQ(NewVLdEnd->getName(), "NewVLdEnd"); |
| EXPECT_EQ(NewVLdEnd->getType(), VLd->getType()); |
| EXPECT_EQ(NewVLdEnd->getPointerOperand(), Arg1); |
| EXPECT_EQ(NewVLdEnd->getAlign(), 8); |
| EXPECT_EQ(NewVLdEnd->getParent(), BB); |
| EXPECT_EQ(NewVLdEnd->getNextNode(), nullptr); |
| } |
| |
| TEST_F(SandboxIRTest, StoreInst) { |
| parseIR(C, R"IR( |
| define void @foo(i8 %val, ptr %ptr) { |
| store i8 %val, ptr %ptr, align 64 |
| store volatile i8 %val, ptr %ptr, align 64 |
| ret void |
| } |
| )IR"); |
| llvm::Function *LLVMF = &*M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(LLVMF); |
| auto *Val = F->getArg(0); |
| auto *Ptr = F->getArg(1); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| auto *St = cast<sandboxir::StoreInst>(&*It++); |
| auto *VSt = cast<sandboxir::StoreInst>(&*It++); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| // Check that the StoreInst has been created correctly. |
| EXPECT_FALSE(St->isVolatile()); |
| EXPECT_TRUE(VSt->isVolatile()); |
| // Check getPointerOperand() |
| EXPECT_EQ(St->getValueOperand(), Val); |
| EXPECT_EQ(St->getPointerOperand(), Ptr); |
| // Check getAlign() |
| EXPECT_EQ(St->getAlign(), 64); |
| // Check create(InsertBefore) |
| sandboxir::StoreInst *NewSt = |
| sandboxir::StoreInst::create(Val, Ptr, Align(8), |
| /*InsertBefore=*/Ret, Ctx); |
| EXPECT_FALSE(NewSt->isVolatile()); |
| EXPECT_EQ(NewSt->getType(), St->getType()); |
| EXPECT_EQ(NewSt->getValueOperand(), Val); |
| EXPECT_EQ(NewSt->getPointerOperand(), Ptr); |
| EXPECT_EQ(NewSt->getAlign(), 8); |
| EXPECT_EQ(NewSt->getNextNode(), Ret); |
| // Check create(InsertBefore, IsVolatile=true) |
| sandboxir::StoreInst *NewVSt = |
| sandboxir::StoreInst::create(Val, Ptr, Align(8), |
| /*InsertBefore=*/Ret, |
| /*IsVolatile=*/true, Ctx); |
| EXPECT_TRUE(NewVSt->isVolatile()); |
| EXPECT_EQ(NewVSt->getType(), VSt->getType()); |
| EXPECT_EQ(NewVSt->getValueOperand(), Val); |
| EXPECT_EQ(NewVSt->getPointerOperand(), Ptr); |
| EXPECT_EQ(NewVSt->getAlign(), 8); |
| EXPECT_EQ(NewVSt->getNextNode(), Ret); |
| // Check create(InsertAtEnd) |
| sandboxir::StoreInst *NewStEnd = |
| sandboxir::StoreInst::create(Val, Ptr, Align(8), |
| /*InsertAtEnd=*/BB, Ctx); |
| EXPECT_FALSE(NewStEnd->isVolatile()); |
| EXPECT_EQ(NewStEnd->getType(), St->getType()); |
| EXPECT_EQ(NewStEnd->getValueOperand(), Val); |
| EXPECT_EQ(NewStEnd->getPointerOperand(), Ptr); |
| EXPECT_EQ(NewStEnd->getAlign(), 8); |
| EXPECT_EQ(NewStEnd->getParent(), BB); |
| EXPECT_EQ(NewStEnd->getNextNode(), nullptr); |
| // Check create(InsertAtEnd, IsVolatile=true) |
| sandboxir::StoreInst *NewVStEnd = |
| sandboxir::StoreInst::create(Val, Ptr, Align(8), |
| /*InsertAtEnd=*/BB, |
| /*IsVolatile=*/true, Ctx); |
| EXPECT_TRUE(NewVStEnd->isVolatile()); |
| EXPECT_EQ(NewVStEnd->getType(), VSt->getType()); |
| EXPECT_EQ(NewVStEnd->getValueOperand(), Val); |
| EXPECT_EQ(NewVStEnd->getPointerOperand(), Ptr); |
| EXPECT_EQ(NewVStEnd->getAlign(), 8); |
| EXPECT_EQ(NewVStEnd->getParent(), BB); |
| EXPECT_EQ(NewVStEnd->getNextNode(), nullptr); |
| } |
| |
| TEST_F(SandboxIRTest, ReturnInst) { |
| parseIR(C, R"IR( |
| define i8 @foo(i8 %val) { |
| %add = add i8 %val, 42 |
| ret i8 %val |
| } |
| )IR"); |
| llvm::Function *LLVMF = &*M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(LLVMF); |
| auto *Val = F->getArg(0); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| It++; |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| // Check that the ReturnInst has been created correctly. |
| // Check getReturnValue(). |
| EXPECT_EQ(Ret->getReturnValue(), Val); |
| |
| // Check create(InsertBefore) a void ReturnInst. |
| auto *NewRet1 = cast<sandboxir::ReturnInst>( |
| sandboxir::ReturnInst::create(nullptr, /*InsertBefore=*/Ret, Ctx)); |
| EXPECT_EQ(NewRet1->getReturnValue(), nullptr); |
| // Check create(InsertBefore) a non-void ReturnInst. |
| auto *NewRet2 = cast<sandboxir::ReturnInst>( |
| sandboxir::ReturnInst::create(Val, /*InsertBefore=*/Ret, Ctx)); |
| EXPECT_EQ(NewRet2->getReturnValue(), Val); |
| |
| // Check create(InsertAtEnd) a void ReturnInst. |
| auto *NewRet3 = cast<sandboxir::ReturnInst>( |
| sandboxir::ReturnInst::create(nullptr, /*InsertAtEnd=*/BB, Ctx)); |
| EXPECT_EQ(NewRet3->getReturnValue(), nullptr); |
| // Check create(InsertAtEnd) a non-void ReturnInst. |
| auto *NewRet4 = cast<sandboxir::ReturnInst>( |
| sandboxir::ReturnInst::create(Val, /*InsertAtEnd=*/BB, Ctx)); |
| EXPECT_EQ(NewRet4->getReturnValue(), Val); |
| } |
| |
| TEST_F(SandboxIRTest, CallBase) { |
| parseIR(C, R"IR( |
| declare void @bar1(i8) |
| declare void @bar2() |
| declare void @bar3() |
| declare void @variadic(ptr, ...) |
| |
| define i8 @foo(i8 %arg0, i32 %arg1, ptr %indirectFoo) { |
| %call = call i8 @foo(i8 %arg0, i32 %arg1) |
| call void @bar1(i8 %arg0) |
| call void @bar2() |
| call void %indirectFoo() |
| call void @bar2() noreturn |
| tail call fastcc void @bar2() |
| call void (ptr, ...) @variadic(ptr %indirectFoo, i32 1) |
| ret i8 %call |
| } |
| )IR"); |
| llvm::Function &LLVMF = *M->getFunction("foo"); |
| unsigned ArgIdx = 0; |
| llvm::Argument *LLVMArg0 = LLVMF.getArg(ArgIdx++); |
| llvm::Argument *LLVMArg1 = LLVMF.getArg(ArgIdx++); |
| llvm::BasicBlock *LLVMBB = &*LLVMF.begin(); |
| SmallVector<llvm::CallBase *, 8> LLVMCalls; |
| auto LLVMIt = LLVMBB->begin(); |
| while (isa<llvm::CallBase>(&*LLVMIt)) |
| LLVMCalls.push_back(cast<llvm::CallBase>(&*LLVMIt++)); |
| |
| sandboxir::Context Ctx(C); |
| sandboxir::Function &F = *Ctx.createFunction(&LLVMF); |
| |
| for (llvm::CallBase *LLVMCall : LLVMCalls) { |
| // Check classof(Instruction *). |
| auto *Call = cast<sandboxir::CallBase>(Ctx.getValue(LLVMCall)); |
| // Check classof(Value *). |
| EXPECT_TRUE(isa<sandboxir::CallBase>((sandboxir::Value *)Call)); |
| // Check getFunctionType(). |
| EXPECT_EQ(Call->getFunctionType(), LLVMCall->getFunctionType()); |
| // Check data_ops(). |
| EXPECT_EQ(range_size(Call->data_ops()), range_size(LLVMCall->data_ops())); |
| auto DataOpIt = Call->data_operands_begin(); |
| for (llvm::Use &LLVMUse : LLVMCall->data_ops()) { |
| Value *LLVMOp = LLVMUse.get(); |
| sandboxir::Use Use = *DataOpIt++; |
| EXPECT_EQ(Ctx.getValue(LLVMOp), Use.get()); |
| // Check isDataOperand(). |
| EXPECT_EQ(Call->isDataOperand(Use), LLVMCall->isDataOperand(&LLVMUse)); |
| // Check getDataOperandNo(). |
| EXPECT_EQ(Call->getDataOperandNo(Use), |
| LLVMCall->getDataOperandNo(&LLVMUse)); |
| // Check isArgOperand(). |
| EXPECT_EQ(Call->isArgOperand(Use), LLVMCall->isArgOperand(&LLVMUse)); |
| // Check isCallee(). |
| EXPECT_EQ(Call->isCallee(Use), LLVMCall->isCallee(&LLVMUse)); |
| } |
| // Check data_operands_empty(). |
| EXPECT_EQ(Call->data_operands_empty(), LLVMCall->data_operands_empty()); |
| // Check data_operands_size(). |
| EXPECT_EQ(Call->data_operands_size(), LLVMCall->data_operands_size()); |
| // Check getNumTotalBundleOperands(). |
| EXPECT_EQ(Call->getNumTotalBundleOperands(), |
| LLVMCall->getNumTotalBundleOperands()); |
| // Check args(). |
| EXPECT_EQ(range_size(Call->args()), range_size(LLVMCall->args())); |
| auto ArgIt = Call->arg_begin(); |
| for (llvm::Use &LLVMUse : LLVMCall->args()) { |
| Value *LLVMArg = LLVMUse.get(); |
| sandboxir::Use Use = *ArgIt++; |
| EXPECT_EQ(Ctx.getValue(LLVMArg), Use.get()); |
| } |
| // Check arg_empty(). |
| EXPECT_EQ(Call->arg_empty(), LLVMCall->arg_empty()); |
| // Check arg_size(). |
| EXPECT_EQ(Call->arg_size(), LLVMCall->arg_size()); |
| for (unsigned ArgIdx = 0, E = Call->arg_size(); ArgIdx != E; ++ArgIdx) { |
| // Check getArgOperand(). |
| EXPECT_EQ(Call->getArgOperand(ArgIdx), |
| Ctx.getValue(LLVMCall->getArgOperand(ArgIdx))); |
| // Check getArgOperandUse(). |
| sandboxir::Use Use = Call->getArgOperandUse(ArgIdx); |
| llvm::Use &LLVMUse = LLVMCall->getArgOperandUse(ArgIdx); |
| EXPECT_EQ(Use.get(), Ctx.getValue(LLVMUse.get())); |
| // Check getArgOperandNo(). |
| EXPECT_EQ(Call->getArgOperandNo(Use), |
| LLVMCall->getArgOperandNo(&LLVMUse)); |
| } |
| // Check hasArgument(). |
| SmallVector<llvm::Value *> TestArgs( |
| {LLVMArg0, LLVMArg1, &LLVMF, LLVMBB, LLVMCall}); |
| for (llvm::Value *LLVMV : TestArgs) { |
| sandboxir::Value *V = Ctx.getValue(LLVMV); |
| EXPECT_EQ(Call->hasArgument(V), LLVMCall->hasArgument(LLVMV)); |
| } |
| // Check getCalledOperand(). |
| EXPECT_EQ(Call->getCalledOperand(), |
| Ctx.getValue(LLVMCall->getCalledOperand())); |
| // Check getCalledOperandUse(). |
| EXPECT_EQ(Call->getCalledOperandUse().get(), |
| Ctx.getValue(LLVMCall->getCalledOperandUse())); |
| // Check getCalledFunction(). |
| if (LLVMCall->getCalledFunction() == nullptr) |
| EXPECT_EQ(Call->getCalledFunction(), nullptr); |
| else { |
| auto *LLVMCF = cast<llvm::Function>(LLVMCall->getCalledFunction()); |
| (void)LLVMCF; |
| EXPECT_EQ(Call->getCalledFunction(), |
| cast<sandboxir::Function>( |
| Ctx.getValue(LLVMCall->getCalledFunction()))); |
| } |
| // Check isIndirectCall(). |
| EXPECT_EQ(Call->isIndirectCall(), LLVMCall->isIndirectCall()); |
| // Check getCaller(). |
| EXPECT_EQ(Call->getCaller(), Ctx.getValue(LLVMCall->getCaller())); |
| // Check isMustTailCall(). |
| EXPECT_EQ(Call->isMustTailCall(), LLVMCall->isMustTailCall()); |
| // Check isTailCall(). |
| EXPECT_EQ(Call->isTailCall(), LLVMCall->isTailCall()); |
| // Check getIntrinsicID(). |
| EXPECT_EQ(Call->getIntrinsicID(), LLVMCall->getIntrinsicID()); |
| // Check getCallingConv(). |
| EXPECT_EQ(Call->getCallingConv(), LLVMCall->getCallingConv()); |
| // Check isInlineAsm(). |
| EXPECT_EQ(Call->isInlineAsm(), LLVMCall->isInlineAsm()); |
| } |
| |
| auto *Arg0 = F.getArg(0); |
| auto *Arg1 = F.getArg(1); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *Call0 = cast<sandboxir::CallBase>(&*It++); |
| [[maybe_unused]] auto *Call1 = cast<sandboxir::CallBase>(&*It++); |
| auto *Call2 = cast<sandboxir::CallBase>(&*It++); |
| // Check setArgOperand |
| Call0->setArgOperand(0, Arg1); |
| EXPECT_EQ(Call0->getArgOperand(0), Arg1); |
| Call0->setArgOperand(0, Arg0); |
| EXPECT_EQ(Call0->getArgOperand(0), Arg0); |
| |
| auto *Bar3F = Ctx.createFunction(M->getFunction("bar3")); |
| |
| // Check setCalledOperand |
| auto *SvOp = Call0->getCalledOperand(); |
| Call0->setCalledOperand(Bar3F); |
| EXPECT_EQ(Call0->getCalledOperand(), Bar3F); |
| Call0->setCalledOperand(SvOp); |
| // Check setCalledFunction |
| Call2->setCalledFunction(Bar3F); |
| EXPECT_EQ(Call2->getCalledFunction(), Bar3F); |
| } |
| |
| TEST_F(SandboxIRTest, CallInst) { |
| parseIR(C, R"IR( |
| define i8 @foo(i8 %arg) { |
| %call = call i8 @foo(i8 %arg) |
| ret i8 %call |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| auto &F = *Ctx.createFunction(&LLVMF); |
| unsigned ArgIdx = 0; |
| auto *Arg0 = F.getArg(ArgIdx++); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *Call = cast<sandboxir::CallInst>(&*It++); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| EXPECT_EQ(Call->getNumOperands(), 2u); |
| EXPECT_EQ(Ret->getOpcode(), sandboxir::Instruction::Opcode::Ret); |
| FunctionType *FTy = F.getFunctionType(); |
| SmallVector<sandboxir::Value *, 1> Args; |
| Args.push_back(Arg0); |
| { |
| // Check create() WhereIt. |
| auto *Call = cast<sandboxir::CallInst>(sandboxir::CallInst::create( |
| FTy, &F, Args, /*WhereIt=*/Ret->getIterator(), BB, Ctx)); |
| EXPECT_EQ(Call->getNextNode(), Ret); |
| EXPECT_EQ(Call->getCalledFunction(), &F); |
| EXPECT_EQ(range_size(Call->args()), 1u); |
| EXPECT_EQ(Call->getArgOperand(0), Arg0); |
| } |
| { |
| // Check create() InsertBefore. |
| auto *Call = cast<sandboxir::CallInst>( |
| sandboxir::CallInst::create(FTy, &F, Args, /*InsertBefore=*/Ret, Ctx)); |
| EXPECT_EQ(Call->getNextNode(), Ret); |
| EXPECT_EQ(Call->getCalledFunction(), &F); |
| EXPECT_EQ(range_size(Call->args()), 1u); |
| EXPECT_EQ(Call->getArgOperand(0), Arg0); |
| } |
| { |
| // Check create() InsertAtEnd. |
| auto *Call = cast<sandboxir::CallInst>( |
| sandboxir::CallInst::create(FTy, &F, Args, /*InsertAtEnd=*/BB, Ctx)); |
| EXPECT_EQ(Call->getPrevNode(), Ret); |
| EXPECT_EQ(Call->getCalledFunction(), &F); |
| EXPECT_EQ(range_size(Call->args()), 1u); |
| EXPECT_EQ(Call->getArgOperand(0), Arg0); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, InvokeInst) { |
| parseIR(C, R"IR( |
| define void @foo(i8 %arg) { |
| bb0: |
| invoke i8 @foo(i8 %arg) to label %normal_bb |
| unwind label %exception_bb |
| normal_bb: |
| ret void |
| exception_bb: |
| %lpad = landingpad { ptr, i32} |
| cleanup |
| ret void |
| other_bb: |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *Arg = F.getArg(0); |
| auto *BB0 = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "bb0"))); |
| auto *NormalBB = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "normal_bb"))); |
| auto *ExceptionBB = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "exception_bb"))); |
| auto *LandingPad = &*ExceptionBB->begin(); |
| auto *OtherBB = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "other_bb"))); |
| auto It = BB0->begin(); |
| // Check classof(Instruction *). |
| auto *Invoke = cast<sandboxir::InvokeInst>(&*It++); |
| |
| // Check getNormalDest(). |
| EXPECT_EQ(Invoke->getNormalDest(), NormalBB); |
| // Check getUnwindDest(). |
| EXPECT_EQ(Invoke->getUnwindDest(), ExceptionBB); |
| // Check getSuccessor(). |
| EXPECT_EQ(Invoke->getSuccessor(0), NormalBB); |
| EXPECT_EQ(Invoke->getSuccessor(1), ExceptionBB); |
| // Check setNormalDest(). |
| Invoke->setNormalDest(OtherBB); |
| EXPECT_EQ(Invoke->getNormalDest(), OtherBB); |
| EXPECT_EQ(Invoke->getUnwindDest(), ExceptionBB); |
| // Check setUnwindDest(). |
| Invoke->setUnwindDest(OtherBB); |
| EXPECT_EQ(Invoke->getNormalDest(), OtherBB); |
| EXPECT_EQ(Invoke->getUnwindDest(), OtherBB); |
| // Check setSuccessor(). |
| Invoke->setSuccessor(0, NormalBB); |
| EXPECT_EQ(Invoke->getNormalDest(), NormalBB); |
| Invoke->setSuccessor(1, ExceptionBB); |
| EXPECT_EQ(Invoke->getUnwindDest(), ExceptionBB); |
| // Check getLandingPadInst(). |
| EXPECT_EQ(Invoke->getLandingPadInst(), LandingPad); |
| |
| { |
| // Check create() WhereIt, WhereBB. |
| SmallVector<sandboxir::Value *> Args({Arg}); |
| auto *InsertBefore = &*BB0->begin(); |
| auto *NewInvoke = cast<sandboxir::InvokeInst>(sandboxir::InvokeInst::create( |
| F.getFunctionType(), &F, NormalBB, ExceptionBB, Args, |
| /*WhereIt=*/InsertBefore->getIterator(), /*WhereBB=*/BB0, Ctx)); |
| EXPECT_EQ(NewInvoke->getNormalDest(), NormalBB); |
| EXPECT_EQ(NewInvoke->getUnwindDest(), ExceptionBB); |
| EXPECT_EQ(NewInvoke->getNextNode(), InsertBefore); |
| } |
| { |
| // Check create() InsertBefore. |
| SmallVector<sandboxir::Value *> Args({Arg}); |
| auto *InsertBefore = &*BB0->begin(); |
| auto *NewInvoke = cast<sandboxir::InvokeInst>( |
| sandboxir::InvokeInst::create(F.getFunctionType(), &F, NormalBB, |
| ExceptionBB, Args, InsertBefore, Ctx)); |
| EXPECT_EQ(NewInvoke->getNormalDest(), NormalBB); |
| EXPECT_EQ(NewInvoke->getUnwindDest(), ExceptionBB); |
| EXPECT_EQ(NewInvoke->getNextNode(), InsertBefore); |
| } |
| { |
| // Check create() InsertAtEnd. |
| SmallVector<sandboxir::Value *> Args({Arg}); |
| auto *NewInvoke = cast<sandboxir::InvokeInst>(sandboxir::InvokeInst::create( |
| F.getFunctionType(), &F, NormalBB, ExceptionBB, Args, |
| /*InsertAtEnd=*/BB0, Ctx)); |
| EXPECT_EQ(NewInvoke->getNormalDest(), NormalBB); |
| EXPECT_EQ(NewInvoke->getUnwindDest(), ExceptionBB); |
| EXPECT_EQ(NewInvoke->getParent(), BB0); |
| EXPECT_EQ(NewInvoke->getNextNode(), nullptr); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, CallBrInst) { |
| parseIR(C, R"IR( |
| define void @foo(i8 %arg) { |
| bb0: |
| callbr void asm "", ""() |
| to label %bb1 [label %bb2] |
| bb1: |
| ret void |
| bb2: |
| ret void |
| other_bb: |
| ret void |
| bb3: |
| callbr void @foo(i8 %arg) |
| to label %bb1 [label %bb2] |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMBB0 = getBasicBlockByName(LLVMF, "bb0"); |
| auto *LLVMCallBr = cast<llvm::CallBrInst>(&*LLVMBB0->begin()); |
| sandboxir::Context Ctx(C); |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *Arg = F.getArg(0); |
| auto *BB0 = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "bb0"))); |
| auto *BB1 = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "bb1"))); |
| auto *BB2 = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "bb2"))); |
| auto *BB3 = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "bb3"))); |
| auto *OtherBB = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "other_bb"))); |
| auto It = BB0->begin(); |
| // Check classof(Instruction *). |
| auto *CallBr0 = cast<sandboxir::CallBrInst>(&*It++); |
| |
| It = BB3->begin(); |
| auto *CallBr1 = cast<sandboxir::CallBrInst>(&*It++); |
| for (sandboxir::CallBrInst *CallBr : {CallBr0, CallBr1}) { |
| // Check getNumIndirectDests(). |
| EXPECT_EQ(CallBr->getNumIndirectDests(), 1u); |
| // Check getIndirectDestLabel(). |
| EXPECT_EQ(CallBr->getIndirectDestLabel(0), |
| Ctx.getValue(LLVMCallBr->getIndirectDestLabel(0))); |
| // Check getIndirectDestLabelUse(). |
| EXPECT_EQ(CallBr->getIndirectDestLabelUse(0), |
| Ctx.getValue(LLVMCallBr->getIndirectDestLabelUse(0))); |
| // Check getDefaultDest(). |
| EXPECT_EQ(CallBr->getDefaultDest(), |
| Ctx.getValue(LLVMCallBr->getDefaultDest())); |
| // Check getIndirectDest(). |
| EXPECT_EQ(CallBr->getIndirectDest(0), |
| Ctx.getValue(LLVMCallBr->getIndirectDest(0))); |
| // Check getIndirectDests(). |
| auto Dests = CallBr->getIndirectDests(); |
| EXPECT_EQ(Dests.size(), LLVMCallBr->getIndirectDests().size()); |
| EXPECT_EQ(Dests[0], Ctx.getValue(LLVMCallBr->getIndirectDests()[0])); |
| // Check getNumSuccessors(). |
| EXPECT_EQ(CallBr->getNumSuccessors(), LLVMCallBr->getNumSuccessors()); |
| // Check getSuccessor(). |
| for (unsigned SuccIdx = 0, E = CallBr->getNumSuccessors(); SuccIdx != E; |
| ++SuccIdx) |
| EXPECT_EQ(CallBr->getSuccessor(SuccIdx), |
| Ctx.getValue(LLVMCallBr->getSuccessor(SuccIdx))); |
| // Check setDefaultDest(). |
| auto *SvDefaultDest = CallBr->getDefaultDest(); |
| CallBr->setDefaultDest(OtherBB); |
| EXPECT_EQ(CallBr->getDefaultDest(), OtherBB); |
| CallBr->setDefaultDest(SvDefaultDest); |
| // Check setIndirectDest(). |
| auto *SvIndirectDest = CallBr->getIndirectDest(0); |
| CallBr->setIndirectDest(0, OtherBB); |
| EXPECT_EQ(CallBr->getIndirectDest(0), OtherBB); |
| CallBr->setIndirectDest(0, SvIndirectDest); |
| } |
| |
| { |
| // Check create() WhereIt, WhereBB. |
| SmallVector<sandboxir::Value *> Args({Arg}); |
| auto *NewCallBr = cast<sandboxir::CallBrInst>(sandboxir::CallBrInst::create( |
| F.getFunctionType(), &F, BB1, {BB2}, Args, /*WhereIt=*/BB0->end(), |
| /*WhereBB=*/BB0, Ctx)); |
| EXPECT_EQ(NewCallBr->getDefaultDest(), BB1); |
| EXPECT_EQ(NewCallBr->getIndirectDests().size(), 1u); |
| EXPECT_EQ(NewCallBr->getIndirectDests()[0], BB2); |
| EXPECT_EQ(NewCallBr->getNextNode(), nullptr); |
| EXPECT_EQ(NewCallBr->getParent(), BB0); |
| } |
| { |
| // Check create() InsertBefore |
| SmallVector<sandboxir::Value *> Args({Arg}); |
| auto *InsertBefore = &*BB0->rbegin(); |
| auto *NewCallBr = cast<sandboxir::CallBrInst>(sandboxir::CallBrInst::create( |
| F.getFunctionType(), &F, BB1, {BB2}, Args, InsertBefore, Ctx)); |
| EXPECT_EQ(NewCallBr->getDefaultDest(), BB1); |
| EXPECT_EQ(NewCallBr->getIndirectDests().size(), 1u); |
| EXPECT_EQ(NewCallBr->getIndirectDests()[0], BB2); |
| EXPECT_EQ(NewCallBr->getNextNode(), InsertBefore); |
| } |
| { |
| // Check create() InsertAtEnd. |
| SmallVector<sandboxir::Value *> Args({Arg}); |
| auto *NewCallBr = cast<sandboxir::CallBrInst>( |
| sandboxir::CallBrInst::create(F.getFunctionType(), &F, BB1, {BB2}, Args, |
| /*InsertAtEnd=*/BB0, Ctx)); |
| EXPECT_EQ(NewCallBr->getDefaultDest(), BB1); |
| EXPECT_EQ(NewCallBr->getIndirectDests().size(), 1u); |
| EXPECT_EQ(NewCallBr->getIndirectDests()[0], BB2); |
| EXPECT_EQ(NewCallBr->getNextNode(), nullptr); |
| EXPECT_EQ(NewCallBr->getParent(), BB0); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, GetElementPtrInstruction) { |
| parseIR(C, R"IR( |
| define void @foo(ptr %ptr, <2 x ptr> %ptrs) { |
| %gep0 = getelementptr i8, ptr %ptr, i32 0 |
| %gep1 = getelementptr nusw i8, ptr %ptr, i32 0 |
| %gep2 = getelementptr nuw i8, ptr %ptr, i32 0 |
| %gep3 = getelementptr inbounds {i32, {i32, i8}}, ptr %ptr, i32 1, i32 0 |
| %gep4 = getelementptr inbounds {i8, i8, {i32, i16}}, <2 x ptr> %ptrs, i32 2, <2 x i32> <i32 0, i32 0> |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| BasicBlock *LLVMBB = &*LLVMF.begin(); |
| auto LLVMIt = LLVMBB->begin(); |
| SmallVector<llvm::GetElementPtrInst *, 4> LLVMGEPs; |
| while (isa<llvm::GetElementPtrInst>(&*LLVMIt)) |
| LLVMGEPs.push_back(cast<llvm::GetElementPtrInst>(&*LLVMIt++)); |
| auto *LLVMRet = cast<llvm::ReturnInst>(&*LLVMIt++); |
| sandboxir::Context Ctx(C); |
| [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); |
| |
| for (llvm::GetElementPtrInst *LLVMGEP : LLVMGEPs) { |
| // Check classof(). |
| auto *GEP = cast<sandboxir::GetElementPtrInst>(Ctx.getValue(LLVMGEP)); |
| // Check getSourceElementType(). |
| EXPECT_EQ(GEP->getSourceElementType(), LLVMGEP->getSourceElementType()); |
| // Check getResultElementType(). |
| EXPECT_EQ(GEP->getResultElementType(), LLVMGEP->getResultElementType()); |
| // Check getAddressSpace(). |
| EXPECT_EQ(GEP->getAddressSpace(), LLVMGEP->getAddressSpace()); |
| // Check indices(). |
| EXPECT_EQ(range_size(GEP->indices()), range_size(LLVMGEP->indices())); |
| auto IdxIt = GEP->idx_begin(); |
| for (llvm::Value *LLVMIdxV : LLVMGEP->indices()) { |
| sandboxir::Value *IdxV = *IdxIt++; |
| EXPECT_EQ(IdxV, Ctx.getValue(LLVMIdxV)); |
| } |
| // Check getPointerOperand(). |
| EXPECT_EQ(GEP->getPointerOperand(), |
| Ctx.getValue(LLVMGEP->getPointerOperand())); |
| // Check getPointerOperandIndex(). |
| EXPECT_EQ(GEP->getPointerOperandIndex(), LLVMGEP->getPointerOperandIndex()); |
| // Check getPointerOperandType(). |
| EXPECT_EQ(GEP->getPointerOperandType(), LLVMGEP->getPointerOperandType()); |
| // Check getPointerAddressSpace(). |
| EXPECT_EQ(GEP->getPointerAddressSpace(), LLVMGEP->getPointerAddressSpace()); |
| // Check getNumIndices(). |
| EXPECT_EQ(GEP->getNumIndices(), LLVMGEP->getNumIndices()); |
| // Check hasIndices(). |
| EXPECT_EQ(GEP->hasIndices(), LLVMGEP->hasIndices()); |
| // Check hasAllConstantIndices(). |
| EXPECT_EQ(GEP->hasAllConstantIndices(), LLVMGEP->hasAllConstantIndices()); |
| // Check getNoWrapFlags(). |
| EXPECT_EQ(GEP->getNoWrapFlags(), LLVMGEP->getNoWrapFlags()); |
| // Check isInBounds(). |
| EXPECT_EQ(GEP->isInBounds(), LLVMGEP->isInBounds()); |
| // Check hasNoUnsignedWrap(). |
| EXPECT_EQ(GEP->hasNoUnsignedWrap(), LLVMGEP->hasNoUnsignedWrap()); |
| // Check accumulateConstantOffset(). |
| DataLayout DL(M.get()); |
| APInt Offset1 = |
| APInt::getZero(DL.getIndexSizeInBits(GEP->getPointerAddressSpace())); |
| APInt Offset2 = |
| APInt::getZero(DL.getIndexSizeInBits(GEP->getPointerAddressSpace())); |
| EXPECT_EQ(GEP->accumulateConstantOffset(DL, Offset1), |
| LLVMGEP->accumulateConstantOffset(DL, Offset2)); |
| EXPECT_EQ(Offset1, Offset2); |
| } |
| |
| auto *BB = &*F.begin(); |
| auto *GEP0 = cast<sandboxir::GetElementPtrInst>(&*BB->begin()); |
| auto *Ret = cast<sandboxir::ReturnInst>(Ctx.getValue(LLVMRet)); |
| SmallVector<sandboxir::Value *> Indices(GEP0->indices()); |
| |
| // Check create() WhereIt, WhereBB. |
| auto *NewGEP0 = |
| cast<sandboxir::GetElementPtrInst>(sandboxir::GetElementPtrInst::create( |
| GEP0->getType(), GEP0->getPointerOperand(), Indices, |
| /*WhereIt=*/Ret->getIterator(), /*WhereBB=*/Ret->getParent(), Ctx, |
| "NewGEP0")); |
| EXPECT_EQ(NewGEP0->getName(), "NewGEP0"); |
| EXPECT_EQ(NewGEP0->getType(), GEP0->getType()); |
| EXPECT_EQ(NewGEP0->getPointerOperand(), GEP0->getPointerOperand()); |
| EXPECT_EQ(range_size(NewGEP0->indices()), range_size(GEP0->indices())); |
| for (auto NewIt = NewGEP0->idx_begin(), NewItE = NewGEP0->idx_end(), |
| OldIt = GEP0->idx_begin(); |
| NewIt != NewItE; ++NewIt) { |
| sandboxir::Value *NewIdxV = *NewIt; |
| sandboxir::Value *OldIdxV = *OldIt; |
| EXPECT_EQ(NewIdxV, OldIdxV); |
| } |
| EXPECT_EQ(NewGEP0->getNextNode(), Ret); |
| |
| // Check create() InsertBefore. |
| auto *NewGEP1 = |
| cast<sandboxir::GetElementPtrInst>(sandboxir::GetElementPtrInst::create( |
| GEP0->getType(), GEP0->getPointerOperand(), Indices, |
| /*InsertBefore=*/Ret, Ctx, "NewGEP1")); |
| EXPECT_EQ(NewGEP1->getName(), "NewGEP1"); |
| EXPECT_EQ(NewGEP1->getType(), GEP0->getType()); |
| EXPECT_EQ(NewGEP1->getPointerOperand(), GEP0->getPointerOperand()); |
| EXPECT_EQ(range_size(NewGEP1->indices()), range_size(GEP0->indices())); |
| for (auto NewIt = NewGEP0->idx_begin(), NewItE = NewGEP0->idx_end(), |
| OldIt = GEP0->idx_begin(); |
| NewIt != NewItE; ++NewIt) { |
| sandboxir::Value *NewIdxV = *NewIt; |
| sandboxir::Value *OldIdxV = *OldIt; |
| EXPECT_EQ(NewIdxV, OldIdxV); |
| } |
| EXPECT_EQ(NewGEP1->getNextNode(), Ret); |
| |
| // Check create() InsertAtEnd. |
| auto *NewGEP2 = |
| cast<sandboxir::GetElementPtrInst>(sandboxir::GetElementPtrInst::create( |
| GEP0->getType(), GEP0->getPointerOperand(), Indices, |
| /*InsertAtEnd=*/BB, Ctx, "NewGEP2")); |
| EXPECT_EQ(NewGEP2->getName(), "NewGEP2"); |
| EXPECT_EQ(NewGEP2->getType(), GEP0->getType()); |
| EXPECT_EQ(NewGEP2->getPointerOperand(), GEP0->getPointerOperand()); |
| EXPECT_EQ(range_size(NewGEP2->indices()), range_size(GEP0->indices())); |
| for (auto NewIt = NewGEP0->idx_begin(), NewItE = NewGEP0->idx_end(), |
| OldIt = GEP0->idx_begin(); |
| NewIt != NewItE; ++NewIt) { |
| sandboxir::Value *NewIdxV = *NewIt; |
| sandboxir::Value *OldIdxV = *OldIt; |
| EXPECT_EQ(NewIdxV, OldIdxV); |
| } |
| EXPECT_EQ(NewGEP2->getPrevNode(), Ret); |
| EXPECT_EQ(NewGEP2->getNextNode(), nullptr); |
| } |
| |
| TEST_F(SandboxIRTest, CastInst) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %arg, float %farg, double %darg, ptr %ptr) { |
| %zext = zext i32 %arg to i64 |
| %sext = sext i32 %arg to i64 |
| %fptoui = fptoui float %farg to i32 |
| %fptosi = fptosi float %farg to i32 |
| %fpext = fpext float %farg to double |
| %ptrtoint = ptrtoint ptr %ptr to i32 |
| %inttoptr = inttoptr i32 %arg to ptr |
| %sitofp = sitofp i32 %arg to float |
| %uitofp = uitofp i32 %arg to float |
| %trunc = trunc i32 %arg to i16 |
| %fptrunc = fptrunc double %darg to float |
| %bitcast = bitcast i32 %arg to float |
| %addrspacecast = addrspacecast ptr %ptr to ptr addrspace(1) |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(&LLVMF); |
| unsigned ArgIdx = 0; |
| auto *Arg = F->getArg(ArgIdx++); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| |
| Type *Ti64 = Type::getInt64Ty(C); |
| Type *Ti32 = Type::getInt32Ty(C); |
| Type *Ti16 = Type::getInt16Ty(C); |
| Type *Tdouble = Type::getDoubleTy(C); |
| Type *Tfloat = Type::getFloatTy(C); |
| Type *Tptr = Tfloat->getPointerTo(); |
| Type *Tptr1 = Tfloat->getPointerTo(1); |
| |
| // Check classof(), getOpcode(), getSrcTy(), getDstTy() |
| auto *ZExt = cast<sandboxir::CastInst>(&*It++); |
| EXPECT_EQ(ZExt->getOpcode(), sandboxir::Instruction::Opcode::ZExt); |
| EXPECT_EQ(ZExt->getSrcTy(), Ti32); |
| EXPECT_EQ(ZExt->getDestTy(), Ti64); |
| |
| auto *SExt = cast<sandboxir::CastInst>(&*It++); |
| EXPECT_EQ(SExt->getOpcode(), sandboxir::Instruction::Opcode::SExt); |
| EXPECT_EQ(SExt->getSrcTy(), Ti32); |
| EXPECT_EQ(SExt->getDestTy(), Ti64); |
| |
| auto *FPToUI = cast<sandboxir::CastInst>(&*It++); |
| EXPECT_EQ(FPToUI->getOpcode(), sandboxir::Instruction::Opcode::FPToUI); |
| EXPECT_EQ(FPToUI->getSrcTy(), Tfloat); |
| EXPECT_EQ(FPToUI->getDestTy(), Ti32); |
| |
| auto *FPToSI = cast<sandboxir::CastInst>(&*It++); |
| EXPECT_EQ(FPToSI->getOpcode(), sandboxir::Instruction::Opcode::FPToSI); |
| EXPECT_EQ(FPToSI->getSrcTy(), Tfloat); |
| EXPECT_EQ(FPToSI->getDestTy(), Ti32); |
| |
| auto *FPExt = cast<sandboxir::CastInst>(&*It++); |
| EXPECT_EQ(FPExt->getOpcode(), sandboxir::Instruction::Opcode::FPExt); |
| EXPECT_EQ(FPExt->getSrcTy(), Tfloat); |
| EXPECT_EQ(FPExt->getDestTy(), Tdouble); |
| |
| auto *PtrToInt = cast<sandboxir::CastInst>(&*It++); |
| EXPECT_TRUE(isa<sandboxir::PtrToIntInst>(PtrToInt)); |
| EXPECT_EQ(PtrToInt->getOpcode(), sandboxir::Instruction::Opcode::PtrToInt); |
| EXPECT_EQ(PtrToInt->getSrcTy(), Tptr); |
| EXPECT_EQ(PtrToInt->getDestTy(), Ti32); |
| |
| auto *IntToPtr = cast<sandboxir::CastInst>(&*It++); |
| EXPECT_EQ(IntToPtr->getOpcode(), sandboxir::Instruction::Opcode::IntToPtr); |
| EXPECT_EQ(IntToPtr->getSrcTy(), Ti32); |
| EXPECT_EQ(IntToPtr->getDestTy(), Tptr); |
| |
| auto *SIToFP = cast<sandboxir::CastInst>(&*It++); |
| EXPECT_EQ(SIToFP->getOpcode(), sandboxir::Instruction::Opcode::SIToFP); |
| EXPECT_EQ(SIToFP->getSrcTy(), Ti32); |
| EXPECT_EQ(SIToFP->getDestTy(), Tfloat); |
| |
| auto *UIToFP = cast<sandboxir::CastInst>(&*It++); |
| EXPECT_EQ(UIToFP->getOpcode(), sandboxir::Instruction::Opcode::UIToFP); |
| EXPECT_EQ(UIToFP->getSrcTy(), Ti32); |
| EXPECT_EQ(UIToFP->getDestTy(), Tfloat); |
| |
| auto *Trunc = cast<sandboxir::CastInst>(&*It++); |
| EXPECT_EQ(Trunc->getOpcode(), sandboxir::Instruction::Opcode::Trunc); |
| EXPECT_EQ(Trunc->getSrcTy(), Ti32); |
| EXPECT_EQ(Trunc->getDestTy(), Ti16); |
| |
| auto *FPTrunc = cast<sandboxir::CastInst>(&*It++); |
| EXPECT_EQ(FPTrunc->getOpcode(), sandboxir::Instruction::Opcode::FPTrunc); |
| EXPECT_EQ(FPTrunc->getSrcTy(), Tdouble); |
| EXPECT_EQ(FPTrunc->getDestTy(), Tfloat); |
| |
| auto *BitCast = cast<sandboxir::CastInst>(&*It++); |
| EXPECT_EQ(BitCast->getOpcode(), sandboxir::Instruction::Opcode::BitCast); |
| EXPECT_EQ(BitCast->getSrcTy(), Ti32); |
| EXPECT_EQ(BitCast->getDestTy(), Tfloat); |
| |
| auto *AddrSpaceCast = cast<sandboxir::CastInst>(&*It++); |
| EXPECT_EQ(AddrSpaceCast->getOpcode(), |
| sandboxir::Instruction::Opcode::AddrSpaceCast); |
| EXPECT_EQ(AddrSpaceCast->getSrcTy(), Tptr); |
| EXPECT_EQ(AddrSpaceCast->getDestTy(), Tptr1); |
| |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| { |
| // Check create() WhereIt, WhereBB |
| auto *NewI = cast<sandboxir::CastInst>(sandboxir::CastInst::create( |
| Ti64, sandboxir::Instruction::Opcode::SExt, Arg, /*WhereIt=*/BB->end(), |
| /*WhereBB=*/BB, Ctx, "SExt")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::SExt); |
| // Check getSrcTy(). |
| EXPECT_EQ(NewI->getSrcTy(), Arg->getType()); |
| // Check getDestTy(). |
| EXPECT_EQ(NewI->getDestTy(), Ti64); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), nullptr); |
| EXPECT_EQ(NewI->getPrevNode(), Ret); |
| } |
| |
| { |
| // Check create() InsertBefore. |
| auto *NewI = cast<sandboxir::CastInst>( |
| sandboxir::CastInst::create(Ti64, sandboxir::Instruction::Opcode::ZExt, |
| Arg, /*InsertBefore=*/Ret, Ctx, "ZExt")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::ZExt); |
| // Check getSrcTy(). |
| EXPECT_EQ(NewI->getSrcTy(), Arg->getType()); |
| // Check getDestTy(). |
| EXPECT_EQ(NewI->getDestTy(), Ti64); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| } |
| { |
| // Check create() InsertAtEnd. |
| auto *NewI = cast<sandboxir::CastInst>( |
| sandboxir::CastInst::create(Ti64, sandboxir::Instruction::Opcode::ZExt, |
| Arg, /*InsertAtEnd=*/BB, Ctx, "ZExt")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::ZExt); |
| // Check getSrcTy(). |
| EXPECT_EQ(NewI->getSrcTy(), Arg->getType()); |
| // Check getDestTy(). |
| EXPECT_EQ(NewI->getDestTy(), Ti64); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), nullptr); |
| EXPECT_EQ(NewI->getParent(), BB); |
| } |
| |
| { |
| #ifndef NDEBUG |
| // Check that passing a non-cast opcode crashes. |
| EXPECT_DEATH( |
| sandboxir::CastInst::create(Ti64, sandboxir::Instruction::Opcode::Store, |
| Arg, /*InsertBefore=*/Ret, Ctx, "Bad"), |
| ".*Opcode.*"); |
| #endif // NDEBUG |
| } |
| } |
| |
| TEST_F(SandboxIRTest, PtrToIntInst) { |
| parseIR(C, R"IR( |
| define void @foo(ptr %ptr) { |
| %ptrtoint = ptrtoint ptr %ptr to i32 |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(&LLVMF); |
| unsigned ArgIdx = 0; |
| auto *Arg = F->getArg(ArgIdx++); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| Type *Ti32 = Type::getInt32Ty(C); |
| Type *Tptr = Ti32->getPointerTo(); |
| |
| auto *PtrToInt = cast<sandboxir::PtrToIntInst>(&*It++); |
| EXPECT_EQ(PtrToInt->getOpcode(), sandboxir::Instruction::Opcode::PtrToInt); |
| EXPECT_EQ(PtrToInt->getSrcTy(), Tptr); |
| EXPECT_EQ(PtrToInt->getDestTy(), Ti32); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| { |
| // Check create() WhereIt, WhereBB |
| auto *NewI = cast<sandboxir::PtrToIntInst>( |
| sandboxir::PtrToIntInst::create(Arg, Ti32, /*WhereIt=*/BB->end(), |
| /*WhereBB=*/BB, Ctx, "PtrToInt")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::PtrToInt); |
| // Check getSrcTy(). |
| EXPECT_EQ(NewI->getSrcTy(), Arg->getType()); |
| // Check getDestTy(). |
| EXPECT_EQ(NewI->getDestTy(), Ti32); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), nullptr); |
| EXPECT_EQ(NewI->getPrevNode(), Ret); |
| } |
| { |
| // Check create() InsertBefore. |
| auto *NewI = cast<sandboxir::PtrToIntInst>( |
| sandboxir::PtrToIntInst::create(Arg, Ti32, |
| /*InsertBefore=*/Ret, Ctx, "PtrToInt")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::PtrToInt); |
| // Check getSrcTy(). |
| EXPECT_EQ(NewI->getSrcTy(), Arg->getType()); |
| // Check getDestTy(). |
| EXPECT_EQ(NewI->getDestTy(), Ti32); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| } |
| { |
| // Check create() InsertAtEnd. |
| auto *NewI = cast<sandboxir::PtrToIntInst>( |
| sandboxir::PtrToIntInst::create(Arg, Ti32, |
| /*InsertAtEnd=*/BB, Ctx, "PtrToInt")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::PtrToInt); |
| // Check getSrcTy(). |
| EXPECT_EQ(NewI->getSrcTy(), Arg->getType()); |
| // Check getDestTy(). |
| EXPECT_EQ(NewI->getDestTy(), Ti32); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), nullptr); |
| EXPECT_EQ(NewI->getParent(), BB); |
| } |
| } |