
Currently, GlobalObject has an "alignment" property... but it's basically nonsense: alignment doesn't mean the same thing for variables and functions, and it's completely meaningless for ifuncs. This "removes" (actually marking protected) the methods from GlobalObject, adds the relevant methods to Function and GlobalVariable, and adjusts the code appropriately. This should make future alignment-related cleanups easier.
6420 lines
234 KiB
C++
6420 lines
234 KiB
C++
//===- 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));
|
|
}
|