
It should not be possible to construct one without a triple. It would also be nice to delete TargetLibraryInfoWrapperPass, but that is more difficult.
250 lines
8.9 KiB
C++
250 lines
8.9 KiB
C++
//===- UtilsTest.cpp ------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/SandboxIR/Utils.h"
|
|
#include "llvm/Analysis/AssumptionCache.h"
|
|
#include "llvm/Analysis/BasicAliasAnalysis.h"
|
|
#include "llvm/Analysis/LoopInfo.h"
|
|
#include "llvm/Analysis/TargetLibraryInfo.h"
|
|
#include "llvm/AsmParser/Parser.h"
|
|
#include "llvm/IR/BasicBlock.h"
|
|
#include "llvm/IR/DataLayout.h"
|
|
#include "llvm/IR/Dominators.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/Instruction.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/SandboxIR/Constant.h"
|
|
#include "llvm/SandboxIR/Context.h"
|
|
#include "llvm/SandboxIR/Function.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
struct UtilsTest : 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("UtilsTest", 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(UtilsTest, getMemoryLocation) {
|
|
parseIR(C, R"IR(
|
|
define void @foo(ptr %arg0) {
|
|
%ld = load i8, ptr %arg0
|
|
ret void
|
|
}
|
|
)IR");
|
|
llvm::Function *LLVMF = &*M->getFunction("foo");
|
|
auto *LLVMBB = &*LLVMF->begin();
|
|
auto *LLVMLd = cast<llvm::LoadInst>(&*LLVMBB->begin());
|
|
sandboxir::Context Ctx(C);
|
|
sandboxir::Function *F = Ctx.createFunction(LLVMF);
|
|
auto *BB = &*F->begin();
|
|
auto *Ld = cast<sandboxir::LoadInst>(&*BB->begin());
|
|
EXPECT_EQ(sandboxir::Utils::memoryLocationGetOrNone(Ld),
|
|
MemoryLocation::getOrNone(LLVMLd));
|
|
}
|
|
|
|
TEST_F(UtilsTest, GetPointerDiffInBytes) {
|
|
parseIR(C, R"IR(
|
|
define void @foo(ptr %ptr) {
|
|
%gep0 = getelementptr inbounds float, ptr %ptr, i64 0
|
|
%gep1 = getelementptr inbounds float, ptr %ptr, i64 1
|
|
%gep2 = getelementptr inbounds float, ptr %ptr, i64 2
|
|
%gep3 = getelementptr inbounds float, ptr %ptr, i64 3
|
|
|
|
%ld0 = load float, ptr %gep0
|
|
%ld1 = load float, ptr %gep1
|
|
%ld2 = load float, ptr %gep2
|
|
%ld3 = load float, ptr %gep3
|
|
|
|
%v2ld0 = load <2 x float>, ptr %gep0
|
|
%v2ld1 = load <2 x float>, ptr %gep1
|
|
%v2ld2 = load <2 x float>, ptr %gep2
|
|
%v2ld3 = load <2 x float>, ptr %gep3
|
|
|
|
%v3ld0 = load <3 x float>, ptr %gep0
|
|
%v3ld1 = load <3 x float>, ptr %gep1
|
|
%v3ld2 = load <3 x float>, ptr %gep2
|
|
%v3ld3 = load <3 x float>, ptr %gep3
|
|
ret void
|
|
}
|
|
)IR");
|
|
llvm::Function &LLVMF = *M->getFunction("foo");
|
|
DominatorTree DT(LLVMF);
|
|
TargetLibraryInfoImpl TLII(M->getTargetTriple());
|
|
TargetLibraryInfo TLI(TLII);
|
|
DataLayout DL(M->getDataLayout());
|
|
AssumptionCache AC(LLVMF);
|
|
BasicAAResult BAA(DL, LLVMF, TLI, AC, &DT);
|
|
AAResults AA(TLI);
|
|
AA.addAAResult(BAA);
|
|
LoopInfo LI(DT);
|
|
ScalarEvolution SE(LLVMF, TLI, AC, DT, LI);
|
|
sandboxir::Context Ctx(C);
|
|
|
|
auto &F = *Ctx.createFunction(&LLVMF);
|
|
auto &BB = *F.begin();
|
|
auto It = std::next(BB.begin(), 4);
|
|
auto *L0 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L1 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L2 = cast<sandboxir::LoadInst>(&*It++);
|
|
[[maybe_unused]] auto *L3 = cast<sandboxir::LoadInst>(&*It++);
|
|
|
|
auto *V2L0 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V2L1 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V2L2 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V2L3 = cast<sandboxir::LoadInst>(&*It++);
|
|
|
|
[[maybe_unused]] auto *V3L0 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V3L1 = cast<sandboxir::LoadInst>(&*It++);
|
|
[[maybe_unused]] auto *V3L2 = cast<sandboxir::LoadInst>(&*It++);
|
|
[[maybe_unused]] auto *V3L3 = cast<sandboxir::LoadInst>(&*It++);
|
|
|
|
// getPointerDiffInBytes
|
|
EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, L1, SE), 4);
|
|
EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, L2, SE), 8);
|
|
EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L1, L0, SE), -4);
|
|
EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, V2L0, SE), 0);
|
|
|
|
EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, V2L1, SE), 4);
|
|
EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, V3L1, SE), 4);
|
|
EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(V2L0, V2L2, SE), 8);
|
|
EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(V2L0, V2L3, SE), 12);
|
|
EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(V2L3, V2L0, SE), -12);
|
|
|
|
// atLowerAddress
|
|
EXPECT_TRUE(sandboxir::Utils::atLowerAddress(L0, L1, SE));
|
|
EXPECT_FALSE(sandboxir::Utils::atLowerAddress(L1, L0, SE));
|
|
EXPECT_FALSE(sandboxir::Utils::atLowerAddress(L3, V3L3, SE));
|
|
}
|
|
|
|
TEST_F(UtilsTest, GetExpected) {
|
|
parseIR(C, R"IR(
|
|
define float @foo(float %v, ptr %ptr) {
|
|
%add = fadd float %v, %v
|
|
store float %v, ptr %ptr
|
|
ret float %v
|
|
}
|
|
define void @bar(float %v, ptr %ptr) {
|
|
ret void
|
|
}
|
|
)IR");
|
|
llvm::Function &Foo = *M->getFunction("foo");
|
|
sandboxir::Context Ctx(C);
|
|
|
|
Ctx.createFunction(&Foo);
|
|
auto *FooBB = cast<sandboxir::BasicBlock>(Ctx.getValue(&*Foo.begin()));
|
|
auto FooIt = FooBB->begin();
|
|
auto Add = cast<sandboxir::Instruction>(&*FooIt++);
|
|
auto *S0 = cast<sandboxir::Instruction>(&*FooIt++);
|
|
auto *RetF = cast<sandboxir::Instruction>(&*FooIt++);
|
|
// getExpectedValue
|
|
EXPECT_EQ(sandboxir::Utils::getExpectedValue(Add), Add);
|
|
EXPECT_EQ(sandboxir::Utils::getExpectedValue(S0),
|
|
cast<sandboxir::StoreInst>(S0)->getValueOperand());
|
|
EXPECT_EQ(sandboxir::Utils::getExpectedValue(RetF),
|
|
cast<sandboxir::ReturnInst>(RetF)->getReturnValue());
|
|
// getExpectedType
|
|
EXPECT_EQ(sandboxir::Utils::getExpectedType(Add), Add->getType());
|
|
EXPECT_EQ(sandboxir::Utils::getExpectedType(S0),
|
|
cast<sandboxir::StoreInst>(S0)->getValueOperand()->getType());
|
|
EXPECT_EQ(sandboxir::Utils::getExpectedType(RetF),
|
|
cast<sandboxir::ReturnInst>(RetF)->getReturnValue()->getType());
|
|
|
|
// getExpectedValue for void returns
|
|
llvm::Function &Bar = *M->getFunction("bar");
|
|
Ctx.createFunction(&Bar);
|
|
auto *BarBB = cast<sandboxir::BasicBlock>(Ctx.getValue(&*Bar.begin()));
|
|
auto BarIt = BarBB->begin();
|
|
auto *RetV = cast<sandboxir::Instruction>(&*BarIt++);
|
|
EXPECT_EQ(sandboxir::Utils::getExpectedValue(RetV), nullptr);
|
|
}
|
|
|
|
TEST_F(UtilsTest, GetNumBits) {
|
|
parseIR(C, R"IR(
|
|
define void @foo(float %arg0, double %arg1, i8 %arg2, i64 %arg3, ptr %arg4) {
|
|
bb0:
|
|
%ld0 = load float, ptr %arg4
|
|
%ld1 = load double, ptr %arg4
|
|
%ld2 = load i8, ptr %arg4
|
|
%ld3 = load i64, ptr %arg4
|
|
ret void
|
|
}
|
|
)IR");
|
|
llvm::Function &Foo = *M->getFunction("foo");
|
|
sandboxir::Context Ctx(C);
|
|
sandboxir::Function *F = Ctx.createFunction(&Foo);
|
|
const DataLayout &DL = M->getDataLayout();
|
|
// getNumBits for scalars via the Value overload
|
|
EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(0), DL),
|
|
DL.getTypeSizeInBits(Type::getFloatTy(C)));
|
|
EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(1), DL),
|
|
DL.getTypeSizeInBits(Type::getDoubleTy(C)));
|
|
EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(2), DL), 8u);
|
|
EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(3), DL), 64u);
|
|
|
|
auto &BB = *F->begin();
|
|
auto It = BB.begin();
|
|
auto *L0 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L1 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L2 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L3 = cast<sandboxir::LoadInst>(&*It++);
|
|
// getNumBits for scalars via the Instruction overload
|
|
EXPECT_EQ(sandboxir::Utils::getNumBits(L0),
|
|
DL.getTypeSizeInBits(Type::getFloatTy(C)));
|
|
EXPECT_EQ(sandboxir::Utils::getNumBits(L1),
|
|
DL.getTypeSizeInBits(Type::getDoubleTy(C)));
|
|
EXPECT_EQ(sandboxir::Utils::getNumBits(L2), 8u);
|
|
EXPECT_EQ(sandboxir::Utils::getNumBits(L3), 64u);
|
|
}
|
|
|
|
TEST_F(UtilsTest, GetMemBase) {
|
|
parseIR(C, R"IR(
|
|
define void @foo(ptr %ptrA, float %val, ptr %ptrB) {
|
|
bb:
|
|
%gepA0 = getelementptr float, ptr %ptrA, i32 0
|
|
%gepA1 = getelementptr float, ptr %ptrA, i32 1
|
|
%gepB0 = getelementptr float, ptr %ptrB, i32 0
|
|
%gepB1 = getelementptr float, ptr %ptrB, i32 1
|
|
store float %val, ptr %gepA0
|
|
store float %val, ptr %gepA1
|
|
store float %val, ptr %gepB0
|
|
store float %val, ptr %gepB1
|
|
ret void
|
|
}
|
|
)IR");
|
|
llvm::Function &Foo = *M->getFunction("foo");
|
|
sandboxir::Context Ctx(C);
|
|
sandboxir::Function *F = Ctx.createFunction(&Foo);
|
|
|
|
auto It = std::next(F->begin()->begin(), 4);
|
|
auto *St0 = cast<sandboxir::StoreInst>(&*It++);
|
|
auto *St1 = cast<sandboxir::StoreInst>(&*It++);
|
|
auto *St2 = cast<sandboxir::StoreInst>(&*It++);
|
|
auto *St3 = cast<sandboxir::StoreInst>(&*It++);
|
|
EXPECT_EQ(sandboxir::Utils::getMemInstructionBase(St0),
|
|
sandboxir::Utils::getMemInstructionBase(St1));
|
|
EXPECT_EQ(sandboxir::Utils::getMemInstructionBase(St2),
|
|
sandboxir::Utils::getMemInstructionBase(St3));
|
|
EXPECT_NE(sandboxir::Utils::getMemInstructionBase(St0),
|
|
sandboxir::Utils::getMemInstructionBase(St3));
|
|
}
|