mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
2248875209
This patch adds an initial, incomeplete and unsound implementation of canReplacePointersIfEqual to check if a pointer value A can be replaced by another pointer value B, that are deemed to be equivalent through some means (e.g. information from conditions). Note that is in general not sound to blindly replace pointers based on equality, for example if they are based on different underlying objects. LLVM's memory model is not completely settled as of now; see https://bugs.llvm.org/show_bug.cgi?id=34548 for a more detailed discussion. The initial version of canReplacePointersIfEqual only rejects a very specific case: replacing a pointer with a constant expression that is not dereferenceable. Such a replacement is problematic and can be restricted relatively easily without impacting most code. Using it to limit replacements in GVN/SCCP/CVP only results in small differences in 7 programs out of MultiSource/SPEC2000/SPEC2006 on X86 with -O3 -flto. This patch is supposed to be an initial step to improve the current situation and the helper should be made stricter in the future. But this will require careful analysis of the impact on performance. Reviewed By: aqjune Differential Revision: https://reviews.llvm.org/D85524
101 lines
3.3 KiB
C++
101 lines
3.3 KiB
C++
//===- LoadsTest.cpp - local load analysis unit tests ---------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Analysis/Loads.h"
|
|
#include "llvm/AsmParser/Parser.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
|
|
SMDiagnostic Err;
|
|
std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
|
|
if (!Mod)
|
|
Err.print("AnalysisTests", errs());
|
|
return Mod;
|
|
}
|
|
|
|
TEST(LoadsTest, FindAvailableLoadedValueSameBasePtrConstantOffsetsNullAA) {
|
|
LLVMContext C;
|
|
std::unique_ptr<Module> M = parseIR(C,
|
|
R"IR(
|
|
%class = type <{ i32, i32 }>
|
|
|
|
define i32 @f() {
|
|
entry:
|
|
%o = alloca %class
|
|
%f1 = getelementptr inbounds %class, %class* %o, i32 0, i32 0
|
|
store i32 42, i32* %f1
|
|
%f2 = getelementptr inbounds %class, %class* %o, i32 0, i32 1
|
|
store i32 43, i32* %f2
|
|
%v = load i32, i32* %f1
|
|
ret i32 %v
|
|
}
|
|
)IR");
|
|
auto *GV = M->getNamedValue("f");
|
|
ASSERT_TRUE(GV);
|
|
auto *F = dyn_cast<Function>(GV);
|
|
ASSERT_TRUE(F);
|
|
Instruction *Inst = &F->front().front();
|
|
auto *AI = dyn_cast<AllocaInst>(Inst);
|
|
ASSERT_TRUE(AI);
|
|
Inst = &*++F->front().rbegin();
|
|
auto *LI = dyn_cast<LoadInst>(Inst);
|
|
ASSERT_TRUE(LI);
|
|
BasicBlock::iterator BBI(LI);
|
|
Value *Loaded = FindAvailableLoadedValue(
|
|
LI, LI->getParent(), BBI, 0, nullptr, nullptr);
|
|
ASSERT_TRUE(Loaded);
|
|
auto *CI = dyn_cast<ConstantInt>(Loaded);
|
|
ASSERT_TRUE(CI);
|
|
ASSERT_TRUE(CI->equalsInt(42));
|
|
}
|
|
|
|
TEST(LoadsTest, CanReplacePointersIfEqual) {
|
|
LLVMContext C;
|
|
std::unique_ptr<Module> M = parseIR(C,
|
|
R"IR(
|
|
@y = common global [1 x i32] zeroinitializer, align 4
|
|
@x = common global [1 x i32] zeroinitializer, align 4
|
|
|
|
declare void @use(i32*)
|
|
|
|
define void @f(i32* %p) {
|
|
call void @use(i32* getelementptr inbounds ([1 x i32], [1 x i32]* @y, i64 0, i64 0))
|
|
call void @use(i32* getelementptr inbounds (i32, i32* getelementptr inbounds ([1 x i32], [1 x i32]* @x, i64 0, i64 0), i64 1))
|
|
ret void
|
|
}
|
|
)IR");
|
|
const auto &DL = M->getDataLayout();
|
|
auto *GV = M->getNamedValue("f");
|
|
ASSERT_TRUE(GV);
|
|
auto *F = dyn_cast<Function>(GV);
|
|
ASSERT_TRUE(F);
|
|
|
|
// NOTE: the implementation of canReplacePointersIfEqual is incomplete.
|
|
// Currently the only the cases it returns false for are really sound and
|
|
// returning true means unknown.
|
|
Value *P = &*F->arg_begin();
|
|
auto InstIter = F->front().begin();
|
|
Value *ConstDerefPtr = *cast<CallInst>(&*InstIter)->arg_begin();
|
|
// ConstDerefPtr is a constant pointer that is provably de-referenceable. We
|
|
// can replace an arbitrary pointer with it.
|
|
EXPECT_TRUE(canReplacePointersIfEqual(P, ConstDerefPtr, DL, nullptr));
|
|
|
|
++InstIter;
|
|
Value *ConstUnDerefPtr = *cast<CallInst>(&*InstIter)->arg_begin();
|
|
// ConstUndDerefPtr is a constant pointer that is provably not
|
|
// de-referenceable. We cannot replace an arbitrary pointer with it.
|
|
EXPECT_FALSE(
|
|
canReplacePointersIfEqual(ConstDerefPtr, ConstUnDerefPtr, DL, nullptr));
|
|
}
|