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"
1024962cedSHiroshi Yamauchi #include "llvm/AsmParser/Parser.h"
11*823b32fbSBill Wendling #include "llvm/IR/Constants.h"
1224962cedSHiroshi Yamauchi #include "llvm/IR/Instructions.h"
1324962cedSHiroshi Yamauchi #include "llvm/IR/LLVMContext.h"
1424962cedSHiroshi Yamauchi #include "llvm/IR/Module.h"
1524962cedSHiroshi Yamauchi #include "llvm/Support/SourceMgr.h"
1624962cedSHiroshi Yamauchi #include "gtest/gtest.h"
1724962cedSHiroshi Yamauchi
1824962cedSHiroshi Yamauchi using namespace llvm;
1924962cedSHiroshi Yamauchi
parseIR(LLVMContext & C,const char * IR)2024962cedSHiroshi Yamauchi static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
2124962cedSHiroshi Yamauchi SMDiagnostic Err;
2224962cedSHiroshi Yamauchi std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
2324962cedSHiroshi Yamauchi if (!Mod)
2424962cedSHiroshi Yamauchi Err.print("AnalysisTests", errs());
2524962cedSHiroshi Yamauchi return Mod;
2624962cedSHiroshi Yamauchi }
2724962cedSHiroshi Yamauchi
TEST(LoadsTest,FindAvailableLoadedValueSameBasePtrConstantOffsetsNullAA)2824962cedSHiroshi Yamauchi TEST(LoadsTest, FindAvailableLoadedValueSameBasePtrConstantOffsetsNullAA) {
2924962cedSHiroshi Yamauchi LLVMContext C;
3024962cedSHiroshi Yamauchi std::unique_ptr<Module> M = parseIR(C,
3124962cedSHiroshi Yamauchi R"IR(
323c51b9e2SAlex Richardson target datalayout = "p:64:64:64:32"
3324962cedSHiroshi Yamauchi %class = type <{ i32, i32 }>
3424962cedSHiroshi Yamauchi
3524962cedSHiroshi Yamauchi define i32 @f() {
3624962cedSHiroshi Yamauchi entry:
3724962cedSHiroshi Yamauchi %o = alloca %class
3824962cedSHiroshi Yamauchi %f1 = getelementptr inbounds %class, %class* %o, i32 0, i32 0
3924962cedSHiroshi Yamauchi store i32 42, i32* %f1
4024962cedSHiroshi Yamauchi %f2 = getelementptr inbounds %class, %class* %o, i32 0, i32 1
4124962cedSHiroshi Yamauchi store i32 43, i32* %f2
4224962cedSHiroshi Yamauchi %v = load i32, i32* %f1
4324962cedSHiroshi Yamauchi ret i32 %v
4424962cedSHiroshi Yamauchi }
4524962cedSHiroshi Yamauchi )IR");
4624962cedSHiroshi Yamauchi auto *GV = M->getNamedValue("f");
4724962cedSHiroshi Yamauchi ASSERT_TRUE(GV);
4824962cedSHiroshi Yamauchi auto *F = dyn_cast<Function>(GV);
4924962cedSHiroshi Yamauchi ASSERT_TRUE(F);
5024962cedSHiroshi Yamauchi Instruction *Inst = &F->front().front();
5124962cedSHiroshi Yamauchi auto *AI = dyn_cast<AllocaInst>(Inst);
5224962cedSHiroshi Yamauchi ASSERT_TRUE(AI);
5324962cedSHiroshi Yamauchi Inst = &*++F->front().rbegin();
5424962cedSHiroshi Yamauchi auto *LI = dyn_cast<LoadInst>(Inst);
5524962cedSHiroshi Yamauchi ASSERT_TRUE(LI);
5624962cedSHiroshi Yamauchi BasicBlock::iterator BBI(LI);
5724962cedSHiroshi Yamauchi Value *Loaded = FindAvailableLoadedValue(
5824962cedSHiroshi Yamauchi LI, LI->getParent(), BBI, 0, nullptr, nullptr);
5924962cedSHiroshi Yamauchi ASSERT_TRUE(Loaded);
6024962cedSHiroshi Yamauchi auto *CI = dyn_cast<ConstantInt>(Loaded);
6124962cedSHiroshi Yamauchi ASSERT_TRUE(CI);
6224962cedSHiroshi Yamauchi ASSERT_TRUE(CI->equalsInt(42));
6324962cedSHiroshi Yamauchi }
640d966ae4SFlorian Hahn
TEST(LoadsTest,CanReplacePointersIfEqual)650d966ae4SFlorian Hahn TEST(LoadsTest, CanReplacePointersIfEqual) {
660d966ae4SFlorian Hahn LLVMContext C;
670d966ae4SFlorian Hahn std::unique_ptr<Module> M = parseIR(C,
680d966ae4SFlorian Hahn R"IR(
690d966ae4SFlorian Hahn @y = common global [1 x i32] zeroinitializer, align 4
700d966ae4SFlorian Hahn @x = common global [1 x i32] zeroinitializer, align 4
710d966ae4SFlorian Hahn
720d966ae4SFlorian Hahn declare void @use(i32*)
730d966ae4SFlorian Hahn
740d966ae4SFlorian Hahn define void @f(i32* %p) {
750d966ae4SFlorian Hahn call void @use(i32* getelementptr inbounds ([1 x i32], [1 x i32]* @y, i64 0, i64 0))
760d966ae4SFlorian Hahn call void @use(i32* getelementptr inbounds (i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @x, i64 0, i64 0), i64 1))
770d966ae4SFlorian Hahn ret void
780d966ae4SFlorian Hahn }
790d966ae4SFlorian Hahn )IR");
800d966ae4SFlorian Hahn const auto &DL = M->getDataLayout();
810d966ae4SFlorian Hahn auto *GV = M->getNamedValue("f");
820d966ae4SFlorian Hahn ASSERT_TRUE(GV);
830d966ae4SFlorian Hahn auto *F = dyn_cast<Function>(GV);
840d966ae4SFlorian Hahn ASSERT_TRUE(F);
850d966ae4SFlorian Hahn
860d966ae4SFlorian Hahn // NOTE: the implementation of canReplacePointersIfEqual is incomplete.
870d966ae4SFlorian Hahn // Currently the only the cases it returns false for are really sound and
880d966ae4SFlorian Hahn // returning true means unknown.
890d966ae4SFlorian Hahn Value *P = &*F->arg_begin();
900d966ae4SFlorian Hahn auto InstIter = F->front().begin();
910d966ae4SFlorian Hahn Value *ConstDerefPtr = *cast<CallInst>(&*InstIter)->arg_begin();
920d966ae4SFlorian Hahn // ConstDerefPtr is a constant pointer that is provably de-referenceable. We
930d966ae4SFlorian Hahn // can replace an arbitrary pointer with it.
940d966ae4SFlorian Hahn EXPECT_TRUE(canReplacePointersIfEqual(P, ConstDerefPtr, DL, nullptr));
950d966ae4SFlorian Hahn
960d966ae4SFlorian Hahn ++InstIter;
970d966ae4SFlorian Hahn Value *ConstUnDerefPtr = *cast<CallInst>(&*InstIter)->arg_begin();
980d966ae4SFlorian Hahn // ConstUndDerefPtr is a constant pointer that is provably not
990d966ae4SFlorian Hahn // de-referenceable. We cannot replace an arbitrary pointer with it.
1000d966ae4SFlorian Hahn EXPECT_FALSE(
1010d966ae4SFlorian Hahn canReplacePointersIfEqual(ConstDerefPtr, ConstUnDerefPtr, DL, nullptr));
1020d966ae4SFlorian Hahn }
103