124962cedSHiroshi Yamauchi //===- LoadsTest.cpp - local load analysis unit tests ---------------------===// 224962cedSHiroshi Yamauchi // 324962cedSHiroshi Yamauchi // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 424962cedSHiroshi Yamauchi // See https://llvm.org/LICENSE.txt for license information. 524962cedSHiroshi Yamauchi // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 624962cedSHiroshi Yamauchi // 724962cedSHiroshi Yamauchi //===----------------------------------------------------------------------===// 824962cedSHiroshi Yamauchi 924962cedSHiroshi Yamauchi #include "llvm/Analysis/Loads.h" 10*ac6061e0SDavid Sherwood #include "llvm/Analysis/AssumptionCache.h" 11*ac6061e0SDavid Sherwood #include "llvm/Analysis/LoopInfo.h" 12*ac6061e0SDavid Sherwood #include "llvm/Analysis/ScalarEvolution.h" 13*ac6061e0SDavid Sherwood #include "llvm/Analysis/TargetLibraryInfo.h" 1424962cedSHiroshi Yamauchi #include "llvm/AsmParser/Parser.h" 15823b32fbSBill Wendling #include "llvm/IR/Constants.h" 16*ac6061e0SDavid Sherwood #include "llvm/IR/Dominators.h" 1724962cedSHiroshi Yamauchi #include "llvm/IR/Instructions.h" 1824962cedSHiroshi Yamauchi #include "llvm/IR/LLVMContext.h" 1924962cedSHiroshi Yamauchi #include "llvm/IR/Module.h" 2024962cedSHiroshi Yamauchi #include "llvm/Support/SourceMgr.h" 2124962cedSHiroshi Yamauchi #include "gtest/gtest.h" 2224962cedSHiroshi Yamauchi 2324962cedSHiroshi Yamauchi using namespace llvm; 2424962cedSHiroshi Yamauchi 2524962cedSHiroshi Yamauchi static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { 2624962cedSHiroshi Yamauchi SMDiagnostic Err; 2724962cedSHiroshi Yamauchi std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C); 2824962cedSHiroshi Yamauchi if (!Mod) 2924962cedSHiroshi Yamauchi Err.print("AnalysisTests", errs()); 3024962cedSHiroshi Yamauchi return Mod; 3124962cedSHiroshi Yamauchi } 3224962cedSHiroshi Yamauchi 3324962cedSHiroshi Yamauchi TEST(LoadsTest, FindAvailableLoadedValueSameBasePtrConstantOffsetsNullAA) { 3424962cedSHiroshi Yamauchi LLVMContext C; 3524962cedSHiroshi Yamauchi std::unique_ptr<Module> M = parseIR(C, 3624962cedSHiroshi Yamauchi R"IR( 373c51b9e2SAlex Richardson target datalayout = "p:64:64:64:32" 3824962cedSHiroshi Yamauchi %class = type <{ i32, i32 }> 3924962cedSHiroshi Yamauchi 4024962cedSHiroshi Yamauchi define i32 @f() { 4124962cedSHiroshi Yamauchi entry: 4224962cedSHiroshi Yamauchi %o = alloca %class 4324962cedSHiroshi Yamauchi %f1 = getelementptr inbounds %class, %class* %o, i32 0, i32 0 4424962cedSHiroshi Yamauchi store i32 42, i32* %f1 4524962cedSHiroshi Yamauchi %f2 = getelementptr inbounds %class, %class* %o, i32 0, i32 1 4624962cedSHiroshi Yamauchi store i32 43, i32* %f2 4724962cedSHiroshi Yamauchi %v = load i32, i32* %f1 4824962cedSHiroshi Yamauchi ret i32 %v 4924962cedSHiroshi Yamauchi } 5024962cedSHiroshi Yamauchi )IR"); 5124962cedSHiroshi Yamauchi auto *GV = M->getNamedValue("f"); 5224962cedSHiroshi Yamauchi ASSERT_TRUE(GV); 5324962cedSHiroshi Yamauchi auto *F = dyn_cast<Function>(GV); 5424962cedSHiroshi Yamauchi ASSERT_TRUE(F); 5524962cedSHiroshi Yamauchi Instruction *Inst = &F->front().front(); 5624962cedSHiroshi Yamauchi auto *AI = dyn_cast<AllocaInst>(Inst); 5724962cedSHiroshi Yamauchi ASSERT_TRUE(AI); 5824962cedSHiroshi Yamauchi Inst = &*++F->front().rbegin(); 5924962cedSHiroshi Yamauchi auto *LI = dyn_cast<LoadInst>(Inst); 6024962cedSHiroshi Yamauchi ASSERT_TRUE(LI); 6124962cedSHiroshi Yamauchi BasicBlock::iterator BBI(LI); 6224962cedSHiroshi Yamauchi Value *Loaded = FindAvailableLoadedValue( 6324962cedSHiroshi Yamauchi LI, LI->getParent(), BBI, 0, nullptr, nullptr); 6424962cedSHiroshi Yamauchi ASSERT_TRUE(Loaded); 6524962cedSHiroshi Yamauchi auto *CI = dyn_cast<ConstantInt>(Loaded); 6624962cedSHiroshi Yamauchi ASSERT_TRUE(CI); 6724962cedSHiroshi Yamauchi ASSERT_TRUE(CI->equalsInt(42)); 6824962cedSHiroshi Yamauchi } 690d966ae4SFlorian Hahn 700d966ae4SFlorian Hahn TEST(LoadsTest, CanReplacePointersIfEqual) { 710d966ae4SFlorian Hahn LLVMContext C; 720d966ae4SFlorian Hahn std::unique_ptr<Module> M = parseIR(C, 730d966ae4SFlorian Hahn R"IR( 740d966ae4SFlorian Hahn @y = common global [1 x i32] zeroinitializer, align 4 750d966ae4SFlorian Hahn @x = common global [1 x i32] zeroinitializer, align 4 760d966ae4SFlorian Hahn declare void @use(i32*) 770d966ae4SFlorian Hahn 78b10e4b82SUsman Nadeem define void @f(i32* %p1, i32* %p2, i64 %i) { 790d966ae4SFlorian Hahn call void @use(i32* getelementptr inbounds ([1 x i32], [1 x i32]* @y, i64 0, i64 0)) 80b10e4b82SUsman Nadeem 81b10e4b82SUsman Nadeem %p1_idx = getelementptr inbounds i32, i32* %p1, i64 %i 82b10e4b82SUsman Nadeem call void @use(i32* %p1_idx) 83b10e4b82SUsman Nadeem 84b10e4b82SUsman Nadeem %icmp = icmp eq i32* %p1, getelementptr inbounds ([1 x i32], [1 x i32]* @y, i64 0, i64 0) 85b10e4b82SUsman Nadeem %ptrInt = ptrtoint i32* %p1 to i64 860d966ae4SFlorian Hahn ret void 870d966ae4SFlorian Hahn } 880d966ae4SFlorian Hahn )IR"); 89b10e4b82SUsman Nadeem const DataLayout &DL = M->getDataLayout(); 900d966ae4SFlorian Hahn auto *GV = M->getNamedValue("f"); 910d966ae4SFlorian Hahn ASSERT_TRUE(GV); 920d966ae4SFlorian Hahn auto *F = dyn_cast<Function>(GV); 930d966ae4SFlorian Hahn ASSERT_TRUE(F); 940d966ae4SFlorian Hahn 95b10e4b82SUsman Nadeem Value *P1 = &*F->arg_begin(); 96b10e4b82SUsman Nadeem Value *P2 = F->getArg(1); 97b10e4b82SUsman Nadeem Value *NullPtr = Constant::getNullValue(P1->getType()); 980d966ae4SFlorian Hahn auto InstIter = F->front().begin(); 99b10e4b82SUsman Nadeem CallInst *UserOfY = cast<CallInst>(&*InstIter); 100b10e4b82SUsman Nadeem Value *ConstDerefPtr = UserOfY->getArgOperand(0); 101b10e4b82SUsman Nadeem // We cannot replace two pointers in arbitrary instructions unless we are 102b10e4b82SUsman Nadeem // replacing with null, a constant dereferencable pointer or they have the 103b10e4b82SUsman Nadeem // same underlying object. 104b10e4b82SUsman Nadeem EXPECT_FALSE(canReplacePointersIfEqual(ConstDerefPtr, P1, DL)); 105b10e4b82SUsman Nadeem EXPECT_FALSE(canReplacePointersIfEqual(P1, P2, DL)); 106b10e4b82SUsman Nadeem EXPECT_TRUE(canReplacePointersIfEqual(P1, ConstDerefPtr, DL)); 107b10e4b82SUsman Nadeem EXPECT_TRUE(canReplacePointersIfEqual(P1, NullPtr, DL)); 1080d966ae4SFlorian Hahn 109b10e4b82SUsman Nadeem GetElementPtrInst *BasedOnP1 = cast<GetElementPtrInst>(&*++InstIter); 110b10e4b82SUsman Nadeem EXPECT_TRUE(canReplacePointersIfEqual(BasedOnP1, P1, DL)); 111b10e4b82SUsman Nadeem EXPECT_FALSE(canReplacePointersIfEqual(BasedOnP1, P2, DL)); 112b10e4b82SUsman Nadeem 113b10e4b82SUsman Nadeem // We can replace two arbitrary pointers in icmp and ptrtoint instructions. 114b10e4b82SUsman Nadeem auto P1UseIter = P1->use_begin(); 115b10e4b82SUsman Nadeem const Use &PtrToIntUse = *P1UseIter; 116b10e4b82SUsman Nadeem const Use &IcmpUse = *++P1UseIter; 117b10e4b82SUsman Nadeem const Use &GEPUse = *++P1UseIter; 118b10e4b82SUsman Nadeem EXPECT_FALSE(canReplacePointersInUseIfEqual(GEPUse, P2, DL)); 119b10e4b82SUsman Nadeem EXPECT_TRUE(canReplacePointersInUseIfEqual(PtrToIntUse, P2, DL)); 120b10e4b82SUsman Nadeem EXPECT_TRUE(canReplacePointersInUseIfEqual(IcmpUse, P2, DL)); 1210d966ae4SFlorian Hahn } 122*ac6061e0SDavid Sherwood 123*ac6061e0SDavid Sherwood TEST(LoadsTest, IsDerefReadOnlyLoop) { 124*ac6061e0SDavid Sherwood LLVMContext C; 125*ac6061e0SDavid Sherwood std::unique_ptr<Module> M = parseIR(C, 126*ac6061e0SDavid Sherwood R"IR( 127*ac6061e0SDavid Sherwood define i64 @f1() { 128*ac6061e0SDavid Sherwood entry: 129*ac6061e0SDavid Sherwood %p1 = alloca [1024 x i8] 130*ac6061e0SDavid Sherwood %p2 = alloca [1024 x i8] 131*ac6061e0SDavid Sherwood br label %loop 132*ac6061e0SDavid Sherwood 133*ac6061e0SDavid Sherwood loop: 134*ac6061e0SDavid Sherwood %index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ] 135*ac6061e0SDavid Sherwood %arrayidx = getelementptr inbounds i8, ptr %p1, i64 %index 136*ac6061e0SDavid Sherwood %ld1 = load i8, ptr %arrayidx, align 1 137*ac6061e0SDavid Sherwood %arrayidx1 = getelementptr inbounds i8, ptr %p2, i64 %index 138*ac6061e0SDavid Sherwood %ld2 = load i8, ptr %arrayidx1, align 1 139*ac6061e0SDavid Sherwood %cmp3 = icmp eq i8 %ld1, %ld2 140*ac6061e0SDavid Sherwood br i1 %cmp3, label %loop.inc, label %loop.end 141*ac6061e0SDavid Sherwood 142*ac6061e0SDavid Sherwood loop.inc: 143*ac6061e0SDavid Sherwood %index.next = add i64 %index, 1 144*ac6061e0SDavid Sherwood %exitcond = icmp ne i64 %index.next, 67 145*ac6061e0SDavid Sherwood br i1 %exitcond, label %loop, label %loop.end 146*ac6061e0SDavid Sherwood 147*ac6061e0SDavid Sherwood loop.end: 148*ac6061e0SDavid Sherwood %retval = phi i64 [ %index, %loop ], [ 67, %loop.inc ] 149*ac6061e0SDavid Sherwood ret i64 %retval 150*ac6061e0SDavid Sherwood } 151*ac6061e0SDavid Sherwood 152*ac6061e0SDavid Sherwood define i64 @f2(ptr %p1) { 153*ac6061e0SDavid Sherwood entry: 154*ac6061e0SDavid Sherwood %p2 = alloca [1024 x i8] 155*ac6061e0SDavid Sherwood br label %loop 156*ac6061e0SDavid Sherwood 157*ac6061e0SDavid Sherwood loop: 158*ac6061e0SDavid Sherwood %index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ] 159*ac6061e0SDavid Sherwood %arrayidx = getelementptr inbounds i8, ptr %p1, i64 %index 160*ac6061e0SDavid Sherwood %ld1 = load i8, ptr %arrayidx, align 1 161*ac6061e0SDavid Sherwood %arrayidx1 = getelementptr inbounds i8, ptr %p2, i64 %index 162*ac6061e0SDavid Sherwood %ld2 = load i8, ptr %arrayidx1, align 1 163*ac6061e0SDavid Sherwood %cmp3 = icmp eq i8 %ld1, %ld2 164*ac6061e0SDavid Sherwood br i1 %cmp3, label %loop.inc, label %loop.end 165*ac6061e0SDavid Sherwood 166*ac6061e0SDavid Sherwood loop.inc: 167*ac6061e0SDavid Sherwood %index.next = add i64 %index, 1 168*ac6061e0SDavid Sherwood %exitcond = icmp ne i64 %index.next, 67 169*ac6061e0SDavid Sherwood br i1 %exitcond, label %loop, label %loop.end 170*ac6061e0SDavid Sherwood 171*ac6061e0SDavid Sherwood loop.end: 172*ac6061e0SDavid Sherwood %retval = phi i64 [ %index, %loop ], [ 67, %loop.inc ] 173*ac6061e0SDavid Sherwood ret i64 %retval 174*ac6061e0SDavid Sherwood } 175*ac6061e0SDavid Sherwood )IR"); 176*ac6061e0SDavid Sherwood auto *GV1 = M->getNamedValue("f1"); 177*ac6061e0SDavid Sherwood auto *GV2 = M->getNamedValue("f2"); 178*ac6061e0SDavid Sherwood ASSERT_TRUE(GV1 && GV2); 179*ac6061e0SDavid Sherwood auto *F1 = dyn_cast<Function>(GV1); 180*ac6061e0SDavid Sherwood auto *F2 = dyn_cast<Function>(GV2); 181*ac6061e0SDavid Sherwood ASSERT_TRUE(F1 && F2); 182*ac6061e0SDavid Sherwood 183*ac6061e0SDavid Sherwood TargetLibraryInfoImpl TLII; 184*ac6061e0SDavid Sherwood TargetLibraryInfo TLI(TLII); 185*ac6061e0SDavid Sherwood 186*ac6061e0SDavid Sherwood auto IsDerefReadOnlyLoop = [&TLI](Function *F) -> bool { 187*ac6061e0SDavid Sherwood AssumptionCache AC(*F); 188*ac6061e0SDavid Sherwood DominatorTree DT(*F); 189*ac6061e0SDavid Sherwood LoopInfo LI(DT); 190*ac6061e0SDavid Sherwood ScalarEvolution SE(*F, TLI, AC, DT, LI); 191*ac6061e0SDavid Sherwood 192*ac6061e0SDavid Sherwood Function::iterator FI = F->begin(); 193*ac6061e0SDavid Sherwood // First basic block is entry - skip it. 194*ac6061e0SDavid Sherwood BasicBlock *Header = &*(++FI); 195*ac6061e0SDavid Sherwood assert(Header->getName() == "loop"); 196*ac6061e0SDavid Sherwood Loop *L = LI.getLoopFor(Header); 197*ac6061e0SDavid Sherwood 198*ac6061e0SDavid Sherwood return isDereferenceableReadOnlyLoop(L, &SE, &DT, &AC); 199*ac6061e0SDavid Sherwood }; 200*ac6061e0SDavid Sherwood 201*ac6061e0SDavid Sherwood ASSERT_TRUE(IsDerefReadOnlyLoop(F1)); 202*ac6061e0SDavid Sherwood ASSERT_FALSE(IsDerefReadOnlyLoop(F2)); 203*ac6061e0SDavid Sherwood } 204