1 //===- UtilsTest.cpp ------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/SandboxIR/Utils.h" 10 #include "llvm/Analysis/AssumptionCache.h" 11 #include "llvm/Analysis/BasicAliasAnalysis.h" 12 #include "llvm/Analysis/LoopInfo.h" 13 #include "llvm/Analysis/TargetLibraryInfo.h" 14 #include "llvm/AsmParser/Parser.h" 15 #include "llvm/IR/BasicBlock.h" 16 #include "llvm/IR/DataLayout.h" 17 #include "llvm/IR/Dominators.h" 18 #include "llvm/IR/Function.h" 19 #include "llvm/IR/Instruction.h" 20 #include "llvm/IR/Module.h" 21 #include "llvm/SandboxIR/Constant.h" 22 #include "llvm/SandboxIR/Context.h" 23 #include "llvm/SandboxIR/Function.h" 24 #include "llvm/Support/SourceMgr.h" 25 #include "gtest/gtest.h" 26 27 using namespace llvm; 28 29 struct UtilsTest : public testing::Test { 30 LLVMContext C; 31 std::unique_ptr<Module> M; 32 33 void parseIR(LLVMContext &C, const char *IR) { 34 SMDiagnostic Err; 35 M = parseAssemblyString(IR, Err, C); 36 if (!M) 37 Err.print("UtilsTest", errs()); 38 } 39 BasicBlock *getBasicBlockByName(Function &F, StringRef Name) { 40 for (BasicBlock &BB : F) 41 if (BB.getName() == Name) 42 return &BB; 43 llvm_unreachable("Expected to find basic block!"); 44 } 45 }; 46 47 TEST_F(UtilsTest, getMemoryLocation) { 48 parseIR(C, R"IR( 49 define void @foo(ptr %arg0) { 50 %ld = load i8, ptr %arg0 51 ret void 52 } 53 )IR"); 54 llvm::Function *LLVMF = &*M->getFunction("foo"); 55 auto *LLVMBB = &*LLVMF->begin(); 56 auto *LLVMLd = cast<llvm::LoadInst>(&*LLVMBB->begin()); 57 sandboxir::Context Ctx(C); 58 sandboxir::Function *F = Ctx.createFunction(LLVMF); 59 auto *BB = &*F->begin(); 60 auto *Ld = cast<sandboxir::LoadInst>(&*BB->begin()); 61 EXPECT_EQ(sandboxir::Utils::memoryLocationGetOrNone(Ld), 62 MemoryLocation::getOrNone(LLVMLd)); 63 } 64 65 TEST_F(UtilsTest, GetPointerDiffInBytes) { 66 parseIR(C, R"IR( 67 define void @foo(ptr %ptr) { 68 %gep0 = getelementptr inbounds float, ptr %ptr, i64 0 69 %gep1 = getelementptr inbounds float, ptr %ptr, i64 1 70 %gep2 = getelementptr inbounds float, ptr %ptr, i64 2 71 %gep3 = getelementptr inbounds float, ptr %ptr, i64 3 72 73 %ld0 = load float, ptr %gep0 74 %ld1 = load float, ptr %gep1 75 %ld2 = load float, ptr %gep2 76 %ld3 = load float, ptr %gep3 77 78 %v2ld0 = load <2 x float>, ptr %gep0 79 %v2ld1 = load <2 x float>, ptr %gep1 80 %v2ld2 = load <2 x float>, ptr %gep2 81 %v2ld3 = load <2 x float>, ptr %gep3 82 83 %v3ld0 = load <3 x float>, ptr %gep0 84 %v3ld1 = load <3 x float>, ptr %gep1 85 %v3ld2 = load <3 x float>, ptr %gep2 86 %v3ld3 = load <3 x float>, ptr %gep3 87 ret void 88 } 89 )IR"); 90 llvm::Function &LLVMF = *M->getFunction("foo"); 91 DominatorTree DT(LLVMF); 92 TargetLibraryInfoImpl TLII; 93 TargetLibraryInfo TLI(TLII); 94 DataLayout DL(M->getDataLayout()); 95 AssumptionCache AC(LLVMF); 96 BasicAAResult BAA(DL, LLVMF, TLI, AC, &DT); 97 AAResults AA(TLI); 98 AA.addAAResult(BAA); 99 LoopInfo LI(DT); 100 ScalarEvolution SE(LLVMF, TLI, AC, DT, LI); 101 sandboxir::Context Ctx(C); 102 103 auto &F = *Ctx.createFunction(&LLVMF); 104 auto &BB = *F.begin(); 105 auto It = std::next(BB.begin(), 4); 106 auto *L0 = cast<sandboxir::LoadInst>(&*It++); 107 auto *L1 = cast<sandboxir::LoadInst>(&*It++); 108 auto *L2 = cast<sandboxir::LoadInst>(&*It++); 109 [[maybe_unused]] auto *L3 = cast<sandboxir::LoadInst>(&*It++); 110 111 auto *V2L0 = cast<sandboxir::LoadInst>(&*It++); 112 auto *V2L1 = cast<sandboxir::LoadInst>(&*It++); 113 auto *V2L2 = cast<sandboxir::LoadInst>(&*It++); 114 auto *V2L3 = cast<sandboxir::LoadInst>(&*It++); 115 116 [[maybe_unused]] auto *V3L0 = cast<sandboxir::LoadInst>(&*It++); 117 auto *V3L1 = cast<sandboxir::LoadInst>(&*It++); 118 [[maybe_unused]] auto *V3L2 = cast<sandboxir::LoadInst>(&*It++); 119 [[maybe_unused]] auto *V3L3 = cast<sandboxir::LoadInst>(&*It++); 120 121 // getPointerDiffInBytes 122 EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, L1, SE), 4); 123 EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, L2, SE), 8); 124 EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L1, L0, SE), -4); 125 EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, V2L0, SE), 0); 126 127 EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, V2L1, SE), 4); 128 EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(L0, V3L1, SE), 4); 129 EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(V2L0, V2L2, SE), 8); 130 EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(V2L0, V2L3, SE), 12); 131 EXPECT_EQ(*sandboxir::Utils::getPointerDiffInBytes(V2L3, V2L0, SE), -12); 132 133 // atLowerAddress 134 EXPECT_TRUE(sandboxir::Utils::atLowerAddress(L0, L1, SE)); 135 EXPECT_FALSE(sandboxir::Utils::atLowerAddress(L1, L0, SE)); 136 EXPECT_FALSE(sandboxir::Utils::atLowerAddress(L3, V3L3, SE)); 137 } 138 139 TEST_F(UtilsTest, GetExpected) { 140 parseIR(C, R"IR( 141 define float @foo(float %v, ptr %ptr) { 142 %add = fadd float %v, %v 143 store float %v, ptr %ptr 144 ret float %v 145 } 146 define void @bar(float %v, ptr %ptr) { 147 ret void 148 } 149 )IR"); 150 llvm::Function &Foo = *M->getFunction("foo"); 151 sandboxir::Context Ctx(C); 152 153 Ctx.createFunction(&Foo); 154 auto *FooBB = cast<sandboxir::BasicBlock>(Ctx.getValue(&*Foo.begin())); 155 auto FooIt = FooBB->begin(); 156 auto Add = cast<sandboxir::Instruction>(&*FooIt++); 157 auto *S0 = cast<sandboxir::Instruction>(&*FooIt++); 158 auto *RetF = cast<sandboxir::Instruction>(&*FooIt++); 159 // getExpectedValue 160 EXPECT_EQ(sandboxir::Utils::getExpectedValue(Add), Add); 161 EXPECT_EQ(sandboxir::Utils::getExpectedValue(S0), 162 cast<sandboxir::StoreInst>(S0)->getValueOperand()); 163 EXPECT_EQ(sandboxir::Utils::getExpectedValue(RetF), 164 cast<sandboxir::ReturnInst>(RetF)->getReturnValue()); 165 // getExpectedType 166 EXPECT_EQ(sandboxir::Utils::getExpectedType(Add), Add->getType()); 167 EXPECT_EQ(sandboxir::Utils::getExpectedType(S0), 168 cast<sandboxir::StoreInst>(S0)->getValueOperand()->getType()); 169 EXPECT_EQ(sandboxir::Utils::getExpectedType(RetF), 170 cast<sandboxir::ReturnInst>(RetF)->getReturnValue()->getType()); 171 172 // getExpectedValue for void returns 173 llvm::Function &Bar = *M->getFunction("bar"); 174 Ctx.createFunction(&Bar); 175 auto *BarBB = cast<sandboxir::BasicBlock>(Ctx.getValue(&*Bar.begin())); 176 auto BarIt = BarBB->begin(); 177 auto *RetV = cast<sandboxir::Instruction>(&*BarIt++); 178 EXPECT_EQ(sandboxir::Utils::getExpectedValue(RetV), nullptr); 179 } 180 181 TEST_F(UtilsTest, GetNumBits) { 182 parseIR(C, R"IR( 183 define void @foo(float %arg0, double %arg1, i8 %arg2, i64 %arg3, ptr %arg4) { 184 bb0: 185 %ld0 = load float, ptr %arg4 186 %ld1 = load double, ptr %arg4 187 %ld2 = load i8, ptr %arg4 188 %ld3 = load i64, ptr %arg4 189 ret void 190 } 191 )IR"); 192 llvm::Function &Foo = *M->getFunction("foo"); 193 sandboxir::Context Ctx(C); 194 sandboxir::Function *F = Ctx.createFunction(&Foo); 195 const DataLayout &DL = M->getDataLayout(); 196 // getNumBits for scalars via the Value overload 197 EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(0), DL), 198 DL.getTypeSizeInBits(Type::getFloatTy(C))); 199 EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(1), DL), 200 DL.getTypeSizeInBits(Type::getDoubleTy(C))); 201 EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(2), DL), 8u); 202 EXPECT_EQ(sandboxir::Utils::getNumBits(F->getArg(3), DL), 64u); 203 204 auto &BB = *F->begin(); 205 auto It = BB.begin(); 206 auto *L0 = cast<sandboxir::LoadInst>(&*It++); 207 auto *L1 = cast<sandboxir::LoadInst>(&*It++); 208 auto *L2 = cast<sandboxir::LoadInst>(&*It++); 209 auto *L3 = cast<sandboxir::LoadInst>(&*It++); 210 // getNumBits for scalars via the Instruction overload 211 EXPECT_EQ(sandboxir::Utils::getNumBits(L0), 212 DL.getTypeSizeInBits(Type::getFloatTy(C))); 213 EXPECT_EQ(sandboxir::Utils::getNumBits(L1), 214 DL.getTypeSizeInBits(Type::getDoubleTy(C))); 215 EXPECT_EQ(sandboxir::Utils::getNumBits(L2), 8u); 216 EXPECT_EQ(sandboxir::Utils::getNumBits(L3), 64u); 217 } 218 219 TEST_F(UtilsTest, GetMemBase) { 220 parseIR(C, R"IR( 221 define void @foo(ptr %ptrA, float %val, ptr %ptrB) { 222 bb: 223 %gepA0 = getelementptr float, ptr %ptrA, i32 0 224 %gepA1 = getelementptr float, ptr %ptrA, i32 1 225 %gepB0 = getelementptr float, ptr %ptrB, i32 0 226 %gepB1 = getelementptr float, ptr %ptrB, i32 1 227 store float %val, ptr %gepA0 228 store float %val, ptr %gepA1 229 store float %val, ptr %gepB0 230 store float %val, ptr %gepB1 231 ret void 232 } 233 )IR"); 234 llvm::Function &Foo = *M->getFunction("foo"); 235 sandboxir::Context Ctx(C); 236 sandboxir::Function *F = Ctx.createFunction(&Foo); 237 238 auto It = std::next(F->begin()->begin(), 4); 239 auto *St0 = cast<sandboxir::StoreInst>(&*It++); 240 auto *St1 = cast<sandboxir::StoreInst>(&*It++); 241 auto *St2 = cast<sandboxir::StoreInst>(&*It++); 242 auto *St3 = cast<sandboxir::StoreInst>(&*It++); 243 EXPECT_EQ(sandboxir::Utils::getMemInstructionBase(St0), 244 sandboxir::Utils::getMemInstructionBase(St1)); 245 EXPECT_EQ(sandboxir::Utils::getMemInstructionBase(St2), 246 sandboxir::Utils::getMemInstructionBase(St3)); 247 EXPECT_NE(sandboxir::Utils::getMemInstructionBase(St0), 248 sandboxir::Utils::getMemInstructionBase(St3)); 249 } 250