xref: /llvm-project/llvm/unittests/Analysis/LoadsTest.cpp (revision 3c51b9e270bac26fdec1b06ae8dd72960a2353a3)
1 //===- LoadsTest.cpp - local load analysis unit tests ---------------------===//
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/Analysis/Loads.h"
10 #include "llvm/AsmParser/Parser.h"
11 #include "llvm/IR/Instructions.h"
12 #include "llvm/IR/LLVMContext.h"
13 #include "llvm/IR/Module.h"
14 #include "llvm/Support/SourceMgr.h"
15 #include "gtest/gtest.h"
16 
17 using namespace llvm;
18 
19 static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
20   SMDiagnostic Err;
21   std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
22   if (!Mod)
23     Err.print("AnalysisTests", errs());
24   return Mod;
25 }
26 
27 TEST(LoadsTest, FindAvailableLoadedValueSameBasePtrConstantOffsetsNullAA) {
28   LLVMContext C;
29   std::unique_ptr<Module> M = parseIR(C,
30                                       R"IR(
31 target datalayout = "p:64:64:64:32"
32 %class = type <{ i32, i32 }>
33 
34 define i32 @f() {
35 entry:
36   %o = alloca %class
37   %f1 = getelementptr inbounds %class, %class* %o, i32 0, i32 0
38   store i32 42, i32* %f1
39   %f2 = getelementptr inbounds %class, %class* %o, i32 0, i32 1
40   store i32 43, i32* %f2
41   %v = load i32, i32* %f1
42   ret i32 %v
43 }
44 )IR");
45   auto *GV = M->getNamedValue("f");
46   ASSERT_TRUE(GV);
47   auto *F = dyn_cast<Function>(GV);
48   ASSERT_TRUE(F);
49   Instruction *Inst = &F->front().front();
50   auto *AI = dyn_cast<AllocaInst>(Inst);
51   ASSERT_TRUE(AI);
52   Inst = &*++F->front().rbegin();
53   auto *LI = dyn_cast<LoadInst>(Inst);
54   ASSERT_TRUE(LI);
55   BasicBlock::iterator BBI(LI);
56   Value *Loaded = FindAvailableLoadedValue(
57       LI, LI->getParent(), BBI, 0, nullptr, nullptr);
58   ASSERT_TRUE(Loaded);
59   auto *CI = dyn_cast<ConstantInt>(Loaded);
60   ASSERT_TRUE(CI);
61   ASSERT_TRUE(CI->equalsInt(42));
62 }
63 
64 TEST(LoadsTest, CanReplacePointersIfEqual) {
65   LLVMContext C;
66   std::unique_ptr<Module> M = parseIR(C,
67                                       R"IR(
68 @y = common global [1 x i32] zeroinitializer, align 4
69 @x = common global [1 x i32] zeroinitializer, align 4
70 
71 declare void @use(i32*)
72 
73 define void @f(i32* %p) {
74   call void @use(i32* getelementptr inbounds ([1 x i32], [1 x i32]* @y, i64 0, i64 0))
75   call void @use(i32* getelementptr inbounds (i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @x, i64 0, i64 0), i64 1))
76   ret void
77 }
78 )IR");
79   const auto &DL = M->getDataLayout();
80   auto *GV = M->getNamedValue("f");
81   ASSERT_TRUE(GV);
82   auto *F = dyn_cast<Function>(GV);
83   ASSERT_TRUE(F);
84 
85   // NOTE: the implementation of canReplacePointersIfEqual is incomplete.
86   // Currently the only the cases it returns false for are really sound and
87   // returning true means unknown.
88   Value *P = &*F->arg_begin();
89   auto InstIter = F->front().begin();
90   Value *ConstDerefPtr = *cast<CallInst>(&*InstIter)->arg_begin();
91   // ConstDerefPtr is a constant pointer that is provably de-referenceable. We
92   // can replace an arbitrary pointer with it.
93   EXPECT_TRUE(canReplacePointersIfEqual(P, ConstDerefPtr, DL, nullptr));
94 
95   ++InstIter;
96   Value *ConstUnDerefPtr = *cast<CallInst>(&*InstIter)->arg_begin();
97   // ConstUndDerefPtr is a constant pointer that is provably not
98   // de-referenceable. We cannot replace an arbitrary pointer with it.
99   EXPECT_FALSE(
100       canReplacePointersIfEqual(ConstDerefPtr, ConstUnDerefPtr, DL, nullptr));
101 }
102