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(IR, Err, C); 23 if (!Mod) 24 Err.print("AnalysisTests", errs()); 25 return Mod; 26 } 27 28 TEST(LoadsTest, FindAvailableLoadedValueSameBasePtrConstantOffsetsNullAA) { 29 LLVMContext C; 30 std::unique_ptr<Module> M = parseIR(C, 31 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("f"); 47 ASSERT_TRUE(GV); 48 auto *F = dyn_cast<Function>(GV); 49 ASSERT_TRUE(F); 50 Instruction *Inst = &F->front().front(); 51 auto *AI = dyn_cast<AllocaInst>(Inst); 52 ASSERT_TRUE(AI); 53 Inst = &*++F->front().rbegin(); 54 auto *LI = dyn_cast<LoadInst>(Inst); 55 ASSERT_TRUE(LI); 56 BasicBlock::iterator BBI(LI); 57 Value *Loaded = FindAvailableLoadedValue( 58 LI, LI->getParent(), BBI, 0, nullptr, nullptr); 59 ASSERT_TRUE(Loaded); 60 auto *CI = dyn_cast<ConstantInt>(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 R"IR( 69 @y = common global [1 x i32] zeroinitializer, align 4 70 @x = common global [1 x i32] zeroinitializer, align 4 71 72 declare void @use(i32*) 73 74 define void @f(i32* %p) { 75 call void @use(i32* getelementptr inbounds ([1 x i32], [1 x i32]* @y, i64 0, i64 0)) 76 call void @use(i32* getelementptr inbounds (i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @x, i64 0, i64 0), i64 1)) 77 ret void 78 } 79 )IR"); 80 const auto &DL = M->getDataLayout(); 81 auto *GV = M->getNamedValue("f"); 82 ASSERT_TRUE(GV); 83 auto *F = dyn_cast<Function>(GV); 84 ASSERT_TRUE(F); 85 86 // NOTE: the implementation of canReplacePointersIfEqual is incomplete. 87 // Currently the only the cases it returns false for are really sound and 88 // returning true means unknown. 89 Value *P = &*F->arg_begin(); 90 auto InstIter = F->front().begin(); 91 Value *ConstDerefPtr = *cast<CallInst>(&*InstIter)->arg_begin(); 92 // ConstDerefPtr is a constant pointer that is provably de-referenceable. We 93 // can replace an arbitrary pointer with it. 94 EXPECT_TRUE(canReplacePointersIfEqual(P, ConstDerefPtr, DL, nullptr)); 95 96 ++InstIter; 97 Value *ConstUnDerefPtr = *cast<CallInst>(&*InstIter)->arg_begin(); 98 // ConstUndDerefPtr is a constant pointer that is provably not 99 // de-referenceable. We cannot replace an arbitrary pointer with it. 100 EXPECT_FALSE( 101 canReplacePointersIfEqual(ConstDerefPtr, ConstUnDerefPtr, DL, nullptr)); 102 } 103