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