1 //===- UtilsTest.cpp ------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
29 struct UtilsTest
: public testing::Test
{
31 std::unique_ptr
<Module
> M
;
33 void parseIR(LLVMContext
&C
, const char *IR
) {
35 M
= parseAssemblyString(IR
, Err
, C
);
37 Err
.print("UtilsTest", errs());
39 BasicBlock
*getBasicBlockByName(Function
&F
, StringRef Name
) {
40 for (BasicBlock
&BB
: F
)
41 if (BB
.getName() == Name
)
43 llvm_unreachable("Expected to find basic block!");
47 TEST_F(UtilsTest
, getMemoryLocation
) {
49 define void @foo(ptr %arg0) {
50 %ld = load i8, ptr %arg0
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
));
65 TEST_F(UtilsTest
, GetPointerDiffInBytes
) {
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
73 %ld0 = load float, ptr %gep0
74 %ld1 = load float, ptr %gep1
75 %ld2 = load float, ptr %gep2
76 %ld3 = load float, ptr %gep3
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
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
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
);
100 ScalarEvolution
SE(LLVMF
, TLI
, AC
, DT
, LI
);
101 sandboxir::Context
Ctx(C
);
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
++);
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
++);
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
++);
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);
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);
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
));
139 TEST_F(UtilsTest
, GetExpected
) {
141 define float @foo(float %v, ptr %ptr) {
142 %add = fadd float %v, %v
143 store float %v, ptr %ptr
146 define void @bar(float %v, ptr %ptr) {
150 llvm::Function
&Foo
= *M
->getFunction("foo");
151 sandboxir::Context
Ctx(C
);
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
++);
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());
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());
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);
181 TEST_F(UtilsTest
, GetNumBits
) {
183 define void @foo(float %arg0, double %arg1, i8 %arg2, i64 %arg3, ptr %arg4) {
185 %ld0 = load float, ptr %arg4
186 %ld1 = load double, ptr %arg4
187 %ld2 = load i8, ptr %arg4
188 %ld3 = load i64, ptr %arg4
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);
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);
219 TEST_F(UtilsTest
, GetMemBase
) {
221 define void @foo(ptr %ptrA, float %val, ptr %ptrB) {
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
234 llvm::Function
&Foo
= *M
->getFunction("foo");
235 sandboxir::Context
Ctx(C
);
236 sandboxir::Function
*F
= Ctx
.createFunction(&Foo
);
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
));