1eba21accSvporpo //===- UtilsTest.cpp ------------------------------------------------------===// 2eba21accSvporpo // 3eba21accSvporpo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4eba21accSvporpo // See https://llvm.org/LICENSE.txt for license information. 5eba21accSvporpo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6eba21accSvporpo // 7eba21accSvporpo //===----------------------------------------------------------------------===// 8eba21accSvporpo 9eba21accSvporpo #include "llvm/SandboxIR/Utils.h" 10df4d7d3bSSterling-Augustine #include "llvm/Analysis/AssumptionCache.h" 11df4d7d3bSSterling-Augustine #include "llvm/Analysis/BasicAliasAnalysis.h" 12df4d7d3bSSterling-Augustine #include "llvm/Analysis/LoopInfo.h" 13df4d7d3bSSterling-Augustine #include "llvm/Analysis/TargetLibraryInfo.h" 14eba21accSvporpo #include "llvm/AsmParser/Parser.h" 15eba21accSvporpo #include "llvm/IR/BasicBlock.h" 16eba21accSvporpo #include "llvm/IR/DataLayout.h" 17df4d7d3bSSterling-Augustine #include "llvm/IR/Dominators.h" 18eba21accSvporpo #include "llvm/IR/Function.h" 19eba21accSvporpo #include "llvm/IR/Instruction.h" 20eba21accSvporpo #include "llvm/IR/Module.h" 212018f4ccSVasileios Porpodas #include "llvm/SandboxIR/Constant.h" 222018f4ccSVasileios Porpodas #include "llvm/SandboxIR/Context.h" 23e22b07e7Svporpo #include "llvm/SandboxIR/Function.h" 24eba21accSvporpo #include "llvm/Support/SourceMgr.h" 25eba21accSvporpo #include "gtest/gtest.h" 26eba21accSvporpo 27eba21accSvporpo using namespace llvm; 28eba21accSvporpo 29eba21accSvporpo struct UtilsTest : public testing::Test { 30eba21accSvporpo LLVMContext C; 31eba21accSvporpo std::unique_ptr<Module> M; 32eba21accSvporpo 33eba21accSvporpo void parseIR(LLVMContext &C, const char *IR) { 34eba21accSvporpo SMDiagnostic Err; 35eba21accSvporpo M = parseAssemblyString(IR, Err, C); 36eba21accSvporpo if (!M) 37eba21accSvporpo Err.print("UtilsTest", errs()); 38eba21accSvporpo } 39eba21accSvporpo BasicBlock *getBasicBlockByName(Function &F, StringRef Name) { 40eba21accSvporpo for (BasicBlock &BB : F) 41eba21accSvporpo if (BB.getName() == Name) 42eba21accSvporpo return &BB; 43eba21accSvporpo llvm_unreachable("Expected to find basic block!"); 44eba21accSvporpo } 45eba21accSvporpo }; 46eba21accSvporpo 47eba21accSvporpo TEST_F(UtilsTest, getMemoryLocation) { 48eba21accSvporpo parseIR(C, R"IR( 49eba21accSvporpo define void @foo(ptr %arg0) { 50eba21accSvporpo %ld = load i8, ptr %arg0 51eba21accSvporpo ret void 52eba21accSvporpo } 53eba21accSvporpo )IR"); 54eba21accSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 55eba21accSvporpo auto *LLVMBB = &*LLVMF->begin(); 56eba21accSvporpo auto *LLVMLd = cast<llvm::LoadInst>(&*LLVMBB->begin()); 57eba21accSvporpo sandboxir::Context Ctx(C); 58eba21accSvporpo sandboxir::Function *F = Ctx.createFunction(LLVMF); 59eba21accSvporpo auto *BB = &*F->begin(); 60eba21accSvporpo auto *Ld = cast<sandboxir::LoadInst>(&*BB->begin()); 61eba21accSvporpo EXPECT_EQ(sandboxir::Utils::memoryLocationGetOrNone(Ld), 62eba21accSvporpo MemoryLocation::getOrNone(LLVMLd)); 63eba21accSvporpo } 64df4d7d3bSSterling-Augustine 65df4d7d3bSSterling-Augustine TEST_F(UtilsTest, GetPointerDiffInBytes) { 66df4d7d3bSSterling-Augustine parseIR(C, R"IR( 67df4d7d3bSSterling-Augustine define void @foo(ptr %ptr) { 68df4d7d3bSSterling-Augustine %gep0 = getelementptr inbounds float, ptr %ptr, i64 0 69df4d7d3bSSterling-Augustine %gep1 = getelementptr inbounds float, ptr %ptr, i64 1 70df4d7d3bSSterling-Augustine %gep2 = getelementptr inbounds float, ptr %ptr, i64 2 71df4d7d3bSSterling-Augustine %gep3 = getelementptr inbounds float, ptr %ptr, i64 3 72df4d7d3bSSterling-Augustine 73df4d7d3bSSterling-Augustine %ld0 = load float, ptr %gep0 74df4d7d3bSSterling-Augustine %ld1 = load float, ptr %gep1 75df4d7d3bSSterling-Augustine %ld2 = load float, ptr %gep2 76df4d7d3bSSterling-Augustine %ld3 = load float, ptr %gep3 77df4d7d3bSSterling-Augustine 78df4d7d3bSSterling-Augustine %v2ld0 = load <2 x float>, ptr %gep0 79df4d7d3bSSterling-Augustine %v2ld1 = load <2 x float>, ptr %gep1 80df4d7d3bSSterling-Augustine %v2ld2 = load <2 x float>, ptr %gep2 81df4d7d3bSSterling-Augustine %v2ld3 = load <2 x float>, ptr %gep3 82df4d7d3bSSterling-Augustine 83df4d7d3bSSterling-Augustine %v3ld0 = load <3 x float>, ptr %gep0 84df4d7d3bSSterling-Augustine %v3ld1 = load <3 x float>, ptr %gep1 85df4d7d3bSSterling-Augustine %v3ld2 = load <3 x float>, ptr %gep2 86df4d7d3bSSterling-Augustine %v3ld3 = load <3 x float>, ptr %gep3 87df4d7d3bSSterling-Augustine ret void 88df4d7d3bSSterling-Augustine } 89df4d7d3bSSterling-Augustine )IR"); 90df4d7d3bSSterling-Augustine llvm::Function &LLVMF = *M->getFunction("foo"); 91df4d7d3bSSterling-Augustine DominatorTree DT(LLVMF); 92df4d7d3bSSterling-Augustine TargetLibraryInfoImpl TLII; 93df4d7d3bSSterling-Augustine TargetLibraryInfo TLI(TLII); 94df4d7d3bSSterling-Augustine DataLayout DL(M->getDataLayout()); 95df4d7d3bSSterling-Augustine AssumptionCache AC(LLVMF); 96df4d7d3bSSterling-Augustine BasicAAResult BAA(DL, LLVMF, TLI, AC, &DT); 97df4d7d3bSSterling-Augustine AAResults AA(TLI); 98df4d7d3bSSterling-Augustine AA.addAAResult(BAA); 99df4d7d3bSSterling-Augustine LoopInfo LI(DT); 100df4d7d3bSSterling-Augustine ScalarEvolution SE(LLVMF, TLI, AC, DT, LI); 101df4d7d3bSSterling-Augustine sandboxir::Context Ctx(C); 102df4d7d3bSSterling-Augustine 103df4d7d3bSSterling-Augustine auto &F = *Ctx.createFunction(&LLVMF); 104df4d7d3bSSterling-Augustine auto &BB = *F.begin(); 105df4d7d3bSSterling-Augustine auto It = std::next(BB.begin(), 4); 106df4d7d3bSSterling-Augustine auto *L0 = cast<sandboxir::LoadInst>(&*It++); 107df4d7d3bSSterling-Augustine auto *L1 = cast<sandboxir::LoadInst>(&*It++); 108df4d7d3bSSterling-Augustine auto *L2 = cast<sandboxir::LoadInst>(&*It++); 109df4d7d3bSSterling-Augustine [[maybe_unused]] auto *L3 = cast<sandboxir::LoadInst>(&*It++); 110df4d7d3bSSterling-Augustine 111df4d7d3bSSterling-Augustine auto *V2L0 = cast<sandboxir::LoadInst>(&*It++); 112df4d7d3bSSterling-Augustine auto *V2L1 = cast<sandboxir::LoadInst>(&*It++); 113df4d7d3bSSterling-Augustine auto *V2L2 = cast<sandboxir::LoadInst>(&*It++); 114df4d7d3bSSterling-Augustine auto *V2L3 = cast<sandboxir::LoadInst>(&*It++); 115df4d7d3bSSterling-Augustine 116df4d7d3bSSterling-Augustine [[maybe_unused]] auto *V3L0 = cast<sandboxir::LoadInst>(&*It++); 117df4d7d3bSSterling-Augustine auto *V3L1 = cast<sandboxir::LoadInst>(&*It++); 118df4d7d3bSSterling-Augustine [[maybe_unused]] auto *V3L2 = cast<sandboxir::LoadInst>(&*It++); 119df4d7d3bSSterling-Augustine [[maybe_unused]] auto *V3L3 = cast<sandboxir::LoadInst>(&*It++); 120df4d7d3bSSterling-Augustine 121df4d7d3bSSterling-Augustine // getPointerDiffInBytes 122376b5c0cSSterling-Augustine EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, L1, SE), 4); 123376b5c0cSSterling-Augustine EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, L2, SE), 8); 124376b5c0cSSterling-Augustine EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L1, L0, SE), -4); 125376b5c0cSSterling-Augustine EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, V2L0, SE), 0); 126df4d7d3bSSterling-Augustine 127376b5c0cSSterling-Augustine EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, V2L1, SE), 4); 128376b5c0cSSterling-Augustine EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, V3L1, SE), 4); 129376b5c0cSSterling-Augustine EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(V2L0, V2L2, SE), 8); 130376b5c0cSSterling-Augustine EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(V2L0, V2L3, SE), 12); 131376b5c0cSSterling-Augustine EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(V2L3, V2L0, SE), -12); 132df4d7d3bSSterling-Augustine 133df4d7d3bSSterling-Augustine // atLowerAddress 134376b5c0cSSterling-Augustine EXPECT_TRUE(sandboxir::Utils::atLowerAddress(L0, L1, SE)); 135376b5c0cSSterling-Augustine EXPECT_FALSE(sandboxir::Utils::atLowerAddress(L1, L0, SE)); 136376b5c0cSSterling-Augustine EXPECT_FALSE(sandboxir::Utils::atLowerAddress(L3, V3L3, SE)); 137df4d7d3bSSterling-Augustine } 1382f432729SSterling-Augustine 139906ffc4bSSterling-Augustine TEST_F(UtilsTest, GetExpected) { 140906ffc4bSSterling-Augustine parseIR(C, R"IR( 141906ffc4bSSterling-Augustine define float @foo(float %v, ptr %ptr) { 142906ffc4bSSterling-Augustine %add = fadd float %v, %v 143906ffc4bSSterling-Augustine store float %v, ptr %ptr 144906ffc4bSSterling-Augustine ret float %v 145906ffc4bSSterling-Augustine } 146906ffc4bSSterling-Augustine define void @bar(float %v, ptr %ptr) { 147906ffc4bSSterling-Augustine ret void 148906ffc4bSSterling-Augustine } 149906ffc4bSSterling-Augustine )IR"); 150906ffc4bSSterling-Augustine llvm::Function &Foo = *M->getFunction("foo"); 151906ffc4bSSterling-Augustine sandboxir::Context Ctx(C); 152906ffc4bSSterling-Augustine 153906ffc4bSSterling-Augustine Ctx.createFunction(&Foo); 154906ffc4bSSterling-Augustine auto *FooBB = cast<sandboxir::BasicBlock>(Ctx.getValue(&*Foo.begin())); 155906ffc4bSSterling-Augustine auto FooIt = FooBB->begin(); 156906ffc4bSSterling-Augustine auto Add = cast<sandboxir::Instruction>(&*FooIt++); 157906ffc4bSSterling-Augustine auto *S0 = cast<sandboxir::Instruction>(&*FooIt++); 158906ffc4bSSterling-Augustine auto *RetF = cast<sandboxir::Instruction>(&*FooIt++); 159906ffc4bSSterling-Augustine // getExpectedValue 160906ffc4bSSterling-Augustine EXPECT_EQ(sandboxir::Utils::getExpectedValue(Add), Add); 161906ffc4bSSterling-Augustine EXPECT_EQ(sandboxir::Utils::getExpectedValue(S0), 162906ffc4bSSterling-Augustine cast<sandboxir::StoreInst>(S0)->getValueOperand()); 163906ffc4bSSterling-Augustine EXPECT_EQ(sandboxir::Utils::getExpectedValue(RetF), 164906ffc4bSSterling-Augustine cast<sandboxir::ReturnInst>(RetF)->getReturnValue()); 165906ffc4bSSterling-Augustine // getExpectedType 166906ffc4bSSterling-Augustine EXPECT_EQ(sandboxir::Utils::getExpectedType(Add), Add->getType()); 167906ffc4bSSterling-Augustine EXPECT_EQ(sandboxir::Utils::getExpectedType(S0), 168906ffc4bSSterling-Augustine cast<sandboxir::StoreInst>(S0)->getValueOperand()->getType()); 169906ffc4bSSterling-Augustine EXPECT_EQ(sandboxir::Utils::getExpectedType(RetF), 170906ffc4bSSterling-Augustine cast<sandboxir::ReturnInst>(RetF)->getReturnValue()->getType()); 171906ffc4bSSterling-Augustine 172906ffc4bSSterling-Augustine // getExpectedValue for void returns 173906ffc4bSSterling-Augustine llvm::Function &Bar = *M->getFunction("bar"); 174906ffc4bSSterling-Augustine Ctx.createFunction(&Bar); 175906ffc4bSSterling-Augustine auto *BarBB = cast<sandboxir::BasicBlock>(Ctx.getValue(&*Bar.begin())); 176906ffc4bSSterling-Augustine auto BarIt = BarBB->begin(); 177906ffc4bSSterling-Augustine auto *RetV = cast<sandboxir::Instruction>(&*BarIt++); 178906ffc4bSSterling-Augustine EXPECT_EQ(sandboxir::Utils::getExpectedValue(RetV), nullptr); 179906ffc4bSSterling-Augustine } 180906ffc4bSSterling-Augustine 1812f432729SSterling-Augustine TEST_F(UtilsTest, GetNumBits) { 1822f432729SSterling-Augustine parseIR(C, R"IR( 1832f432729SSterling-Augustine define void @foo(float %arg0, double %arg1, i8 %arg2, i64 %arg3, ptr %arg4) { 1842f432729SSterling-Augustine bb0: 1852f432729SSterling-Augustine %ld0 = load float, ptr %arg4 1862f432729SSterling-Augustine %ld1 = load double, ptr %arg4 1872f432729SSterling-Augustine %ld2 = load i8, ptr %arg4 1882f432729SSterling-Augustine %ld3 = load i64, ptr %arg4 1892f432729SSterling-Augustine ret void 1902f432729SSterling-Augustine } 1912f432729SSterling-Augustine )IR"); 1922f432729SSterling-Augustine llvm::Function &Foo = *M->getFunction("foo"); 1932f432729SSterling-Augustine sandboxir::Context Ctx(C); 1942f432729SSterling-Augustine sandboxir::Function *F = Ctx.createFunction(&Foo); 1952f432729SSterling-Augustine const DataLayout &DL = M->getDataLayout(); 1962f432729SSterling-Augustine // getNumBits for scalars via the Value overload 1972f432729SSterling-Augustine EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(0), DL), 1982f432729SSterling-Augustine DL.getTypeSizeInBits(Type::getFloatTy(C))); 1992f432729SSterling-Augustine EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(1), DL), 2002f432729SSterling-Augustine DL.getTypeSizeInBits(Type::getDoubleTy(C))); 2012f432729SSterling-Augustine EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(2), DL), 8u); 2022f432729SSterling-Augustine EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(3), DL), 64u); 2032f432729SSterling-Augustine 2042f432729SSterling-Augustine auto &BB = *F->begin(); 2052f432729SSterling-Augustine auto It = BB.begin(); 2062f432729SSterling-Augustine auto *L0 = cast<sandboxir::LoadInst>(&*It++); 2072f432729SSterling-Augustine auto *L1 = cast<sandboxir::LoadInst>(&*It++); 2082f432729SSterling-Augustine auto *L2 = cast<sandboxir::LoadInst>(&*It++); 2092f432729SSterling-Augustine auto *L3 = cast<sandboxir::LoadInst>(&*It++); 2102f432729SSterling-Augustine // getNumBits for scalars via the Instruction overload 2112f432729SSterling-Augustine EXPECT_EQ(sandboxir::Utils::getNumBits(L0), 2122f432729SSterling-Augustine DL.getTypeSizeInBits(Type::getFloatTy(C))); 2132f432729SSterling-Augustine EXPECT_EQ(sandboxir::Utils::getNumBits(L1), 2142f432729SSterling-Augustine DL.getTypeSizeInBits(Type::getDoubleTy(C))); 2152f432729SSterling-Augustine EXPECT_EQ(sandboxir::Utils::getNumBits(L2), 8u); 2162f432729SSterling-Augustine EXPECT_EQ(sandboxir::Utils::getNumBits(L3), 64u); 2172f432729SSterling-Augustine } 218*f0909e3aSSterling-Augustine 219*f0909e3aSSterling-Augustine TEST_F(UtilsTest, GetMemBase) { 220*f0909e3aSSterling-Augustine parseIR(C, R"IR( 221*f0909e3aSSterling-Augustine define void @foo(ptr %ptrA, float %val, ptr %ptrB) { 222*f0909e3aSSterling-Augustine bb: 223*f0909e3aSSterling-Augustine %gepA0 = getelementptr float, ptr %ptrA, i32 0 224*f0909e3aSSterling-Augustine %gepA1 = getelementptr float, ptr %ptrA, i32 1 225*f0909e3aSSterling-Augustine %gepB0 = getelementptr float, ptr %ptrB, i32 0 226*f0909e3aSSterling-Augustine %gepB1 = getelementptr float, ptr %ptrB, i32 1 227*f0909e3aSSterling-Augustine store float %val, ptr %gepA0 228*f0909e3aSSterling-Augustine store float %val, ptr %gepA1 229*f0909e3aSSterling-Augustine store float %val, ptr %gepB0 230*f0909e3aSSterling-Augustine store float %val, ptr %gepB1 231*f0909e3aSSterling-Augustine ret void 232*f0909e3aSSterling-Augustine } 233*f0909e3aSSterling-Augustine )IR"); 234*f0909e3aSSterling-Augustine llvm::Function &Foo = *M->getFunction("foo"); 235*f0909e3aSSterling-Augustine sandboxir::Context Ctx(C); 236*f0909e3aSSterling-Augustine sandboxir::Function *F = Ctx.createFunction(&Foo); 237*f0909e3aSSterling-Augustine 238*f0909e3aSSterling-Augustine auto It = std::next(F->begin()->begin(), 4); 239*f0909e3aSSterling-Augustine auto *St0 = cast<sandboxir::StoreInst>(&*It++); 240*f0909e3aSSterling-Augustine auto *St1 = cast<sandboxir::StoreInst>(&*It++); 241*f0909e3aSSterling-Augustine auto *St2 = cast<sandboxir::StoreInst>(&*It++); 242*f0909e3aSSterling-Augustine auto *St3 = cast<sandboxir::StoreInst>(&*It++); 243*f0909e3aSSterling-Augustine EXPECT_EQ(sandboxir::Utils::getMemInstructionBase(St0), 244*f0909e3aSSterling-Augustine sandboxir::Utils::getMemInstructionBase(St1)); 245*f0909e3aSSterling-Augustine EXPECT_EQ(sandboxir::Utils::getMemInstructionBase(St2), 246*f0909e3aSSterling-Augustine sandboxir::Utils::getMemInstructionBase(St3)); 247*f0909e3aSSterling-Augustine EXPECT_NE(sandboxir::Utils::getMemInstructionBase(St0), 248*f0909e3aSSterling-Augustine sandboxir::Utils::getMemInstructionBase(St3)); 249*f0909e3aSSterling-Augustine } 250