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/Constants.h" |
12 | #include "llvm/IR/Instructions.h" |
13 | #include "llvm/IR/LLVMContext.h" |
14 | #include "llvm/IR/Module.h" |
15 | #include "llvm/Support/SourceMgr.h" |
16 | #include "gtest/gtest.h" |
17 | |
18 | using namespace llvm; |
19 | |
20 | static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { |
21 | SMDiagnostic Err; |
22 | std::unique_ptr<Module> Mod = parseAssemblyString(AsmString: IR, Err, Context&: C); |
23 | if (!Mod) |
24 | Err.print(ProgName: "AnalysisTests" , S&: errs()); |
25 | return Mod; |
26 | } |
27 | |
28 | TEST(LoadsTest, FindAvailableLoadedValueSameBasePtrConstantOffsetsNullAA) { |
29 | LLVMContext C; |
30 | std::unique_ptr<Module> M = parseIR(C, |
31 | IR: R"IR( |
32 | target datalayout = "p:64:64:64:32" |
33 | %class = type <{ i32, i32 }> |
34 | |
35 | define i32 @f() { |
36 | entry: |
37 | %o = alloca %class |
38 | %f1 = getelementptr inbounds %class, %class* %o, i32 0, i32 0 |
39 | store i32 42, i32* %f1 |
40 | %f2 = getelementptr inbounds %class, %class* %o, i32 0, i32 1 |
41 | store i32 43, i32* %f2 |
42 | %v = load i32, i32* %f1 |
43 | ret i32 %v |
44 | } |
45 | )IR" ); |
46 | auto *GV = M->getNamedValue(Name: "f" ); |
47 | ASSERT_TRUE(GV); |
48 | auto *F = dyn_cast<Function>(Val: GV); |
49 | ASSERT_TRUE(F); |
50 | Instruction *Inst = &F->front().front(); |
51 | auto *AI = dyn_cast<AllocaInst>(Val: Inst); |
52 | ASSERT_TRUE(AI); |
53 | Inst = &*++F->front().rbegin(); |
54 | auto *LI = dyn_cast<LoadInst>(Val: Inst); |
55 | ASSERT_TRUE(LI); |
56 | BasicBlock::iterator BBI(LI); |
57 | Value *Loaded = FindAvailableLoadedValue( |
58 | Load: LI, ScanBB: LI->getParent(), ScanFrom&: BBI, MaxInstsToScan: 0, AA: nullptr, IsLoadCSE: nullptr); |
59 | ASSERT_TRUE(Loaded); |
60 | auto *CI = dyn_cast<ConstantInt>(Val: Loaded); |
61 | ASSERT_TRUE(CI); |
62 | ASSERT_TRUE(CI->equalsInt(42)); |
63 | } |
64 | |
65 | TEST(LoadsTest, CanReplacePointersIfEqual) { |
66 | LLVMContext C; |
67 | std::unique_ptr<Module> M = parseIR(C, |
68 | IR: R"IR( |
69 | @y = common global [1 x i32] zeroinitializer, align 4 |
70 | @x = common global [1 x i32] zeroinitializer, align 4 |
71 | declare void @use(i32*) |
72 | |
73 | define void @f(i32* %p1, i32* %p2, i64 %i) { |
74 | call void @use(i32* getelementptr inbounds ([1 x i32], [1 x i32]* @y, i64 0, i64 0)) |
75 | |
76 | %p1_idx = getelementptr inbounds i32, i32* %p1, i64 %i |
77 | call void @use(i32* %p1_idx) |
78 | |
79 | %icmp = icmp eq i32* %p1, getelementptr inbounds ([1 x i32], [1 x i32]* @y, i64 0, i64 0) |
80 | %ptrInt = ptrtoint i32* %p1 to i64 |
81 | ret void |
82 | } |
83 | )IR" ); |
84 | const DataLayout &DL = M->getDataLayout(); |
85 | auto *GV = M->getNamedValue(Name: "f" ); |
86 | ASSERT_TRUE(GV); |
87 | auto *F = dyn_cast<Function>(Val: GV); |
88 | ASSERT_TRUE(F); |
89 | |
90 | Value *P1 = &*F->arg_begin(); |
91 | Value *P2 = F->getArg(i: 1); |
92 | Value *NullPtr = Constant::getNullValue(Ty: P1->getType()); |
93 | auto InstIter = F->front().begin(); |
94 | CallInst *UserOfY = cast<CallInst>(Val: &*InstIter); |
95 | Value *ConstDerefPtr = UserOfY->getArgOperand(i: 0); |
96 | // We cannot replace two pointers in arbitrary instructions unless we are |
97 | // replacing with null, a constant dereferencable pointer or they have the |
98 | // same underlying object. |
99 | EXPECT_FALSE(canReplacePointersIfEqual(ConstDerefPtr, P1, DL)); |
100 | EXPECT_FALSE(canReplacePointersIfEqual(P1, P2, DL)); |
101 | EXPECT_TRUE(canReplacePointersIfEqual(P1, ConstDerefPtr, DL)); |
102 | EXPECT_TRUE(canReplacePointersIfEqual(P1, NullPtr, DL)); |
103 | |
104 | GetElementPtrInst *BasedOnP1 = cast<GetElementPtrInst>(Val: &*++InstIter); |
105 | EXPECT_TRUE(canReplacePointersIfEqual(BasedOnP1, P1, DL)); |
106 | EXPECT_FALSE(canReplacePointersIfEqual(BasedOnP1, P2, DL)); |
107 | |
108 | // We can replace two arbitrary pointers in icmp and ptrtoint instructions. |
109 | auto P1UseIter = P1->use_begin(); |
110 | const Use &PtrToIntUse = *P1UseIter; |
111 | const Use &IcmpUse = *++P1UseIter; |
112 | const Use &GEPUse = *++P1UseIter; |
113 | EXPECT_FALSE(canReplacePointersInUseIfEqual(GEPUse, P2, DL)); |
114 | EXPECT_TRUE(canReplacePointersInUseIfEqual(PtrToIntUse, P2, DL)); |
115 | EXPECT_TRUE(canReplacePointersInUseIfEqual(IcmpUse, P2, DL)); |
116 | } |
117 | |