xref: /llvm-project/llvm/unittests/SandboxIR/UtilsTest.cpp (revision f0909e3a991c7b6515cafe2ce0a069a856fe675f)
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