| //===- 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/AsmParser/Parser.h" |
| #include "llvm/IR/BasicBlock.h" |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/DataLayout.h" |
| #include "llvm/IR/Function.h" |
| #include "llvm/IR/Instruction.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/SandboxIR/BasicBlock.h" |
| #include "llvm/SandboxIR/Constant.h" |
| #include "llvm/SandboxIR/Function.h" |
| #include "llvm/SandboxIR/Instruction.h" |
| #include "llvm/SandboxIR/Module.h" |
| #include "llvm/SandboxIR/Utils.h" |
| #include "llvm/SandboxIR/Value.h" |
| #include "llvm/Support/SourceMgr.h" |
| #include "gmock/gmock.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::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::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_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::OpaqueInst>(F)); |
| EXPECT_FALSE(isa<sandboxir::OpaqueInst>(Arg0)); |
| EXPECT_FALSE(isa<sandboxir::OpaqueInst>(BB)); |
| EXPECT_FALSE(isa<sandboxir::OpaqueInst>(AddI)); |
| EXPECT_FALSE(isa<sandboxir::OpaqueInst>(Const0)); |
| |
| 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::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)); |
| |
| #ifndef NDEBUG |
| std::string Buff; |
| raw_string_ostream BS(Buff); |
| F->dumpOS(BS); |
| Arg0->dumpOS(BS); |
| BB->dumpOS(BS); |
| AddI->dumpOS(BS); |
| Const0->dumpOS(BS); |
| #endif |
| } |
| |
| TEST_F(SandboxIRTest, ConstantInt) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %v0) { |
| %add0 = add i32 %v0, 42 |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMBB = &*LLVMF.begin(); |
| auto *LLVMAdd0 = &*LLVMBB->begin(); |
| auto *LLVMFortyTwo = cast<llvm::ConstantInt>(LLVMAdd0->getOperand(1)); |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto &BB = *F.begin(); |
| auto It = BB.begin(); |
| auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++); |
| auto *FortyTwo = cast<sandboxir::ConstantInt>(Add0->getOperand(1)); |
| |
| // Check that creating an identical constant gives us the same object. |
| auto *NewCI = |
| sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 42); |
| EXPECT_EQ(NewCI, FortyTwo); |
| { |
| // Check getTrue(Ctx). |
| auto *True = sandboxir::ConstantInt::getTrue(Ctx); |
| EXPECT_EQ(True, Ctx.getValue(llvm::ConstantInt::getTrue(C))); |
| // Check getFalse(Ctx). |
| auto *False = sandboxir::ConstantInt::getFalse(Ctx); |
| EXPECT_EQ(False, Ctx.getValue(llvm::ConstantInt::getFalse(C))); |
| // Check getBool(Ctx). |
| auto *Bool = sandboxir::ConstantInt::getBool(Ctx, true); |
| EXPECT_EQ(Bool, Ctx.getValue(llvm::ConstantInt::getBool(C, true))); |
| } |
| { |
| auto *Int1Ty = sandboxir::Type::getInt1Ty(Ctx); |
| auto *LLVMInt1Ty = llvm::Type::getInt1Ty(C); |
| // Check getTrue(Ty). |
| auto *True = sandboxir::ConstantInt::getTrue(Int1Ty); |
| EXPECT_EQ(True, Ctx.getValue(llvm::ConstantInt::getTrue(LLVMInt1Ty))); |
| // Check getFalse(Ty). |
| auto *False = sandboxir::ConstantInt::getFalse(Int1Ty); |
| EXPECT_EQ(False, Ctx.getValue(llvm::ConstantInt::getFalse(LLVMInt1Ty))); |
| // Check getBool(Ty). |
| auto *Bool = sandboxir::ConstantInt::getBool(Int1Ty, true); |
| EXPECT_EQ(Bool, Ctx.getValue(llvm::ConstantInt::getBool(LLVMInt1Ty, true))); |
| } |
| |
| auto *Int32Ty = sandboxir::Type::getInt32Ty(Ctx); |
| auto *LLVMInt32Ty = llvm::Type::getInt32Ty(C); |
| { |
| // Check get(Type, V). |
| auto *FortyThree = sandboxir::ConstantInt::get(Int32Ty, 43); |
| auto *LLVMFortyThree = llvm::ConstantInt::get(LLVMInt32Ty, 43); |
| EXPECT_NE(FortyThree, FortyTwo); |
| EXPECT_EQ(FortyThree, Ctx.getValue(LLVMFortyThree)); |
| } |
| { |
| // Check get(Type, V, IsSigned). |
| auto *FortyThree = |
| sandboxir::ConstantInt::get(Int32Ty, 43, /*IsSigned=*/true); |
| auto *LLVMFortyThree = |
| llvm::ConstantInt::get(LLVMInt32Ty, 43, /*IsSigned=*/true); |
| EXPECT_NE(FortyThree, FortyTwo); |
| EXPECT_EQ(FortyThree, Ctx.getValue(LLVMFortyThree)); |
| } |
| |
| { |
| // Check get(IntegerType, V). |
| auto *FortyThree = |
| sandboxir::ConstantInt::get(sandboxir::IntegerType::get(Ctx, 32), 43); |
| auto *LLVMFortyThree = |
| llvm::ConstantInt::get(llvm::IntegerType::get(C, 32), 43); |
| EXPECT_NE(FortyThree, FortyTwo); |
| EXPECT_EQ(FortyThree, Ctx.getValue(LLVMFortyThree)); |
| } |
| { |
| // Check get(IntegerType, V, IsSigned). |
| auto *FortyThree = sandboxir::ConstantInt::get( |
| sandboxir::IntegerType::get(Ctx, 32), 43, /*IsSigned=*/true); |
| auto *LLVMFortyThree = llvm::ConstantInt::get(llvm::IntegerType::get(C, 32), |
| 43, /*IsSigned=*/true); |
| EXPECT_NE(FortyThree, FortyTwo); |
| EXPECT_EQ(FortyThree, Ctx.getValue(LLVMFortyThree)); |
| } |
| |
| { |
| // Check getSigned(IntegerType, V). |
| auto *FortyThree = sandboxir::ConstantInt::getSigned( |
| sandboxir::IntegerType::get(Ctx, 32), 43); |
| auto *LLVMFortyThree = |
| llvm::ConstantInt::getSigned(llvm::IntegerType::get(C, 32), 43); |
| EXPECT_NE(FortyThree, FortyTwo); |
| EXPECT_EQ(FortyThree, Ctx.getValue(LLVMFortyThree)); |
| } |
| { |
| // Check getSigned(Type, V). |
| auto *FortyThree = sandboxir::ConstantInt::getSigned(Int32Ty, 43); |
| auto *LLVMFortyThree = llvm::ConstantInt::getSigned(LLVMInt32Ty, 43); |
| EXPECT_NE(FortyThree, FortyTwo); |
| EXPECT_EQ(FortyThree, Ctx.getValue(LLVMFortyThree)); |
| } |
| { |
| // Check get(Ctx, APInt). |
| APInt APInt43(32, 43); |
| auto *FortyThree = sandboxir::ConstantInt::get(Ctx, APInt43); |
| auto *LLVMFortyThree = llvm::ConstantInt::get(C, APInt43); |
| EXPECT_NE(FortyThree, FortyTwo); |
| EXPECT_EQ(FortyThree, Ctx.getValue(LLVMFortyThree)); |
| } |
| { |
| // Check get(Ty, Str, Radix). |
| StringRef Str("43"); |
| uint8_t Radix(10); |
| auto *FortyThree = sandboxir::ConstantInt::get( |
| sandboxir::IntegerType::get(Ctx, 32), Str, Radix); |
| auto *LLVMFortyThree = |
| llvm::ConstantInt::get(llvm::IntegerType::get(C, 32), Str, Radix); |
| EXPECT_NE(FortyThree, FortyTwo); |
| EXPECT_EQ(FortyThree, Ctx.getValue(LLVMFortyThree)); |
| } |
| { |
| // Check get(Ty, APInt). |
| APInt APInt43(32, 43); |
| auto *FortyThree = sandboxir::ConstantInt::get(Int32Ty, APInt43); |
| auto *LLVMFortyThree = llvm::ConstantInt::get(LLVMInt32Ty, APInt43); |
| EXPECT_NE(FortyThree, FortyTwo); |
| EXPECT_EQ(FortyThree, Ctx.getValue(LLVMFortyThree)); |
| } |
| // Check getValue(). |
| EXPECT_EQ(FortyTwo->getValue(), LLVMFortyTwo->getValue()); |
| // Check getBitWidth(). |
| EXPECT_EQ(FortyTwo->getBitWidth(), LLVMFortyTwo->getBitWidth()); |
| // Check getZExtValue(). |
| EXPECT_EQ(FortyTwo->getZExtValue(), LLVMFortyTwo->getZExtValue()); |
| // Check getSExtValue(). |
| EXPECT_EQ(FortyTwo->getSExtValue(), LLVMFortyTwo->getSExtValue()); |
| // Check getMaybeAlignValue(). |
| auto *SixtyFour = |
| cast<sandboxir::ConstantInt>(sandboxir::ConstantInt::get(Int32Ty, 64)); |
| auto *LLVMSixtyFour = |
| cast<llvm::ConstantInt>(llvm::ConstantInt::get(LLVMInt32Ty, 64)); |
| EXPECT_EQ(SixtyFour->getMaybeAlignValue(), |
| LLVMSixtyFour->getMaybeAlignValue()); |
| // Check getAlignValue(). |
| EXPECT_EQ(SixtyFour->getAlignValue(), LLVMSixtyFour->getAlignValue()); |
| // Check equalsInt(). |
| EXPECT_TRUE(FortyTwo->equalsInt(42)); |
| EXPECT_FALSE(FortyTwo->equalsInt(43)); |
| // Check getIntegerType(). |
| EXPECT_EQ(FortyTwo->getIntegerType(), sandboxir::IntegerType::get(Ctx, 32)); |
| // Check isValueValidForType(). |
| EXPECT_TRUE( |
| sandboxir::ConstantInt::isValueValidForType(Int32Ty, (uint64_t)42)); |
| EXPECT_TRUE( |
| sandboxir::ConstantInt::isValueValidForType(Int32Ty, (int64_t)42)); |
| // Check isNegative(). |
| EXPECT_FALSE(FortyTwo->isNegative()); |
| EXPECT_TRUE(sandboxir::ConstantInt::get(Int32Ty, -42)); |
| // Check isZero(). |
| EXPECT_FALSE(FortyTwo->isZero()); |
| EXPECT_TRUE(sandboxir::ConstantInt::get(Int32Ty, 0)->isZero()); |
| // Check isOne(). |
| EXPECT_FALSE(FortyTwo->isOne()); |
| EXPECT_TRUE(sandboxir::ConstantInt::get(Int32Ty, 1)->isOne()); |
| // Check isMinusOne(). |
| EXPECT_FALSE(FortyTwo->isMinusOne()); |
| EXPECT_TRUE(sandboxir::ConstantInt::get(Int32Ty, -1)->isMinusOne()); |
| // Check isMaxValue(). |
| EXPECT_FALSE(FortyTwo->isMaxValue(/*Signed=*/true)); |
| EXPECT_TRUE( |
| sandboxir::ConstantInt::get(Int32Ty, std::numeric_limits<int32_t>::max()) |
| ->isMaxValue(/*Signed=*/true)); |
| // Check isMinValue(). |
| EXPECT_FALSE(FortyTwo->isMinValue(/*Signed=*/true)); |
| EXPECT_TRUE( |
| sandboxir::ConstantInt::get(Int32Ty, std::numeric_limits<int32_t>::min()) |
| ->isMinValue(/*Signed=*/true)); |
| // Check uge(). |
| EXPECT_TRUE(FortyTwo->uge(41)); |
| EXPECT_FALSE(FortyTwo->uge(43)); |
| // Check getLimitedValue(). |
| EXPECT_EQ(FortyTwo->getLimitedValue(40u), 40u); |
| EXPECT_EQ(FortyTwo->getLimitedValue(50u), 42u); |
| } |
| |
| TEST_F(SandboxIRTest, ConstantFP) { |
| parseIR(C, R"IR( |
| define void @foo(float %v0, double %v1, half %v2) { |
| %fadd0 = fadd float %v0, 42.0 |
| %fadd1 = fadd double %v1, 43.0 |
| %fadd2 = fadd half %v2, 44.0 |
| 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 *FAdd0 = cast<sandboxir::BinaryOperator>(&*It++); |
| auto *FAdd1 = cast<sandboxir::BinaryOperator>(&*It++); |
| auto *FAdd2 = cast<sandboxir::BinaryOperator>(&*It++); |
| auto *FortyTwo = cast<sandboxir::ConstantFP>(FAdd0->getOperand(1)); |
| [[maybe_unused]] auto *FortyThree = |
| cast<sandboxir::ConstantFP>(FAdd1->getOperand(1)); |
| |
| auto *FloatTy = sandboxir::Type::getFloatTy(Ctx); |
| auto *DoubleTy = sandboxir::Type::getDoubleTy(Ctx); |
| auto *HalfTy = sandboxir::Type::getHalfTy(Ctx); |
| EXPECT_EQ(HalfTy, Ctx.getType(llvm::Type::getHalfTy(C))); |
| EXPECT_EQ(FAdd2->getType(), HalfTy); |
| auto *LLVMFloatTy = Type::getFloatTy(C); |
| auto *LLVMDoubleTy = Type::getDoubleTy(C); |
| // Check that creating an identical constant gives us the same object. |
| auto *NewFortyTwo = sandboxir::ConstantFP::get(FloatTy, 42.0); |
| EXPECT_EQ(NewFortyTwo, FortyTwo); |
| // Check get(Type, double). |
| auto *FortyFour = |
| cast<sandboxir::ConstantFP>(sandboxir::ConstantFP::get(FloatTy, 44.0)); |
| auto *LLVMFortyFour = |
| cast<llvm::ConstantFP>(llvm::ConstantFP::get(LLVMFloatTy, 44.0)); |
| EXPECT_NE(FortyFour, FortyTwo); |
| EXPECT_EQ(FortyFour, Ctx.getValue(LLVMFortyFour)); |
| // Check get(Type, APFloat). |
| auto *FortyFive = cast<sandboxir::ConstantFP>( |
| sandboxir::ConstantFP::get(DoubleTy, APFloat(45.0))); |
| auto *LLVMFortyFive = cast<llvm::ConstantFP>( |
| llvm::ConstantFP::get(LLVMDoubleTy, APFloat(45.0))); |
| EXPECT_EQ(FortyFive, Ctx.getValue(LLVMFortyFive)); |
| // Check get(Type, StringRef). |
| auto *FortySix = sandboxir::ConstantFP::get(FloatTy, "46.0"); |
| EXPECT_EQ(FortySix, Ctx.getValue(llvm::ConstantFP::get(LLVMFloatTy, "46.0"))); |
| // Check get(APFloat). |
| auto *FortySeven = sandboxir::ConstantFP::get(APFloat(47.0), Ctx); |
| EXPECT_EQ(FortySeven, Ctx.getValue(llvm::ConstantFP::get(C, APFloat(47.0)))); |
| // Check getNaN(). |
| { |
| auto *NaN = sandboxir::ConstantFP::getNaN(FloatTy); |
| EXPECT_EQ(NaN, Ctx.getValue(llvm::ConstantFP::getNaN(LLVMFloatTy))); |
| } |
| { |
| auto *NaN = sandboxir::ConstantFP::getNaN(FloatTy, /*Negative=*/true); |
| EXPECT_EQ(NaN, Ctx.getValue(llvm::ConstantFP::getNaN(LLVMFloatTy, |
| /*Negative=*/true))); |
| } |
| { |
| auto *NaN = sandboxir::ConstantFP::getNaN(FloatTy, /*Negative=*/true, |
| /*Payload=*/1); |
| EXPECT_EQ(NaN, Ctx.getValue(llvm::ConstantFP::getNaN( |
| LLVMFloatTy, /*Negative=*/true, /*Payload=*/1))); |
| } |
| // Check getQNaN(). |
| { |
| auto *QNaN = sandboxir::ConstantFP::getQNaN(FloatTy); |
| EXPECT_EQ(QNaN, Ctx.getValue(llvm::ConstantFP::getQNaN(LLVMFloatTy))); |
| } |
| { |
| auto *QNaN = sandboxir::ConstantFP::getQNaN(FloatTy, /*Negative=*/true); |
| EXPECT_EQ(QNaN, Ctx.getValue(llvm::ConstantFP::getQNaN(LLVMFloatTy, |
| /*Negative=*/true))); |
| } |
| { |
| APInt Payload(1, 1); |
| auto *QNaN = |
| sandboxir::ConstantFP::getQNaN(FloatTy, /*Negative=*/true, &Payload); |
| EXPECT_EQ(QNaN, Ctx.getValue(llvm::ConstantFP::getQNaN( |
| LLVMFloatTy, /*Negative=*/true, &Payload))); |
| } |
| // Check getSNaN(). |
| { |
| auto *SNaN = sandboxir::ConstantFP::getSNaN(FloatTy); |
| EXPECT_EQ(SNaN, Ctx.getValue(llvm::ConstantFP::getSNaN(LLVMFloatTy))); |
| } |
| { |
| auto *SNaN = sandboxir::ConstantFP::getSNaN(FloatTy, /*Negative=*/true); |
| EXPECT_EQ(SNaN, Ctx.getValue(llvm::ConstantFP::getSNaN(LLVMFloatTy, |
| /*Negative=*/true))); |
| } |
| { |
| APInt Payload(1, 1); |
| auto *SNaN = |
| sandboxir::ConstantFP::getSNaN(FloatTy, /*Negative=*/true, &Payload); |
| EXPECT_EQ(SNaN, Ctx.getValue(llvm::ConstantFP::getSNaN( |
| LLVMFloatTy, /*Negative=*/true, &Payload))); |
| } |
| |
| // Check getZero(). |
| { |
| auto *Zero = sandboxir::ConstantFP::getZero(FloatTy); |
| EXPECT_EQ(Zero, Ctx.getValue(llvm::ConstantFP::getZero(LLVMFloatTy))); |
| } |
| { |
| auto *Zero = sandboxir::ConstantFP::getZero(FloatTy, /*Negative=*/true); |
| EXPECT_EQ(Zero, Ctx.getValue(llvm::ConstantFP::getZero(LLVMFloatTy, |
| /*Negative=*/true))); |
| } |
| |
| // Check getNegativeZero(). |
| auto *NegZero = cast<sandboxir::ConstantFP>( |
| sandboxir::ConstantFP::getNegativeZero(FloatTy)); |
| EXPECT_EQ(NegZero, |
| Ctx.getValue(llvm::ConstantFP::getNegativeZero(LLVMFloatTy))); |
| |
| // Check getInfinity(). |
| { |
| auto *Inf = sandboxir::ConstantFP::getInfinity(FloatTy); |
| EXPECT_EQ(Inf, Ctx.getValue(llvm::ConstantFP::getInfinity(LLVMFloatTy))); |
| } |
| { |
| auto *Inf = sandboxir::ConstantFP::getInfinity(FloatTy, /*Negative=*/true); |
| EXPECT_EQ(Inf, Ctx.getValue(llvm::ConstantFP::getInfinity( |
| LLVMFloatTy, /*Negative=*/true))); |
| } |
| |
| // Check isValueValidForType(). |
| APFloat V(1.1); |
| EXPECT_EQ(sandboxir::ConstantFP::isValueValidForType(FloatTy, V), |
| llvm::ConstantFP::isValueValidForType(LLVMFloatTy, V)); |
| // Check getValueAPF(). |
| EXPECT_EQ(FortyFour->getValueAPF(), LLVMFortyFour->getValueAPF()); |
| // Check getValue(). |
| EXPECT_EQ(FortyFour->getValue(), LLVMFortyFour->getValue()); |
| // Check isZero(). |
| EXPECT_EQ(FortyFour->isZero(), LLVMFortyFour->isZero()); |
| EXPECT_TRUE(sandboxir::ConstantFP::getZero(FloatTy)); |
| EXPECT_TRUE(sandboxir::ConstantFP::getZero(FloatTy, /*Negative=*/true)); |
| // Check isNegative(). |
| EXPECT_TRUE(cast<sandboxir::ConstantFP>( |
| sandboxir::ConstantFP::getZero(FloatTy, /*Negative=*/true)) |
| ->isNegative()); |
| // Check isInfinity(). |
| EXPECT_TRUE( |
| cast<sandboxir::ConstantFP>(sandboxir::ConstantFP::getInfinity(FloatTy)) |
| ->isInfinity()); |
| // Check isNaN(). |
| EXPECT_TRUE( |
| cast<sandboxir::ConstantFP>(sandboxir::ConstantFP::getNaN(FloatTy)) |
| ->isNaN()); |
| // Check isExactlyValue(APFloat). |
| EXPECT_TRUE(NegZero->isExactlyValue(NegZero->getValueAPF())); |
| // Check isExactlyValue(double). |
| EXPECT_TRUE(NegZero->isExactlyValue(-0.0)); |
| } |
| |
| // Tests ConstantArray, ConstantStruct and ConstantVector. |
| TEST_F(SandboxIRTest, ConstantAggregate) { |
| // Note: we are using i42 to avoid the creation of ConstantDataVector or |
| // ConstantDataArray. |
| parseIR(C, R"IR( |
| define void @foo() { |
| %array = extractvalue [2 x i42] [i42 0, i42 1], 0 |
| %struct = extractvalue {i42, i42} {i42 0, i42 1}, 0 |
| %vector = extractelement <2 x i42> <i42 0, i42 1>, i32 0 |
| 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 *I0 = &*It++; |
| auto *I1 = &*It++; |
| auto *I2 = &*It++; |
| // Check classof() and creation. |
| auto *Array = cast<sandboxir::ConstantArray>(I0->getOperand(0)); |
| EXPECT_TRUE(isa<sandboxir::ConstantAggregate>(Array)); |
| auto *Struct = cast<sandboxir::ConstantStruct>(I1->getOperand(0)); |
| EXPECT_TRUE(isa<sandboxir::ConstantAggregate>(Struct)); |
| auto *Vector = cast<sandboxir::ConstantVector>(I2->getOperand(0)); |
| EXPECT_TRUE(isa<sandboxir::ConstantAggregate>(Vector)); |
| |
| auto *ZeroI42 = cast<sandboxir::ConstantInt>(Array->getOperand(0)); |
| auto *OneI42 = cast<sandboxir::ConstantInt>(Array->getOperand(1)); |
| // Check ConstantArray::get(), getType(). |
| auto *NewCA = |
| sandboxir::ConstantArray::get(Array->getType(), {ZeroI42, OneI42}); |
| EXPECT_EQ(NewCA, Array); |
| |
| // Check ConstantStruct::get(), getType(). |
| auto *NewCS = |
| sandboxir::ConstantStruct::get(Struct->getType(), {ZeroI42, OneI42}); |
| EXPECT_EQ(NewCS, Struct); |
| // Check ConstantStruct::get(...). |
| auto *NewCS2 = |
| sandboxir::ConstantStruct::get(Struct->getType(), ZeroI42, OneI42); |
| EXPECT_EQ(NewCS2, Struct); |
| // Check ConstantStruct::getAnon(ArayRef). |
| auto *AnonCS = sandboxir::ConstantStruct::getAnon({ZeroI42, OneI42}); |
| EXPECT_FALSE(cast<sandboxir::StructType>(AnonCS->getType())->isPacked()); |
| auto *AnonCSPacked = |
| sandboxir::ConstantStruct::getAnon({ZeroI42, OneI42}, /*Packed=*/true); |
| EXPECT_TRUE(cast<sandboxir::StructType>(AnonCSPacked->getType())->isPacked()); |
| // Check ConstantStruct::getAnon(Ctx, ArrayRef). |
| auto *AnonCS2 = sandboxir::ConstantStruct::getAnon(Ctx, {ZeroI42, OneI42}); |
| EXPECT_EQ(AnonCS2, AnonCS); |
| auto *AnonCS2Packed = sandboxir::ConstantStruct::getAnon( |
| Ctx, {ZeroI42, OneI42}, /*Packed=*/true); |
| EXPECT_EQ(AnonCS2Packed, AnonCSPacked); |
| // Check ConstantStruct::getTypeForElements(Ctx, ArrayRef). |
| auto *StructTy = |
| sandboxir::ConstantStruct::getTypeForElements(Ctx, {ZeroI42, OneI42}); |
| EXPECT_EQ(StructTy, Struct->getType()); |
| EXPECT_FALSE(StructTy->isPacked()); |
| // Check ConstantStruct::getTypeForElements(Ctx, ArrayRef, Packed). |
| auto *StructTyPacked = sandboxir::ConstantStruct::getTypeForElements( |
| Ctx, {ZeroI42, OneI42}, /*Packed=*/true); |
| EXPECT_TRUE(StructTyPacked->isPacked()); |
| // Check ConstantStruct::getTypeForElements(ArrayRef). |
| auto *StructTy2 = |
| sandboxir::ConstantStruct::getTypeForElements(Ctx, {ZeroI42, OneI42}); |
| EXPECT_EQ(StructTy2, Struct->getType()); |
| // Check ConstantStruct::getTypeForElements(ArrayRef, Packed). |
| auto *StructTy2Packed = sandboxir::ConstantStruct::getTypeForElements( |
| Ctx, {ZeroI42, OneI42}, /*Packed=*/true); |
| EXPECT_EQ(StructTy2Packed, StructTyPacked); |
| |
| // Check ConstantVector::get(). |
| auto *NewCV = sandboxir::ConstantVector::get({ZeroI42, OneI42}); |
| EXPECT_EQ(NewCV, Vector); |
| // Check ConstantVector::getSplat(), getType(). |
| auto *SplatRaw = |
| sandboxir::ConstantVector::getSplat(ElementCount::getFixed(2), OneI42); |
| auto *Splat = cast<sandboxir::ConstantVector>(SplatRaw); |
| EXPECT_EQ(Splat->getType()->getNumElements(), 2u); |
| EXPECT_THAT(Splat->operands(), testing::ElementsAre(OneI42, OneI42)); |
| // Check ConstantVector::getSplatValue(). |
| EXPECT_EQ(Splat->getSplatValue(), OneI42); |
| } |
| |
| TEST_F(SandboxIRTest, ConstantAggregateZero) { |
| parseIR(C, R"IR( |
| define void @foo(ptr %ptr, {i32, i8} %v1, <2 x i8> %v2) { |
| %extr0 = extractvalue [2 x i8] zeroinitializer, 0 |
| %extr1 = extractvalue {i32, i8} zeroinitializer, 0 |
| %extr2 = extractelement <2 x i8> zeroinitializer, i32 0 |
| 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 *Extr0 = &*It++; |
| auto *Extr1 = &*It++; |
| auto *Extr2 = &*It++; |
| [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| auto *Zero32 = |
| sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 0); |
| auto *Zero8 = sandboxir::ConstantInt::get(sandboxir::Type::getInt8Ty(Ctx), 0); |
| auto *Int8Ty = sandboxir::Type::getInt8Ty(Ctx); |
| auto *Int32Ty = sandboxir::Type::getInt32Ty(Ctx); |
| auto *ArrayTy = sandboxir::ArrayType::get(Int8Ty, 2u); |
| auto *StructTy = sandboxir::StructType::get(Ctx, {Int32Ty, Int8Ty}); |
| auto *VectorTy = |
| sandboxir::VectorType::get(Int8Ty, ElementCount::getFixed(2u)); |
| |
| // Check creation and classof(). |
| auto *ArrayCAZ = cast<sandboxir::ConstantAggregateZero>(Extr0->getOperand(0)); |
| EXPECT_EQ(ArrayCAZ->getType(), ArrayTy); |
| auto *StructCAZ = |
| cast<sandboxir::ConstantAggregateZero>(Extr1->getOperand(0)); |
| EXPECT_EQ(StructCAZ->getType(), StructTy); |
| auto *VectorCAZ = |
| cast<sandboxir::ConstantAggregateZero>(Extr2->getOperand(0)); |
| EXPECT_EQ(VectorCAZ->getType(), VectorTy); |
| // Check get(). |
| auto *SameVectorCAZ = |
| sandboxir::ConstantAggregateZero::get(sandboxir::VectorType::get( |
| sandboxir::Type::getInt8Ty(Ctx), ElementCount::getFixed(2))); |
| EXPECT_EQ(SameVectorCAZ, VectorCAZ); // Should be uniqued. |
| auto *NewVectorCAZ = |
| sandboxir::ConstantAggregateZero::get(sandboxir::VectorType::get( |
| sandboxir::Type::getInt8Ty(Ctx), ElementCount::getFixed(4))); |
| EXPECT_NE(NewVectorCAZ, VectorCAZ); |
| // Check getSequentialElement(). |
| auto *SeqElm = VectorCAZ->getSequentialElement(); |
| EXPECT_EQ(SeqElm, |
| sandboxir::ConstantInt::get(sandboxir::Type::getInt8Ty(Ctx), 0)); |
| // Check getStructElement(). |
| auto *StructElm0 = StructCAZ->getStructElement(0); |
| auto *StructElm1 = StructCAZ->getStructElement(1); |
| EXPECT_EQ(StructElm0, Zero32); |
| EXPECT_EQ(StructElm1, Zero8); |
| // Check getElementValue(Constant). |
| EXPECT_EQ(ArrayCAZ->getElementValue(Zero32), Zero8); |
| EXPECT_EQ(StructCAZ->getElementValue(Zero32), Zero32); |
| EXPECT_EQ(VectorCAZ->getElementValue(Zero32), Zero8); |
| // Check getElementValue(unsigned). |
| EXPECT_EQ(ArrayCAZ->getElementValue(0u), Zero8); |
| EXPECT_EQ(StructCAZ->getElementValue(0u), Zero32); |
| EXPECT_EQ(VectorCAZ->getElementValue(0u), Zero8); |
| // Check getElementCount(). |
| EXPECT_EQ(ArrayCAZ->getElementCount(), ElementCount::getFixed(2)); |
| EXPECT_EQ(NewVectorCAZ->getElementCount(), ElementCount::getFixed(4)); |
| } |
| |
| // Tests ConstantDataSequential, ConstantDataArray and ConstantDataVector. |
| TEST_F(SandboxIRTest, ConstantDataSequential) { |
| parseIR(C, R"IR( |
| define void @foo() { |
| %array = extractvalue [2 x i8] [i8 0, i8 1], 0 |
| %vector = extractelement <2 x i8> <i8 0, i8 1>, i32 0 |
| %farray = extractvalue [2 x float] [float 0.0, float 1.0], 0 |
| %fvector = extractelement <2 x double> <double 0.0, double 1.0>, i32 0 |
| %string = extractvalue [6 x i8] [i8 72, i8 69, i8 76, i8 76, i8 79, i8 0], 0 |
| %stringNoNull = extractvalue [5 x i8] [i8 72, i8 69, i8 76, i8 76, i8 79], 0 |
| %splat = extractelement <4 x i8> <i8 1, i8 1, i8 1, i8 1>, i32 0 |
| 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 *I0 = &*It++; |
| auto *I1 = &*It++; |
| auto *I2 = &*It++; |
| auto *I3 = &*It++; |
| auto *I4 = &*It++; |
| auto *I5 = &*It++; |
| auto *I6 = &*It++; |
| auto *Array = cast<sandboxir::ConstantDataArray>(I0->getOperand(0)); |
| EXPECT_TRUE(isa<sandboxir::ConstantDataSequential>(Array)); |
| auto *Vector = cast<sandboxir::ConstantDataVector>(I1->getOperand(0)); |
| EXPECT_TRUE(isa<sandboxir::ConstantDataVector>(Vector)); |
| auto *FArray = cast<sandboxir::ConstantDataArray>(I2->getOperand(0)); |
| EXPECT_TRUE(isa<sandboxir::ConstantDataSequential>(FArray)); |
| auto *FVector = cast<sandboxir::ConstantDataVector>(I3->getOperand(0)); |
| EXPECT_TRUE(isa<sandboxir::ConstantDataVector>(FVector)); |
| auto *String = cast<sandboxir::ConstantDataArray>(I4->getOperand(0)); |
| EXPECT_TRUE(isa<sandboxir::ConstantDataArray>(String)); |
| auto *StringNoNull = cast<sandboxir::ConstantDataArray>(I5->getOperand(0)); |
| EXPECT_TRUE(isa<sandboxir::ConstantDataArray>(StringNoNull)); |
| auto *Splat = cast<sandboxir::ConstantDataVector>(I6->getOperand(0)); |
| EXPECT_TRUE(isa<sandboxir::ConstantDataVector>(Splat)); |
| |
| auto *Zero8 = sandboxir::ConstantInt::get(sandboxir::Type::getInt8Ty(Ctx), 0); |
| auto *One8 = sandboxir::ConstantInt::get(sandboxir::Type::getInt8Ty(Ctx), 1); |
| |
| // Check isElementTypeCompatible(). |
| for (llvm::Type *LLVMTy : |
| {llvm::Type::getIntNTy(C, 42), llvm::Type::getInt8Ty(C)}) |
| EXPECT_EQ(llvm::ConstantDataSequential::isElementTypeCompatible(LLVMTy), |
| sandboxir::ConstantDataSequential::isElementTypeCompatible( |
| Ctx.getType(LLVMTy))); |
| // Check getElementAsInteger(). |
| EXPECT_EQ(Array->getElementAsInteger(0), 0u); |
| EXPECT_EQ(Array->getElementAsInteger(1), 1u); |
| EXPECT_EQ(Vector->getElementAsInteger(0), 0u); |
| EXPECT_EQ(Vector->getElementAsInteger(1), 1u); |
| // Check getElementAsAPInt(). |
| EXPECT_EQ(Array->getElementAsAPInt(0), 0u); |
| EXPECT_EQ(Array->getElementAsAPInt(1), 1u); |
| EXPECT_EQ(Vector->getElementAsAPInt(0), 0u); |
| EXPECT_EQ(Vector->getElementAsAPInt(1), 1u); |
| // Check geteElementAsFloat(). |
| EXPECT_EQ(FArray->getElementAsFloat(0), 0.0); |
| EXPECT_EQ(FArray->getElementAsFloat(1), 1.0); |
| // Check getElementAsDouble(). |
| EXPECT_EQ(FVector->getElementAsDouble(0), 0.0); |
| EXPECT_EQ(FVector->getElementAsDouble(1), 1.0); |
| // Check getElementAsConstant(). |
| EXPECT_EQ(Array->getElementAsConstant(0), Zero8); |
| EXPECT_EQ(Array->getElementAsConstant(1), One8); |
| EXPECT_EQ(Vector->getElementAsConstant(0), Zero8); |
| EXPECT_EQ(Vector->getElementAsConstant(1), One8); |
| // Check getElementType(). |
| EXPECT_EQ(Array->getElementType(), sandboxir::Type::getInt8Ty(Ctx)); |
| EXPECT_EQ(Vector->getElementType(), sandboxir::Type::getInt8Ty(Ctx)); |
| EXPECT_EQ(FArray->getElementType(), sandboxir::Type::getFloatTy(Ctx)); |
| EXPECT_EQ(FVector->getElementType(), sandboxir::Type::getDoubleTy(Ctx)); |
| // Check getNumElements(), |
| EXPECT_EQ(Array->getNumElements(), 2u); |
| EXPECT_EQ(Vector->getNumElements(), 2u); |
| EXPECT_EQ(FArray->getNumElements(), 2u); |
| EXPECT_EQ(FVector->getNumElements(), 2u); |
| // Check getElementByteSize(). |
| EXPECT_EQ(Array->getElementByteSize(), 1u); |
| EXPECT_EQ(Vector->getElementByteSize(), 1u); |
| EXPECT_EQ(FArray->getElementByteSize(), 4u); |
| EXPECT_EQ(FVector->getElementByteSize(), 8u); |
| // Check isString(). |
| EXPECT_EQ(Array->isString(), true); |
| EXPECT_EQ(Vector->isString(), false); |
| EXPECT_EQ(FArray->isString(), false); |
| EXPECT_EQ(FVector->isString(), false); |
| EXPECT_EQ(String->isString(), true); |
| // Check isCString(). |
| EXPECT_EQ(Array->isCString(), false); |
| EXPECT_EQ(Vector->isCString(), false); |
| EXPECT_EQ(FArray->isCString(), false); |
| EXPECT_EQ(FVector->isCString(), false); |
| EXPECT_EQ(String->isCString(), true); |
| // Check getAsString(). |
| char Data[] = {'H', 'E', 'L', 'L', 'O', '\0'}; |
| StringRef HelloWithNull(Data, 6); |
| EXPECT_EQ(String->getAsString(), HelloWithNull); |
| // Check getAsCString(). |
| EXPECT_EQ(String->getAsCString(), "HELLO"); |
| // Check getRawDataValues(). |
| EXPECT_EQ(String->getRawDataValues(), HelloWithNull); |
| |
| // Check ConstantDataArray member functions |
| // ---------------------------------------- |
| // Check get<ElementTy>(). |
| EXPECT_EQ(sandboxir::ConstantDataArray::get<char>(Ctx, {0, 1}), Array); |
| // Check get<ArrayTy>(). |
| SmallVector<char> Elmts({0, 1}); |
| EXPECT_EQ(sandboxir::ConstantDataArray::get<SmallVector<char>>(Ctx, Elmts), |
| Array); |
| // Check getRaw(). |
| EXPECT_EQ(sandboxir::ConstantDataArray::getRaw(StringRef("HELLO"), 5, |
| Zero8->getType()), |
| StringNoNull); |
| // Check getFP(). |
| SmallVector<uint16_t> Elts16({42, 43}); |
| SmallVector<uint32_t> Elts32({42, 43}); |
| SmallVector<uint64_t> Elts64({42, 43}); |
| auto *F16Ty = sandboxir::Type::getHalfTy(Ctx); |
| auto *F32Ty = sandboxir::Type::getFloatTy(Ctx); |
| auto *F64Ty = sandboxir::Type::getDoubleTy(Ctx); |
| |
| auto *CDA16 = sandboxir::ConstantDataArray::getFP(F16Ty, Elts16); |
| EXPECT_EQ(CDA16, cast<sandboxir::ConstantDataArray>( |
| Ctx.getValue(llvm::ConstantDataArray::getFP( |
| llvm::Type::getHalfTy(C), Elts16)))); |
| auto *CDA32 = sandboxir::ConstantDataArray::getFP(F32Ty, Elts32); |
| EXPECT_EQ(CDA32, cast<sandboxir::ConstantDataArray>( |
| Ctx.getValue(llvm::ConstantDataArray::getFP( |
| llvm::Type::getFloatTy(C), Elts32)))); |
| auto *CDA64 = sandboxir::ConstantDataArray::getFP(F64Ty, Elts64); |
| EXPECT_EQ(CDA64, cast<sandboxir::ConstantDataArray>( |
| Ctx.getValue(llvm::ConstantDataArray::getFP( |
| llvm::Type::getDoubleTy(C), Elts64)))); |
| // Check getString(). |
| EXPECT_EQ(sandboxir::ConstantDataArray::getString(Ctx, "HELLO"), String); |
| |
| EXPECT_EQ(sandboxir::ConstantDataArray::getString(Ctx, "HELLO", |
| /*AddNull=*/false), |
| StringNoNull); |
| EXPECT_EQ( |
| sandboxir::ConstantDataArray::getString(Ctx, "HELLO", /*AddNull=*/false), |
| StringNoNull); |
| |
| { |
| // Check ConstantDataArray member functions |
| // ---------------------------------------- |
| // Check get(). |
| SmallVector<uint8_t> Elts8({0u, 1u}); |
| SmallVector<uint16_t> Elts16({0u, 1u}); |
| SmallVector<uint32_t> Elts32({0u, 1u}); |
| SmallVector<uint64_t> Elts64({0u, 1u}); |
| SmallVector<float> EltsF32({0.0, 1.0}); |
| SmallVector<double> EltsF64({0.0, 1.0}); |
| auto *CDV8 = sandboxir::ConstantDataVector::get(Ctx, Elts8); |
| EXPECT_EQ(CDV8, cast<sandboxir::ConstantDataVector>( |
| Ctx.getValue(llvm::ConstantDataVector::get(C, Elts8)))); |
| auto *CDV16 = sandboxir::ConstantDataVector::get(Ctx, Elts16); |
| EXPECT_EQ(CDV16, cast<sandboxir::ConstantDataVector>(Ctx.getValue( |
| llvm::ConstantDataVector::get(C, Elts16)))); |
| auto *CDV32 = sandboxir::ConstantDataVector::get(Ctx, Elts32); |
| EXPECT_EQ(CDV32, cast<sandboxir::ConstantDataVector>(Ctx.getValue( |
| llvm::ConstantDataVector::get(C, Elts32)))); |
| auto *CDVF32 = sandboxir::ConstantDataVector::get(Ctx, EltsF32); |
| EXPECT_EQ(CDVF32, cast<sandboxir::ConstantDataVector>(Ctx.getValue( |
| llvm::ConstantDataVector::get(C, EltsF32)))); |
| auto *CDVF64 = sandboxir::ConstantDataVector::get(Ctx, EltsF64); |
| EXPECT_EQ(CDVF64, cast<sandboxir::ConstantDataVector>(Ctx.getValue( |
| llvm::ConstantDataVector::get(C, EltsF64)))); |
| // Check getRaw(). |
| auto *CDVRaw = sandboxir::ConstantDataVector::getRaw( |
| StringRef("HELLO"), 5, sandboxir::Type::getInt8Ty(Ctx)); |
| EXPECT_EQ(CDVRaw, |
| cast<sandboxir::ConstantDataVector>( |
| Ctx.getValue(llvm::ConstantDataVector::getRaw( |
| StringRef("HELLO"), 5, llvm::Type::getInt8Ty(C))))); |
| // Check getFP(). |
| auto *CDVFP16 = sandboxir::ConstantDataVector::getFP(F16Ty, Elts16); |
| EXPECT_EQ(CDVFP16, cast<sandboxir::ConstantDataVector>( |
| Ctx.getValue(llvm::ConstantDataVector::getFP( |
| llvm::Type::getHalfTy(C), Elts16)))); |
| auto *CDVFP32 = sandboxir::ConstantDataVector::getFP(F32Ty, Elts32); |
| EXPECT_EQ(CDVFP32, cast<sandboxir::ConstantDataVector>( |
| Ctx.getValue(llvm::ConstantDataVector::getFP( |
| llvm::Type::getFloatTy(C), Elts32)))); |
| auto *CDVFP64 = sandboxir::ConstantDataVector::getFP(F64Ty, Elts64); |
| EXPECT_EQ(CDVFP64, cast<sandboxir::ConstantDataVector>( |
| Ctx.getValue(llvm::ConstantDataVector::getFP( |
| llvm::Type::getDoubleTy(C), Elts64)))); |
| // Check getSplat(). |
| auto *NewSplat = cast<sandboxir::ConstantDataVector>( |
| sandboxir::ConstantDataVector::getSplat(4, One8)); |
| EXPECT_EQ(NewSplat, Splat); |
| // Check isSplat(). |
| EXPECT_TRUE(NewSplat->isSplat()); |
| EXPECT_FALSE(Vector->isSplat()); |
| // Check getSplatValue(). |
| EXPECT_EQ(NewSplat->getSplatValue(), One8); |
| // Check getType(). |
| EXPECT_TRUE(isa<sandboxir::FixedVectorType>(NewSplat->getType())); |
| EXPECT_EQ( |
| cast<sandboxir::FixedVectorType>(NewSplat->getType())->getNumElements(), |
| 4u); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, ConstantPointerNull) { |
| parseIR(C, R"IR( |
| define ptr @foo() { |
| ret ptr null |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto &BB = *F.begin(); |
| auto It = BB.begin(); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| // Check classof() and creation. |
| auto *CPNull = cast<sandboxir::ConstantPointerNull>(Ret->getReturnValue()); |
| // Check get(). |
| auto *NewCPNull = |
| sandboxir::ConstantPointerNull::get(sandboxir::PointerType::get(Ctx, 0u)); |
| EXPECT_EQ(NewCPNull, CPNull); |
| auto *NewCPNull2 = |
| sandboxir::ConstantPointerNull::get(sandboxir::PointerType::get(Ctx, 1u)); |
| EXPECT_NE(NewCPNull2, CPNull); |
| // Check getType(). |
| EXPECT_EQ(CPNull->getType(), sandboxir::PointerType::get(Ctx, 0u)); |
| EXPECT_EQ(NewCPNull2->getType(), sandboxir::PointerType::get(Ctx, 1u)); |
| } |
| |
| TEST_F(SandboxIRTest, PoisonValue) { |
| parseIR(C, R"IR( |
| define void @foo() { |
| %i0 = add i32 poison, poison |
| %i1 = add <2 x i32> poison, poison |
| %i2 = extractvalue {i32, i8} poison, 0 |
| 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 *I0 = &*It++; |
| auto *I1 = &*It++; |
| auto *I2 = &*It++; |
| auto *Int32Ty = sandboxir::Type::getInt32Ty(Ctx); |
| auto *Int8Ty = sandboxir::Type::getInt8Ty(Ctx); |
| auto *Zero32 = sandboxir::ConstantInt::get(Int32Ty, 0u); |
| auto *One32 = sandboxir::ConstantInt::get(Int32Ty, 1u); |
| |
| // Check classof() and creation. |
| auto *Poison = cast<sandboxir::PoisonValue>(I0->getOperand(0)); |
| EXPECT_EQ(Poison->getType(), Int32Ty); |
| EXPECT_TRUE(isa<sandboxir::UndefValue>(Poison)); // Poison is Undef |
| // Check get(). |
| auto *NewPoison = sandboxir::PoisonValue::get(Int32Ty); |
| EXPECT_EQ(NewPoison, Poison); |
| auto *NewPoison2 = |
| sandboxir::PoisonValue::get(sandboxir::PointerType::get(Ctx, 0u)); |
| EXPECT_NE(NewPoison2, Poison); |
| // Check getSequentialElement(). |
| auto *PoisonVector = cast<sandboxir::PoisonValue>(I1->getOperand(0)); |
| auto *SeqElm = PoisonVector->getSequentialElement(); |
| EXPECT_EQ(SeqElm->getType(), Int32Ty); |
| // Check getStructElement(). |
| auto *PoisonStruct = cast<sandboxir::PoisonValue>(I2->getOperand(0)); |
| auto *StrElm0 = PoisonStruct->getStructElement(0); |
| auto *StrElm1 = PoisonStruct->getStructElement(1); |
| EXPECT_EQ(StrElm0->getType(), Int32Ty); |
| EXPECT_EQ(StrElm1->getType(), Int8Ty); |
| // Check getElementValue(Constant) |
| EXPECT_EQ(PoisonStruct->getElementValue(Zero32), |
| sandboxir::PoisonValue::get(Int32Ty)); |
| EXPECT_EQ(PoisonStruct->getElementValue(One32), |
| sandboxir::PoisonValue::get(Int8Ty)); |
| // Check getElementValue(unsigned) |
| EXPECT_EQ(PoisonStruct->getElementValue(0u), |
| sandboxir::PoisonValue::get(Int32Ty)); |
| EXPECT_EQ(PoisonStruct->getElementValue(1u), |
| sandboxir::PoisonValue::get(Int8Ty)); |
| } |
| |
| TEST_F(SandboxIRTest, UndefValue) { |
| parseIR(C, R"IR( |
| define void @foo() { |
| %i0 = add i32 undef, undef |
| %i1 = add <2 x i32> undef, undef |
| %i2 = extractvalue {i32, i8} undef, 0 |
| 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 *I0 = &*It++; |
| auto *I1 = &*It++; |
| auto *I2 = &*It++; |
| auto *Int32Ty = sandboxir::Type::getInt32Ty(Ctx); |
| auto *Int8Ty = sandboxir::Type::getInt8Ty(Ctx); |
| auto *Zero32 = sandboxir::ConstantInt::get(Int32Ty, 0u); |
| auto *One32 = sandboxir::ConstantInt::get(Int32Ty, 1u); |
| |
| // Check classof() and creation. |
| auto *Undef = cast<sandboxir::UndefValue>(I0->getOperand(0)); |
| EXPECT_EQ(Undef->getType(), Int32Ty); |
| EXPECT_FALSE(isa<sandboxir::PoisonValue>(Undef)); // Undef is not Poison |
| // Check get(). |
| auto *NewUndef = sandboxir::UndefValue::get(Int32Ty); |
| EXPECT_EQ(NewUndef, Undef); |
| auto *NewUndef2 = |
| sandboxir::UndefValue::get(sandboxir::PointerType::get(Ctx, 0u)); |
| EXPECT_NE(NewUndef2, Undef); |
| // Check getSequentialElement(). |
| auto *UndefVector = cast<sandboxir::UndefValue>(I1->getOperand(0)); |
| auto *SeqElm = UndefVector->getSequentialElement(); |
| EXPECT_EQ(SeqElm->getType(), Int32Ty); |
| // Check getStructElement(). |
| auto *UndefStruct = cast<sandboxir::UndefValue>(I2->getOperand(0)); |
| auto *StrElm0 = UndefStruct->getStructElement(0); |
| auto *StrElm1 = UndefStruct->getStructElement(1); |
| EXPECT_EQ(StrElm0->getType(), Int32Ty); |
| EXPECT_EQ(StrElm1->getType(), Int8Ty); |
| // Check getElementValue(Constant) |
| EXPECT_EQ(UndefStruct->getElementValue(Zero32), |
| sandboxir::UndefValue::get(Int32Ty)); |
| EXPECT_EQ(UndefStruct->getElementValue(One32), |
| sandboxir::UndefValue::get(Int8Ty)); |
| // Check getElementValue(unsigned) |
| EXPECT_EQ(UndefStruct->getElementValue(0u), |
| sandboxir::UndefValue::get(Int32Ty)); |
| EXPECT_EQ(UndefStruct->getElementValue(1u), |
| sandboxir::UndefValue::get(Int8Ty)); |
| // Check getNumElements(). |
| EXPECT_EQ(UndefVector->getNumElements(), 2u); |
| EXPECT_EQ(UndefStruct->getNumElements(), 2u); |
| } |
| |
| TEST_F(SandboxIRTest, GlobalValue) { |
| parseIR(C, R"IR( |
| declare external void @bar() |
| define void @foo() { |
| call void @bar() |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMBB = &*LLVMF.begin(); |
| auto LLVMIt = LLVMBB->begin(); |
| auto *LLVMCall = cast<llvm::CallInst>(&*LLVMIt++); |
| auto *LLVMGV = cast<llvm::GlobalValue>(LLVMCall->getCalledOperand()); |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *Call = cast<sandboxir::CallInst>(&*It++); |
| [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| // Check classof(), creation, getFunction(), getBasicBlock(). |
| auto *GV = cast<sandboxir::GlobalValue>(Call->getCalledOperand()); |
| // Check getAddressSpace(). |
| EXPECT_EQ(GV->getAddressSpace(), LLVMGV->getAddressSpace()); |
| // Check hasGlobalUnnamedAddr(). |
| EXPECT_EQ(GV->hasGlobalUnnamedAddr(), LLVMGV->hasGlobalUnnamedAddr()); |
| // Check hasAtLeastLocalUnnamedAddr(). |
| EXPECT_EQ(GV->hasAtLeastLocalUnnamedAddr(), |
| LLVMGV->hasAtLeastLocalUnnamedAddr()); |
| // Check getUnnamedAddr(). |
| EXPECT_EQ(GV->getUnnamedAddr(), LLVMGV->getUnnamedAddr()); |
| // Check setUnnamedAddr(). |
| auto OrigUnnamedAddr = GV->getUnnamedAddr(); |
| auto NewUnnamedAddr = sandboxir::GlobalValue::UnnamedAddr::Global; |
| EXPECT_NE(NewUnnamedAddr, OrigUnnamedAddr); |
| GV->setUnnamedAddr(NewUnnamedAddr); |
| EXPECT_EQ(GV->getUnnamedAddr(), NewUnnamedAddr); |
| GV->setUnnamedAddr(OrigUnnamedAddr); |
| EXPECT_EQ(GV->getUnnamedAddr(), OrigUnnamedAddr); |
| // Check getMinUnnamedAddr(). |
| EXPECT_EQ( |
| sandboxir::GlobalValue::getMinUnnamedAddr(OrigUnnamedAddr, |
| NewUnnamedAddr), |
| llvm::GlobalValue::getMinUnnamedAddr(OrigUnnamedAddr, NewUnnamedAddr)); |
| // Check hasComdat(). |
| EXPECT_EQ(GV->hasComdat(), LLVMGV->hasComdat()); |
| // Check getVisibility(). |
| EXPECT_EQ(GV->getVisibility(), LLVMGV->getVisibility()); |
| // Check hasDefaultVisibility(). |
| EXPECT_EQ(GV->hasDefaultVisibility(), LLVMGV->hasDefaultVisibility()); |
| // Check hasHiddenVisibility(). |
| EXPECT_EQ(GV->hasHiddenVisibility(), LLVMGV->hasHiddenVisibility()); |
| // Check hasProtectedVisibility(). |
| EXPECT_EQ(GV->hasProtectedVisibility(), LLVMGV->hasProtectedVisibility()); |
| // Check setVisibility(). |
| auto OrigVisibility = GV->getVisibility(); |
| auto NewVisibility = |
| sandboxir::GlobalValue::VisibilityTypes::ProtectedVisibility; |
| EXPECT_NE(NewVisibility, OrigVisibility); |
| GV->setVisibility(NewVisibility); |
| EXPECT_EQ(GV->getVisibility(), NewVisibility); |
| GV->setVisibility(OrigVisibility); |
| EXPECT_EQ(GV->getVisibility(), OrigVisibility); |
| } |
| |
| TEST_F(SandboxIRTest, GlobalObject) { |
| parseIR(C, R"IR( |
| declare external void @bar() |
| define void @foo() { |
| call void @bar() |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMBB = &*LLVMF.begin(); |
| auto LLVMIt = LLVMBB->begin(); |
| auto *LLVMCall = cast<llvm::CallInst>(&*LLVMIt++); |
| auto *LLVMGO = cast<llvm::GlobalObject>(LLVMCall->getCalledOperand()); |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *Call = cast<sandboxir::CallInst>(&*It++); |
| // Check classof(), creation. |
| auto *GO = cast<sandboxir::GlobalObject>(Call->getCalledOperand()); |
| // Check hasSection(). |
| EXPECT_EQ(GO->hasSection(), LLVMGO->hasSection()); |
| // Check getSection(). |
| EXPECT_EQ(GO->getSection(), LLVMGO->getSection()); |
| // Check setSection(). |
| auto OrigSection = GO->getSection(); |
| auto NewSection = ".some_section"; |
| EXPECT_NE(NewSection, OrigSection); |
| GO->setSection(NewSection); |
| EXPECT_EQ(GO->getSection(), NewSection); |
| GO->setSection(OrigSection); |
| EXPECT_EQ(GO->getSection(), OrigSection); |
| // Check hasComdat(). |
| EXPECT_EQ(GO->hasComdat(), LLVMGO->hasComdat()); |
| // Check getVCallVisibility(). |
| EXPECT_EQ(GO->getVCallVisibility(), LLVMGO->getVCallVisibility()); |
| // Check canIncreaseAlignment(). |
| EXPECT_EQ(GO->canIncreaseAlignment(), LLVMGO->canIncreaseAlignment()); |
| } |
| |
| TEST_F(SandboxIRTest, GlobalIFunc) { |
| parseIR(C, R"IR( |
| declare external void @bar() |
| @ifunc0 = ifunc void(), ptr @foo |
| @ifunc1 = ifunc void(), ptr @foo |
| define void @foo() { |
| call void @ifunc0() |
| call void @ifunc1() |
| call void @bar() |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMBB = &*LLVMF.begin(); |
| auto LLVMIt = LLVMBB->begin(); |
| auto *LLVMCall0 = cast<llvm::CallInst>(&*LLVMIt++); |
| auto *LLVMIFunc0 = cast<llvm::GlobalIFunc>(LLVMCall0->getCalledOperand()); |
| |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *Call0 = cast<sandboxir::CallInst>(&*It++); |
| auto *Call1 = cast<sandboxir::CallInst>(&*It++); |
| auto *CallBar = cast<sandboxir::CallInst>(&*It++); |
| // Check classof(), creation. |
| auto *IFunc0 = cast<sandboxir::GlobalIFunc>(Call0->getCalledOperand()); |
| auto *IFunc1 = cast<sandboxir::GlobalIFunc>(Call1->getCalledOperand()); |
| auto *Bar = cast<sandboxir::Function>(CallBar->getCalledOperand()); |
| |
| // Check getIterator(). |
| { |
| auto It0 = IFunc0->getIterator(); |
| auto It1 = IFunc1->getIterator(); |
| EXPECT_EQ(&*It0, IFunc0); |
| EXPECT_EQ(&*It1, IFunc1); |
| EXPECT_EQ(std::next(It0), It1); |
| EXPECT_EQ(std::prev(It1), It0); |
| EXPECT_EQ(&*std::next(It0), IFunc1); |
| EXPECT_EQ(&*std::prev(It1), IFunc0); |
| } |
| // Check getReverseIterator(). |
| { |
| auto RevIt0 = IFunc0->getReverseIterator(); |
| auto RevIt1 = IFunc1->getReverseIterator(); |
| EXPECT_EQ(&*RevIt0, IFunc0); |
| EXPECT_EQ(&*RevIt1, IFunc1); |
| EXPECT_EQ(std::prev(RevIt0), RevIt1); |
| EXPECT_EQ(std::next(RevIt1), RevIt0); |
| EXPECT_EQ(&*std::prev(RevIt0), IFunc1); |
| EXPECT_EQ(&*std::next(RevIt1), IFunc0); |
| } |
| |
| // Check setResolver(), getResolver(). |
| EXPECT_EQ(IFunc0->getResolver(), Ctx.getValue(LLVMIFunc0->getResolver())); |
| auto *OrigResolver = IFunc0->getResolver(); |
| auto *NewResolver = Bar; |
| EXPECT_NE(NewResolver, OrigResolver); |
| IFunc0->setResolver(NewResolver); |
| EXPECT_EQ(IFunc0->getResolver(), NewResolver); |
| IFunc0->setResolver(OrigResolver); |
| EXPECT_EQ(IFunc0->getResolver(), OrigResolver); |
| // Check getResolverFunction(). |
| EXPECT_EQ(IFunc0->getResolverFunction(), |
| Ctx.getValue(LLVMIFunc0->getResolverFunction())); |
| // Check isValidLinkage(). |
| for (auto L : |
| {GlobalValue::ExternalLinkage, GlobalValue::AvailableExternallyLinkage, |
| GlobalValue::LinkOnceAnyLinkage, GlobalValue::LinkOnceODRLinkage, |
| GlobalValue::WeakAnyLinkage, GlobalValue::WeakODRLinkage, |
| GlobalValue::AppendingLinkage, GlobalValue::InternalLinkage, |
| GlobalValue::PrivateLinkage, GlobalValue::ExternalWeakLinkage, |
| GlobalValue::CommonLinkage}) { |
| EXPECT_EQ(IFunc0->isValidLinkage(L), LLVMIFunc0->isValidLinkage(L)); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, GlobalVariable) { |
| parseIR(C, R"IR( |
| @glob0 = global i32 42 |
| @glob1 = global i32 43 |
| define void @foo() { |
| %ld0 = load i32, ptr @glob0 |
| %ld1 = load i32, ptr @glob1 |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMBB = &*LLVMF.begin(); |
| auto LLVMIt = LLVMBB->begin(); |
| auto *LLVMLd0 = cast<llvm::LoadInst>(&*LLVMIt++); |
| auto *LLVMGV0 = cast<llvm::GlobalVariable>(LLVMLd0->getPointerOperand()); |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *Ld0 = cast<sandboxir::LoadInst>(&*It++); |
| auto *Ld1 = cast<sandboxir::LoadInst>(&*It++); |
| // Check classof(), creation. |
| auto *GV0 = cast<sandboxir::GlobalVariable>(Ld0->getPointerOperand()); |
| auto *GV1 = cast<sandboxir::GlobalVariable>(Ld1->getPointerOperand()); |
| // Check getIterator(). |
| { |
| auto It0 = GV0->getIterator(); |
| auto It1 = GV1->getIterator(); |
| EXPECT_EQ(&*It0, GV0); |
| EXPECT_EQ(&*It1, GV1); |
| EXPECT_EQ(std::next(It0), It1); |
| EXPECT_EQ(std::prev(It1), It0); |
| EXPECT_EQ(&*std::next(It0), GV1); |
| EXPECT_EQ(&*std::prev(It1), GV0); |
| } |
| // Check getReverseIterator(). |
| { |
| auto RevIt0 = GV0->getReverseIterator(); |
| auto RevIt1 = GV1->getReverseIterator(); |
| EXPECT_EQ(&*RevIt0, GV0); |
| EXPECT_EQ(&*RevIt1, GV1); |
| EXPECT_EQ(std::prev(RevIt0), RevIt1); |
| EXPECT_EQ(std::next(RevIt1), RevIt0); |
| EXPECT_EQ(&*std::prev(RevIt0), GV1); |
| EXPECT_EQ(&*std::next(RevIt1), GV0); |
| } |
| // Check hasInitializer(). |
| EXPECT_EQ(GV0->hasInitializer(), LLVMGV0->hasInitializer()); |
| // Check hasDefinitiveInitializer(). |
| EXPECT_EQ(GV0->hasDefinitiveInitializer(), |
| LLVMGV0->hasDefinitiveInitializer()); |
| // Check hasUniqueInitializer(). |
| EXPECT_EQ(GV0->hasUniqueInitializer(), LLVMGV0->hasUniqueInitializer()); |
| // Check getInitializer(). |
| EXPECT_EQ(GV0->getInitializer(), Ctx.getValue(LLVMGV0->getInitializer())); |
| // Check setInitializer(). |
| auto *OrigInitializer = GV0->getInitializer(); |
| auto *NewInitializer = GV1->getInitializer(); |
| EXPECT_NE(NewInitializer, OrigInitializer); |
| GV0->setInitializer(NewInitializer); |
| EXPECT_EQ(GV0->getInitializer(), NewInitializer); |
| GV0->setInitializer(OrigInitializer); |
| EXPECT_EQ(GV0->getInitializer(), OrigInitializer); |
| // Check isConstant(). |
| EXPECT_EQ(GV0->isConstant(), LLVMGV0->isConstant()); |
| // Check setConstant(). |
| bool OrigIsConstant = GV0->isConstant(); |
| bool NewIsConstant = !OrigIsConstant; |
| GV0->setConstant(NewIsConstant); |
| EXPECT_EQ(GV0->isConstant(), NewIsConstant); |
| GV0->setConstant(OrigIsConstant); |
| EXPECT_EQ(GV0->isConstant(), OrigIsConstant); |
| // Check isExternallyInitialized(). |
| EXPECT_EQ(GV0->isExternallyInitialized(), LLVMGV0->isExternallyInitialized()); |
| // Check setExternallyInitialized(). |
| bool OrigIsExtInit = GV0->isExternallyInitialized(); |
| bool NewIsExtInit = !OrigIsExtInit; |
| GV0->setExternallyInitialized(NewIsExtInit); |
| EXPECT_EQ(GV0->isExternallyInitialized(), NewIsExtInit); |
| GV0->setExternallyInitialized(OrigIsExtInit); |
| EXPECT_EQ(GV0->isExternallyInitialized(), OrigIsExtInit); |
| for (auto KindIdx : seq<int>(0, Attribute::AttrKind::EndAttrKinds)) { |
| // Check hasAttribute(AttrKind). |
| auto Kind = static_cast<Attribute::AttrKind>(KindIdx); |
| EXPECT_EQ(GV0->hasAttribute(Kind), LLVMGV0->hasAttribute(Kind)); |
| // Check hasAttribute(StringRef). |
| StringRef KindStr = Attribute::getNameFromAttrKind(Kind); |
| EXPECT_EQ(GV0->hasAttribute(KindStr), LLVMGV0->hasAttribute(KindStr)); |
| } |
| // Check hasAttributes(). |
| EXPECT_EQ(GV0->hasAttributes(), LLVMGV0->hasAttributes()); |
| |
| for (auto KindIdx : seq<int>(0, Attribute::AttrKind::EndAttrKinds)) { |
| // Check getAttribute(AttrKind). |
| auto Kind = static_cast<Attribute::AttrKind>(KindIdx); |
| EXPECT_EQ(GV0->getAttribute(Kind), LLVMGV0->getAttribute(Kind)); |
| // Check getAttribute(StringRef). |
| StringRef KindStr = Attribute::getNameFromAttrKind(Kind); |
| EXPECT_EQ(GV0->getAttribute(KindStr), LLVMGV0->getAttribute(KindStr)); |
| } |
| // Check getAttributes(). |
| EXPECT_EQ(GV0->getAttributes(), LLVMGV0->getAttributes()); |
| // Check getAttributesAsList(). |
| EXPECT_THAT(GV0->getAttributesAsList(0u), |
| testing::ContainerEq(LLVMGV0->getAttributesAsList(0u))); |
| // Check hasImplicitSection(). |
| EXPECT_EQ(GV0->hasImplicitSection(), LLVMGV0->hasImplicitSection()); |
| // Check getCodeModelRaw(). |
| EXPECT_EQ(GV0->getCodeModelRaw(), LLVMGV0->getCodeModelRaw()); |
| // Check getCodeModel(). |
| EXPECT_EQ(GV0->getCodeModel(), LLVMGV0->getCodeModel()); |
| // Check getAlign(). |
| EXPECT_EQ(GV0->getAlign(), LLVMGV0->getAlign()); |
| // Check setAlignment(). |
| auto OrigMaybeAlign = GV0->getAlign(); |
| auto NewMaybeAlign = MaybeAlign(128); |
| EXPECT_NE(NewMaybeAlign, OrigMaybeAlign); |
| GV0->setAlignment(NewMaybeAlign); |
| EXPECT_EQ(GV0->getAlign(), NewMaybeAlign); |
| GV0->setAlignment(OrigMaybeAlign); |
| EXPECT_EQ(GV0->getAlign(), OrigMaybeAlign); |
| } |
| |
| TEST_F(SandboxIRTest, GlobalAlias) { |
| parseIR(C, R"IR( |
| @alias0 = dso_local alias void(), ptr @foo |
| @alias1 = dso_local alias void(), ptr @foo |
| declare void @bar(); |
| define void @foo() { |
| call void @alias0() |
| call void @alias1() |
| call void @bar() |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMBB = &*LLVMF.begin(); |
| auto LLVMIt = LLVMBB->begin(); |
| auto *LLVMCall0 = cast<llvm::CallInst>(&*LLVMIt++); |
| auto *LLVMAlias0 = cast<llvm::GlobalAlias>(LLVMCall0->getCalledOperand()); |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *Call0 = cast<sandboxir::CallInst>(&*It++); |
| auto *Call1 = cast<sandboxir::CallInst>(&*It++); |
| auto *CallBar = cast<sandboxir::CallInst>(&*It++); |
| auto *CalleeBar = cast<sandboxir::Constant>(CallBar->getCalledOperand()); |
| // Check classof(), creation. |
| auto *Alias0 = cast<sandboxir::GlobalAlias>(Call0->getCalledOperand()); |
| auto *Alias1 = cast<sandboxir::GlobalAlias>(Call1->getCalledOperand()); |
| // Check getIterator(). |
| { |
| auto It0 = Alias0->getIterator(); |
| auto It1 = Alias1->getIterator(); |
| EXPECT_EQ(&*It0, Alias0); |
| EXPECT_EQ(&*It1, Alias1); |
| EXPECT_EQ(std::next(It0), It1); |
| EXPECT_EQ(std::prev(It1), It0); |
| EXPECT_EQ(&*std::next(It0), Alias1); |
| EXPECT_EQ(&*std::prev(It1), Alias0); |
| } |
| // Check getReverseIterator(). |
| { |
| auto RevIt0 = Alias0->getReverseIterator(); |
| auto RevIt1 = Alias1->getReverseIterator(); |
| EXPECT_EQ(&*RevIt0, Alias0); |
| EXPECT_EQ(&*RevIt1, Alias1); |
| EXPECT_EQ(std::prev(RevIt0), RevIt1); |
| EXPECT_EQ(std::next(RevIt1), RevIt0); |
| EXPECT_EQ(&*std::prev(RevIt0), Alias1); |
| EXPECT_EQ(&*std::next(RevIt1), Alias0); |
| } |
| // Check getAliasee(). |
| EXPECT_EQ(Alias0->getAliasee(), Ctx.getValue(LLVMAlias0->getAliasee())); |
| // Check setAliasee(). |
| auto *OrigAliasee = Alias0->getAliasee(); |
| auto *NewAliasee = CalleeBar; |
| EXPECT_NE(NewAliasee, OrigAliasee); |
| Alias0->setAliasee(NewAliasee); |
| EXPECT_EQ(Alias0->getAliasee(), NewAliasee); |
| Alias0->setAliasee(OrigAliasee); |
| EXPECT_EQ(Alias0->getAliasee(), OrigAliasee); |
| // Check getAliaseeObject(). |
| EXPECT_EQ(Alias0->getAliaseeObject(), |
| Ctx.getValue(LLVMAlias0->getAliaseeObject())); |
| } |
| |
| TEST_F(SandboxIRTest, NoCFIValue) { |
| parseIR(C, R"IR( |
| define void @foo() { |
| call void no_cfi @foo() |
| 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 *Call = cast<sandboxir::CallInst>(&*It++); |
| // Check classof(), creation. |
| auto *NoCFI = cast<sandboxir::NoCFIValue>(Call->getCalledOperand()); |
| // Check get(). |
| auto *NewNoCFI = sandboxir::NoCFIValue::get(&F); |
| EXPECT_EQ(NewNoCFI, NoCFI); |
| // Check getGlobalValue(). |
| EXPECT_EQ(NoCFI->getGlobalValue(), &F); |
| // Check getType(). |
| EXPECT_EQ(NoCFI->getType(), F.getType()); |
| } |
| |
| TEST_F(SandboxIRTest, ConstantPtrAuth) { |
| parseIR(C, R"IR( |
| define ptr @foo() { |
| ret ptr ptrauth (ptr @foo, i32 2, i64 1234) |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMBB = &*LLVMF.begin(); |
| auto *LLVMRet = cast<llvm::ReturnInst>(&*LLVMBB->begin()); |
| auto *LLVMPtrAuth = cast<llvm::ConstantPtrAuth>(LLVMRet->getReturnValue()); |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| // Check classof(), creation. |
| auto *PtrAuth = cast<sandboxir::ConstantPtrAuth>(Ret->getReturnValue()); |
| // Check get(), getKey(), getDiscriminator(), getAddrDiscriminator(). |
| auto *NewPtrAuth = sandboxir::ConstantPtrAuth::get( |
| &F, PtrAuth->getKey(), PtrAuth->getDiscriminator(), |
| PtrAuth->getAddrDiscriminator()); |
| EXPECT_EQ(NewPtrAuth, PtrAuth); |
| // Check hasAddressDiscriminator(). |
| EXPECT_EQ(PtrAuth->hasAddressDiscriminator(), |
| LLVMPtrAuth->hasAddressDiscriminator()); |
| // Check hasSpecialAddressDiscriminator(). |
| EXPECT_EQ(PtrAuth->hasSpecialAddressDiscriminator(0u), |
| LLVMPtrAuth->hasSpecialAddressDiscriminator(0u)); |
| // Check isKnownCompatibleWith(). |
| const DataLayout &DL = M->getDataLayout(); |
| EXPECT_TRUE(PtrAuth->isKnownCompatibleWith(PtrAuth->getKey(), |
| PtrAuth->getDiscriminator(), DL)); |
| // Check getWithSameSchema(). |
| EXPECT_EQ(PtrAuth->getWithSameSchema(&F), PtrAuth); |
| } |
| |
| TEST_F(SandboxIRTest, ConstantExpr) { |
| parseIR(C, R"IR( |
| define i32 @foo() { |
| ret i32 ptrtoint (ptr @foo to i32) |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| // Check classof(), creation. |
| [[maybe_unused]] auto *ConstExpr = |
| cast<sandboxir::ConstantExpr>(Ret->getReturnValue()); |
| } |
| |
| TEST_F(SandboxIRTest, BlockAddress) { |
| parseIR(C, R"IR( |
| define void @foo(ptr %ptr) { |
| bb0: |
| store ptr blockaddress(@foo, %bb0), ptr %ptr |
| ret void |
| bb1: |
| ret void |
| bb2: |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| 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 It = BB0->begin(); |
| auto *SI = cast<sandboxir::StoreInst>(&*It++); |
| [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| // Check classof(), creation, getFunction(), getBasicBlock(). |
| auto *BB0Addr = cast<sandboxir::BlockAddress>(SI->getValueOperand()); |
| EXPECT_EQ(BB0Addr->getBasicBlock(), BB0); |
| EXPECT_EQ(BB0Addr->getFunction(), &F); |
| // Check get(F, BB). |
| auto *NewBB0Addr = sandboxir::BlockAddress::get(&F, BB0); |
| EXPECT_EQ(NewBB0Addr, BB0Addr); |
| // Check get(BB). |
| auto *NewBB0Addr2 = sandboxir::BlockAddress::get(BB0); |
| EXPECT_EQ(NewBB0Addr2, BB0Addr); |
| auto *BB1Addr = sandboxir::BlockAddress::get(BB1); |
| EXPECT_EQ(BB1Addr->getBasicBlock(), BB1); |
| EXPECT_NE(BB1Addr, BB0Addr); |
| // Check lookup(). |
| auto *LookupBB0Addr = sandboxir::BlockAddress::lookup(BB0); |
| EXPECT_EQ(LookupBB0Addr, BB0Addr); |
| auto *LookupBB1Addr = sandboxir::BlockAddress::lookup(BB1); |
| EXPECT_EQ(LookupBB1Addr, BB1Addr); |
| auto *LookupBB2Addr = sandboxir::BlockAddress::lookup(BB2); |
| EXPECT_EQ(LookupBB2Addr, nullptr); |
| } |
| |
| TEST_F(SandboxIRTest, DSOLocalEquivalent) { |
| parseIR(C, R"IR( |
| declare void @bar() |
| define void @foo() { |
| call void dso_local_equivalent @bar() |
| 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 *CI = cast<sandboxir::CallInst>(&*It++); |
| // Check classof(). |
| auto *DSOLE = cast<sandboxir::DSOLocalEquivalent>(CI->getCalledOperand()); |
| // Check getGlobalValue(). |
| auto *GV = DSOLE->getGlobalValue(); |
| // Check get(). |
| auto *NewDSOLE = sandboxir::DSOLocalEquivalent::get(GV); |
| EXPECT_EQ(NewDSOLE, DSOLE); |
| } |
| |
| TEST_F(SandboxIRTest, ConstantTokenNone) { |
| parseIR(C, R"IR( |
| define void @foo(ptr %ptr) { |
| bb0: |
| %cs = catchswitch within none [label %handler] unwind to caller |
| handler: |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| |
| [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); |
| auto *BB0 = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "bb0"))); |
| auto *CS = cast<sandboxir::CatchSwitchInst>(&*BB0->begin()); |
| |
| // Check classof(), creation, getFunction(), getBasicBlock(). |
| auto *CTN = cast<sandboxir::ConstantTokenNone>(CS->getParentPad()); |
| // Check get(). |
| auto *NewCTN = sandboxir::ConstantTokenNone::get(Ctx); |
| EXPECT_EQ(NewCTN, CTN); |
| } |
| |
| 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).dumpOS(BS); |
| EXPECT_EQ(Buff, R"IR( |
| Def: i32 %v0 ; SB2. (Argument) |
| User: %add0 = add i32 %v0, %v1 ; SB5. (BinaryOperator) |
| 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 Value.getExpectedType |
| |
| // 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 @foo0(i32 %arg0, i32 %arg1) { |
| bb0: |
| br label %bb1 |
| bb1: |
| ret void |
| } |
| define void @foo1() { |
| ret void |
| } |
| |
| )IR"); |
| llvm::Function *LLVMF0 = &*M->getFunction("foo0"); |
| llvm::Function *LLVMF1 = &*M->getFunction("foo1"); |
| llvm::Argument *LLVMArg0 = LLVMF0->getArg(0); |
| llvm::Argument *LLVMArg1 = LLVMF0->getArg(1); |
| |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F0 = Ctx.createFunction(LLVMF0); |
| sandboxir::Function *F1 = Ctx.createFunction(LLVMF1); |
| |
| // Check getIterator(). |
| { |
| auto It0 = F0->getIterator(); |
| auto It1 = F1->getIterator(); |
| EXPECT_EQ(&*It0, F0); |
| EXPECT_EQ(&*It1, F1); |
| EXPECT_EQ(std::next(It0), It1); |
| EXPECT_EQ(std::prev(It1), It0); |
| EXPECT_EQ(&*std::next(It0), F1); |
| EXPECT_EQ(&*std::prev(It1), F0); |
| } |
| // Check getReverseIterator(). |
| { |
| auto RevIt0 = F0->getReverseIterator(); |
| auto RevIt1 = F1->getReverseIterator(); |
| EXPECT_EQ(&*RevIt0, F0); |
| EXPECT_EQ(&*RevIt1, F1); |
| EXPECT_EQ(std::prev(RevIt0), RevIt1); |
| EXPECT_EQ(std::next(RevIt1), RevIt0); |
| EXPECT_EQ(&*std::prev(RevIt0), F1); |
| EXPECT_EQ(&*std::next(RevIt1), F0); |
| } |
| |
| // Check F arguments |
| EXPECT_EQ(F0->arg_size(), 2u); |
| EXPECT_FALSE(F0->arg_empty()); |
| EXPECT_EQ(F0->getArg(0), Ctx.getValue(LLVMArg0)); |
| EXPECT_EQ(F0->getArg(1), Ctx.getValue(LLVMArg1)); |
| |
| // Check F.begin(), F.end(), Function::iterator |
| llvm::BasicBlock *LLVMBB = &*LLVMF0->begin(); |
| for (sandboxir::BasicBlock &BB : *F0) { |
| EXPECT_EQ(&BB, Ctx.getValue(LLVMBB)); |
| LLVMBB = LLVMBB->getNextNode(); |
| } |
| |
| #ifndef NDEBUG |
| { |
| // Check F.dumpNameAndArgs() |
| std::string Buff; |
| raw_string_ostream BS(Buff); |
| F0->dumpNameAndArgs(BS); |
| EXPECT_EQ(Buff, "void @foo0(i32 %arg0, i32 %arg1)"); |
| } |
| { |
| // Check F.dump() |
| std::string Buff; |
| raw_string_ostream BS(Buff); |
| BS << "\n"; |
| F0->dumpOS(BS); |
| EXPECT_EQ(Buff, R"IR( |
| void @foo0(i32 %arg0, i32 %arg1) { |
| bb0: |
| br label %bb1 ; SB4. (Br) |
| |
| bb1: |
| ret void ; SB6. (Ret) |
| } |
| )IR"); |
| } |
| #endif // NDEBUG |
| |
| // Check getAlign(). |
| EXPECT_EQ(F0->getAlign(), F0->getAlign()); |
| // Check setAlignment(). |
| auto OrigMaybeAlign = F0->getAlign(); |
| auto NewMaybeAlign = MaybeAlign(128); |
| EXPECT_NE(NewMaybeAlign, OrigMaybeAlign); |
| F0->setAlignment(NewMaybeAlign); |
| EXPECT_EQ(F0->getAlign(), NewMaybeAlign); |
| F0->setAlignment(OrigMaybeAlign); |
| EXPECT_EQ(F0->getAlign(), OrigMaybeAlign); |
| } |
| |
| TEST_F(SandboxIRTest, Module) { |
| parseIR(C, R"IR( |
| @glob0 = global i32 42 |
| @glob1 = global i32 43 |
| @internal0 = internal global i32 42 |
| @const0 = constant i32 42 |
| @alias0 = dso_local alias void(), ptr @foo |
| @ifunc = ifunc void(), ptr @foo |
| define void @foo() { |
| ret void |
| } |
| define void @bar() { |
| ret void |
| } |
| )IR"); |
| llvm::Module *LLVMM = &*M; |
| llvm::Function *LLVMFFoo = &*M->getFunction("foo"); |
| llvm::Function *LLVMFBar = &*M->getFunction("bar"); |
| |
| sandboxir::Context Ctx(C); |
| auto *M = Ctx.createModule(LLVMM); |
| // Check getContext(). |
| EXPECT_EQ(&M->getContext(), &Ctx); |
| // Check getFunction(). |
| auto *FFoo = M->getFunction("foo"); |
| auto *FBar = M->getFunction("bar"); |
| EXPECT_EQ(FFoo, Ctx.getValue(LLVMFFoo)); |
| EXPECT_EQ(FBar, Ctx.getValue(LLVMFBar)); |
| // Check getDataLayout(). |
| EXPECT_EQ(&M->getDataLayout(), &LLVMM->getDataLayout()); |
| // Check getSourceFileName(). |
| EXPECT_EQ(M->getSourceFileName(), LLVMM->getSourceFileName()); |
| // Check getGlobalVariable(). |
| for (const char *Name : {"global0", "global1", "internal0"}) |
| EXPECT_EQ(M->getGlobalVariable(Name), |
| Ctx.getValue(LLVMM->getGlobalVariable(Name))); |
| // Check getGlobalVariable(AllowInternal). |
| { |
| auto *Internal0 = M->getGlobalVariable("internal0", /*AllowInternal=*/true); |
| EXPECT_TRUE(Internal0 != nullptr); |
| EXPECT_EQ(Internal0, Ctx.getValue(LLVMM->getNamedGlobal("internal0"))); |
| } |
| // Check getNamedGlobal(). |
| { |
| auto *Internal = M->getNamedGlobal("internal0"); |
| EXPECT_TRUE(Internal != nullptr); |
| EXPECT_EQ(Internal, Ctx.getValue(LLVMM->getNamedGlobal("internal0"))); |
| } |
| // Check getNamedAlias(). |
| auto *Alias0 = M->getNamedAlias("alias0"); |
| EXPECT_EQ(Alias0, Ctx.getValue(LLVMM->getNamedAlias("alias0"))); |
| EXPECT_EQ(M->getNamedAlias("aliasFOO"), nullptr); |
| // Check getNamedIFunc(). |
| auto *IFunc0 = M->getNamedIFunc("ifunc0"); |
| EXPECT_EQ(IFunc0, Ctx.getValue(LLVMM->getNamedAlias("ifunc0"))); |
| EXPECT_EQ(M->getNamedIFunc("ifuncFOO"), nullptr); |
| } |
| |
| 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(); |
| // Check getNodeParent(). |
| EXPECT_EQ(I.getIterator().getNodeParent(), &BB0); |
| } |
| LLVMI = &*LLVMBB1->begin(); |
| for (sandboxir::Instruction &I : BB1) { |
| EXPECT_EQ(&I, Ctx.getValue(LLVMI)); |
| LLVMI = LLVMI->getNextNode(); |
| } |
| // Check NodeParent() for BB::end(). |
| EXPECT_EQ(BB0.end().getNodeParent(), &BB0); |
| |
| // 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.dumpOS(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, ptr %ptr) { |
| bb0: |
| %add0 = add i8 %v1, %v1 |
| %sub1 = sub i8 %add0, %v1 |
| ret void |
| |
| bb1: |
| %add1 = add i8 %v1, %v1 |
| %sub2 = sub i8 %add1, %v1 |
| %ld0 = load i8, ptr %ptr |
| store i8 %ld0, ptr %ptr |
| store volatile i8 %ld0, ptr %ptr |
| %atomicrmw = atomicrmw add ptr %ptr, i8 %v1 acquire |
| %udiv = udiv i8 %ld0, %v1 |
| %urem = urem i8 %ld0, %v1 |
| call void @foo(), !dbg !1 |
| ret void, !tbaa !2 |
| } |
| |
| !1 = !{} |
| !2 = !{} |
| )IR"); |
| llvm::Function *LLVMF = &*M->getFunction("foo"); |
| llvm::BasicBlock *LLVMBB1 = getBasicBlockByName(*LLVMF, "bb1"); |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(LLVMF); |
| auto *Arg = F->getArg(0); |
| auto *BB = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(*LLVMF, "bb0"))); |
| 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::Add); |
| EXPECT_EQ(I1->getOpcode(), sandboxir::Instruction::Opcode::Sub); |
| EXPECT_EQ(Ret->getOpcode(), sandboxir::Instruction::Opcode::Ret); |
| |
| // Check getOpcodeName(). |
| EXPECT_STREQ(I0->getOpcodeName(), "Add"); |
| EXPECT_STREQ(I1->getOpcodeName(), "Sub"); |
| EXPECT_STREQ(Ret->getOpcodeName(), "Ret"); |
| |
| EXPECT_STREQ(sandboxir::Instruction::getOpcodeName( |
| sandboxir::Instruction::Opcode::Alloca), |
| "Alloca"); |
| |
| // 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 comesBefore(I). |
| EXPECT_TRUE(I0->comesBefore(I1)); |
| EXPECT_FALSE(I1->comesBefore(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); |
| |
| for (auto &LLVMI : *LLVMBB1) { |
| auto &I = cast<sandboxir::Instruction>(*Ctx.getValue(&LLVMI)); |
| // Check isTerminator(). |
| EXPECT_EQ(LLVMI.isTerminator(), I.isTerminator()); |
| // Check isUnaryOp(). |
| EXPECT_EQ(LLVMI.isUnaryOp(), I.isUnaryOp()); |
| // Check isBinaryOp(). |
| EXPECT_EQ(LLVMI.isBinaryOp(), I.isBinaryOp()); |
| // Check isIntDivRem(). |
| EXPECT_EQ(LLVMI.isIntDivRem(), I.isIntDivRem()); |
| // Check isShift(). |
| EXPECT_EQ(LLVMI.isShift(), I.isShift()); |
| // Check isCast(). |
| EXPECT_EQ(LLVMI.isCast(), I.isCast()); |
| // Check isFuncletPad(). |
| EXPECT_EQ(LLVMI.isFuncletPad(), I.isFuncletPad()); |
| // Check isSpecialTerminator(). |
| EXPECT_EQ(LLVMI.isSpecialTerminator(), I.isSpecialTerminator()); |
| // Check isOnlyUserOfAnyOperand(). |
| EXPECT_EQ(LLVMI.isOnlyUserOfAnyOperand(), I.isOnlyUserOfAnyOperand()); |
| // Check isLogicalShift(). |
| EXPECT_EQ(LLVMI.isLogicalShift(), I.isLogicalShift()); |
| // Check hasMetadata(). |
| EXPECT_EQ(LLVMI.hasMetadata(), I.hasMetadata()); |
| // Check hasMetadataOtherThanDebugLoc(). |
| EXPECT_EQ(LLVMI.hasMetadataOtherThanDebugLoc(), |
| I.hasMetadataOtherThanDebugLoc()); |
| // Check isAssociative(). |
| EXPECT_EQ(LLVMI.isAssociative(), I.isAssociative()); |
| // Check isCommutative(). |
| EXPECT_EQ(LLVMI.isCommutative(), I.isCommutative()); |
| // Check isIdempotent(). |
| EXPECT_EQ(LLVMI.isIdempotent(), I.isIdempotent()); |
| // Check isNilpotent(). |
| EXPECT_EQ(LLVMI.isNilpotent(), I.isNilpotent()); |
| // Check mayWriteToMemory(). |
| EXPECT_EQ(LLVMI.mayWriteToMemory(), I.mayWriteToMemory()); |
| // Check mayReadFromMemory(). |
| EXPECT_EQ(LLVMI.mayReadFromMemory(), I.mayReadFromMemory()); |
| // Check mayReadOrWriteMemory(). |
| EXPECT_EQ(LLVMI.mayReadOrWriteMemory(), I.mayReadOrWriteMemory()); |
| // Check isAtomic(). |
| EXPECT_EQ(LLVMI.isAtomic(), I.isAtomic()); |
| if (I.isAtomic()) { |
| // Check hasAtomicLoad(). |
| EXPECT_EQ(LLVMI.hasAtomicLoad(), I.hasAtomicLoad()); |
| // Check hasAtomicStore(). |
| EXPECT_EQ(LLVMI.hasAtomicStore(), I.hasAtomicStore()); |
| } |
| // Check isVolatile(). |
| EXPECT_EQ(LLVMI.isVolatile(), I.isVolatile()); |
| // Check getAccessType(). |
| EXPECT_EQ(Ctx.getType(LLVMI.getAccessType()), I.getAccessType()); |
| // Check mayThrow(). |
| EXPECT_EQ(LLVMI.mayThrow(), I.mayThrow()); |
| // Check isFenceLike(). |
| EXPECT_EQ(LLVMI.isFenceLike(), I.isFenceLike()); |
| // Check mayHaveSideEffects(). |
| EXPECT_EQ(LLVMI.mayHaveSideEffects(), I.mayHaveSideEffects()); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, VAArgInst) { |
| parseIR(C, R"IR( |
| define void @foo(ptr %va) { |
| %va_arg = va_arg ptr %va, i32 |
| 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 *VA = cast<sandboxir::VAArgInst>(&*It++); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| // Check getPointerOperand(). |
| EXPECT_EQ(VA->getPointerOperand(), Arg); |
| // Check getPOinterOperandIndex(). |
| EXPECT_EQ(sandboxir::VAArgInst::getPointerOperandIndex(), |
| llvm::VAArgInst::getPointerOperandIndex()); |
| // Check create(). |
| auto *NewVATy = sandboxir::Type::getInt8Ty(Ctx); |
| auto *NewVA = sandboxir::VAArgInst::create(Arg, NewVATy, Ret->getIterator(), |
| Ctx, "NewVA"); |
| EXPECT_EQ(NewVA->getNextNode(), Ret); |
| EXPECT_EQ(NewVA->getType(), NewVATy); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewVA->getName(), "NewVA"); |
| #endif // NDEBUG |
| } |
| |
| TEST_F(SandboxIRTest, FreezeInst) { |
| parseIR(C, R"IR( |
| define void @foo(i8 %arg) { |
| freeze i8 %arg |
| 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 *Freeze = cast<sandboxir::FreezeInst>(&*It++); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(Freeze)); |
| EXPECT_EQ(Freeze->getOperand(0), Arg); |
| |
| // Check create(). |
| auto *NewFreeze = |
| sandboxir::FreezeInst::create(Arg, Ret->getIterator(), Ctx, "NewFreeze"); |
| EXPECT_EQ(NewFreeze->getNextNode(), Ret); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewFreeze->getName(), "NewFreeze"); |
| #endif // NDEBUG |
| } |
| |
| TEST_F(SandboxIRTest, FenceInst) { |
| parseIR(C, R"IR( |
| define void @foo() { |
| fence syncscope("singlethread") seq_cst |
| ret void |
| } |
| )IR"); |
| llvm::Function *LLVMF = &*M->getFunction("foo"); |
| llvm::BasicBlock *LLVMBB = &*LLVMF->begin(); |
| auto *LLVMFence = cast<llvm::FenceInst>(&*LLVMBB->begin()); |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(LLVMF); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| auto *Fence = cast<sandboxir::FenceInst>(&*It++); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| // Check getOrdering(). |
| EXPECT_EQ(Fence->getOrdering(), LLVMFence->getOrdering()); |
| // Check setOrdering(). |
| auto OrigOrdering = Fence->getOrdering(); |
| auto NewOrdering = AtomicOrdering::Release; |
| EXPECT_NE(NewOrdering, OrigOrdering); |
| Fence->setOrdering(NewOrdering); |
| EXPECT_EQ(Fence->getOrdering(), NewOrdering); |
| Fence->setOrdering(OrigOrdering); |
| EXPECT_EQ(Fence->getOrdering(), OrigOrdering); |
| // Check getSyncScopeID(). |
| EXPECT_EQ(Fence->getSyncScopeID(), LLVMFence->getSyncScopeID()); |
| // Check setSyncScopeID(). |
| auto OrigSSID = Fence->getSyncScopeID(); |
| auto NewSSID = SyncScope::System; |
| EXPECT_NE(NewSSID, OrigSSID); |
| Fence->setSyncScopeID(NewSSID); |
| EXPECT_EQ(Fence->getSyncScopeID(), NewSSID); |
| Fence->setSyncScopeID(OrigSSID); |
| EXPECT_EQ(Fence->getSyncScopeID(), OrigSSID); |
| // Check create(). |
| auto *NewFence = |
| sandboxir::FenceInst::create(AtomicOrdering::Release, Ret->getIterator(), |
| Ctx, SyncScope::SingleThread); |
| EXPECT_EQ(NewFence->getNextNode(), Ret); |
| EXPECT_EQ(NewFence->getOrdering(), AtomicOrdering::Release); |
| EXPECT_EQ(NewFence->getSyncScopeID(), SyncScope::SingleThread); |
| } |
| |
| 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++); |
| const auto *ConstSelect = Select; // To test the const getters. |
| auto *Ret = &*It++; |
| |
| // Check getCondition(). |
| EXPECT_EQ(Select->getCondition(), Cond0); |
| EXPECT_EQ(ConstSelect->getCondition(), Cond0); |
| // Check getTrueValue(). |
| EXPECT_EQ(Select->getTrueValue(), V0); |
| EXPECT_EQ(ConstSelect->getTrueValue(), V0); |
| // Check getFalseValue(). |
| EXPECT_EQ(Select->getFalseValue(), V1); |
| EXPECT_EQ(ConstSelect->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 swapValues(). |
| Select->swapValues(); |
| EXPECT_EQ(Select->getTrueValue(), V0); |
| EXPECT_EQ(Select->getFalseValue(), V1); |
| // Check areInvalidOperands. |
| EXPECT_EQ(sandboxir::SelectInst::areInvalidOperands(Cond0, V0, V1), nullptr); |
| EXPECT_NE(sandboxir::SelectInst::areInvalidOperands(V0, V1, Cond0), nullptr); |
| |
| { |
| // Check SelectInst::create() InsertBefore. |
| auto *NewSel = cast<sandboxir::SelectInst>(sandboxir::SelectInst::create( |
| Cond0, V0, V1, /*InsertBefore=*/Ret->getIterator(), 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::ConstantInt::get(sandboxir::Type::getInt1Ty(Ctx), |
| 0, /*IsSigned=*/false); |
| auto *FortyTwo = |
| sandboxir::ConstantInt::get(sandboxir::Type::getInt1Ty(Ctx), 42, |
| /*IsSigned=*/false); |
| auto *NewSel = sandboxir::SelectInst::create(False, FortyTwo, FortyTwo, |
| Ret->getIterator(), Ctx); |
| EXPECT_TRUE(isa<sandboxir::Constant>(NewSel)); |
| EXPECT_EQ(NewSel, FortyTwo); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, ExtractElementInst) { |
| parseIR(C, R"IR( |
| define void @foo(<2 x i8> %vec, i32 %idx) { |
| %ins0 = extractelement <2 x i8> %vec, i32 %idx |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *ArgVec = F.getArg(0); |
| auto *ArgIdx = F.getArg(1); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *EI = cast<sandboxir::ExtractElementInst>(&*It++); |
| auto *Ret = &*It++; |
| |
| EXPECT_EQ(EI->getOpcode(), sandboxir::Instruction::Opcode::ExtractElement); |
| EXPECT_EQ(EI->getOperand(0), ArgVec); |
| EXPECT_EQ(EI->getOperand(1), ArgIdx); |
| EXPECT_EQ(EI->getVectorOperand(), ArgVec); |
| EXPECT_EQ(EI->getIndexOperand(), ArgIdx); |
| EXPECT_EQ(EI->getVectorOperandType(), ArgVec->getType()); |
| |
| auto *NewI1 = |
| cast<sandboxir::ExtractElementInst>(sandboxir::ExtractElementInst::create( |
| ArgVec, ArgIdx, Ret->getIterator(), Ctx, "NewExtrBeforeRet")); |
| EXPECT_EQ(NewI1->getOperand(0), ArgVec); |
| EXPECT_EQ(NewI1->getOperand(1), ArgIdx); |
| EXPECT_EQ(NewI1->getNextNode(), Ret); |
| |
| auto *NewI2 = |
| cast<sandboxir::ExtractElementInst>(sandboxir::ExtractElementInst::create( |
| ArgVec, ArgIdx, BB, Ctx, "NewExtrAtEndOfBB")); |
| EXPECT_EQ(NewI2->getPrevNode(), Ret); |
| |
| auto *LLVMArgVec = LLVMF.getArg(0); |
| auto *LLVMArgIdx = LLVMF.getArg(1); |
| EXPECT_EQ(sandboxir::ExtractElementInst::isValidOperands(ArgVec, ArgIdx), |
| llvm::ExtractElementInst::isValidOperands(LLVMArgVec, LLVMArgIdx)); |
| EXPECT_EQ(sandboxir::ExtractElementInst::isValidOperands(ArgIdx, ArgVec), |
| llvm::ExtractElementInst::isValidOperands(LLVMArgIdx, LLVMArgVec)); |
| } |
| |
| TEST_F(SandboxIRTest, InsertElementInst) { |
| parseIR(C, R"IR( |
| define void @foo(i8 %v0, i8 %v1, <2 x i8> %vec) { |
| %ins0 = insertelement <2 x i8> poison, i8 %v0, i32 0 |
| %ins1 = insertelement <2 x i8> %ins0, i8 %v1, i32 1 |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *Arg0 = F.getArg(0); |
| auto *Arg1 = F.getArg(1); |
| auto *ArgVec = F.getArg(2); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *Ins0 = cast<sandboxir::InsertElementInst>(&*It++); |
| auto *Ins1 = cast<sandboxir::InsertElementInst>(&*It++); |
| auto *Ret = &*It++; |
| |
| EXPECT_EQ(Ins0->getOpcode(), sandboxir::Instruction::Opcode::InsertElement); |
| EXPECT_EQ(Ins0->getOperand(1), Arg0); |
| EXPECT_EQ(Ins1->getOperand(1), Arg1); |
| EXPECT_EQ(Ins1->getOperand(0), Ins0); |
| auto *Poison = Ins0->getOperand(0); |
| auto *Idx = Ins0->getOperand(2); |
| auto *NewI1 = |
| cast<sandboxir::InsertElementInst>(sandboxir::InsertElementInst::create( |
| Poison, Arg0, Idx, Ret->getIterator(), Ctx, "NewIns1")); |
| EXPECT_EQ(NewI1->getOperand(0), Poison); |
| EXPECT_EQ(NewI1->getNextNode(), Ret); |
| |
| auto *NewI2 = |
| cast<sandboxir::InsertElementInst>(sandboxir::InsertElementInst::create( |
| Poison, Arg0, Idx, BB, Ctx, "NewIns2")); |
| EXPECT_EQ(NewI2->getPrevNode(), Ret); |
| |
| auto *LLVMArg0 = LLVMF.getArg(0); |
| auto *LLVMArgVec = LLVMF.getArg(2); |
| auto *Zero = sandboxir::ConstantInt::get(sandboxir::Type::getInt8Ty(Ctx), 0); |
| auto *LLVMZero = llvm::ConstantInt::get(Type::getInt8Ty(C), 0); |
| EXPECT_EQ( |
| sandboxir::InsertElementInst::isValidOperands(ArgVec, Arg0, Zero), |
| llvm::InsertElementInst::isValidOperands(LLVMArgVec, LLVMArg0, LLVMZero)); |
| EXPECT_EQ( |
| sandboxir::InsertElementInst::isValidOperands(Arg0, ArgVec, Zero), |
| llvm::InsertElementInst::isValidOperands(LLVMArg0, LLVMArgVec, LLVMZero)); |
| } |
| |
| TEST_F(SandboxIRTest, ShuffleVectorInst) { |
| parseIR(C, R"IR( |
| define void @foo(<2 x i8> %v1, <2 x i8> %v2) { |
| %shuf = shufflevector <2 x i8> %v1, <2 x i8> %v2, <2 x i32> <i32 0, i32 2> |
| %extr = extractelement <2 x i8> <i8 0, i8 1>, i32 0 |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *ArgV1 = F.getArg(0); |
| auto *ArgV2 = F.getArg(1); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *SVI = cast<sandboxir::ShuffleVectorInst>(&*It++); |
| auto *EEI = cast<sandboxir::ExtractElementInst>(&*It++); |
| auto *Ret = &*It++; |
| |
| EXPECT_EQ(SVI->getOpcode(), sandboxir::Instruction::Opcode::ShuffleVector); |
| EXPECT_EQ(SVI->getOperand(0), ArgV1); |
| EXPECT_EQ(SVI->getOperand(1), ArgV2); |
| |
| // In order to test all the methods we need masks of different lengths, so we |
| // can't simply reuse one of the instructions created above. This helper |
| // creates a new `shufflevector %v1, %2, <mask>` with the given mask indices. |
| auto CreateShuffleWithMask = [&](auto &&...Indices) { |
| SmallVector<int, 4> Mask = {Indices...}; |
| return cast<sandboxir::ShuffleVectorInst>( |
| sandboxir::ShuffleVectorInst::create(ArgV1, ArgV2, Mask, |
| Ret->getIterator(), Ctx)); |
| }; |
| |
| // create (InsertBefore) |
| auto *NewI1 = |
| cast<sandboxir::ShuffleVectorInst>(sandboxir::ShuffleVectorInst::create( |
| ArgV1, ArgV2, ArrayRef<int>({0, 2, 1, 3}), Ret->getIterator(), Ctx, |
| "NewShuffleBeforeRet")); |
| EXPECT_EQ(NewI1->getOperand(0), ArgV1); |
| EXPECT_EQ(NewI1->getOperand(1), ArgV2); |
| EXPECT_EQ(NewI1->getNextNode(), Ret); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewI1->getName(), "NewShuffleBeforeRet"); |
| #endif |
| |
| // create (InsertAtEnd) |
| auto *NewI2 = |
| cast<sandboxir::ShuffleVectorInst>(sandboxir::ShuffleVectorInst::create( |
| ArgV1, ArgV2, ArrayRef<int>({0, 1}), BB, Ctx, "NewShuffleAtEndOfBB")); |
| EXPECT_EQ(NewI2->getPrevNode(), Ret); |
| |
| // Test the path that creates a folded constant. We're currently using an |
| // extractelement instruction with a constant operand in the textual IR above |
| // to obtain a constant vector to work with. |
| // TODO: Refactor this once sandboxir::ConstantVector lands. |
| auto *ShouldBeConstant = sandboxir::ShuffleVectorInst::create( |
| EEI->getOperand(0), EEI->getOperand(0), ArrayRef<int>({0, 3}), BB, Ctx); |
| EXPECT_TRUE(isa<sandboxir::Constant>(ShouldBeConstant)); |
| |
| // isValidOperands |
| auto *LLVMArgV1 = LLVMF.getArg(0); |
| auto *LLVMArgV2 = LLVMF.getArg(1); |
| SmallVector<int, 2> Mask({1, 2}); |
| EXPECT_EQ( |
| sandboxir::ShuffleVectorInst::isValidOperands(ArgV1, ArgV2, Mask), |
| llvm::ShuffleVectorInst::isValidOperands(LLVMArgV1, LLVMArgV2, Mask)); |
| EXPECT_EQ(sandboxir::ShuffleVectorInst::isValidOperands(ArgV1, ArgV1, ArgV1), |
| llvm::ShuffleVectorInst::isValidOperands(LLVMArgV1, LLVMArgV1, |
| LLVMArgV1)); |
| |
| // commute |
| { |
| auto *I = CreateShuffleWithMask(0, 2); |
| I->commute(); |
| EXPECT_EQ(I->getOperand(0), ArgV2); |
| EXPECT_EQ(I->getOperand(1), ArgV1); |
| EXPECT_THAT(I->getShuffleMask(), testing::ElementsAre(2, 0)); |
| } |
| |
| // getType |
| EXPECT_EQ(SVI->getType(), ArgV1->getType()); |
| |
| // getMaskValue |
| EXPECT_EQ(SVI->getMaskValue(0), 0); |
| EXPECT_EQ(SVI->getMaskValue(1), 2); |
| |
| // getShuffleMask / getShuffleMaskForBitcode |
| { |
| EXPECT_THAT(SVI->getShuffleMask(), testing::ElementsAre(0, 2)); |
| |
| SmallVector<int, 2> Result; |
| SVI->getShuffleMask(Result); |
| EXPECT_THAT(Result, testing::ElementsAre(0, 2)); |
| |
| Result.clear(); |
| sandboxir::ShuffleVectorInst::getShuffleMask( |
| SVI->getShuffleMaskForBitcode(), Result); |
| EXPECT_THAT(Result, testing::ElementsAre(0, 2)); |
| } |
| |
| // convertShuffleMaskForBitcode |
| { |
| auto *C = sandboxir::ShuffleVectorInst::convertShuffleMaskForBitcode( |
| ArrayRef<int>({2, 3}), ArgV1->getType()); |
| SmallVector<int, 2> Result; |
| sandboxir::ShuffleVectorInst::getShuffleMask(C, Result); |
| EXPECT_THAT(Result, testing::ElementsAre(2, 3)); |
| } |
| |
| // setShuffleMask |
| { |
| auto *I = CreateShuffleWithMask(0, 1); |
| I->setShuffleMask(ArrayRef<int>({2, 3})); |
| EXPECT_THAT(I->getShuffleMask(), testing::ElementsAre(2, 3)); |
| } |
| |
| // The following functions check different mask properties. Note that most |
| // of these come in three different flavors: a method that checks the mask |
| // in the current instructions and two static member functions that check |
| // a mask given as an ArrayRef<int> or Constant*, so there's quite a bit of |
| // repetition in order to check all of them. |
| |
| // changesLength / increasesLength |
| { |
| auto *I = CreateShuffleWithMask(1); |
| EXPECT_TRUE(I->changesLength()); |
| EXPECT_FALSE(I->increasesLength()); |
| } |
| { |
| auto *I = CreateShuffleWithMask(1, 1); |
| EXPECT_FALSE(I->changesLength()); |
| EXPECT_FALSE(I->increasesLength()); |
| } |
| { |
| auto *I = CreateShuffleWithMask(1, 1, 1); |
| EXPECT_TRUE(I->changesLength()); |
| EXPECT_TRUE(I->increasesLength()); |
| } |
| |
| // isSingleSource / isSingleSourceMask |
| { |
| auto *I = CreateShuffleWithMask(0, 1); |
| EXPECT_TRUE(I->isSingleSource()); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isSingleSourceMask( |
| I->getShuffleMaskForBitcode(), 2)); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isSingleSourceMask( |
| I->getShuffleMask(), 2)); |
| } |
| { |
| auto *I = CreateShuffleWithMask(0, 2); |
| EXPECT_FALSE(I->isSingleSource()); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isSingleSourceMask( |
| I->getShuffleMaskForBitcode(), 2)); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isSingleSourceMask( |
| I->getShuffleMask(), 2)); |
| } |
| |
| // isIdentity / isIdentityMask |
| { |
| auto *I = CreateShuffleWithMask(0, 1); |
| EXPECT_TRUE(I->isIdentity()); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isIdentityMask( |
| I->getShuffleMaskForBitcode(), 2)); |
| EXPECT_TRUE( |
| sandboxir::ShuffleVectorInst::isIdentityMask(I->getShuffleMask(), 2)); |
| } |
| { |
| auto *I = CreateShuffleWithMask(1, 0); |
| EXPECT_FALSE(I->isIdentity()); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isIdentityMask( |
| I->getShuffleMaskForBitcode(), 2)); |
| EXPECT_FALSE( |
| sandboxir::ShuffleVectorInst::isIdentityMask(I->getShuffleMask(), 2)); |
| } |
| |
| // isIdentityWithPadding |
| EXPECT_TRUE(CreateShuffleWithMask(0, 1, -1, -1)->isIdentityWithPadding()); |
| EXPECT_FALSE(CreateShuffleWithMask(0, 1)->isIdentityWithPadding()); |
| |
| // isIdentityWithExtract |
| EXPECT_TRUE(CreateShuffleWithMask(0)->isIdentityWithExtract()); |
| EXPECT_FALSE(CreateShuffleWithMask(0, 1)->isIdentityWithExtract()); |
| EXPECT_FALSE(CreateShuffleWithMask(0, 1, 2)->isIdentityWithExtract()); |
| EXPECT_FALSE(CreateShuffleWithMask(1)->isIdentityWithExtract()); |
| |
| // isConcat |
| EXPECT_TRUE(CreateShuffleWithMask(0, 1, 2, 3)->isConcat()); |
| EXPECT_FALSE(CreateShuffleWithMask(0, 3)->isConcat()); |
| |
| // isSelect / isSelectMask |
| { |
| auto *I = CreateShuffleWithMask(0, 3); |
| EXPECT_TRUE(I->isSelect()); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isSelectMask( |
| I->getShuffleMaskForBitcode(), 2)); |
| EXPECT_TRUE( |
| sandboxir::ShuffleVectorInst::isSelectMask(I->getShuffleMask(), 2)); |
| } |
| { |
| auto *I = CreateShuffleWithMask(0, 2); |
| EXPECT_FALSE(I->isSelect()); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isSelectMask( |
| I->getShuffleMaskForBitcode(), 2)); |
| EXPECT_FALSE( |
| sandboxir::ShuffleVectorInst::isSelectMask(I->getShuffleMask(), 2)); |
| } |
| |
| // isReverse / isReverseMask |
| { |
| auto *I = CreateShuffleWithMask(1, 0); |
| EXPECT_TRUE(I->isReverse()); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isReverseMask( |
| I->getShuffleMaskForBitcode(), 2)); |
| EXPECT_TRUE( |
| sandboxir::ShuffleVectorInst::isReverseMask(I->getShuffleMask(), 2)); |
| } |
| { |
| auto *I = CreateShuffleWithMask(1, 2); |
| EXPECT_FALSE(I->isReverse()); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isReverseMask( |
| I->getShuffleMaskForBitcode(), 2)); |
| EXPECT_FALSE( |
| sandboxir::ShuffleVectorInst::isReverseMask(I->getShuffleMask(), 2)); |
| } |
| |
| // isZeroEltSplat / isZeroEltSplatMask |
| { |
| auto *I = CreateShuffleWithMask(0, 0); |
| EXPECT_TRUE(I->isZeroEltSplat()); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isZeroEltSplatMask( |
| I->getShuffleMaskForBitcode(), 2)); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isZeroEltSplatMask( |
| I->getShuffleMask(), 2)); |
| } |
| { |
| auto *I = CreateShuffleWithMask(1, 1); |
| EXPECT_FALSE(I->isZeroEltSplat()); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isZeroEltSplatMask( |
| I->getShuffleMaskForBitcode(), 2)); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isZeroEltSplatMask( |
| I->getShuffleMask(), 2)); |
| } |
| |
| // isTranspose / isTransposeMask |
| { |
| auto *I = CreateShuffleWithMask(0, 2); |
| EXPECT_TRUE(I->isTranspose()); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isTransposeMask( |
| I->getShuffleMaskForBitcode(), 2)); |
| EXPECT_TRUE( |
| sandboxir::ShuffleVectorInst::isTransposeMask(I->getShuffleMask(), 2)); |
| } |
| { |
| auto *I = CreateShuffleWithMask(1, 1); |
| EXPECT_FALSE(I->isTranspose()); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isTransposeMask( |
| I->getShuffleMaskForBitcode(), 2)); |
| EXPECT_FALSE( |
| sandboxir::ShuffleVectorInst::isTransposeMask(I->getShuffleMask(), 2)); |
| } |
| |
| // isSplice / isSpliceMask |
| { |
| auto *I = CreateShuffleWithMask(1, 2); |
| int Index; |
| EXPECT_TRUE(I->isSplice(Index)); |
| EXPECT_EQ(Index, 1); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isSpliceMask( |
| I->getShuffleMaskForBitcode(), 2, Index)); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isSpliceMask(I->getShuffleMask(), |
| 2, Index)); |
| } |
| { |
| auto *I = CreateShuffleWithMask(2, 1); |
| int Index; |
| EXPECT_FALSE(I->isSplice(Index)); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isSpliceMask( |
| I->getShuffleMaskForBitcode(), 2, Index)); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isSpliceMask(I->getShuffleMask(), |
| 2, Index)); |
| } |
| |
| // isExtractSubvectorMask |
| { |
| auto *I = CreateShuffleWithMask(1); |
| int Index; |
| EXPECT_TRUE(I->isExtractSubvectorMask(Index)); |
| EXPECT_EQ(Index, 1); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isExtractSubvectorMask( |
| I->getShuffleMaskForBitcode(), 2, Index)); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isExtractSubvectorMask( |
| I->getShuffleMask(), 2, Index)); |
| } |
| { |
| auto *I = CreateShuffleWithMask(1, 2); |
| int Index; |
| EXPECT_FALSE(I->isExtractSubvectorMask(Index)); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isExtractSubvectorMask( |
| I->getShuffleMaskForBitcode(), 2, Index)); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isExtractSubvectorMask( |
| I->getShuffleMask(), 2, Index)); |
| } |
| |
| // isInsertSubvectorMask |
| { |
| auto *I = CreateShuffleWithMask(0, 2); |
| int NumSubElts, Index; |
| EXPECT_TRUE(I->isInsertSubvectorMask(NumSubElts, Index)); |
| EXPECT_EQ(Index, 1); |
| EXPECT_EQ(NumSubElts, 1); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isInsertSubvectorMask( |
| I->getShuffleMaskForBitcode(), 2, NumSubElts, Index)); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isInsertSubvectorMask( |
| I->getShuffleMask(), 2, NumSubElts, Index)); |
| } |
| { |
| auto *I = CreateShuffleWithMask(0, 1); |
| int NumSubElts, Index; |
| EXPECT_FALSE(I->isInsertSubvectorMask(NumSubElts, Index)); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isInsertSubvectorMask( |
| I->getShuffleMaskForBitcode(), 2, NumSubElts, Index)); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isInsertSubvectorMask( |
| I->getShuffleMask(), 2, NumSubElts, Index)); |
| } |
| |
| // isReplicationMask |
| { |
| auto *I = CreateShuffleWithMask(0, 0, 0, 1, 1, 1); |
| int ReplicationFactor, VF; |
| EXPECT_TRUE(I->isReplicationMask(ReplicationFactor, VF)); |
| EXPECT_EQ(ReplicationFactor, 3); |
| EXPECT_EQ(VF, 2); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isReplicationMask( |
| I->getShuffleMaskForBitcode(), ReplicationFactor, VF)); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isReplicationMask( |
| I->getShuffleMask(), ReplicationFactor, VF)); |
| } |
| { |
| auto *I = CreateShuffleWithMask(1, 2); |
| int ReplicationFactor, VF; |
| EXPECT_FALSE(I->isReplicationMask(ReplicationFactor, VF)); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isReplicationMask( |
| I->getShuffleMaskForBitcode(), ReplicationFactor, VF)); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isReplicationMask( |
| I->getShuffleMask(), ReplicationFactor, VF)); |
| } |
| |
| // isOneUseSingleSourceMask |
| { |
| auto *I = CreateShuffleWithMask(0, 1, 1, 0); |
| EXPECT_TRUE(I->isOneUseSingleSourceMask(2)); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isOneUseSingleSourceMask( |
| I->getShuffleMask(), 2)); |
| } |
| { |
| auto *I = CreateShuffleWithMask(0, 1, 0, 0); |
| EXPECT_FALSE(I->isOneUseSingleSourceMask(2)); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isOneUseSingleSourceMask( |
| I->getShuffleMask(), 2)); |
| } |
| |
| // commuteShuffleMask |
| { |
| SmallVector<int, 4> M = {0, 2, 1, 3}; |
| ShuffleVectorInst::commuteShuffleMask(M, 2); |
| EXPECT_THAT(M, testing::ElementsAre(2, 0, 3, 1)); |
| } |
| |
| // isInterleave / isInterleaveMask |
| { |
| auto *I = CreateShuffleWithMask(0, 2, 1, 3); |
| EXPECT_TRUE(I->isInterleave(2)); |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isInterleaveMask( |
| I->getShuffleMask(), 2, 4)); |
| SmallVector<unsigned, 4> StartIndexes; |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isInterleaveMask( |
| I->getShuffleMask(), 2, 4, StartIndexes)); |
| EXPECT_THAT(StartIndexes, testing::ElementsAre(0, 2)); |
| } |
| { |
| auto *I = CreateShuffleWithMask(0, 3, 1, 2); |
| EXPECT_FALSE(I->isInterleave(2)); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isInterleaveMask( |
| I->getShuffleMask(), 2, 4)); |
| } |
| |
| // isDeInterleaveMaskOfFactor |
| { |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isDeInterleaveMaskOfFactor( |
| ArrayRef<int>({0, 2}), 2)); |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isDeInterleaveMaskOfFactor( |
| ArrayRef<int>({0, 1}), 2)); |
| |
| unsigned Index; |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isDeInterleaveMaskOfFactor( |
| ArrayRef<int>({1, 3}), 2, Index)); |
| EXPECT_EQ(Index, 1u); |
| } |
| |
| // isBitRotateMask |
| { |
| unsigned NumSubElts, RotateAmt; |
| EXPECT_TRUE(sandboxir::ShuffleVectorInst::isBitRotateMask( |
| ArrayRef<int>({1, 0, 3, 2, 5, 4, 7, 6}), 8, 2, 2, NumSubElts, |
| RotateAmt)); |
| EXPECT_EQ(NumSubElts, 2u); |
| EXPECT_EQ(RotateAmt, 8u); |
| |
| EXPECT_FALSE(sandboxir::ShuffleVectorInst::isBitRotateMask( |
| ArrayRef<int>({0, 7, 1, 6, 2, 5, 3, 4}), 8, 2, 2, NumSubElts, |
| RotateAmt)); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, ExtractValueInst) { |
| parseIR(C, R"IR( |
| define void @foo({i32, float} %agg) { |
| %ext_simple = extractvalue {i32, float} %agg, 0 |
| %ext_nested = extractvalue {float, {i32}} undef, 1, 0 |
| %const1 = extractvalue {i32, float} {i32 0, float 99.0}, 0 |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMBB = &*LLVMF.begin(); |
| auto LLVMIt = LLVMBB->begin(); |
| [[maybe_unused]] auto *LLVMExtSimple = |
| cast<llvm::ExtractValueInst>(&*LLVMIt++); |
| auto *LLVMExtNested = cast<llvm::ExtractValueInst>(&*LLVMIt++); |
| |
| sandboxir::Context Ctx(C); |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *ArgAgg = F.getArg(0); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *ExtSimple = cast<sandboxir::ExtractValueInst>(&*It++); |
| auto *ExtNested = cast<sandboxir::ExtractValueInst>(&*It++); |
| auto *Const1 = cast<sandboxir::ExtractValueInst>(&*It++); |
| auto *Ret = &*It++; |
| |
| EXPECT_EQ(ExtSimple->getOperand(0), ArgAgg); |
| |
| // create before instruction |
| auto *NewExtBeforeRet = |
| cast<sandboxir::ExtractValueInst>(sandboxir::ExtractValueInst::create( |
| ArgAgg, ArrayRef<unsigned>({0}), Ret->getIterator(), Ctx, |
| "NewExtBeforeRet")); |
| EXPECT_EQ(NewExtBeforeRet->getNextNode(), Ret); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewExtBeforeRet->getName(), "NewExtBeforeRet"); |
| #endif // NDEBUG |
| |
| // create at end of BB |
| auto *NewExtAtEnd = |
| cast<sandboxir::ExtractValueInst>(sandboxir::ExtractValueInst::create( |
| ArgAgg, ArrayRef<unsigned>({0}), BB->end(), Ctx, "NewExtAtEnd")); |
| EXPECT_EQ(NewExtAtEnd->getPrevNode(), Ret); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewExtAtEnd->getName(), "NewExtAtEnd"); |
| #endif // NDEBUG |
| |
| // Test the path that creates a folded constant. |
| auto *ShouldBeConstant = sandboxir::ExtractValueInst::create( |
| Const1->getOperand(0), ArrayRef<unsigned>({0}), BB->end(), Ctx); |
| EXPECT_TRUE(isa<sandboxir::Constant>(ShouldBeConstant)); |
| |
| auto *Zero = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 0); |
| EXPECT_EQ(ShouldBeConstant, Zero); |
| |
| // getIndexedType |
| sandboxir::Type *AggType = ExtNested->getAggregateOperand()->getType(); |
| llvm::Type *LLVMAggType = LLVMExtNested->getAggregateOperand()->getType(); |
| EXPECT_EQ(sandboxir::ExtractValueInst::getIndexedType( |
| AggType, ArrayRef<unsigned>({1, 0})), |
| Ctx.getType(llvm::ExtractValueInst::getIndexedType( |
| LLVMAggType, ArrayRef<unsigned>({1, 0})))); |
| |
| EXPECT_EQ(sandboxir::ExtractValueInst::getIndexedType( |
| AggType, ArrayRef<unsigned>({2})), |
| nullptr); |
| |
| // idx_begin / idx_end |
| { |
| SmallVector<int, 2> IndicesSimple(ExtSimple->idx_begin(), |
| ExtSimple->idx_end()); |
| EXPECT_THAT(IndicesSimple, testing::ElementsAre(0u)); |
| |
| SmallVector<int, 2> IndicesNested(ExtNested->idx_begin(), |
| ExtNested->idx_end()); |
| EXPECT_THAT(IndicesNested, testing::ElementsAre(1u, 0u)); |
| } |
| |
| // indices |
| { |
| SmallVector<int, 2> IndicesSimple(ExtSimple->indices()); |
| EXPECT_THAT(IndicesSimple, testing::ElementsAre(0u)); |
| |
| SmallVector<int, 2> IndicesNested(ExtNested->indices()); |
| EXPECT_THAT(IndicesNested, testing::ElementsAre(1u, 0u)); |
| } |
| |
| // getAggregateOperand |
| EXPECT_EQ(ExtSimple->getAggregateOperand(), ArgAgg); |
| const auto *ConstExtSimple = ExtSimple; |
| EXPECT_EQ(ConstExtSimple->getAggregateOperand(), ArgAgg); |
| |
| // getAggregateOperandIndex |
| EXPECT_EQ(sandboxir::ExtractValueInst::getAggregateOperandIndex(), |
| llvm::ExtractValueInst::getAggregateOperandIndex()); |
| |
| // getIndices |
| EXPECT_EQ(ExtSimple->getIndices().size(), 1u); |
| EXPECT_EQ(ExtSimple->getIndices()[0], 0u); |
| |
| // getNumIndices |
| EXPECT_EQ(ExtSimple->getNumIndices(), 1u); |
| |
| // hasIndices |
| EXPECT_EQ(ExtSimple->hasIndices(), true); |
| } |
| |
| TEST_F(SandboxIRTest, InsertValueInst) { |
| parseIR(C, R"IR( |
| define void @foo({i32, float} %agg, i32 %i) { |
| %ins_simple = insertvalue {i32, float} %agg, i32 %i, 0 |
| %ins_nested = insertvalue {float, {i32}} undef, i32 %i, 1, 0 |
| %const1 = insertvalue {i32, float} {i32 99, float 99.0}, i32 %i, 0 |
| %const2 = insertvalue {i32, float} {i32 0, float 99.0}, i32 %i, 0 |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *ArgAgg = F.getArg(0); |
| auto *ArgInt = F.getArg(1); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *InsSimple = cast<sandboxir::InsertValueInst>(&*It++); |
| auto *InsNested = cast<sandboxir::InsertValueInst>(&*It++); |
| // These "const" instructions are helpers to create constant struct operands. |
| // TODO: Remove them once sandboxir::ConstantStruct gets added. |
| auto *Const1 = cast<sandboxir::InsertValueInst>(&*It++); |
| auto *Const2 = cast<sandboxir::InsertValueInst>(&*It++); |
| auto *Ret = &*It++; |
| |
| EXPECT_EQ(InsSimple->getOperand(0), ArgAgg); |
| EXPECT_EQ(InsSimple->getOperand(1), ArgInt); |
| |
| // create before instruction |
| auto *NewInsBeforeRet = |
| cast<sandboxir::InsertValueInst>(sandboxir::InsertValueInst::create( |
| ArgAgg, ArgInt, ArrayRef<unsigned>({0}), Ret->getIterator(), Ctx, |
| "NewInsBeforeRet")); |
| EXPECT_EQ(NewInsBeforeRet->getNextNode(), Ret); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewInsBeforeRet->getName(), "NewInsBeforeRet"); |
| #endif // NDEBUG |
| |
| // create at end of BB |
| auto *NewInsAtEnd = |
| cast<sandboxir::InsertValueInst>(sandboxir::InsertValueInst::create( |
| ArgAgg, ArgInt, ArrayRef<unsigned>({0}), BB, Ctx, "NewInsAtEnd")); |
| EXPECT_EQ(NewInsAtEnd->getPrevNode(), Ret); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewInsAtEnd->getName(), "NewInsAtEnd"); |
| #endif // NDEBUG |
| |
| // Test the path that creates a folded constant. |
| auto *Zero = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 0); |
| auto *ShouldBeConstant = sandboxir::InsertValueInst::create( |
| Const1->getOperand(0), Zero, ArrayRef<unsigned>({0}), BB, Ctx); |
| auto *ExpectedConstant = Const2->getOperand(0); |
| EXPECT_TRUE(isa<sandboxir::Constant>(ShouldBeConstant)); |
| EXPECT_EQ(ShouldBeConstant, ExpectedConstant); |
| |
| // idx_begin / idx_end |
| { |
| SmallVector<int, 2> IndicesSimple(InsSimple->idx_begin(), |
| InsSimple->idx_end()); |
| EXPECT_THAT(IndicesSimple, testing::ElementsAre(0u)); |
| |
| SmallVector<int, 2> IndicesNested(InsNested->idx_begin(), |
| InsNested->idx_end()); |
| EXPECT_THAT(IndicesNested, testing::ElementsAre(1u, 0u)); |
| } |
| |
| // indices |
| { |
| SmallVector<int, 2> IndicesSimple(InsSimple->indices()); |
| EXPECT_THAT(IndicesSimple, testing::ElementsAre(0u)); |
| |
| SmallVector<int, 2> IndicesNested(InsNested->indices()); |
| EXPECT_THAT(IndicesNested, testing::ElementsAre(1u, 0u)); |
| } |
| |
| // getAggregateOperand |
| EXPECT_EQ(InsSimple->getAggregateOperand(), ArgAgg); |
| const auto *ConstInsSimple = InsSimple; |
| EXPECT_EQ(ConstInsSimple->getAggregateOperand(), ArgAgg); |
| |
| // getAggregateOperandIndex |
| EXPECT_EQ(sandboxir::InsertValueInst::getAggregateOperandIndex(), |
| llvm::InsertValueInst::getAggregateOperandIndex()); |
| |
| // getInsertedValueOperand |
| EXPECT_EQ(InsSimple->getInsertedValueOperand(), ArgInt); |
| EXPECT_EQ(ConstInsSimple->getInsertedValueOperand(), ArgInt); |
| |
| // getInsertedValueOperandIndex |
| EXPECT_EQ(sandboxir::InsertValueInst::getInsertedValueOperandIndex(), |
| llvm::InsertValueInst::getInsertedValueOperandIndex()); |
| |
| // getIndices |
| EXPECT_EQ(InsSimple->getIndices().size(), 1u); |
| EXPECT_EQ(InsSimple->getIndices()[0], 0u); |
| |
| // getNumIndices |
| EXPECT_EQ(InsSimple->getNumIndices(), 1u); |
| |
| // hasIndices |
| EXPECT_EQ(InsSimple->hasIndices(), true); |
| } |
| |
| 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, Ret1->getIterator(), 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, |
| Ret1->getIterator(), 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++); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(Ld)); |
| auto *VLd = cast<sandboxir::LoadInst>(&*It++); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| bool OrigVolatileValue; |
| |
| // 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), Ret->getIterator(), Ctx, "NewLd"); |
| EXPECT_FALSE(NewLd->isVolatile()); |
| OrigVolatileValue = NewLd->isVolatile(); |
| NewLd->setVolatile(true); |
| EXPECT_TRUE(NewLd->isVolatile()); |
| NewLd->setVolatile(OrigVolatileValue); |
| 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), Ret->getIterator(), |
| /*IsVolatile=*/true, Ctx, "NewVLd"); |
| |
| EXPECT_TRUE(NewVLd->isVolatile()); |
| OrigVolatileValue = NewVLd->isVolatile(); |
| NewVLd->setVolatile(false); |
| EXPECT_FALSE(NewVLd->isVolatile()); |
| NewVLd->setVolatile(OrigVolatileValue); |
| 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++); |
| bool OrigVolatileValue; |
| |
| // 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), Ret->getIterator(), Ctx); |
| EXPECT_FALSE(NewSt->isVolatile()); |
| OrigVolatileValue = NewSt->isVolatile(); |
| NewSt->setVolatile(true); |
| EXPECT_TRUE(NewSt->isVolatile()); |
| NewSt->setVolatile(OrigVolatileValue); |
| 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), Ret->getIterator(), |
| /*IsVolatile=*/true, Ctx); |
| EXPECT_TRUE(NewVSt->isVolatile()); |
| OrigVolatileValue = NewVSt->isVolatile(); |
| NewVSt->setVolatile(false); |
| EXPECT_FALSE(NewVSt->isVolatile()); |
| NewVSt->setVolatile(OrigVolatileValue); |
| 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, Ret->getIterator(), Ctx)); |
| EXPECT_EQ(NewRet1->getReturnValue(), nullptr); |
| // Check create(InsertBefore) a non-void ReturnInst. |
| auto *NewRet2 = cast<sandboxir::ReturnInst>( |
| sandboxir::ReturnInst::create(Val, Ret->getIterator(), 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(), |
| Ctx.getType(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); |
| sandboxir::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(), 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, Ret->getIterator(), 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, |
| InsertBefore->getIterator(), 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->getIterator(), 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, 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, BB0->end(), 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->getIterator(), 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, 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, LandingPadInst) { |
| parseIR(C, R"IR( |
| define void @foo() { |
| entry: |
| invoke void @foo() |
| to label %bb unwind label %unwind |
| unwind: |
| %lpad = landingpad { ptr, i32 } |
| catch ptr null |
| ret void |
| bb: |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMUnwind = getBasicBlockByName(LLVMF, "unwind"); |
| auto *LLVMLPad = cast<llvm::LandingPadInst>(&*LLVMUnwind->begin()); |
| |
| sandboxir::Context Ctx(C); |
| [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); |
| auto *Unwind = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMUnwind)); |
| auto *BB = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "bb"))); |
| auto It = Unwind->begin(); |
| auto *LPad = cast<sandboxir::LandingPadInst>(&*It++); |
| [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| // Check isCleanup(). |
| EXPECT_EQ(LPad->isCleanup(), LLVMLPad->isCleanup()); |
| // Check setCleanup(). |
| auto OrigIsCleanup = LPad->isCleanup(); |
| auto NewIsCleanup = true; |
| EXPECT_NE(NewIsCleanup, OrigIsCleanup); |
| LPad->setCleanup(NewIsCleanup); |
| EXPECT_EQ(LPad->isCleanup(), NewIsCleanup); |
| LPad->setCleanup(OrigIsCleanup); |
| EXPECT_EQ(LPad->isCleanup(), OrigIsCleanup); |
| // Check getNumClauses(). |
| EXPECT_EQ(LPad->getNumClauses(), LLVMLPad->getNumClauses()); |
| // Check getClause(). |
| for (auto Idx : seq<unsigned>(0, LPad->getNumClauses())) |
| EXPECT_EQ(LPad->getClause(Idx), Ctx.getValue(LLVMLPad->getClause(Idx))); |
| // Check isCatch(). |
| for (auto Idx : seq<unsigned>(0, LPad->getNumClauses())) |
| EXPECT_EQ(LPad->isCatch(Idx), LLVMLPad->isCatch(Idx)); |
| // Check isFilter(). |
| for (auto Idx : seq<unsigned>(0, LPad->getNumClauses())) |
| EXPECT_EQ(LPad->isFilter(Idx), LLVMLPad->isFilter(Idx)); |
| // Check create(). |
| auto *BBRet = &*BB->begin(); |
| auto *NewLPad = cast<sandboxir::LandingPadInst>( |
| sandboxir::LandingPadInst::create(sandboxir::Type::getInt8Ty(Ctx), 0, |
| BBRet->getIterator(), Ctx, "NewLPad")); |
| EXPECT_EQ(NewLPad->getNextNode(), BBRet); |
| EXPECT_FALSE(NewLPad->isCleanup()); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewLPad->getName(), "NewLPad"); |
| #endif // NDEBUG |
| } |
| |
| TEST_F(SandboxIRTest, FuncletPadInst_CatchPadInst_CleanupPadInst) { |
| parseIR(C, R"IR( |
| define void @foo() { |
| dispatch: |
| %cs = catchswitch within none [label %handler0] unwind to caller |
| handler0: |
| %catchpad = catchpad within %cs [ptr @foo] |
| ret void |
| handler1: |
| %cleanuppad = cleanuppad within %cs [ptr @foo] |
| ret void |
| bb: |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| BasicBlock *LLVMDispatch = getBasicBlockByName(LLVMF, "dispatch"); |
| BasicBlock *LLVMHandler0 = getBasicBlockByName(LLVMF, "handler0"); |
| BasicBlock *LLVMHandler1 = getBasicBlockByName(LLVMF, "handler1"); |
| auto *LLVMCP = cast<llvm::CatchPadInst>(&*LLVMHandler0->begin()); |
| auto *LLVMCLP = cast<llvm::CleanupPadInst>(&*LLVMHandler1->begin()); |
| |
| sandboxir::Context Ctx(C); |
| [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); |
| auto *Dispatch = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMDispatch)); |
| auto *Handler0 = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMHandler0)); |
| auto *Handler1 = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMHandler1)); |
| auto *BB = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "bb"))); |
| auto *BBRet = cast<sandboxir::ReturnInst>(&*BB->begin()); |
| auto *CS = cast<sandboxir::CatchSwitchInst>(&*Dispatch->begin()); |
| [[maybe_unused]] auto *CP = |
| cast<sandboxir::CatchPadInst>(&*Handler0->begin()); |
| [[maybe_unused]] auto *CLP = |
| cast<sandboxir::CleanupPadInst>(&*Handler1->begin()); |
| |
| // Check getCatchSwitch(). |
| EXPECT_EQ(CP->getCatchSwitch(), CS); |
| EXPECT_EQ(CP->getCatchSwitch(), Ctx.getValue(LLVMCP->getCatchSwitch())); |
| |
| for (llvm::FuncletPadInst *LLVMFPI : |
| {static_cast<llvm::FuncletPadInst *>(LLVMCP), |
| static_cast<llvm::FuncletPadInst *>(LLVMCLP)}) { |
| auto *FPI = cast<sandboxir::FuncletPadInst>(Ctx.getValue(LLVMFPI)); |
| // Check arg_size(). |
| EXPECT_EQ(FPI->arg_size(), LLVMFPI->arg_size()); |
| // Check getParentPad(). |
| EXPECT_EQ(FPI->getParentPad(), Ctx.getValue(LLVMFPI->getParentPad())); |
| // Check setParentPad(). |
| auto *OrigParentPad = FPI->getParentPad(); |
| auto *NewParentPad = Dispatch; |
| EXPECT_NE(NewParentPad, OrigParentPad); |
| FPI->setParentPad(NewParentPad); |
| EXPECT_EQ(FPI->getParentPad(), NewParentPad); |
| FPI->setParentPad(OrigParentPad); |
| EXPECT_EQ(FPI->getParentPad(), OrigParentPad); |
| // Check getArgOperand(). |
| for (auto Idx : seq<unsigned>(0, FPI->arg_size())) |
| EXPECT_EQ(FPI->getArgOperand(Idx), |
| Ctx.getValue(LLVMFPI->getArgOperand(Idx))); |
| // Check setArgOperand(). |
| auto *OrigArgOperand = FPI->getArgOperand(0); |
| auto *NewArgOperand = Dispatch; |
| EXPECT_NE(NewArgOperand, OrigArgOperand); |
| FPI->setArgOperand(0, NewArgOperand); |
| EXPECT_EQ(FPI->getArgOperand(0), NewArgOperand); |
| FPI->setArgOperand(0, OrigArgOperand); |
| EXPECT_EQ(FPI->getArgOperand(0), OrigArgOperand); |
| } |
| // Check CatchPadInst::create(). |
| auto *NewCPI = cast<sandboxir::CatchPadInst>(sandboxir::CatchPadInst::create( |
| CS, {}, BBRet->getIterator(), Ctx, "NewCPI")); |
| EXPECT_EQ(NewCPI->getCatchSwitch(), CS); |
| EXPECT_EQ(NewCPI->arg_size(), 0u); |
| EXPECT_EQ(NewCPI->getNextNode(), BBRet); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewCPI->getName(), "NewCPI"); |
| #endif // NDEBUG |
| // Check CleanupPadInst::create(). |
| auto *NewCLPI = |
| cast<sandboxir::CleanupPadInst>(sandboxir::CleanupPadInst::create( |
| CS, {}, BBRet->getIterator(), Ctx, "NewCLPI")); |
| EXPECT_EQ(NewCLPI->getParentPad(), CS); |
| EXPECT_EQ(NewCLPI->arg_size(), 0u); |
| EXPECT_EQ(NewCLPI->getNextNode(), BBRet); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewCLPI->getName(), "NewCLPI"); |
| #endif // NDEBUG |
| } |
| |
| TEST_F(SandboxIRTest, CatchReturnInst) { |
| parseIR(C, R"IR( |
| define void @foo() { |
| dispatch: |
| %cs = catchswitch within none [label %catch] unwind to caller |
| catch: |
| %catchpad = catchpad within %cs [ptr @foo] |
| catchret from %catchpad to label %continue |
| continue: |
| ret void |
| catch2: |
| %catchpad2 = catchpad within %cs [ptr @foo] |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| BasicBlock *LLVMCatch = getBasicBlockByName(LLVMF, "catch"); |
| auto LLVMIt = LLVMCatch->begin(); |
| [[maybe_unused]] auto *LLVMCP = cast<llvm::CatchPadInst>(&*LLVMIt++); |
| auto *LLVMCR = cast<llvm::CatchReturnInst>(&*LLVMIt++); |
| |
| sandboxir::Context Ctx(C); |
| [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); |
| auto *Catch = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMCatch)); |
| auto *Catch2 = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "catch2"))); |
| auto It = Catch->begin(); |
| [[maybe_unused]] auto *CP = cast<sandboxir::CatchPadInst>(&*It++); |
| auto *CR = cast<sandboxir::CatchReturnInst>(&*It++); |
| auto *CP2 = cast<sandboxir::CatchPadInst>(&*Catch2->begin()); |
| |
| // Check getCatchPad(). |
| EXPECT_EQ(CR->getCatchPad(), Ctx.getValue(LLVMCR->getCatchPad())); |
| // Check setCatchPad(). |
| auto *OrigCP = CR->getCatchPad(); |
| auto *NewCP = CP2; |
| EXPECT_NE(NewCP, OrigCP); |
| CR->setCatchPad(NewCP); |
| EXPECT_EQ(CR->getCatchPad(), NewCP); |
| CR->setCatchPad(OrigCP); |
| EXPECT_EQ(CR->getCatchPad(), OrigCP); |
| // Check getSuccessor(). |
| EXPECT_EQ(CR->getSuccessor(), Ctx.getValue(LLVMCR->getSuccessor())); |
| // Check setSuccessor(). |
| auto *OrigSucc = CR->getSuccessor(); |
| auto *NewSucc = Catch; |
| EXPECT_NE(NewSucc, OrigSucc); |
| CR->setSuccessor(NewSucc); |
| EXPECT_EQ(CR->getSuccessor(), NewSucc); |
| CR->setSuccessor(OrigSucc); |
| EXPECT_EQ(CR->getSuccessor(), OrigSucc); |
| // Check getNumSuccessors(). |
| EXPECT_EQ(CR->getNumSuccessors(), LLVMCR->getNumSuccessors()); |
| // Check getCatchSwitchParentPad(). |
| EXPECT_EQ(CR->getCatchSwitchParentPad(), |
| Ctx.getValue(LLVMCR->getCatchSwitchParentPad())); |
| // Check create(). |
| auto *CRI = cast<sandboxir::CatchReturnInst>( |
| sandboxir::CatchReturnInst::create(CP, Catch, CP->getIterator(), Ctx)); |
| EXPECT_EQ(CRI->getNextNode(), CP); |
| EXPECT_EQ(CRI->getCatchPad(), CP); |
| EXPECT_EQ(CRI->getSuccessor(), Catch); |
| } |
| |
| TEST_F(SandboxIRTest, CleanupReturnInst) { |
| parseIR(C, R"IR( |
| define void @foo() { |
| dispatch: |
| invoke void @foo() |
| to label %throw unwind label %cleanup |
| throw: |
| ret void |
| cleanup: |
| %cleanuppad = cleanuppad within none [] |
| cleanupret from %cleanuppad unwind label %cleanup2 |
| cleanup2: |
| %cleanuppad2 = cleanuppad within none [] |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| BasicBlock *LLVMCleanup = getBasicBlockByName(LLVMF, "cleanup"); |
| auto LLVMIt = LLVMCleanup->begin(); |
| [[maybe_unused]] auto *LLVMCP = cast<llvm::CleanupPadInst>(&*LLVMIt++); |
| auto *LLVMCRI = cast<llvm::CleanupReturnInst>(&*LLVMIt++); |
| |
| sandboxir::Context Ctx(C); |
| [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); |
| auto *Throw = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "throw"))); |
| auto *Cleanup = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMCleanup)); |
| auto *Cleanup2 = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "cleanup2"))); |
| auto It = Cleanup->begin(); |
| [[maybe_unused]] auto *CP = cast<sandboxir::CleanupPadInst>(&*It++); |
| auto *CRI = cast<sandboxir::CleanupReturnInst>(&*It++); |
| It = Cleanup2->begin(); |
| auto *CP2 = cast<sandboxir::CleanupPadInst>(&*It++); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| // Check hasUnwindDest(). |
| EXPECT_EQ(CRI->hasUnwindDest(), LLVMCRI->hasUnwindDest()); |
| // Check unwindsToCaller(). |
| EXPECT_EQ(CRI->unwindsToCaller(), LLVMCRI->unwindsToCaller()); |
| // Check getCleanupPad(). |
| EXPECT_EQ(CRI->getCleanupPad(), Ctx.getValue(LLVMCRI->getCleanupPad())); |
| // Check setCleanupPad(). |
| auto *OrigCleanupPad = CRI->getCleanupPad(); |
| auto *NewCleanupPad = CP2; |
| EXPECT_NE(NewCleanupPad, OrigCleanupPad); |
| CRI->setCleanupPad(NewCleanupPad); |
| EXPECT_EQ(CRI->getCleanupPad(), NewCleanupPad); |
| CRI->setCleanupPad(OrigCleanupPad); |
| EXPECT_EQ(CRI->getCleanupPad(), OrigCleanupPad); |
| // Check setNumSuccessors(). |
| EXPECT_EQ(CRI->getNumSuccessors(), LLVMCRI->getNumSuccessors()); |
| // Check getUnwindDest(). |
| EXPECT_EQ(CRI->getUnwindDest(), Ctx.getValue(LLVMCRI->getUnwindDest())); |
| // Check setUnwindDest(). |
| auto *OrigUnwindDest = CRI->getUnwindDest(); |
| auto *NewUnwindDest = Throw; |
| EXPECT_NE(NewUnwindDest, OrigUnwindDest); |
| CRI->setUnwindDest(NewUnwindDest); |
| EXPECT_EQ(CRI->getUnwindDest(), NewUnwindDest); |
| CRI->setUnwindDest(OrigUnwindDest); |
| EXPECT_EQ(CRI->getUnwindDest(), OrigUnwindDest); |
| // Check create(). |
| auto *UnwindBB = Cleanup; |
| auto *NewCRI = sandboxir::CleanupReturnInst::create(CP2, UnwindBB, |
| Ret->getIterator(), Ctx); |
| EXPECT_EQ(NewCRI->getCleanupPad(), CP2); |
| EXPECT_EQ(NewCRI->getUnwindDest(), UnwindBB); |
| EXPECT_EQ(NewCRI->getNextNode(), Ret); |
| } |
| |
| 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(), |
| Ctx.getType(LLVMGEP->getSourceElementType())); |
| // Check getResultElementType(). |
| EXPECT_EQ(GEP->getResultElementType(), |
| Ctx.getType(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(), |
| Ctx.getType(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(). |
| const DataLayout &DL = M->getDataLayout(); |
| 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, |
| Ret->getIterator(), 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, |
| Ret->getIterator(), 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, 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, Flags) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %arg, float %farg) { |
| %add = add i32 %arg, %arg |
| %fadd = fadd float %farg, %farg |
| %udiv = udiv i32 %arg, %arg |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| BasicBlock *LLVMBB = &*LLVMF.begin(); |
| auto LLVMIt = LLVMBB->begin(); |
| auto *LLVMAdd = &*LLVMIt++; |
| auto *LLVMFAdd = &*LLVMIt++; |
| auto *LLVMUDiv = &*LLVMIt++; |
| |
| sandboxir::Context Ctx(C); |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *Add = &*It++; |
| auto *FAdd = &*It++; |
| auto *UDiv = &*It++; |
| |
| #define CHECK_FLAG(I, LLVMI, GETTER, SETTER) \ |
| { \ |
| EXPECT_EQ(I->GETTER(), LLVMI->GETTER()); \ |
| bool NewFlagVal = !I->GETTER(); \ |
| I->SETTER(NewFlagVal); \ |
| EXPECT_EQ(I->GETTER(), NewFlagVal); \ |
| EXPECT_EQ(I->GETTER(), LLVMI->GETTER()); \ |
| } |
| |
| CHECK_FLAG(Add, LLVMAdd, hasNoUnsignedWrap, setHasNoUnsignedWrap); |
| CHECK_FLAG(Add, LLVMAdd, hasNoSignedWrap, setHasNoSignedWrap); |
| CHECK_FLAG(FAdd, LLVMFAdd, isFast, setFast); |
| CHECK_FLAG(FAdd, LLVMFAdd, hasAllowReassoc, setHasAllowReassoc); |
| CHECK_FLAG(UDiv, LLVMUDiv, isExact, setIsExact); |
| CHECK_FLAG(FAdd, LLVMFAdd, hasNoNaNs, setHasNoNaNs); |
| CHECK_FLAG(FAdd, LLVMFAdd, hasNoInfs, setHasNoInfs); |
| CHECK_FLAG(FAdd, LLVMFAdd, hasNoSignedZeros, setHasNoSignedZeros); |
| CHECK_FLAG(FAdd, LLVMFAdd, hasAllowReciprocal, setHasAllowReciprocal); |
| CHECK_FLAG(FAdd, LLVMFAdd, hasAllowContract, setHasAllowContract); |
| CHECK_FLAG(FAdd, LLVMFAdd, hasApproxFunc, setHasApproxFunc); |
| |
| // Check getFastMathFlags(), copyFastMathFlags(). |
| FAdd->setFastMathFlags(FastMathFlags::getFast()); |
| EXPECT_FALSE(FAdd->getFastMathFlags() != LLVMFAdd->getFastMathFlags()); |
| FastMathFlags OrigFMF = FAdd->getFastMathFlags(); |
| FastMathFlags NewFMF; |
| NewFMF.setAllowReassoc(true); |
| EXPECT_TRUE(NewFMF != OrigFMF); |
| FAdd->setFastMathFlags(NewFMF); |
| EXPECT_FALSE(FAdd->getFastMathFlags() != OrigFMF); |
| FAdd->copyFastMathFlags(NewFMF); |
| EXPECT_FALSE(FAdd->getFastMathFlags() != NewFMF); |
| EXPECT_FALSE(FAdd->getFastMathFlags() != LLVMFAdd->getFastMathFlags()); |
| } |
| |
| TEST_F(SandboxIRTest, CatchSwitchInst) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %cond0, i32 %cond1) { |
| bb0: |
| %cs0 = catchswitch within none [label %handler0, label %handler1] unwind to caller |
| bb1: |
| %cs1 = catchswitch within %cs0 [label %handler0, label %handler1] unwind label %cleanup |
| handler0: |
| ret void |
| handler1: |
| ret void |
| cleanup: |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMBB0 = getBasicBlockByName(LLVMF, "bb0"); |
| auto *LLVMBB1 = getBasicBlockByName(LLVMF, "bb1"); |
| auto *LLVMHandler0 = getBasicBlockByName(LLVMF, "handler0"); |
| auto *LLVMHandler1 = getBasicBlockByName(LLVMF, "handler1"); |
| auto *LLVMCleanup = getBasicBlockByName(LLVMF, "cleanup"); |
| auto *LLVMCS0 = cast<llvm::CatchSwitchInst>(&*LLVMBB0->begin()); |
| auto *LLVMCS1 = cast<llvm::CatchSwitchInst>(&*LLVMBB1->begin()); |
| |
| sandboxir::Context Ctx(C); |
| [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); |
| auto *BB0 = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMBB0)); |
| auto *BB1 = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMBB1)); |
| auto *Handler0 = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMHandler0)); |
| auto *Handler1 = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMHandler1)); |
| auto *Cleanup = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMCleanup)); |
| auto *CS0 = cast<sandboxir::CatchSwitchInst>(&*BB0->begin()); |
| auto *CS1 = cast<sandboxir::CatchSwitchInst>(&*BB1->begin()); |
| |
| // Check getParentPad(). |
| EXPECT_EQ(CS0->getParentPad(), Ctx.getValue(LLVMCS0->getParentPad())); |
| EXPECT_EQ(CS1->getParentPad(), Ctx.getValue(LLVMCS1->getParentPad())); |
| // Check setParentPad(). |
| auto *OrigPad = CS0->getParentPad(); |
| auto *NewPad = CS1; |
| EXPECT_NE(NewPad, OrigPad); |
| CS0->setParentPad(NewPad); |
| EXPECT_EQ(CS0->getParentPad(), NewPad); |
| CS0->setParentPad(OrigPad); |
| EXPECT_EQ(CS0->getParentPad(), OrigPad); |
| // Check hasUnwindDest(). |
| EXPECT_EQ(CS0->hasUnwindDest(), LLVMCS0->hasUnwindDest()); |
| EXPECT_EQ(CS1->hasUnwindDest(), LLVMCS1->hasUnwindDest()); |
| // Check unwindsToCaller(). |
| EXPECT_EQ(CS0->unwindsToCaller(), LLVMCS0->unwindsToCaller()); |
| EXPECT_EQ(CS1->unwindsToCaller(), LLVMCS1->unwindsToCaller()); |
| // Check getUnwindDest(). |
| EXPECT_EQ(CS0->getUnwindDest(), Ctx.getValue(LLVMCS0->getUnwindDest())); |
| EXPECT_EQ(CS1->getUnwindDest(), Ctx.getValue(LLVMCS1->getUnwindDest())); |
| // Check setUnwindDest(). |
| auto *OrigUnwindDest = CS1->getUnwindDest(); |
| auto *NewUnwindDest = BB0; |
| EXPECT_NE(NewUnwindDest, OrigUnwindDest); |
| CS1->setUnwindDest(NewUnwindDest); |
| EXPECT_EQ(CS1->getUnwindDest(), NewUnwindDest); |
| CS1->setUnwindDest(OrigUnwindDest); |
| EXPECT_EQ(CS1->getUnwindDest(), OrigUnwindDest); |
| // Check getNumHandlers(). |
| EXPECT_EQ(CS0->getNumHandlers(), LLVMCS0->getNumHandlers()); |
| EXPECT_EQ(CS1->getNumHandlers(), LLVMCS1->getNumHandlers()); |
| // Check handler_begin(), handler_end(). |
| auto It = CS0->handler_begin(); |
| EXPECT_EQ(*It++, Handler0); |
| EXPECT_EQ(*It++, Handler1); |
| EXPECT_EQ(It, CS0->handler_end()); |
| // Check handlers(). |
| SmallVector<sandboxir::BasicBlock *, 2> Handlers; |
| for (sandboxir::BasicBlock *Handler : CS0->handlers()) |
| Handlers.push_back(Handler); |
| EXPECT_EQ(Handlers.size(), 2u); |
| EXPECT_EQ(Handlers[0], Handler0); |
| EXPECT_EQ(Handlers[1], Handler1); |
| // Check addHandler(). |
| CS0->addHandler(BB0); |
| EXPECT_EQ(CS0->getNumHandlers(), 3u); |
| EXPECT_EQ(*std::next(CS0->handler_begin(), 2), BB0); |
| // Check getNumSuccessors(). |
| EXPECT_EQ(CS0->getNumSuccessors(), LLVMCS0->getNumSuccessors()); |
| EXPECT_EQ(CS1->getNumSuccessors(), LLVMCS1->getNumSuccessors()); |
| // Check getSuccessor(). |
| for (auto SuccIdx : seq<unsigned>(0, CS0->getNumSuccessors())) |
| EXPECT_EQ(CS0->getSuccessor(SuccIdx), |
| Ctx.getValue(LLVMCS0->getSuccessor(SuccIdx))); |
| // Check setSuccessor(). |
| auto *OrigSuccessor = CS0->getSuccessor(0); |
| auto *NewSuccessor = BB0; |
| EXPECT_NE(NewSuccessor, OrigSuccessor); |
| CS0->setSuccessor(0, NewSuccessor); |
| EXPECT_EQ(CS0->getSuccessor(0), NewSuccessor); |
| CS0->setSuccessor(0, OrigSuccessor); |
| EXPECT_EQ(CS0->getSuccessor(0), OrigSuccessor); |
| // Check create(). |
| CS1->eraseFromParent(); |
| auto *NewCSI = sandboxir::CatchSwitchInst::create( |
| CS0, Cleanup, 2, BB1->begin(), Ctx, "NewCSI"); |
| EXPECT_TRUE(isa<sandboxir::CatchSwitchInst>(NewCSI)); |
| EXPECT_EQ(NewCSI->getParentPad(), CS0); |
| } |
| |
| TEST_F(SandboxIRTest, ResumeInst) { |
| parseIR(C, R"IR( |
| define void @foo() { |
| entry: |
| invoke void @foo() |
| to label %bb unwind label %unwind |
| bb: |
| ret void |
| unwind: |
| %lpad = landingpad { ptr, i32 } |
| cleanup |
| resume { ptr, i32 } %lpad |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMUnwindBB = getBasicBlockByName(LLVMF, "unwind"); |
| auto LLVMIt = LLVMUnwindBB->begin(); |
| [[maybe_unused]] auto *LLVMLPad = cast<llvm::LandingPadInst>(&*LLVMIt++); |
| auto *LLVMResume = cast<llvm::ResumeInst>(&*LLVMIt++); |
| |
| sandboxir::Context Ctx(C); |
| [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); |
| auto *UnwindBB = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMUnwindBB)); |
| auto It = UnwindBB->begin(); |
| auto *LPad = cast<sandboxir::LandingPadInst>(&*It++); |
| auto *Resume = cast<sandboxir::ResumeInst>(&*It++); |
| // Check getValue(). |
| EXPECT_EQ(Resume->getValue(), LPad); |
| EXPECT_EQ(Resume->getValue(), Ctx.getValue(LLVMResume->getValue())); |
| // Check getNumSuccessors(). |
| EXPECT_EQ(Resume->getNumSuccessors(), LLVMResume->getNumSuccessors()); |
| // Check create(). |
| auto *NewResume = sandboxir::ResumeInst::create(LPad, UnwindBB->end(), Ctx); |
| EXPECT_EQ(NewResume->getValue(), LPad); |
| EXPECT_EQ(NewResume->getParent(), UnwindBB); |
| EXPECT_EQ(NewResume->getNextNode(), nullptr); |
| } |
| |
| TEST_F(SandboxIRTest, SwitchInst) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %cond0, i32 %cond1) { |
| entry: |
| switch i32 %cond0, label %default [ i32 0, label %bb0 |
| i32 1, label %bb1 ] |
| bb0: |
| ret void |
| bb1: |
| ret void |
| default: |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMEntry = getBasicBlockByName(LLVMF, "entry"); |
| auto *LLVMSwitch = cast<llvm::SwitchInst>(&*LLVMEntry->begin()); |
| |
| sandboxir::Context Ctx(C); |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *Cond1 = F.getArg(1); |
| auto *Entry = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMEntry)); |
| auto *Switch = cast<sandboxir::SwitchInst>(&*Entry->begin()); |
| auto *BB0 = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "bb0"))); |
| auto *BB1 = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "bb1"))); |
| auto *Default = cast<sandboxir::BasicBlock>( |
| Ctx.getValue(getBasicBlockByName(LLVMF, "default"))); |
| |
| // Check getCondition(). |
| EXPECT_EQ(Switch->getCondition(), Ctx.getValue(LLVMSwitch->getCondition())); |
| // Check setCondition(). |
| auto *OrigCond = Switch->getCondition(); |
| auto *NewCond = Cond1; |
| EXPECT_NE(NewCond, OrigCond); |
| Switch->setCondition(NewCond); |
| EXPECT_EQ(Switch->getCondition(), NewCond); |
| Switch->setCondition(OrigCond); |
| EXPECT_EQ(Switch->getCondition(), OrigCond); |
| // Check getDefaultDest(). |
| EXPECT_EQ(Switch->getDefaultDest(), |
| Ctx.getValue(LLVMSwitch->getDefaultDest())); |
| EXPECT_EQ(Switch->getDefaultDest(), Default); |
| // Check defaultDestUnreachable(). |
| EXPECT_EQ(Switch->defaultDestUnreachable(), |
| LLVMSwitch->defaultDestUnreachable()); |
| // Check setDefaultDest(). |
| auto *OrigDefaultDest = Switch->getDefaultDest(); |
| auto *NewDefaultDest = Entry; |
| EXPECT_NE(NewDefaultDest, OrigDefaultDest); |
| Switch->setDefaultDest(NewDefaultDest); |
| EXPECT_EQ(Switch->getDefaultDest(), NewDefaultDest); |
| Switch->setDefaultDest(OrigDefaultDest); |
| EXPECT_EQ(Switch->getDefaultDest(), OrigDefaultDest); |
| // Check getNumCases(). |
| EXPECT_EQ(Switch->getNumCases(), LLVMSwitch->getNumCases()); |
| // Check getNumSuccessors(). |
| EXPECT_EQ(Switch->getNumSuccessors(), LLVMSwitch->getNumSuccessors()); |
| // Check getSuccessor(). |
| for (auto SuccIdx : seq<unsigned>(0, Switch->getNumSuccessors())) |
| EXPECT_EQ(Switch->getSuccessor(SuccIdx), |
| Ctx.getValue(LLVMSwitch->getSuccessor(SuccIdx))); |
| // Check setSuccessor(). |
| auto *OrigSucc = Switch->getSuccessor(0); |
| auto *NewSucc = Entry; |
| EXPECT_NE(NewSucc, OrigSucc); |
| Switch->setSuccessor(0, NewSucc); |
| EXPECT_EQ(Switch->getSuccessor(0), NewSucc); |
| Switch->setSuccessor(0, OrigSucc); |
| EXPECT_EQ(Switch->getSuccessor(0), OrigSucc); |
| // Check case_begin(), case_end(), CaseIt. |
| auto *Zero = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 0); |
| auto *One = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 1); |
| auto CaseIt = Switch->case_begin(); |
| { |
| sandboxir::SwitchInst::CaseHandle Case = *CaseIt++; |
| EXPECT_EQ(Case.getCaseValue(), Zero); |
| EXPECT_EQ(Case.getCaseSuccessor(), BB0); |
| EXPECT_EQ(Case.getCaseIndex(), 0u); |
| EXPECT_EQ(Case.getSuccessorIndex(), 1u); |
| } |
| { |
| sandboxir::SwitchInst::CaseHandle Case = *CaseIt++; |
| EXPECT_EQ(Case.getCaseValue(), One); |
| EXPECT_EQ(Case.getCaseSuccessor(), BB1); |
| EXPECT_EQ(Case.getCaseIndex(), 1u); |
| EXPECT_EQ(Case.getSuccessorIndex(), 2u); |
| } |
| EXPECT_EQ(CaseIt, Switch->case_end()); |
| // Check cases(). |
| unsigned CntCase = 0; |
| for (auto &Case : Switch->cases()) { |
| EXPECT_EQ(Case.getCaseIndex(), CntCase); |
| ++CntCase; |
| } |
| EXPECT_EQ(CntCase, 2u); |
| // Check case_default(). |
| auto CaseDefault = *Switch->case_default(); |
| EXPECT_EQ(CaseDefault.getCaseSuccessor(), Default); |
| EXPECT_EQ(CaseDefault.getCaseIndex(), |
| sandboxir::SwitchInst::DefaultPseudoIndex); |
| // Check findCaseValue(). |
| EXPECT_EQ(Switch->findCaseValue(Zero)->getCaseIndex(), 0u); |
| EXPECT_EQ(Switch->findCaseValue(One)->getCaseIndex(), 1u); |
| // Check findCaseDest(). |
| EXPECT_EQ(Switch->findCaseDest(BB0), Zero); |
| EXPECT_EQ(Switch->findCaseDest(BB1), One); |
| EXPECT_EQ(Switch->findCaseDest(Entry), nullptr); |
| // Check addCase(). |
| auto *Two = sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 2); |
| Switch->addCase(Two, Entry); |
| auto CaseTwoIt = Switch->findCaseValue(Two); |
| auto CaseTwo = *CaseTwoIt; |
| EXPECT_EQ(CaseTwo.getCaseValue(), Two); |
| EXPECT_EQ(CaseTwo.getCaseSuccessor(), Entry); |
| EXPECT_EQ(Switch->getNumCases(), 3u); |
| // Check removeCase(). |
| auto RemovedIt = Switch->removeCase(CaseTwoIt); |
| EXPECT_EQ(RemovedIt, Switch->case_end()); |
| EXPECT_EQ(Switch->getNumCases(), 2u); |
| // Check create(). |
| auto NewSwitch = sandboxir::SwitchInst::create( |
| Cond1, Default, 1, Default->begin(), Ctx, "NewSwitch"); |
| EXPECT_TRUE(isa<sandboxir::SwitchInst>(NewSwitch)); |
| EXPECT_EQ(NewSwitch->getCondition(), Cond1); |
| EXPECT_EQ(NewSwitch->getDefaultDest(), Default); |
| } |
| |
| TEST_F(SandboxIRTest, UnaryOperator) { |
| parseIR(C, R"IR( |
| define void @foo(float %arg0) { |
| %fneg = fneg float %arg0 |
| %copyfrom = fadd reassoc float %arg0, 42.0 |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *Arg0 = F.getArg(0); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| auto *I = cast<sandboxir::UnaryOperator>(&*It++); |
| auto *CopyFrom = cast<sandboxir::BinaryOperator>(&*It++); |
| auto *Ret = &*It++; |
| EXPECT_EQ(I->getOpcode(), sandboxir::Instruction::Opcode::FNeg); |
| EXPECT_EQ(I->getOperand(0), Arg0); |
| |
| { |
| // Check create() WhereIt, WhereBB. |
| auto *NewI = |
| cast<sandboxir::UnaryOperator>(sandboxir::UnaryOperator::create( |
| sandboxir::Instruction::Opcode::FNeg, Arg0, Ret->getIterator(), Ctx, |
| "New1")); |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::FNeg); |
| EXPECT_EQ(NewI->getOperand(0), Arg0); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewI->getName(), "New1"); |
| #endif // NDEBUG |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| } |
| { |
| // Check create() InsertBefore. |
| auto *NewI = |
| cast<sandboxir::UnaryOperator>(sandboxir::UnaryOperator::create( |
| sandboxir::Instruction::Opcode::FNeg, Arg0, Ret->getIterator(), Ctx, |
| "New2")); |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::FNeg); |
| EXPECT_EQ(NewI->getOperand(0), Arg0); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewI->getName(), "New2"); |
| #endif // NDEBUG |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| } |
| { |
| // Check create() InsertAtEnd. |
| auto *NewI = |
| cast<sandboxir::UnaryOperator>(sandboxir::UnaryOperator::create( |
| sandboxir::Instruction::Opcode::FNeg, Arg0, BB, Ctx, "New3")); |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::FNeg); |
| EXPECT_EQ(NewI->getOperand(0), Arg0); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewI->getName(), "New3"); |
| #endif // NDEBUG |
| EXPECT_EQ(NewI->getParent(), BB); |
| EXPECT_EQ(NewI->getNextNode(), nullptr); |
| } |
| { |
| // Check create() when it gets folded. |
| auto *FortyTwo = CopyFrom->getOperand(1); |
| auto *NewV = sandboxir::UnaryOperator::create( |
| sandboxir::Instruction::Opcode::FNeg, FortyTwo, Ret->getIterator(), Ctx, |
| "Folded"); |
| EXPECT_TRUE(isa<sandboxir::Constant>(NewV)); |
| } |
| |
| { |
| // Check createWithCopiedFlags() WhereIt, WhereBB. |
| auto *NewI = cast<sandboxir::UnaryOperator>( |
| sandboxir::UnaryOperator::createWithCopiedFlags( |
| sandboxir::Instruction::Opcode::FNeg, Arg0, CopyFrom, |
| Ret->getIterator(), Ctx, "NewCopyFrom1")); |
| EXPECT_EQ(NewI->hasAllowReassoc(), CopyFrom->hasAllowReassoc()); |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::FNeg); |
| EXPECT_EQ(NewI->getOperand(0), Arg0); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewI->getName(), "NewCopyFrom1"); |
| #endif // NDEBUG |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| } |
| { |
| // Check createWithCopiedFlags() InsertBefore, |
| auto *NewI = cast<sandboxir::UnaryOperator>( |
| sandboxir::UnaryOperator::createWithCopiedFlags( |
| sandboxir::Instruction::Opcode::FNeg, Arg0, CopyFrom, |
| Ret->getIterator(), Ctx, "NewCopyFrom2")); |
| EXPECT_EQ(NewI->hasAllowReassoc(), CopyFrom->hasAllowReassoc()); |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::FNeg); |
| EXPECT_EQ(NewI->getOperand(0), Arg0); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewI->getName(), "NewCopyFrom2"); |
| #endif // NDEBUG |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| } |
| { |
| // Check createWithCopiedFlags() InsertAtEnd, |
| auto *NewI = cast<sandboxir::UnaryOperator>( |
| sandboxir::UnaryOperator::createWithCopiedFlags( |
| sandboxir::Instruction::Opcode::FNeg, Arg0, CopyFrom, BB, Ctx, |
| "NewCopyFrom3")); |
| EXPECT_EQ(NewI->hasAllowReassoc(), CopyFrom->hasAllowReassoc()); |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::FNeg); |
| EXPECT_EQ(NewI->getOperand(0), Arg0); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewI->getName(), "NewCopyFrom3"); |
| #endif // NDEBUG |
| EXPECT_EQ(NewI->getParent(), BB); |
| EXPECT_EQ(NewI->getNextNode(), nullptr); |
| } |
| { |
| // Check createWithCopiedFlags() when it gets folded. |
| auto *FortyTwo = CopyFrom->getOperand(1); |
| auto *NewV = sandboxir::UnaryOperator::createWithCopiedFlags( |
| sandboxir::Instruction::Opcode::FNeg, FortyTwo, CopyFrom, BB, Ctx, |
| "Folded"); |
| EXPECT_TRUE(isa<sandboxir::Constant>(NewV)); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, BinaryOperator) { |
| parseIR(C, R"IR( |
| define void @foo(i8 %arg0, i8 %arg1, float %farg0, float %farg1) { |
| %add = add i8 %arg0, %arg1 |
| %fadd = fadd float %farg0, %farg1 |
| %sub = sub i8 %arg0, %arg1 |
| %fsub = fsub float %farg0, %farg1 |
| %mul = mul i8 %arg0, %arg1 |
| %fmul = fmul float %farg0, %farg1 |
| %udiv = udiv i8 %arg0, %arg1 |
| %sdiv = sdiv i8 %arg0, %arg1 |
| %fdiv = fdiv float %farg0, %farg1 |
| %urem = urem i8 %arg0, %arg1 |
| %srem = srem i8 %arg0, %arg1 |
| %frem = frem float %farg0, %farg1 |
| %shl = shl i8 %arg0, %arg1 |
| %lshr = lshr i8 %arg0, %arg1 |
| %ashr = ashr i8 %arg0, %arg1 |
| %and = and i8 %arg0, %arg1 |
| %or = or i8 %arg0, %arg1 |
| %xor = xor i8 %arg0, %arg1 |
| |
| %copyfrom = add nsw i8 %arg0, %arg1 |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto *Arg0 = F.getArg(0); |
| auto *Arg1 = F.getArg(1); |
| auto *FArg0 = F.getArg(2); |
| auto *FArg1 = F.getArg(3); |
| auto *BB = &*F.begin(); |
| auto It = BB->begin(); |
| |
| #define CHECK_IBINOP(OPCODE) \ |
| { \ |
| auto *I = cast<sandboxir::BinaryOperator>(&*It++); \ |
| EXPECT_EQ(I->getOpcode(), OPCODE); \ |
| EXPECT_EQ(I->getOperand(0), Arg0); \ |
| EXPECT_EQ(I->getOperand(1), Arg1); \ |
| } |
| #define CHECK_FBINOP(OPCODE) \ |
| { \ |
| auto *I = cast<sandboxir::BinaryOperator>(&*It++); \ |
| EXPECT_EQ(I->getOpcode(), OPCODE); \ |
| EXPECT_EQ(I->getOperand(0), FArg0); \ |
| EXPECT_EQ(I->getOperand(1), FArg1); \ |
| } |
| |
| CHECK_IBINOP(sandboxir::Instruction::Opcode::Add); |
| CHECK_FBINOP(sandboxir::Instruction::Opcode::FAdd); |
| CHECK_IBINOP(sandboxir::Instruction::Opcode::Sub); |
| CHECK_FBINOP(sandboxir::Instruction::Opcode::FSub); |
| CHECK_IBINOP(sandboxir::Instruction::Opcode::Mul); |
| CHECK_FBINOP(sandboxir::Instruction::Opcode::FMul); |
| CHECK_IBINOP(sandboxir::Instruction::Opcode::UDiv); |
| CHECK_IBINOP(sandboxir::Instruction::Opcode::SDiv); |
| CHECK_FBINOP(sandboxir::Instruction::Opcode::FDiv); |
| CHECK_IBINOP(sandboxir::Instruction::Opcode::URem); |
| CHECK_IBINOP(sandboxir::Instruction::Opcode::SRem); |
| CHECK_FBINOP(sandboxir::Instruction::Opcode::FRem); |
| CHECK_IBINOP(sandboxir::Instruction::Opcode::Shl); |
| CHECK_IBINOP(sandboxir::Instruction::Opcode::LShr); |
| CHECK_IBINOP(sandboxir::Instruction::Opcode::AShr); |
| CHECK_IBINOP(sandboxir::Instruction::Opcode::And); |
| CHECK_IBINOP(sandboxir::Instruction::Opcode::Or); |
| CHECK_IBINOP(sandboxir::Instruction::Opcode::Xor); |
| |
| auto *CopyFrom = cast<sandboxir::BinaryOperator>(&*It++); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| { |
| // Check create() WhereIt, WhereBB. |
| auto *NewI = |
| cast<sandboxir::BinaryOperator>(sandboxir::BinaryOperator::create( |
| sandboxir::Instruction::Opcode::Add, Arg0, Arg1, Ret->getIterator(), |
| Ctx, "New1")); |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::Add); |
| EXPECT_EQ(NewI->getOperand(0), Arg0); |
| EXPECT_EQ(NewI->getOperand(1), Arg1); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewI->getName(), "New1"); |
| #endif // NDEBUG |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| } |
| { |
| // Check create() InsertBefore. |
| auto *NewI = |
| cast<sandboxir::BinaryOperator>(sandboxir::BinaryOperator::create( |
| sandboxir::Instruction::Opcode::Add, Arg0, Arg1, Ret->getIterator(), |
| Ctx, "New2")); |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::Add); |
| EXPECT_EQ(NewI->getOperand(0), Arg0); |
| EXPECT_EQ(NewI->getOperand(1), Arg1); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewI->getName(), "New2"); |
| #endif // NDEBUG |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| } |
| { |
| // Check create() InsertAtEnd. |
| auto *NewI = |
| cast<sandboxir::BinaryOperator>(sandboxir::BinaryOperator::create( |
| sandboxir::Instruction::Opcode::Add, Arg0, Arg1, |
| /*InsertAtEnd=*/BB, Ctx, "New3")); |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::Add); |
| EXPECT_EQ(NewI->getOperand(0), Arg0); |
| EXPECT_EQ(NewI->getOperand(1), Arg1); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewI->getName(), "New3"); |
| #endif // NDEBUG |
| EXPECT_EQ(NewI->getNextNode(), nullptr); |
| EXPECT_EQ(NewI->getParent(), BB); |
| } |
| { |
| // Check create() when it gets folded. |
| auto *FortyTwo = |
| sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 42); |
| auto *NewV = sandboxir::BinaryOperator::create( |
| sandboxir::Instruction::Opcode::Add, FortyTwo, FortyTwo, |
| Ret->getIterator(), Ctx, "Folded"); |
| EXPECT_TRUE(isa<sandboxir::Constant>(NewV)); |
| } |
| |
| { |
| // Check createWithCopiedFlags() WhereIt, WhereBB. |
| auto *NewI = cast<sandboxir::BinaryOperator>( |
| sandboxir::BinaryOperator::createWithCopiedFlags( |
| sandboxir::Instruction::Opcode::Add, Arg0, Arg1, CopyFrom, |
| Ret->getIterator(), Ctx, "NewNSW1")); |
| EXPECT_EQ(NewI->hasNoSignedWrap(), CopyFrom->hasNoSignedWrap()); |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::Add); |
| EXPECT_EQ(NewI->getOperand(0), Arg0); |
| EXPECT_EQ(NewI->getOperand(1), Arg1); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewI->getName(), "NewNSW1"); |
| #endif // NDEBUG |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| } |
| { |
| // Check createWithCopiedFlags() InsertBefore. |
| auto *NewI = cast<sandboxir::BinaryOperator>( |
| sandboxir::BinaryOperator::createWithCopiedFlags( |
| sandboxir::Instruction::Opcode::Add, Arg0, Arg1, CopyFrom, |
| Ret->getIterator(), Ctx, "NewNSW2")); |
| EXPECT_EQ(NewI->hasNoSignedWrap(), CopyFrom->hasNoSignedWrap()); |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::Add); |
| EXPECT_EQ(NewI->getOperand(0), Arg0); |
| EXPECT_EQ(NewI->getOperand(1), Arg1); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewI->getName(), "NewNSW2"); |
| #endif // NDEBUG |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| } |
| { |
| // Check createWithCopiedFlags() InsertAtEnd. |
| auto *NewI = cast<sandboxir::BinaryOperator>( |
| sandboxir::BinaryOperator::createWithCopiedFlags( |
| sandboxir::Instruction::Opcode::Add, Arg0, Arg1, CopyFrom, BB, Ctx, |
| "NewNSW3")); |
| EXPECT_EQ(NewI->hasNoSignedWrap(), CopyFrom->hasNoSignedWrap()); |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::Add); |
| EXPECT_EQ(NewI->getOperand(0), Arg0); |
| EXPECT_EQ(NewI->getOperand(1), Arg1); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewI->getName(), "NewNSW3"); |
| #endif // NDEBUG |
| EXPECT_EQ(NewI->getParent(), BB); |
| EXPECT_EQ(NewI->getNextNode(), nullptr); |
| } |
| { |
| // Check createWithCopiedFlags() when it gets folded. |
| auto *FortyTwo = |
| sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 42); |
| auto *NewV = sandboxir::BinaryOperator::createWithCopiedFlags( |
| sandboxir::Instruction::Opcode::Add, FortyTwo, FortyTwo, CopyFrom, |
| Ret->getIterator(), Ctx, "Folded"); |
| EXPECT_TRUE(isa<sandboxir::Constant>(NewV)); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, PossiblyDisjointInst) { |
| parseIR(C, R"IR( |
| define void @foo(i8 %arg0, i8 %arg1) { |
| %or = or i8 %arg0, %arg1 |
| 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 *PDI = cast<sandboxir::PossiblyDisjointInst>(&*It++); |
| |
| // Check setIsDisjoint(), isDisjoint(). |
| auto OrigIsDisjoint = PDI->isDisjoint(); |
| auto NewIsDisjoint = true; |
| EXPECT_NE(NewIsDisjoint, OrigIsDisjoint); |
| PDI->setIsDisjoint(NewIsDisjoint); |
| EXPECT_EQ(PDI->isDisjoint(), NewIsDisjoint); |
| PDI->setIsDisjoint(OrigIsDisjoint); |
| EXPECT_EQ(PDI->isDisjoint(), OrigIsDisjoint); |
| } |
| |
| TEST_F(SandboxIRTest, AtomicRMWInst) { |
| parseIR(C, R"IR( |
| define void @foo(ptr %ptr, i8 %arg) { |
| %atomicrmw = atomicrmw add ptr %ptr, i8 %arg acquire, align 128 |
| ret void |
| } |
| )IR"); |
| llvm::Function &LLVMF = *M->getFunction("foo"); |
| llvm::BasicBlock *LLVMBB = &*LLVMF.begin(); |
| auto LLVMIt = LLVMBB->begin(); |
| auto *LLVMRMW = cast<llvm::AtomicRMWInst>(&*LLVMIt++); |
| |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(&LLVMF); |
| auto *Ptr = F->getArg(0); |
| auto *Arg = F->getArg(1); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| auto *RMW = cast<sandboxir::AtomicRMWInst>(&*It++); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| // Check getOperationName(). |
| EXPECT_EQ( |
| sandboxir::AtomicRMWInst::getOperationName( |
| sandboxir::AtomicRMWInst::BinOp::Add), |
| llvm::AtomicRMWInst::getOperationName(llvm::AtomicRMWInst::BinOp::Add)); |
| // Check isFPOperation(). |
| EXPECT_EQ( |
| sandboxir::AtomicRMWInst::isFPOperation( |
| sandboxir::AtomicRMWInst::BinOp::Add), |
| llvm::AtomicRMWInst::isFPOperation(llvm::AtomicRMWInst::BinOp::Add)); |
| EXPECT_FALSE(sandboxir::AtomicRMWInst::isFPOperation( |
| sandboxir::AtomicRMWInst::BinOp::Add)); |
| EXPECT_TRUE(sandboxir::AtomicRMWInst::isFPOperation( |
| sandboxir::AtomicRMWInst::BinOp::FAdd)); |
| // Check setOperation(), getOperation(). |
| EXPECT_EQ(RMW->getOperation(), LLVMRMW->getOperation()); |
| RMW->setOperation(sandboxir::AtomicRMWInst::BinOp::Sub); |
| EXPECT_EQ(RMW->getOperation(), sandboxir::AtomicRMWInst::BinOp::Sub); |
| RMW->setOperation(sandboxir::AtomicRMWInst::BinOp::Add); |
| // Check getAlign(). |
| EXPECT_EQ(RMW->getAlign(), LLVMRMW->getAlign()); |
| auto OrigAlign = RMW->getAlign(); |
| Align NewAlign(256); |
| EXPECT_NE(NewAlign, OrigAlign); |
| RMW->setAlignment(NewAlign); |
| EXPECT_EQ(RMW->getAlign(), NewAlign); |
| RMW->setAlignment(OrigAlign); |
| EXPECT_EQ(RMW->getAlign(), OrigAlign); |
| // Check isVolatile(), setVolatile(). |
| EXPECT_EQ(RMW->isVolatile(), LLVMRMW->isVolatile()); |
| bool OrigV = RMW->isVolatile(); |
| bool NewV = true; |
| EXPECT_NE(NewV, OrigV); |
| RMW->setVolatile(NewV); |
| EXPECT_EQ(RMW->isVolatile(), NewV); |
| RMW->setVolatile(OrigV); |
| EXPECT_EQ(RMW->isVolatile(), OrigV); |
| // Check getOrdering(), setOrdering(). |
| EXPECT_EQ(RMW->getOrdering(), LLVMRMW->getOrdering()); |
| auto OldOrdering = RMW->getOrdering(); |
| auto NewOrdering = AtomicOrdering::Monotonic; |
| EXPECT_NE(NewOrdering, OldOrdering); |
| RMW->setOrdering(NewOrdering); |
| EXPECT_EQ(RMW->getOrdering(), NewOrdering); |
| RMW->setOrdering(OldOrdering); |
| EXPECT_EQ(RMW->getOrdering(), OldOrdering); |
| // Check getSyncScopeID(), setSyncScopeID(). |
| EXPECT_EQ(RMW->getSyncScopeID(), LLVMRMW->getSyncScopeID()); |
| auto OrigSSID = RMW->getSyncScopeID(); |
| SyncScope::ID NewSSID = SyncScope::SingleThread; |
| EXPECT_NE(NewSSID, OrigSSID); |
| RMW->setSyncScopeID(NewSSID); |
| EXPECT_EQ(RMW->getSyncScopeID(), NewSSID); |
| RMW->setSyncScopeID(OrigSSID); |
| EXPECT_EQ(RMW->getSyncScopeID(), OrigSSID); |
| // Check getPointerOperand(). |
| EXPECT_EQ(RMW->getPointerOperand(), |
| Ctx.getValue(LLVMRMW->getPointerOperand())); |
| // Check getValOperand(). |
| EXPECT_EQ(RMW->getValOperand(), Ctx.getValue(LLVMRMW->getValOperand())); |
| // Check getPointerAddressSpace(). |
| EXPECT_EQ(RMW->getPointerAddressSpace(), LLVMRMW->getPointerAddressSpace()); |
| // Check isFloatingPointOperation(). |
| EXPECT_EQ(RMW->isFloatingPointOperation(), |
| LLVMRMW->isFloatingPointOperation()); |
| |
| Align Align(1024); |
| auto Ordering = AtomicOrdering::Acquire; |
| auto SSID = SyncScope::System; |
| { |
| // Check create() WhereIt, WhereBB. |
| auto *NewI = |
| cast<sandboxir::AtomicRMWInst>(sandboxir::AtomicRMWInst::create( |
| sandboxir::AtomicRMWInst::BinOp::Sub, Ptr, Arg, Align, Ordering, |
| Ret->getIterator(), Ctx, SSID, "NewAtomicRMW1")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::AtomicRMW); |
| // Check getAlign(). |
| EXPECT_EQ(NewI->getAlign(), Align); |
| // Check getSuccessOrdering(). |
| EXPECT_EQ(NewI->getOrdering(), Ordering); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| // Check getPointerOperand(). |
| EXPECT_EQ(NewI->getPointerOperand(), Ptr); |
| // Check getValOperand(). |
| EXPECT_EQ(NewI->getValOperand(), Arg); |
| #ifndef NDEBUG |
| // Check getName(). |
| EXPECT_EQ(NewI->getName(), "NewAtomicRMW1"); |
| #endif // NDEBUG |
| } |
| { |
| // Check create() InsertBefore. |
| auto *NewI = |
| cast<sandboxir::AtomicRMWInst>(sandboxir::AtomicRMWInst::create( |
| sandboxir::AtomicRMWInst::BinOp::Sub, Ptr, Arg, Align, Ordering, |
| Ret->getIterator(), Ctx, SSID, "NewAtomicRMW2")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::AtomicRMW); |
| // Check getAlign(). |
| EXPECT_EQ(NewI->getAlign(), Align); |
| // Check getSuccessOrdering(). |
| EXPECT_EQ(NewI->getOrdering(), Ordering); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| // Check getPointerOperand(). |
| EXPECT_EQ(NewI->getPointerOperand(), Ptr); |
| // Check getValOperand(). |
| EXPECT_EQ(NewI->getValOperand(), Arg); |
| #ifndef NDEBUG |
| // Check getName(). |
| EXPECT_EQ(NewI->getName(), "NewAtomicRMW2"); |
| #endif // NDEBUG |
| } |
| { |
| // Check create() InsertAtEnd. |
| auto *NewI = |
| cast<sandboxir::AtomicRMWInst>(sandboxir::AtomicRMWInst::create( |
| sandboxir::AtomicRMWInst::BinOp::Sub, Ptr, Arg, Align, Ordering, BB, |
| Ctx, SSID, "NewAtomicRMW3")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::AtomicRMW); |
| // Check getAlign(). |
| EXPECT_EQ(NewI->getAlign(), Align); |
| // Check getSuccessOrdering(). |
| EXPECT_EQ(NewI->getOrdering(), Ordering); |
| // Check instr position. |
| EXPECT_EQ(NewI->getParent(), BB); |
| EXPECT_EQ(NewI->getNextNode(), nullptr); |
| // Check getPointerOperand(). |
| EXPECT_EQ(NewI->getPointerOperand(), Ptr); |
| // Check getValOperand(). |
| EXPECT_EQ(NewI->getValOperand(), Arg); |
| #ifndef NDEBUG |
| // Check getName(). |
| EXPECT_EQ(NewI->getName(), "NewAtomicRMW3"); |
| #endif // NDEBUG |
| } |
| } |
| |
| TEST_F(SandboxIRTest, AtomicCmpXchgInst) { |
| parseIR(C, R"IR( |
| define void @foo(ptr %ptr, i8 %cmp, i8 %new) { |
| %cmpxchg = cmpxchg ptr %ptr, i8 %cmp, i8 %new monotonic monotonic, align 128 |
| ret void |
| } |
| )IR"); |
| llvm::Function &LLVMF = *M->getFunction("foo"); |
| llvm::BasicBlock *LLVMBB = &*LLVMF.begin(); |
| auto LLVMIt = LLVMBB->begin(); |
| auto *LLVMCmpXchg = cast<llvm::AtomicCmpXchgInst>(&*LLVMIt++); |
| |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(&LLVMF); |
| auto *Ptr = F->getArg(0); |
| auto *Cmp = F->getArg(1); |
| auto *New = F->getArg(2); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| auto *CmpXchg = cast<sandboxir::AtomicCmpXchgInst>(&*It++); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| // Check getAlign(), setAlignment(). |
| EXPECT_EQ(CmpXchg->getAlign(), LLVMCmpXchg->getAlign()); |
| auto OrigAlign = CmpXchg->getAlign(); |
| Align NewAlign(256); |
| EXPECT_NE(NewAlign, OrigAlign); |
| CmpXchg->setAlignment(NewAlign); |
| EXPECT_EQ(CmpXchg->getAlign(), NewAlign); |
| CmpXchg->setAlignment(OrigAlign); |
| EXPECT_EQ(CmpXchg->getAlign(), OrigAlign); |
| // Check isVolatile(), setVolatile(). |
| EXPECT_EQ(CmpXchg->isVolatile(), LLVMCmpXchg->isVolatile()); |
| bool OrigV = CmpXchg->isVolatile(); |
| bool NewV = true; |
| EXPECT_NE(NewV, OrigV); |
| CmpXchg->setVolatile(NewV); |
| EXPECT_EQ(CmpXchg->isVolatile(), NewV); |
| CmpXchg->setVolatile(OrigV); |
| EXPECT_EQ(CmpXchg->isVolatile(), OrigV); |
| // Check isWeak(), setWeak(). |
| EXPECT_EQ(CmpXchg->isWeak(), LLVMCmpXchg->isWeak()); |
| bool OrigWeak = CmpXchg->isWeak(); |
| bool NewWeak = true; |
| EXPECT_NE(NewWeak, OrigWeak); |
| CmpXchg->setWeak(NewWeak); |
| EXPECT_EQ(CmpXchg->isWeak(), NewWeak); |
| CmpXchg->setWeak(OrigWeak); |
| EXPECT_EQ(CmpXchg->isWeak(), OrigWeak); |
| // Check isValidSuccessOrdering(), isValidFailureOrdering(). |
| SmallVector<AtomicOrdering> AllOrderings( |
| {AtomicOrdering::NotAtomic, AtomicOrdering::Unordered, |
| AtomicOrdering::Monotonic, AtomicOrdering::Acquire, |
| AtomicOrdering::Release, AtomicOrdering::AcquireRelease, |
| AtomicOrdering::SequentiallyConsistent}); |
| for (auto Ordering : AllOrderings) { |
| EXPECT_EQ(sandboxir::AtomicCmpXchgInst::isValidSuccessOrdering(Ordering), |
| llvm::AtomicCmpXchgInst::isValidSuccessOrdering(Ordering)); |
| EXPECT_EQ(sandboxir::AtomicCmpXchgInst::isValidFailureOrdering(Ordering), |
| llvm::AtomicCmpXchgInst::isValidFailureOrdering(Ordering)); |
| } |
| // Check getSuccessOrdering(), setSuccessOrdering(). |
| EXPECT_EQ(CmpXchg->getSuccessOrdering(), LLVMCmpXchg->getSuccessOrdering()); |
| auto OldSuccOrdering = CmpXchg->getSuccessOrdering(); |
| auto NewSuccOrdering = AtomicOrdering::Acquire; |
| EXPECT_NE(NewSuccOrdering, OldSuccOrdering); |
| CmpXchg->setSuccessOrdering(NewSuccOrdering); |
| EXPECT_EQ(CmpXchg->getSuccessOrdering(), NewSuccOrdering); |
| CmpXchg->setSuccessOrdering(OldSuccOrdering); |
| EXPECT_EQ(CmpXchg->getSuccessOrdering(), OldSuccOrdering); |
| // Check getFailureOrdering(), setFailureOrdering(). |
| EXPECT_EQ(CmpXchg->getFailureOrdering(), LLVMCmpXchg->getFailureOrdering()); |
| auto OldFailOrdering = CmpXchg->getFailureOrdering(); |
| auto NewFailOrdering = AtomicOrdering::Acquire; |
| EXPECT_NE(NewFailOrdering, OldFailOrdering); |
| CmpXchg->setFailureOrdering(NewFailOrdering); |
| EXPECT_EQ(CmpXchg->getFailureOrdering(), NewFailOrdering); |
| CmpXchg->setFailureOrdering(OldFailOrdering); |
| EXPECT_EQ(CmpXchg->getFailureOrdering(), OldFailOrdering); |
| // Check getMergedOrdering(). |
| EXPECT_EQ(CmpXchg->getMergedOrdering(), LLVMCmpXchg->getMergedOrdering()); |
| // Check getSyncScopeID(), setSyncScopeID(). |
| EXPECT_EQ(CmpXchg->getSyncScopeID(), LLVMCmpXchg->getSyncScopeID()); |
| auto OrigSSID = CmpXchg->getSyncScopeID(); |
| SyncScope::ID NewSSID = SyncScope::SingleThread; |
| EXPECT_NE(NewSSID, OrigSSID); |
| CmpXchg->setSyncScopeID(NewSSID); |
| EXPECT_EQ(CmpXchg->getSyncScopeID(), NewSSID); |
| CmpXchg->setSyncScopeID(OrigSSID); |
| EXPECT_EQ(CmpXchg->getSyncScopeID(), OrigSSID); |
| // Check getPointerOperand(). |
| EXPECT_EQ(CmpXchg->getPointerOperand(), |
| Ctx.getValue(LLVMCmpXchg->getPointerOperand())); |
| // Check getCompareOperand(). |
| EXPECT_EQ(CmpXchg->getCompareOperand(), |
| Ctx.getValue(LLVMCmpXchg->getCompareOperand())); |
| // Check getNewValOperand(). |
| EXPECT_EQ(CmpXchg->getNewValOperand(), |
| Ctx.getValue(LLVMCmpXchg->getNewValOperand())); |
| // Check getPointerAddressSpace(). |
| EXPECT_EQ(CmpXchg->getPointerAddressSpace(), |
| LLVMCmpXchg->getPointerAddressSpace()); |
| |
| Align Align(1024); |
| auto SuccOrdering = AtomicOrdering::Acquire; |
| auto FailOrdering = AtomicOrdering::Monotonic; |
| auto SSID = SyncScope::System; |
| { |
| // Check create() WhereIt, WhereBB. |
| auto *NewI = |
| cast<sandboxir::AtomicCmpXchgInst>(sandboxir::AtomicCmpXchgInst::create( |
| Ptr, Cmp, New, Align, SuccOrdering, FailOrdering, |
| Ret->getIterator(), Ctx, SSID, "NewAtomicCmpXchg1")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::AtomicCmpXchg); |
| // Check getAlign(). |
| EXPECT_EQ(NewI->getAlign(), Align); |
| // Check getSuccessOrdering(). |
| EXPECT_EQ(NewI->getSuccessOrdering(), SuccOrdering); |
| // Check getFailureOrdering(). |
| EXPECT_EQ(NewI->getFailureOrdering(), FailOrdering); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| // Check getPointerOperand(). |
| EXPECT_EQ(NewI->getPointerOperand(), Ptr); |
| // Check getCompareOperand(). |
| EXPECT_EQ(NewI->getCompareOperand(), Cmp); |
| // Check getNewValOperand(). |
| EXPECT_EQ(NewI->getNewValOperand(), New); |
| #ifndef NDEBUG |
| // Check getName(). |
| EXPECT_EQ(NewI->getName(), "NewAtomicCmpXchg1"); |
| #endif // NDEBUG |
| } |
| { |
| // Check create() InsertBefore. |
| auto *NewI = |
| cast<sandboxir::AtomicCmpXchgInst>(sandboxir::AtomicCmpXchgInst::create( |
| Ptr, Cmp, New, Align, SuccOrdering, FailOrdering, |
| Ret->getIterator(), Ctx, SSID, "NewAtomicCmpXchg2")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::AtomicCmpXchg); |
| // Check getAlign(). |
| EXPECT_EQ(NewI->getAlign(), Align); |
| // Check getSuccessOrdering(). |
| EXPECT_EQ(NewI->getSuccessOrdering(), SuccOrdering); |
| // Check getFailureOrdering(). |
| EXPECT_EQ(NewI->getFailureOrdering(), FailOrdering); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| // Check getPointerOperand(). |
| EXPECT_EQ(NewI->getPointerOperand(), Ptr); |
| // Check getCompareOperand(). |
| EXPECT_EQ(NewI->getCompareOperand(), Cmp); |
| // Check getNewValOperand(). |
| EXPECT_EQ(NewI->getNewValOperand(), New); |
| #ifndef NDEBUG |
| // Check getName(). |
| EXPECT_EQ(NewI->getName(), "NewAtomicCmpXchg2"); |
| #endif // NDEBUG |
| } |
| { |
| // Check create() InsertAtEnd. |
| auto *NewI = |
| cast<sandboxir::AtomicCmpXchgInst>(sandboxir::AtomicCmpXchgInst::create( |
| Ptr, Cmp, New, Align, SuccOrdering, FailOrdering, BB, Ctx, SSID, |
| "NewAtomicCmpXchg3")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::AtomicCmpXchg); |
| // Check getAlign(). |
| EXPECT_EQ(NewI->getAlign(), Align); |
| // Check getSuccessOrdering(). |
| EXPECT_EQ(NewI->getSuccessOrdering(), SuccOrdering); |
| // Check getFailureOrdering(). |
| EXPECT_EQ(NewI->getFailureOrdering(), FailOrdering); |
| // Check instr position. |
| EXPECT_EQ(NewI->getParent(), BB); |
| EXPECT_EQ(NewI->getNextNode(), nullptr); |
| // Check getPointerOperand(). |
| EXPECT_EQ(NewI->getPointerOperand(), Ptr); |
| // Check getCompareOperand(). |
| EXPECT_EQ(NewI->getCompareOperand(), Cmp); |
| // Check getNewValOperand(). |
| EXPECT_EQ(NewI->getNewValOperand(), New); |
| #ifndef NDEBUG |
| // Check getName(). |
| EXPECT_EQ(NewI->getName(), "NewAtomicCmpXchg3"); |
| #endif // NDEBUG |
| } |
| } |
| |
| TEST_F(SandboxIRTest, AllocaInst) { |
| parseIR(C, R"IR( |
| define void @foo() { |
| %allocaScalar = alloca i32, align 1024 |
| %allocaArray = alloca i32, i32 42 |
| ret void |
| } |
| )IR"); |
| const DataLayout &DL = M->getDataLayout(); |
| llvm::Function &LLVMF = *M->getFunction("foo"); |
| llvm::BasicBlock *LLVMBB = &*LLVMF.begin(); |
| auto LLVMIt = LLVMBB->begin(); |
| auto *LLVMAllocaScalar = cast<llvm::AllocaInst>(&*LLVMIt++); |
| auto *LLVMAllocaArray = cast<llvm::AllocaInst>(&*LLVMIt++); |
| |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(&LLVMF); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| auto *AllocaScalar = cast<sandboxir::AllocaInst>(&*It++); |
| auto *AllocaArray = cast<sandboxir::AllocaInst>(&*It++); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| // Check isArrayAllocation(). |
| EXPECT_EQ(AllocaScalar->isArrayAllocation(), |
| LLVMAllocaScalar->isArrayAllocation()); |
| EXPECT_EQ(AllocaArray->isArrayAllocation(), |
| LLVMAllocaArray->isArrayAllocation()); |
| // Check getArraySize(). |
| EXPECT_EQ(AllocaScalar->getArraySize(), |
| Ctx.getValue(LLVMAllocaScalar->getArraySize())); |
| EXPECT_EQ(AllocaArray->getArraySize(), |
| Ctx.getValue(LLVMAllocaArray->getArraySize())); |
| // Check getType(). |
| EXPECT_EQ(AllocaScalar->getType(), Ctx.getType(LLVMAllocaScalar->getType())); |
| EXPECT_EQ(AllocaArray->getType(), Ctx.getType(LLVMAllocaArray->getType())); |
| // Check getAddressSpace(). |
| EXPECT_EQ(AllocaScalar->getAddressSpace(), |
| LLVMAllocaScalar->getAddressSpace()); |
| EXPECT_EQ(AllocaArray->getAddressSpace(), LLVMAllocaArray->getAddressSpace()); |
| // Check getAllocationSize(). |
| EXPECT_EQ(AllocaScalar->getAllocationSize(DL), |
| LLVMAllocaScalar->getAllocationSize(DL)); |
| EXPECT_EQ(AllocaArray->getAllocationSize(DL), |
| LLVMAllocaArray->getAllocationSize(DL)); |
| // Check getAllocationSizeInBits(). |
| EXPECT_EQ(AllocaScalar->getAllocationSizeInBits(DL), |
| LLVMAllocaScalar->getAllocationSizeInBits(DL)); |
| EXPECT_EQ(AllocaArray->getAllocationSizeInBits(DL), |
| LLVMAllocaArray->getAllocationSizeInBits(DL)); |
| // Check getAllocatedType(). |
| EXPECT_EQ(AllocaScalar->getAllocatedType(), |
| Ctx.getType(LLVMAllocaScalar->getAllocatedType())); |
| EXPECT_EQ(AllocaArray->getAllocatedType(), |
| Ctx.getType(LLVMAllocaArray->getAllocatedType())); |
| // Check setAllocatedType(). |
| auto *OrigType = AllocaScalar->getAllocatedType(); |
| auto *NewType = sandboxir::PointerType::get(Ctx, 0); |
| EXPECT_NE(NewType, OrigType); |
| AllocaScalar->setAllocatedType(NewType); |
| EXPECT_EQ(AllocaScalar->getAllocatedType(), NewType); |
| AllocaScalar->setAllocatedType(OrigType); |
| EXPECT_EQ(AllocaScalar->getAllocatedType(), OrigType); |
| // Check getAlign(). |
| EXPECT_EQ(AllocaScalar->getAlign(), LLVMAllocaScalar->getAlign()); |
| EXPECT_EQ(AllocaArray->getAlign(), LLVMAllocaArray->getAlign()); |
| // Check setAlignment(). |
| Align OrigAlign = AllocaScalar->getAlign(); |
| Align NewAlign(16); |
| EXPECT_NE(NewAlign, OrigAlign); |
| AllocaScalar->setAlignment(NewAlign); |
| EXPECT_EQ(AllocaScalar->getAlign(), NewAlign); |
| AllocaScalar->setAlignment(OrigAlign); |
| EXPECT_EQ(AllocaScalar->getAlign(), OrigAlign); |
| // Check isStaticAlloca(). |
| EXPECT_EQ(AllocaScalar->isStaticAlloca(), LLVMAllocaScalar->isStaticAlloca()); |
| EXPECT_EQ(AllocaArray->isStaticAlloca(), LLVMAllocaArray->isStaticAlloca()); |
| // Check isUsedWithInAlloca(), setUsedWithInAlloca(). |
| EXPECT_EQ(AllocaScalar->isUsedWithInAlloca(), |
| LLVMAllocaScalar->isUsedWithInAlloca()); |
| bool OrigUsedWithInAlloca = AllocaScalar->isUsedWithInAlloca(); |
| bool NewUsedWithInAlloca = true; |
| EXPECT_NE(NewUsedWithInAlloca, OrigUsedWithInAlloca); |
| AllocaScalar->setUsedWithInAlloca(NewUsedWithInAlloca); |
| EXPECT_EQ(AllocaScalar->isUsedWithInAlloca(), NewUsedWithInAlloca); |
| AllocaScalar->setUsedWithInAlloca(OrigUsedWithInAlloca); |
| EXPECT_EQ(AllocaScalar->isUsedWithInAlloca(), OrigUsedWithInAlloca); |
| |
| auto *Ty = sandboxir::Type::getInt32Ty(Ctx); |
| unsigned AddrSpace = 42; |
| auto *PtrTy = sandboxir::PointerType::get(Ctx, AddrSpace); |
| auto *ArraySize = sandboxir::ConstantInt::get(Ty, 43); |
| { |
| // Check create() WhereIt, WhereBB. |
| auto *NewI = cast<sandboxir::AllocaInst>(sandboxir::AllocaInst::create( |
| Ty, AddrSpace, Ret->getIterator(), Ctx, ArraySize, "NewAlloca1")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::Alloca); |
| // Check getType(). |
| EXPECT_EQ(NewI->getType(), PtrTy); |
| // Check getArraySize(). |
| EXPECT_EQ(NewI->getArraySize(), ArraySize); |
| // Check getAddrSpace(). |
| EXPECT_EQ(NewI->getAddressSpace(), AddrSpace); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| } |
| { |
| // Check create() InsertBefore. |
| auto *NewI = cast<sandboxir::AllocaInst>(sandboxir::AllocaInst::create( |
| Ty, AddrSpace, Ret->getIterator(), Ctx, ArraySize, "NewAlloca2")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::Alloca); |
| // Check getType(). |
| EXPECT_EQ(NewI->getType(), PtrTy); |
| // Check getArraySize(). |
| EXPECT_EQ(NewI->getArraySize(), ArraySize); |
| // Check getAddrSpace(). |
| EXPECT_EQ(NewI->getAddressSpace(), AddrSpace); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| } |
| { |
| // Check create() InsertAtEnd. |
| auto *NewI = cast<sandboxir::AllocaInst>(sandboxir::AllocaInst::create( |
| Ty, AddrSpace, BB, Ctx, ArraySize, "NewAlloca3")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), sandboxir::Instruction::Opcode::Alloca); |
| // Check getType(). |
| EXPECT_EQ(NewI->getType(), PtrTy); |
| // Check getArraySize(). |
| EXPECT_EQ(NewI->getArraySize(), ArraySize); |
| // Check getAddrSpace(). |
| EXPECT_EQ(NewI->getAddressSpace(), AddrSpace); |
| // Check instr position. |
| EXPECT_EQ(NewI->getParent(), BB); |
| EXPECT_EQ(NewI->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(); |
| |
| auto *Ti64 = sandboxir::Type::getInt64Ty(Ctx); |
| auto *Ti32 = sandboxir::Type::getInt32Ty(Ctx); |
| auto *Ti16 = sandboxir::Type::getInt16Ty(Ctx); |
| auto *Tdouble = sandboxir::Type::getDoubleTy(Ctx); |
| auto *Tfloat = sandboxir::Type::getFloatTy(Ctx); |
| auto *Tptr = sandboxir::PointerType::get(Ctx, 0); |
| auto *Tptr1 = sandboxir::PointerType::get(Ctx, 1); |
| |
| // Check classof(), getOpcode(), getSrcTy(), getDstTy() |
| auto *ZExt = cast<sandboxir::CastInst>(&*It++); |
| auto *ZExtI = cast<sandboxir::ZExtInst>(ZExt); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(ZExtI)); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(ZExtI)); |
| EXPECT_EQ(ZExt->getOpcode(), sandboxir::Instruction::Opcode::ZExt); |
| EXPECT_EQ(ZExt->getSrcTy(), Ti32); |
| EXPECT_EQ(ZExt->getDestTy(), Ti64); |
| |
| auto *SExt = cast<sandboxir::CastInst>(&*It++); |
| auto *SExtI = cast<sandboxir::SExtInst>(SExt); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(SExt)); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(SExtI)); |
| EXPECT_EQ(SExt->getOpcode(), sandboxir::Instruction::Opcode::SExt); |
| EXPECT_EQ(SExt->getSrcTy(), Ti32); |
| EXPECT_EQ(SExt->getDestTy(), Ti64); |
| |
| auto *FPToUI = cast<sandboxir::CastInst>(&*It++); |
| auto *FPToUII = cast<sandboxir::FPToUIInst>(FPToUI); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(FPToUI)); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(FPToUII)); |
| EXPECT_EQ(FPToUI->getOpcode(), sandboxir::Instruction::Opcode::FPToUI); |
| EXPECT_EQ(FPToUI->getSrcTy(), Tfloat); |
| EXPECT_EQ(FPToUI->getDestTy(), Ti32); |
| |
| auto *FPToSI = cast<sandboxir::CastInst>(&*It++); |
| auto *FPToSII = cast<sandboxir::FPToSIInst>(FPToSI); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(FPToSI)); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(FPToSII)); |
| EXPECT_EQ(FPToSI->getOpcode(), sandboxir::Instruction::Opcode::FPToSI); |
| EXPECT_EQ(FPToSI->getSrcTy(), Tfloat); |
| EXPECT_EQ(FPToSI->getDestTy(), Ti32); |
| |
| auto *FPExt = cast<sandboxir::CastInst>(&*It++); |
| auto *FPExtI = cast<sandboxir::FPExtInst>(FPExt); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(FPExt)); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(FPExtI)); |
| EXPECT_EQ(FPExt->getOpcode(), sandboxir::Instruction::Opcode::FPExt); |
| EXPECT_EQ(FPExt->getSrcTy(), Tfloat); |
| EXPECT_EQ(FPExt->getDestTy(), Tdouble); |
| |
| auto *PtrToInt = cast<sandboxir::CastInst>(&*It++); |
| auto *PtrToIntI = cast<sandboxir::PtrToIntInst>(PtrToInt); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(PtrToInt)); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(PtrToIntI)); |
| EXPECT_EQ(PtrToInt->getOpcode(), sandboxir::Instruction::Opcode::PtrToInt); |
| EXPECT_EQ(PtrToInt->getSrcTy(), Tptr); |
| EXPECT_EQ(PtrToInt->getDestTy(), Ti32); |
| |
| auto *IntToPtr = cast<sandboxir::CastInst>(&*It++); |
| auto *IntToPtrI = cast<sandboxir::IntToPtrInst>(IntToPtr); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(IntToPtr)); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(IntToPtrI)); |
| EXPECT_EQ(IntToPtr->getOpcode(), sandboxir::Instruction::Opcode::IntToPtr); |
| EXPECT_EQ(IntToPtr->getSrcTy(), Ti32); |
| EXPECT_EQ(IntToPtr->getDestTy(), Tptr); |
| |
| auto *SIToFP = cast<sandboxir::CastInst>(&*It++); |
| auto *SIToFPI = cast<sandboxir::SIToFPInst>(SIToFP); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(SIToFP)); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(SIToFPI)); |
| EXPECT_EQ(SIToFP->getOpcode(), sandboxir::Instruction::Opcode::SIToFP); |
| EXPECT_EQ(SIToFP->getSrcTy(), Ti32); |
| EXPECT_EQ(SIToFP->getDestTy(), Tfloat); |
| |
| auto *UIToFP = cast<sandboxir::CastInst>(&*It++); |
| auto *UIToFPI = cast<sandboxir::UIToFPInst>(UIToFP); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(UIToFP)); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(UIToFPI)); |
| EXPECT_EQ(UIToFP->getOpcode(), sandboxir::Instruction::Opcode::UIToFP); |
| EXPECT_EQ(UIToFP->getSrcTy(), Ti32); |
| EXPECT_EQ(UIToFP->getDestTy(), Tfloat); |
| |
| auto *Trunc = cast<sandboxir::CastInst>(&*It++); |
| auto *TruncI = cast<sandboxir::TruncInst>(Trunc); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(Trunc)); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(TruncI)); |
| EXPECT_EQ(Trunc->getOpcode(), sandboxir::Instruction::Opcode::Trunc); |
| EXPECT_EQ(Trunc->getSrcTy(), Ti32); |
| EXPECT_EQ(Trunc->getDestTy(), Ti16); |
| |
| auto *FPTrunc = cast<sandboxir::CastInst>(&*It++); |
| auto *FPTruncI = cast<sandboxir::FPTruncInst>(FPTrunc); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(FPTrunc)); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(FPTruncI)); |
| EXPECT_EQ(FPTrunc->getOpcode(), sandboxir::Instruction::Opcode::FPTrunc); |
| EXPECT_EQ(FPTrunc->getSrcTy(), Tdouble); |
| EXPECT_EQ(FPTrunc->getDestTy(), Tfloat); |
| |
| auto *BitCast = cast<sandboxir::CastInst>(&*It++); |
| auto *BitCastI = cast<sandboxir::BitCastInst>(BitCast); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(BitCast)); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(BitCastI)); |
| EXPECT_EQ(BitCast->getOpcode(), sandboxir::Instruction::Opcode::BitCast); |
| EXPECT_EQ(BitCast->getSrcTy(), Ti32); |
| EXPECT_EQ(BitCast->getDestTy(), Tfloat); |
| |
| auto *AddrSpaceCast = cast<sandboxir::CastInst>(&*It++); |
| auto *AddrSpaceCastI = cast<sandboxir::AddrSpaceCastInst>(AddrSpaceCast); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(AddrSpaceCast)); |
| EXPECT_TRUE(isa<sandboxir::UnaryInstruction>(AddrSpaceCastI)); |
| 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, BB->end(), 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, Ret->getIterator(), 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, 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, Ret->getIterator(), Ctx, "Bad"), |
| ".*Opcode.*"); |
| #endif // NDEBUG |
| } |
| } |
| |
| TEST_F(SandboxIRTest, PossiblyNonNegInst) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %arg, float %farg, double %darg, ptr %ptr) { |
| %zext = zext i32 %arg to i64 |
| %uitofp = uitofp i32 %arg to float |
| |
| %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 |
| %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); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| auto *PNNI0 = cast<sandboxir::PossiblyNonNegInst>(&*It++); |
| auto *PNNI1 = cast<sandboxir::PossiblyNonNegInst>(&*It++); |
| for (auto ItE = BB->end(); It != ItE; ++It) |
| EXPECT_FALSE(isa<sandboxir::PossiblyNonNegInst>(&*It++)); |
| |
| for (auto *PNNI : {PNNI0, PNNI1}) { |
| // Check setNonNeg(), hasNonNeg(). |
| auto OrigNonNeg = PNNI->hasNonNeg(); |
| auto NewNonNeg = true; |
| EXPECT_NE(NewNonNeg, OrigNonNeg); |
| PNNI->setNonNeg(NewNonNeg); |
| EXPECT_EQ(PNNI->hasNonNeg(), NewNonNeg); |
| PNNI->setNonNeg(OrigNonNeg); |
| EXPECT_EQ(PNNI->hasNonNeg(), OrigNonNeg); |
| } |
| } |
| |
| /// CastInst's subclasses are very similar so we can use a common test function |
| /// for them. |
| template <typename SubclassT, sandboxir::Instruction::Opcode OpcodeT> |
| void testCastInst(llvm::Module &M, llvm::Type *LLVMSrcTy, |
| llvm::Type *LLVMDstTy) { |
| Function &LLVMF = *M.getFunction("foo"); |
| sandboxir::Context Ctx(M.getContext()); |
| sandboxir::Function *F = Ctx.createFunction(&LLVMF); |
| sandboxir::Type *SrcTy = Ctx.getType(LLVMSrcTy); |
| sandboxir::Type *DstTy = Ctx.getType(LLVMDstTy); |
| unsigned ArgIdx = 0; |
| auto *Arg = F->getArg(ArgIdx++); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| |
| auto *CI = cast<SubclassT>(&*It++); |
| EXPECT_EQ(CI->getOpcode(), OpcodeT); |
| EXPECT_EQ(CI->getSrcTy(), SrcTy); |
| EXPECT_EQ(CI->getDestTy(), DstTy); |
| auto *Ret = cast<sandboxir::ReturnInst>(&*It++); |
| |
| { |
| // Check create() WhereIt, WhereBB |
| auto *NewI = |
| cast<SubclassT>(SubclassT::create(Arg, DstTy, BB->end(), Ctx, "NewCI")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), OpcodeT); |
| // Check getSrcTy(). |
| EXPECT_EQ(NewI->getSrcTy(), Arg->getType()); |
| // Check getDestTy(). |
| EXPECT_EQ(NewI->getDestTy(), DstTy); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), nullptr); |
| EXPECT_EQ(NewI->getPrevNode(), Ret); |
| // Check instr name. |
| EXPECT_EQ(NewI->getName(), "NewCI"); |
| } |
| { |
| // Check create() InsertBefore. |
| auto *NewI = cast<SubclassT>( |
| SubclassT::create(Arg, DstTy, Ret->getIterator(), Ctx, "NewCI")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), OpcodeT); |
| // Check getSrcTy(). |
| EXPECT_EQ(NewI->getSrcTy(), Arg->getType()); |
| // Check getDestTy(). |
| EXPECT_EQ(NewI->getDestTy(), DstTy); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), Ret); |
| } |
| { |
| // Check create() InsertAtEnd. |
| auto *NewI = |
| cast<SubclassT>(SubclassT::create(Arg, DstTy, |
| /*InsertAtEnd=*/BB, Ctx, "NewCI")); |
| // Check getOpcode(). |
| EXPECT_EQ(NewI->getOpcode(), OpcodeT); |
| // Check getSrcTy(). |
| EXPECT_EQ(NewI->getSrcTy(), Arg->getType()); |
| // Check getDestTy(). |
| EXPECT_EQ(NewI->getDestTy(), DstTy); |
| // Check instr position. |
| EXPECT_EQ(NewI->getNextNode(), nullptr); |
| EXPECT_EQ(NewI->getParent(), BB); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, TruncInst) { |
| parseIR(C, R"IR( |
| define void @foo(i64 %arg) { |
| %trunc = trunc i64 %arg to i32 |
| ret void |
| } |
| )IR"); |
| testCastInst<sandboxir::TruncInst, sandboxir::Instruction::Opcode::Trunc>( |
| *M, |
| /*SrcTy=*/Type::getInt64Ty(C), /*DstTy=*/Type::getInt32Ty(C)); |
| } |
| |
| TEST_F(SandboxIRTest, ZExtInst) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %arg) { |
| %zext = zext i32 %arg to i64 |
| ret void |
| } |
| )IR"); |
| testCastInst<sandboxir::ZExtInst, sandboxir::Instruction::Opcode::ZExt>( |
| *M, |
| /*SrcTy=*/Type::getInt32Ty(C), /*DstTy=*/Type::getInt64Ty(C)); |
| } |
| |
| TEST_F(SandboxIRTest, SExtInst) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %arg) { |
| %sext = sext i32 %arg to i64 |
| ret void |
| } |
| )IR"); |
| testCastInst<sandboxir::SExtInst, sandboxir::Instruction::Opcode::SExt>( |
| *M, |
| /*SrcTy=*/Type::getInt32Ty(C), /*DstTy=*/Type::getInt64Ty(C)); |
| } |
| |
| TEST_F(SandboxIRTest, FPTruncInst) { |
| parseIR(C, R"IR( |
| define void @foo(double %arg) { |
| %fptrunc = fptrunc double %arg to float |
| ret void |
| } |
| )IR"); |
| testCastInst<sandboxir::FPTruncInst, sandboxir::Instruction::Opcode::FPTrunc>( |
| *M, |
| /*SrcTy=*/Type::getDoubleTy(C), /*DstTy=*/Type::getFloatTy(C)); |
| } |
| |
| TEST_F(SandboxIRTest, FPExtInst) { |
| parseIR(C, R"IR( |
| define void @foo(float %arg) { |
| %fpext = fpext float %arg to double |
| ret void |
| } |
| )IR"); |
| testCastInst<sandboxir::FPExtInst, sandboxir::Instruction::Opcode::FPExt>( |
| *M, |
| /*SrcTy=*/Type::getFloatTy(C), /*DstTy=*/Type::getDoubleTy(C)); |
| } |
| |
| TEST_F(SandboxIRTest, UIToFPInst) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %arg) { |
| %uitofp = uitofp i32 %arg to float |
| ret void |
| } |
| )IR"); |
| testCastInst<sandboxir::UIToFPInst, sandboxir::Instruction::Opcode::UIToFP>( |
| *M, |
| /*SrcTy=*/Type::getInt32Ty(C), /*DstTy=*/Type::getFloatTy(C)); |
| } |
| |
| TEST_F(SandboxIRTest, SIToFPInst) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %arg) { |
| %sitofp = sitofp i32 %arg to float |
| ret void |
| } |
| )IR"); |
| testCastInst<sandboxir::SIToFPInst, sandboxir::Instruction::Opcode::SIToFP>( |
| *M, |
| /*SrcTy=*/Type::getInt32Ty(C), |
| /*DstTy=*/Type::getFloatTy(C)); |
| } |
| |
| TEST_F(SandboxIRTest, FPToUIInst) { |
| parseIR(C, R"IR( |
| define void @foo(float %arg) { |
| %fptoui = fptoui float %arg to i32 |
| ret void |
| } |
| )IR"); |
| testCastInst<sandboxir::FPToUIInst, sandboxir::Instruction::Opcode::FPToUI>( |
| |
| *M, /*SrcTy=*/Type::getFloatTy(C), /*DstTy=*/Type::getInt32Ty(C)); |
| } |
| |
| TEST_F(SandboxIRTest, FPToSIInst) { |
| parseIR(C, R"IR( |
| define void @foo(float %arg) { |
| %fptosi = fptosi float %arg to i32 |
| ret void |
| } |
| )IR"); |
| testCastInst<sandboxir::FPToSIInst, sandboxir::Instruction::Opcode::FPToSI>( |
| *M, /*SrcTy=*/Type::getFloatTy(C), /*DstTy=*/Type::getInt32Ty(C)); |
| } |
| |
| TEST_F(SandboxIRTest, IntToPtrInst) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %arg) { |
| %inttoptr = inttoptr i32 %arg to ptr |
| ret void |
| } |
| )IR"); |
| testCastInst<sandboxir::IntToPtrInst, |
| sandboxir::Instruction::Opcode::IntToPtr>( |
| *M, |
| /*SrcTy=*/Type::getInt32Ty(C), /*DstTy=*/PointerType::get(C, 0)); |
| } |
| |
| TEST_F(SandboxIRTest, PtrToIntInst) { |
| parseIR(C, R"IR( |
| define void @foo(ptr %ptr) { |
| %ptrtoint = ptrtoint ptr %ptr to i32 |
| ret void |
| } |
| )IR"); |
| testCastInst<sandboxir::PtrToIntInst, |
| sandboxir::Instruction::Opcode::PtrToInt>( |
| *M, /*SrcTy=*/PointerType::get(C, 0), /*DstTy=*/Type::getInt32Ty(C)); |
| } |
| |
| TEST_F(SandboxIRTest, BitCastInst) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %arg) { |
| %bitcast = bitcast i32 %arg to float |
| ret void |
| } |
| )IR"); |
| testCastInst<sandboxir::BitCastInst, sandboxir::Instruction::Opcode::BitCast>( |
| *M, |
| /*SrcTy=*/Type::getInt32Ty(C), /*DstTy=*/Type::getFloatTy(C)); |
| } |
| |
| TEST_F(SandboxIRTest, AddrSpaceCastInst) { |
| parseIR(C, R"IR( |
| define void @foo(ptr %ptr) { |
| %addrspacecast = addrspacecast ptr %ptr to ptr addrspace(1) |
| ret void |
| } |
| )IR"); |
| Type *Tptr0 = PointerType::get(C, 0); |
| Type *Tptr1 = PointerType::get(C, 1); |
| testCastInst<sandboxir::AddrSpaceCastInst, |
| sandboxir::Instruction::Opcode::AddrSpaceCast>(*M, |
| /*SrcTy=*/Tptr0, |
| /*DstTy=*/Tptr1); |
| 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(); |
| |
| auto *AddrSpaceCast = cast<sandboxir::AddrSpaceCastInst>(&*It++); |
| EXPECT_EQ(AddrSpaceCast->getOpcode(), |
| sandboxir::Instruction::Opcode::AddrSpaceCast); |
| EXPECT_EQ(AddrSpaceCast->getPointerOperand(), Arg); |
| EXPECT_EQ(sandboxir::AddrSpaceCastInst::getPointerOperandIndex(), 0u); |
| EXPECT_EQ(AddrSpaceCast->getSrcAddressSpace(), |
| cast<PointerType>(Tptr0)->getPointerAddressSpace()); |
| EXPECT_EQ(AddrSpaceCast->getDestAddressSpace(), |
| cast<PointerType>(Tptr1)->getPointerAddressSpace()); |
| } |
| |
| TEST_F(SandboxIRTest, PHINode) { |
| parseIR(C, R"IR( |
| define void @foo(i32 %arg) { |
| bb1: |
| br label %bb2 |
| |
| bb2: |
| %phi = phi i32 [ %arg, %bb1 ], [ 0, %bb2 ], [ 1, %bb3 ], [ 2, %bb4 ], [ 3, %bb5 ] |
| br label %bb2 |
| |
| bb3: |
| br label %bb2 |
| |
| bb4: |
| br label %bb2 |
| |
| bb5: |
| br label %bb2 |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| auto *LLVMBB1 = getBasicBlockByName(LLVMF, "bb1"); |
| auto *LLVMBB2 = getBasicBlockByName(LLVMF, "bb2"); |
| auto *LLVMBB3 = getBasicBlockByName(LLVMF, "bb3"); |
| auto LLVMIt = LLVMBB2->begin(); |
| auto *LLVMPHI = cast<llvm::PHINode>(&*LLVMIt++); |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(&LLVMF); |
| auto *Arg = F->getArg(0); |
| auto *BB1 = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMBB1)); |
| auto *BB2 = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMBB2)); |
| auto *BB3 = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMBB3)); |
| auto It = BB2->begin(); |
| // Check classof(). |
| auto *PHI = cast<sandboxir::PHINode>(&*It++); |
| auto *Br = cast<sandboxir::BranchInst>(&*It++); |
| // Check blocks(). |
| EXPECT_EQ(range_size(PHI->blocks()), range_size(LLVMPHI->blocks())); |
| auto BlockIt = PHI->block_begin(); |
| for (llvm::BasicBlock *LLVMBB : LLVMPHI->blocks()) { |
| sandboxir::BasicBlock *BB = *BlockIt++; |
| EXPECT_EQ(BB, Ctx.getValue(LLVMBB)); |
| } |
| // Check incoming_values(). |
| EXPECT_EQ(range_size(PHI->incoming_values()), |
| range_size(LLVMPHI->incoming_values())); |
| auto IncIt = PHI->incoming_values().begin(); |
| for (llvm::Value *LLVMV : LLVMPHI->incoming_values()) { |
| sandboxir::Value *IncV = *IncIt++; |
| EXPECT_EQ(IncV, Ctx.getValue(LLVMV)); |
| } |
| // Check getNumIncomingValues(). |
| EXPECT_EQ(PHI->getNumIncomingValues(), LLVMPHI->getNumIncomingValues()); |
| // Check getIncomingValue(). |
| EXPECT_EQ(PHI->getIncomingValue(0), |
| Ctx.getValue(LLVMPHI->getIncomingValue(0))); |
| EXPECT_EQ(PHI->getIncomingValue(1), |
| Ctx.getValue(LLVMPHI->getIncomingValue(1))); |
| // Check setIncomingValue(). |
| auto *OrigV = PHI->getIncomingValue(0); |
| PHI->setIncomingValue(0, PHI); |
| EXPECT_EQ(PHI->getIncomingValue(0), PHI); |
| PHI->setIncomingValue(0, OrigV); |
| // Check getOperandNumForIncomingValue(). |
| EXPECT_EQ(sandboxir::PHINode::getOperandNumForIncomingValue(0), |
| llvm::PHINode::getOperandNumForIncomingValue(0)); |
| // Check getIncomingValueNumForOperand(). |
| EXPECT_EQ(sandboxir::PHINode::getIncomingValueNumForOperand(0), |
| llvm::PHINode::getIncomingValueNumForOperand(0)); |
| // Check getIncomingBlock(unsigned). |
| EXPECT_EQ(PHI->getIncomingBlock(0), |
| Ctx.getValue(LLVMPHI->getIncomingBlock(0))); |
| // Check getIncomingBlock(Use). |
| llvm::Use &LLVMUse = LLVMPHI->getOperandUse(0); |
| sandboxir::Use Use = PHI->getOperandUse(0); |
| EXPECT_EQ(PHI->getIncomingBlock(Use), |
| Ctx.getValue(LLVMPHI->getIncomingBlock(LLVMUse))); |
| // Check setIncomingBlock(). |
| sandboxir::BasicBlock *OrigBB = PHI->getIncomingBlock(0); |
| EXPECT_NE(OrigBB, BB2); |
| PHI->setIncomingBlock(0, BB2); |
| EXPECT_EQ(PHI->getIncomingBlock(0), BB2); |
| PHI->setIncomingBlock(0, OrigBB); |
| EXPECT_EQ(PHI->getIncomingBlock(0), OrigBB); |
| // Check addIncoming(). |
| unsigned OrigNumIncoming = PHI->getNumIncomingValues(); |
| PHI->addIncoming(Arg, BB3); |
| EXPECT_EQ(PHI->getNumIncomingValues(), LLVMPHI->getNumIncomingValues()); |
| EXPECT_EQ(PHI->getNumIncomingValues(), OrigNumIncoming + 1); |
| EXPECT_EQ(PHI->getIncomingValue(OrigNumIncoming), Arg); |
| EXPECT_EQ(PHI->getIncomingBlock(OrigNumIncoming), BB3); |
| // Check removeIncomingValue(unsigned). |
| PHI->removeIncomingValue(OrigNumIncoming); |
| EXPECT_EQ(PHI->getNumIncomingValues(), OrigNumIncoming); |
| // Check removeIncomingValue(BasicBlock *). |
| PHI->addIncoming(Arg, BB3); |
| PHI->removeIncomingValue(BB3); |
| EXPECT_EQ(PHI->getNumIncomingValues(), OrigNumIncoming); |
| // Check getBasicBlockIndex(). |
| EXPECT_EQ(PHI->getBasicBlockIndex(BB1), LLVMPHI->getBasicBlockIndex(LLVMBB1)); |
| // Check getIncomingValueForBlock(). |
| EXPECT_EQ(PHI->getIncomingValueForBlock(BB1), |
| Ctx.getValue(LLVMPHI->getIncomingValueForBlock(LLVMBB1))); |
| // Check hasConstantValue(). |
| llvm::Value *ConstV = LLVMPHI->hasConstantValue(); |
| EXPECT_EQ(PHI->hasConstantValue(), |
| ConstV != nullptr ? Ctx.getValue(ConstV) : nullptr); |
| // Check hasConstantOrUndefValue(). |
| EXPECT_EQ(PHI->hasConstantOrUndefValue(), LLVMPHI->hasConstantOrUndefValue()); |
| // Check isComplete(). |
| EXPECT_EQ(PHI->isComplete(), LLVMPHI->isComplete()); |
| // Check replaceIncomingValueIf |
| EXPECT_EQ(PHI->getNumIncomingValues(), 5u); |
| auto *RemainBB0 = PHI->getIncomingBlock(0); |
| auto *RemoveBB0 = PHI->getIncomingBlock(1); |
| auto *RemainBB1 = PHI->getIncomingBlock(2); |
| auto *RemoveBB1 = PHI->getIncomingBlock(3); |
| auto *RemainBB2 = PHI->getIncomingBlock(4); |
| PHI->removeIncomingValueIf([&](unsigned Idx) { |
| return PHI->getIncomingBlock(Idx) == RemoveBB0 || |
| PHI->getIncomingBlock(Idx) == RemoveBB1; |
| }); |
| EXPECT_EQ(PHI->getNumIncomingValues(), 3u); |
| EXPECT_EQ(PHI->getIncomingBlock(0), RemainBB0); |
| EXPECT_EQ(PHI->getIncomingBlock(1), RemainBB1); |
| EXPECT_EQ(PHI->getIncomingBlock(2), RemainBB2); |
| // Check replaceIncomingBlockWith |
| OrigBB = RemainBB0; |
| auto *NewBB = RemainBB1; |
| EXPECT_NE(NewBB, OrigBB); |
| PHI->replaceIncomingBlockWith(OrigBB, NewBB); |
| EXPECT_EQ(PHI->getIncomingBlock(0), NewBB); |
| EXPECT_EQ(PHI->getIncomingBlock(1), RemainBB1); |
| EXPECT_EQ(PHI->getIncomingBlock(2), RemainBB2); |
| // Check create(). |
| auto *NewPHI = cast<sandboxir::PHINode>(sandboxir::PHINode::create( |
| PHI->getType(), 0, Br->getIterator(), Ctx, "NewPHI")); |
| EXPECT_EQ(NewPHI->getType(), PHI->getType()); |
| EXPECT_EQ(NewPHI->getNextNode(), Br); |
| EXPECT_EQ(NewPHI->getName(), "NewPHI"); |
| EXPECT_EQ(NewPHI->getNumIncomingValues(), 0u); |
| for (auto [Idx, V] : enumerate(PHI->incoming_values())) { |
| sandboxir::BasicBlock *IncBB = PHI->getIncomingBlock(Idx); |
| NewPHI->addIncoming(V, IncBB); |
| } |
| EXPECT_EQ(NewPHI->getNumIncomingValues(), PHI->getNumIncomingValues()); |
| } |
| |
| static void checkSwapOperands(sandboxir::Context &Ctx, |
| llvm::sandboxir::CmpInst *Cmp, |
| llvm::CmpInst *LLVMCmp) { |
| auto OrigOp0 = Cmp->getOperand(0); |
| auto OrigOp1 = Cmp->getOperand(1); |
| EXPECT_EQ(Ctx.getValue(LLVMCmp->getOperand(0)), OrigOp0); |
| EXPECT_EQ(Ctx.getValue(LLVMCmp->getOperand(1)), OrigOp1); |
| // This checks the dispatch mechanism in CmpInst, as well as |
| // the specific implementations. |
| Cmp->swapOperands(); |
| EXPECT_EQ(Ctx.getValue(LLVMCmp->getOperand(1)), OrigOp0); |
| EXPECT_EQ(Ctx.getValue(LLVMCmp->getOperand(0)), OrigOp1); |
| EXPECT_EQ(Cmp->getOperand(0), OrigOp1); |
| EXPECT_EQ(Cmp->getOperand(1), OrigOp0); |
| // Undo it to keep the rest of the test consistent |
| Cmp->swapOperands(); |
| } |
| |
| static void checkCommonPredicates(sandboxir::CmpInst *Cmp, |
| llvm::CmpInst *LLVMCmp) { |
| // Check proper creation |
| auto Pred = Cmp->getPredicate(); |
| auto LLVMPred = LLVMCmp->getPredicate(); |
| EXPECT_EQ(Pred, LLVMPred); |
| // Check setPredicate |
| Cmp->setPredicate(llvm::CmpInst::FCMP_FALSE); |
| EXPECT_EQ(Cmp->getPredicate(), llvm::CmpInst::FCMP_FALSE); |
| EXPECT_EQ(LLVMCmp->getPredicate(), llvm::CmpInst::FCMP_FALSE); |
| Cmp->setPredicate(Pred); |
| EXPECT_EQ(LLVMCmp->getPredicate(), Pred); |
| // Ensure the accessors properly forward to the underlying implementation |
| EXPECT_STREQ(sandboxir::CmpInst::getPredicateName(Pred).data(), |
| llvm::CmpInst::getPredicateName(LLVMPred).data()); |
| EXPECT_EQ(Cmp->isFPPredicate(), LLVMCmp->isFPPredicate()); |
| EXPECT_EQ(Cmp->isIntPredicate(), LLVMCmp->isIntPredicate()); |
| EXPECT_EQ(Cmp->getInversePredicate(), LLVMCmp->getInversePredicate()); |
| EXPECT_EQ(Cmp->getOrderedPredicate(), LLVMCmp->getOrderedPredicate()); |
| EXPECT_EQ(Cmp->getUnorderedPredicate(), LLVMCmp->getUnorderedPredicate()); |
| EXPECT_EQ(Cmp->getSwappedPredicate(), LLVMCmp->getSwappedPredicate()); |
| EXPECT_EQ(Cmp->isStrictPredicate(), LLVMCmp->isStrictPredicate()); |
| EXPECT_EQ(Cmp->isNonStrictPredicate(), LLVMCmp->isNonStrictPredicate()); |
| EXPECT_EQ(Cmp->isRelational(), LLVMCmp->isRelational()); |
| if (Cmp->isRelational()) { |
| EXPECT_EQ(Cmp->getFlippedStrictnessPredicate(), |
| LLVMCmp->getFlippedStrictnessPredicate()); |
| } |
| EXPECT_EQ(Cmp->isCommutative(), LLVMCmp->isCommutative()); |
| EXPECT_EQ(Cmp->isTrueWhenEqual(), LLVMCmp->isTrueWhenEqual()); |
| EXPECT_EQ(Cmp->isFalseWhenEqual(), LLVMCmp->isFalseWhenEqual()); |
| EXPECT_EQ(sandboxir::CmpInst::isOrdered(Pred), |
| llvm::CmpInst::isOrdered(LLVMPred)); |
| EXPECT_EQ(sandboxir::CmpInst::isUnordered(Pred), |
| llvm::CmpInst::isUnordered(LLVMPred)); |
| } |
| |
| TEST_F(SandboxIRTest, ICmpInst) { |
| SCOPED_TRACE("SandboxIRTest sandboxir::ICmpInst tests"); |
| parseIR(C, R"IR( |
| define void @foo(i32 %i0, i32 %i1) { |
| bb: |
| %ine = icmp ne i32 %i0, %i1 |
| %iugt = icmp ugt i32 %i0, %i1 |
| %iuge = icmp uge i32 %i0, %i1 |
| %iult = icmp ult i32 %i0, %i1 |
| %iule = icmp ule i32 %i0, %i1 |
| %isgt = icmp sgt i32 %i0, %i1 |
| %isle = icmp sle i32 %i0, %i1 |
| %ieg = icmp eq i32 %i0, %i1 |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); |
| |
| auto *LLVMBB = getBasicBlockByName(LLVMF, "bb"); |
| auto LLVMIt = LLVMBB->begin(); |
| auto *BB = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMBB)); |
| auto It = BB->begin(); |
| // Check classof() |
| while (auto *ICmp = dyn_cast<sandboxir::ICmpInst>(&*It++)) { |
| auto *LLVMICmp = cast<llvm::ICmpInst>(&*LLVMIt++); |
| checkSwapOperands(Ctx, ICmp, LLVMICmp); |
| checkCommonPredicates(ICmp, LLVMICmp); |
| EXPECT_EQ(ICmp->isSigned(), LLVMICmp->isSigned()); |
| EXPECT_EQ(ICmp->isUnsigned(), LLVMICmp->isUnsigned()); |
| EXPECT_EQ(ICmp->getSignedPredicate(), LLVMICmp->getSignedPredicate()); |
| EXPECT_EQ(ICmp->getUnsignedPredicate(), LLVMICmp->getUnsignedPredicate()); |
| } |
| auto *NewCmp = cast<sandboxir::CmpInst>( |
| sandboxir::CmpInst::create(llvm::CmpInst::ICMP_ULE, F.getArg(0), |
| F.getArg(1), BB->begin(), Ctx, "NewCmp")); |
| EXPECT_EQ(NewCmp, &*BB->begin()); |
| EXPECT_EQ(NewCmp->getPredicate(), llvm::CmpInst::ICMP_ULE); |
| EXPECT_EQ(NewCmp->getOperand(0), F.getArg(0)); |
| EXPECT_EQ(NewCmp->getOperand(1), F.getArg(1)); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewCmp->getName(), "NewCmp"); |
| #endif // NDEBUG |
| // TODO: Improve this test when sandboxir::VectorType is more completely |
| // implemented. |
| sandboxir::Type *RT = |
| sandboxir::CmpInst::makeCmpResultType(F.getArg(0)->getType()); |
| EXPECT_TRUE(RT->isIntegerTy(1)); // Only one bit in a single comparison |
| |
| { |
| // Check create() when operands are constant. |
| auto *Const42 = |
| sandboxir::ConstantInt::get(sandboxir::Type::getInt32Ty(Ctx), 42); |
| auto *NewConstCmp = |
| sandboxir::CmpInst::create(llvm::CmpInst::ICMP_ULE, Const42, Const42, |
| BB->begin(), Ctx, "NewConstCmp"); |
| EXPECT_TRUE(isa<sandboxir::Constant>(NewConstCmp)); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, FCmpInst) { |
| SCOPED_TRACE("SandboxIRTest sandboxir::FCmpInst tests"); |
| parseIR(C, R"IR( |
| define void @foo(float %f0, float %f1) { |
| bb: |
| %ffalse = fcmp false float %f0, %f1 |
| %foeq = fcmp oeq float %f0, %f1 |
| %fogt = fcmp ogt float %f0, %f1 |
| %folt = fcmp olt float %f0, %f1 |
| %fole = fcmp ole float %f0, %f1 |
| %fone = fcmp one float %f0, %f1 |
| %ford = fcmp ord float %f0, %f1 |
| %funo = fcmp uno float %f0, %f1 |
| %fueq = fcmp ueq float %f0, %f1 |
| %fugt = fcmp ugt float %f0, %f1 |
| %fuge = fcmp uge float %f0, %f1 |
| %fult = fcmp ult float %f0, %f1 |
| %fule = fcmp ule float %f0, %f1 |
| %fune = fcmp une float %f0, %f1 |
| %ftrue = fcmp true float %f0, %f1 |
| ret void |
| bb1: |
| %copyfrom = fadd reassoc float %f0, 42.0 |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| [[maybe_unused]] auto &F = *Ctx.createFunction(&LLVMF); |
| |
| auto *LLVMBB = getBasicBlockByName(LLVMF, "bb"); |
| auto LLVMIt = LLVMBB->begin(); |
| auto *BB = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMBB)); |
| auto It = BB->begin(); |
| // Check classof() |
| while (auto *FCmp = dyn_cast<sandboxir::ICmpInst>(&*It++)) { |
| auto *LLVMFCmp = cast<llvm::ICmpInst>(&*LLVMIt++); |
| checkSwapOperands(Ctx, FCmp, LLVMFCmp); |
| checkCommonPredicates(FCmp, LLVMFCmp); |
| } |
| |
| auto *LLVMBB1 = getBasicBlockByName(LLVMF, "bb1"); |
| auto *BB1 = cast<sandboxir::BasicBlock>(Ctx.getValue(LLVMBB1)); |
| auto It1 = BB1->begin(); |
| auto *CopyFrom = &*It1++; |
| CopyFrom->setFastMathFlags(FastMathFlags::getFast()); |
| |
| // create with default flags |
| auto *NewFCmp = cast<sandboxir::CmpInst>(sandboxir::CmpInst::create( |
| llvm::CmpInst::FCMP_ONE, F.getArg(0), F.getArg(1), It1, Ctx, "NewFCmp")); |
| EXPECT_EQ(NewFCmp->getPredicate(), llvm::CmpInst::FCMP_ONE); |
| EXPECT_EQ(NewFCmp->getOperand(0), F.getArg(0)); |
| EXPECT_EQ(NewFCmp->getOperand(1), F.getArg(1)); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewFCmp->getName(), "NewFCmp"); |
| #endif // NDEBUG |
| FastMathFlags DefaultFMF = NewFCmp->getFastMathFlags(); |
| EXPECT_TRUE(CopyFrom->getFastMathFlags() != DefaultFMF); |
| // create with copied flags |
| auto *NewFCmpFlags = |
| cast<sandboxir::CmpInst>(sandboxir::CmpInst::createWithCopiedFlags( |
| llvm::CmpInst::FCMP_ONE, F.getArg(0), F.getArg(1), CopyFrom, It1, Ctx, |
| "NewFCmpFlags")); |
| EXPECT_FALSE(NewFCmpFlags->getFastMathFlags() != |
| CopyFrom->getFastMathFlags()); |
| EXPECT_EQ(NewFCmpFlags->getPredicate(), llvm::CmpInst::FCMP_ONE); |
| EXPECT_EQ(NewFCmpFlags->getOperand(0), F.getArg(0)); |
| EXPECT_EQ(NewFCmpFlags->getOperand(1), F.getArg(1)); |
| #ifndef NDEBUG |
| EXPECT_EQ(NewFCmpFlags->getName(), "NewFCmpFlags"); |
| #endif // NDEBUG |
| |
| { |
| // Check create() when operands are constant. |
| auto *Const42 = |
| sandboxir::ConstantFP::get(sandboxir::Type::getFloatTy(Ctx), 42.0); |
| auto *NewConstCmp = |
| sandboxir::CmpInst::create(llvm::CmpInst::FCMP_ULE, Const42, Const42, |
| BB->begin(), Ctx, "NewConstCmp"); |
| EXPECT_TRUE(isa<sandboxir::Constant>(NewConstCmp)); |
| } |
| } |
| |
| TEST_F(SandboxIRTest, UnreachableInst) { |
| parseIR(C, R"IR( |
| define void @foo() { |
| unreachable |
| } |
| )IR"); |
| llvm::Function *LLVMF = &*M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| sandboxir::Function *F = Ctx.createFunction(LLVMF); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| auto *UI = cast<sandboxir::UnreachableInst>(&*It++); |
| |
| EXPECT_EQ(UI->getNumSuccessors(), 0u); |
| EXPECT_EQ(UI->getNumOfIRInstrs(), 1u); |
| // Check create(InsertBefore) |
| sandboxir::UnreachableInst *NewUI = |
| sandboxir::UnreachableInst::create(UI->getIterator(), Ctx); |
| EXPECT_EQ(NewUI->getNextNode(), UI); |
| // Check create(InsertAtEnd) |
| sandboxir::UnreachableInst *NewUIEnd = |
| sandboxir::UnreachableInst::create(/*InsertAtEnd=*/BB, Ctx); |
| EXPECT_EQ(NewUIEnd->getParent(), BB); |
| EXPECT_EQ(NewUIEnd->getNextNode(), nullptr); |
| } |
| |
| /// Makes sure that all Instruction sub-classes have a classof(). |
| TEST_F(SandboxIRTest, CheckClassof) { |
| #define DEF_INSTR(ID, OPC, CLASS) \ |
| EXPECT_NE(&sandboxir::CLASS::classof, &sandboxir::Instruction::classof); |
| #include "llvm/SandboxIR/Values.def" |
| } |
| |
| TEST_F(SandboxIRTest, InstructionCallbacks) { |
| parseIR(C, R"IR( |
| define void @foo(ptr %ptr, i8 %val) { |
| ret void |
| } |
| )IR"); |
| Function &LLVMF = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| |
| auto &F = *Ctx.createFunction(&LLVMF); |
| auto &BB = *F.begin(); |
| sandboxir::Argument *Ptr = F.getArg(0); |
| sandboxir::Argument *Val = F.getArg(1); |
| sandboxir::Instruction *Ret = &BB.front(); |
| |
| SmallVector<sandboxir::Instruction *> Inserted; |
| auto InsertCbId = Ctx.registerCreateInstrCallback( |
| [&Inserted](sandboxir::Instruction *I) { Inserted.push_back(I); }); |
| |
| SmallVector<sandboxir::Instruction *> Removed; |
| auto RemoveCbId = Ctx.registerEraseInstrCallback( |
| [&Removed](sandboxir::Instruction *I) { Removed.push_back(I); }); |
| |
| // Keep the moved instruction and the instruction pointed by the Where |
| // iterator so we can check both callback arguments work as expected. |
| SmallVector<std::pair<sandboxir::Instruction *, sandboxir::Instruction *>> |
| Moved; |
| auto MoveCbId = Ctx.registerMoveInstrCallback( |
| [&Moved](sandboxir::Instruction *I, const sandboxir::BBIterator &Where) { |
| // Use a nullptr to signal "move to end" to keep it single. We only |
| // have a basic block in this test case anyway. |
| if (Where == Where.getNodeParent()->end()) |
| Moved.push_back(std::make_pair(I, nullptr)); |
| else |
| Moved.push_back(std::make_pair(I, &*Where)); |
| }); |
| |
| // Two more insertion callbacks, to check that they're called in registration |
| // order. |
| SmallVector<int> Order; |
| auto CheckOrderInsertCbId1 = Ctx.registerCreateInstrCallback( |
| [&Order](sandboxir::Instruction *I) { Order.push_back(1); }); |
| |
| auto CheckOrderInsertCbId2 = Ctx.registerCreateInstrCallback( |
| [&Order](sandboxir::Instruction *I) { Order.push_back(2); }); |
| |
| Ctx.save(); |
| auto *NewI = sandboxir::StoreInst::create(Val, Ptr, /*Align=*/std::nullopt, |
| Ret->getIterator(), Ctx); |
| EXPECT_THAT(Inserted, testing::ElementsAre(NewI)); |
| EXPECT_THAT(Removed, testing::IsEmpty()); |
| EXPECT_THAT(Moved, testing::IsEmpty()); |
| EXPECT_THAT(Order, testing::ElementsAre(1, 2)); |
| |
| Ret->moveBefore(NewI); |
| EXPECT_THAT(Inserted, testing::ElementsAre(NewI)); |
| EXPECT_THAT(Removed, testing::IsEmpty()); |
| EXPECT_THAT(Moved, testing::ElementsAre(std::make_pair(Ret, NewI))); |
| |
| Ret->eraseFromParent(); |
| EXPECT_THAT(Inserted, testing::ElementsAre(NewI)); |
| EXPECT_THAT(Removed, testing::ElementsAre(Ret)); |
| EXPECT_THAT(Moved, testing::ElementsAre(std::make_pair(Ret, NewI))); |
| |
| NewI->eraseFromParent(); |
| EXPECT_THAT(Inserted, testing::ElementsAre(NewI)); |
| EXPECT_THAT(Removed, testing::ElementsAre(Ret, NewI)); |
| EXPECT_THAT(Moved, testing::ElementsAre(std::make_pair(Ret, NewI))); |
| |
| // Check that after revert the callbacks have been called for the inverse |
| // operations of the changes made so far. |
| Ctx.revert(); |
| EXPECT_THAT(Inserted, testing::ElementsAre(NewI, NewI, Ret)); |
| EXPECT_THAT(Removed, testing::ElementsAre(Ret, NewI, NewI)); |
| EXPECT_THAT(Moved, testing::ElementsAre(std::make_pair(Ret, NewI), |
| std::make_pair(Ret, nullptr))); |
| EXPECT_THAT(Order, testing::ElementsAre(1, 2, 1, 2, 1, 2)); |
| |
| // Check that deregistration works. Do an operation of each type after |
| // deregistering callbacks and check. |
| Inserted.clear(); |
| Removed.clear(); |
| Moved.clear(); |
| Ctx.unregisterCreateInstrCallback(InsertCbId); |
| Ctx.unregisterEraseInstrCallback(RemoveCbId); |
| Ctx.unregisterMoveInstrCallback(MoveCbId); |
| Ctx.unregisterCreateInstrCallback(CheckOrderInsertCbId1); |
| Ctx.unregisterCreateInstrCallback(CheckOrderInsertCbId2); |
| auto *NewI2 = sandboxir::StoreInst::create(Val, Ptr, /*Align=*/std::nullopt, |
| Ret->getIterator(), Ctx); |
| Ret->moveBefore(NewI2); |
| Ret->eraseFromParent(); |
| EXPECT_THAT(Inserted, testing::IsEmpty()); |
| EXPECT_THAT(Removed, testing::IsEmpty()); |
| EXPECT_THAT(Moved, testing::IsEmpty()); |
| } |
| |
| // Check callbacks when we set a Use. |
| TEST_F(SandboxIRTest, SetUseCallbacks) { |
| parseIR(C, R"IR( |
| define void @foo(i8 %v0, i8 %v1) { |
| %add0 = add i8 %v0, %v1 |
| %add1 = add i8 %add0, %v1 |
| ret void |
| } |
| )IR"); |
| llvm::Function *LLVMF = &*M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| auto *F = Ctx.createFunction(LLVMF); |
| auto *Arg0 = F->getArg(0); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++); |
| auto *Add1 = cast<sandboxir::BinaryOperator>(&*It++); |
| |
| SmallVector<std::pair<sandboxir::Use, sandboxir::Value *>> UsesSet; |
| auto Id = Ctx.registerSetUseCallback( |
| [&UsesSet](sandboxir::Use U, sandboxir::Value *NewSrc) { |
| UsesSet.push_back({U, NewSrc}); |
| }); |
| |
| // Now change %add1 operand to not use %add0. |
| Add1->setOperand(0, Arg0); |
| EXPECT_EQ(UsesSet.size(), 1u); |
| EXPECT_EQ(UsesSet[0].first.get(), Add1->getOperandUse(0).get()); |
| EXPECT_EQ(UsesSet[0].second, Arg0); |
| // Restore to previous state. |
| Add1->setOperand(0, Add0); |
| UsesSet.clear(); |
| |
| // RAUW |
| Add0->replaceAllUsesWith(Arg0); |
| EXPECT_EQ(UsesSet.size(), 1u); |
| EXPECT_EQ(UsesSet[0].first.get(), Add1->getOperandUse(0).get()); |
| EXPECT_EQ(UsesSet[0].second, Arg0); |
| // Restore to previous state. |
| Add1->setOperand(0, Add0); |
| UsesSet.clear(); |
| |
| // RUWIf |
| Add0->replaceUsesWithIf(Arg0, [](const auto &U) { return true; }); |
| EXPECT_EQ(UsesSet.size(), 1u); |
| EXPECT_EQ(UsesSet[0].first.get(), Add1->getOperandUse(0).get()); |
| EXPECT_EQ(UsesSet[0].second, Arg0); |
| // Restore to previous state. |
| Add1->setOperand(0, Add0); |
| UsesSet.clear(); |
| |
| // RUOW |
| Add1->replaceUsesOfWith(Add0, Arg0); |
| EXPECT_EQ(UsesSet.size(), 1u); |
| EXPECT_EQ(UsesSet[0].first.get(), Add1->getOperandUse(0).get()); |
| EXPECT_EQ(UsesSet[0].second, Arg0); |
| // Restore to previous state. |
| Add1->setOperand(0, Add0); |
| UsesSet.clear(); |
| |
| // Check unregister. |
| Ctx.unregisterSetUseCallback(Id); |
| Add0->replaceAllUsesWith(Arg0); |
| EXPECT_TRUE(UsesSet.empty()); |
| } |
| |
| TEST_F(SandboxIRTest, FunctionObjectAlreadyExists) { |
| parseIR(C, R"IR( |
| define void @foo() { |
| call void @bar() |
| ret void |
| } |
| define void @bar() { |
| ret void |
| } |
| )IR"); |
| Function &LLVMFoo = *M->getFunction("foo"); |
| Function &LLVMBar = *M->getFunction("bar"); |
| sandboxir::Context Ctx(C); |
| // This will create a Function object for @bar(). |
| Ctx.createFunction(&LLVMFoo); |
| EXPECT_NE(Ctx.getValue(&LLVMBar), nullptr); |
| // This should not crash, even though there is already a value for LLVMBar. |
| Ctx.createFunction(&LLVMBar); |
| } |
| |
| TEST_F(SandboxIRTest, OpaqueValue) { |
| parseIR(C, R"IR( |
| declare void @bar(metadata) |
| define void @foo() { |
| call void @bar(metadata !1) |
| call void asm "asm", ""() |
| ret void |
| } |
| !1 = !{} |
| )IR"); |
| Function &LLVMFoo = *M->getFunction("foo"); |
| sandboxir::Context Ctx(C); |
| auto *F = Ctx.createFunction(&LLVMFoo); |
| auto *BB = &*F->begin(); |
| auto It = BB->begin(); |
| auto *Call = cast<sandboxir::CallInst>(&*It++); |
| auto *Op0 = Call->getOperand(0); |
| EXPECT_TRUE(isa<sandboxir::OpaqueValue>(Op0)); |
| auto *Asm = cast<sandboxir::CallInst>(&*It++); |
| auto *AsmOp0 = Asm->getOperand(0); |
| EXPECT_TRUE(isa<sandboxir::OpaqueValue>(AsmOp0)); |
| } |