mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
2d5e031754
"external" AA wrapper pass. This is a generic hook that can be used to thread custom code into the primary AAResultsWrapperPass for the legacy pass manager in order to allow it to merge external AA results into the AA results it is building. It does this by threading in a raw callback and so it is *very* powerful and should serve almost any use case I have come up with for extending the set of alias analyses used. The only thing not well supported here is using a *different order* of alias analyses. That form of extension *is* supportable with the new pass manager, and I can make the callback structure here more elaborate to support it in the legacy pass manager if this is a critical use case that people are already depending on, but the only use cases I have heard of thus far should be reasonably satisfied by this simpler extension mechanism. It is hard to test this using normal facilities (the built-in AAs don't use this for obvious reasons) so I've written a fairly extensive set of custom passes in the alias analysis unit test that should be an excellent test case because it models the out-of-tree users: it adds a totally custom AA to the system. This should also serve as a reasonably good example and guide for out-of-tree users to follow in order to rig up their existing alias analyses. No support in opt for commandline control is provided here however. I'm really unhappy with the kind of contortions that would be required to support that. It would fully re-introduce the analysis group self-recursion kind of patterns. =/ I've heard from out-of-tree users that this will unblock their use cases with extending AAs on top of the new infrastructure and let us retain the new analysis-group-free-world. Differential Revision: http://reviews.llvm.org/D13418 llvm-svn: 250894
257 lines
8.4 KiB
C++
257 lines
8.4 KiB
C++
//===--- AliasAnalysisTest.cpp - Mixed TBAA unit tests --------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Analysis/AliasAnalysis.h"
|
|
#include "llvm/ADT/SetVector.h"
|
|
#include "llvm/Analysis/AssumptionCache.h"
|
|
#include "llvm/Analysis/BasicAliasAnalysis.h"
|
|
#include "llvm/Analysis/TargetLibraryInfo.h"
|
|
#include "llvm/AsmParser/Parser.h"
|
|
#include "llvm/IR/Constants.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/InstIterator.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/LegacyPassManager.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
// Set up some test passes.
|
|
namespace llvm {
|
|
void initializeAATestPassPass(PassRegistry&);
|
|
void initializeTestCustomAAWrapperPassPass(PassRegistry&);
|
|
}
|
|
|
|
namespace {
|
|
struct AATestPass : FunctionPass {
|
|
static char ID;
|
|
AATestPass() : FunctionPass(ID) {
|
|
initializeAATestPassPass(*PassRegistry::getPassRegistry());
|
|
}
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.addRequired<AAResultsWrapperPass>();
|
|
AU.setPreservesAll();
|
|
}
|
|
|
|
bool runOnFunction(Function &F) override {
|
|
AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
|
|
|
|
SetVector<Value *> Pointers;
|
|
for (Argument &A : F.args())
|
|
if (A.getType()->isPointerTy())
|
|
Pointers.insert(&A);
|
|
for (Instruction &I : instructions(F))
|
|
if (I.getType()->isPointerTy())
|
|
Pointers.insert(&I);
|
|
|
|
for (Value *P1 : Pointers)
|
|
for (Value *P2 : Pointers)
|
|
(void)AA.alias(P1, MemoryLocation::UnknownSize, P2,
|
|
MemoryLocation::UnknownSize);
|
|
|
|
return false;
|
|
}
|
|
};
|
|
}
|
|
|
|
char AATestPass::ID = 0;
|
|
INITIALIZE_PASS_BEGIN(AATestPass, "aa-test-pas", "Alias Analysis Test Pass",
|
|
false, true)
|
|
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
|
|
INITIALIZE_PASS_END(AATestPass, "aa-test-pass", "Alias Analysis Test Pass",
|
|
false, true)
|
|
|
|
namespace {
|
|
/// A test customizable AA result. It merely accepts a callback to run whenever
|
|
/// it receives an alias query. Useful for testing that a particular AA result
|
|
/// is reached.
|
|
struct TestCustomAAResult : AAResultBase<TestCustomAAResult> {
|
|
friend AAResultBase<TestCustomAAResult>;
|
|
|
|
std::function<void()> CB;
|
|
|
|
explicit TestCustomAAResult(const TargetLibraryInfo &TLI,
|
|
std::function<void()> CB)
|
|
: AAResultBase(TLI), CB(std::move(CB)) {}
|
|
TestCustomAAResult(TestCustomAAResult &&Arg)
|
|
: AAResultBase(std::move(Arg)), CB(std::move(Arg.CB)) {}
|
|
|
|
bool invalidate(Function &, const PreservedAnalyses &) { return false; }
|
|
|
|
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB) {
|
|
CB();
|
|
return MayAlias;
|
|
}
|
|
};
|
|
}
|
|
|
|
namespace {
|
|
/// A wrapper pass for the legacy pass manager to use with the above custom AA
|
|
/// result.
|
|
class TestCustomAAWrapperPass : public ImmutablePass {
|
|
std::function<void()> CB;
|
|
std::unique_ptr<TestCustomAAResult> Result;
|
|
|
|
public:
|
|
static char ID;
|
|
|
|
explicit TestCustomAAWrapperPass(
|
|
std::function<void()> CB = std::function<void()>())
|
|
: ImmutablePass(ID), CB(std::move(CB)) {
|
|
initializeTestCustomAAWrapperPassPass(*PassRegistry::getPassRegistry());
|
|
}
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesAll();
|
|
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
|
}
|
|
|
|
bool doInitialization(Module &M) override {
|
|
Result.reset(new TestCustomAAResult(
|
|
getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(), std::move(CB)));
|
|
return true;
|
|
}
|
|
|
|
bool doFinalization(Module &M) override {
|
|
Result.reset();
|
|
return true;
|
|
}
|
|
|
|
TestCustomAAResult &getResult() { return *Result; }
|
|
const TestCustomAAResult &getResult() const { return *Result; }
|
|
};
|
|
}
|
|
|
|
char TestCustomAAWrapperPass::ID = 0;
|
|
INITIALIZE_PASS_BEGIN(TestCustomAAWrapperPass, "test-custom-aa",
|
|
"Test Custom AA Wrapper Pass", false, true)
|
|
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
|
|
INITIALIZE_PASS_END(TestCustomAAWrapperPass, "test-custom-aa",
|
|
"Test Custom AA Wrapper Pass", false, true)
|
|
|
|
namespace {
|
|
|
|
class AliasAnalysisTest : public testing::Test {
|
|
protected:
|
|
LLVMContext C;
|
|
Module M;
|
|
TargetLibraryInfoImpl TLII;
|
|
TargetLibraryInfo TLI;
|
|
std::unique_ptr<AssumptionCache> AC;
|
|
std::unique_ptr<BasicAAResult> BAR;
|
|
std::unique_ptr<AAResults> AAR;
|
|
|
|
AliasAnalysisTest() : M("AliasAnalysisTest", C), TLI(TLII) {}
|
|
|
|
AAResults &getAAResults(Function &F) {
|
|
// Reset the Function AA results first to clear out any references.
|
|
AAR.reset(new AAResults());
|
|
|
|
// Build the various AA results and register them.
|
|
AC.reset(new AssumptionCache(F));
|
|
BAR.reset(new BasicAAResult(M.getDataLayout(), TLI, *AC));
|
|
AAR->addAAResult(*BAR);
|
|
|
|
return *AAR;
|
|
}
|
|
};
|
|
|
|
TEST_F(AliasAnalysisTest, getModRefInfo) {
|
|
// Setup function.
|
|
FunctionType *FTy =
|
|
FunctionType::get(Type::getVoidTy(C), std::vector<Type *>(), false);
|
|
auto *F = cast<Function>(M.getOrInsertFunction("f", FTy));
|
|
auto *BB = BasicBlock::Create(C, "entry", F);
|
|
auto IntType = Type::getInt32Ty(C);
|
|
auto PtrType = Type::getInt32PtrTy(C);
|
|
auto *Value = ConstantInt::get(IntType, 42);
|
|
auto *Addr = ConstantPointerNull::get(PtrType);
|
|
|
|
auto *Store1 = new StoreInst(Value, Addr, BB);
|
|
auto *Load1 = new LoadInst(Addr, "load", BB);
|
|
auto *Add1 = BinaryOperator::CreateAdd(Value, Value, "add", BB);
|
|
auto *VAArg1 = new VAArgInst(Addr, PtrType, "vaarg", BB);
|
|
auto *CmpXChg1 = new AtomicCmpXchgInst(Addr, ConstantInt::get(IntType, 0),
|
|
ConstantInt::get(IntType, 1),
|
|
Monotonic, Monotonic, CrossThread, BB);
|
|
auto *AtomicRMW =
|
|
new AtomicRMWInst(AtomicRMWInst::Xchg, Addr, ConstantInt::get(IntType, 1),
|
|
Monotonic, CrossThread, BB);
|
|
|
|
ReturnInst::Create(C, nullptr, BB);
|
|
|
|
auto &AA = getAAResults(*F);
|
|
|
|
// Check basic results
|
|
EXPECT_EQ(AA.getModRefInfo(Store1, MemoryLocation()), MRI_Mod);
|
|
EXPECT_EQ(AA.getModRefInfo(Store1), MRI_Mod);
|
|
EXPECT_EQ(AA.getModRefInfo(Load1, MemoryLocation()), MRI_Ref);
|
|
EXPECT_EQ(AA.getModRefInfo(Load1), MRI_Ref);
|
|
EXPECT_EQ(AA.getModRefInfo(Add1, MemoryLocation()), MRI_NoModRef);
|
|
EXPECT_EQ(AA.getModRefInfo(Add1), MRI_NoModRef);
|
|
EXPECT_EQ(AA.getModRefInfo(VAArg1, MemoryLocation()), MRI_ModRef);
|
|
EXPECT_EQ(AA.getModRefInfo(VAArg1), MRI_ModRef);
|
|
EXPECT_EQ(AA.getModRefInfo(CmpXChg1, MemoryLocation()), MRI_ModRef);
|
|
EXPECT_EQ(AA.getModRefInfo(CmpXChg1), MRI_ModRef);
|
|
EXPECT_EQ(AA.getModRefInfo(AtomicRMW, MemoryLocation()), MRI_ModRef);
|
|
EXPECT_EQ(AA.getModRefInfo(AtomicRMW), MRI_ModRef);
|
|
}
|
|
|
|
class AAPassInfraTest : public testing::Test {
|
|
protected:
|
|
LLVMContext &C;
|
|
SMDiagnostic Err;
|
|
std::unique_ptr<Module> M;
|
|
|
|
public:
|
|
AAPassInfraTest()
|
|
: C(getGlobalContext()),
|
|
M(parseAssemblyString("define i32 @f(i32* %x, i32* %y) {\n"
|
|
"entry:\n"
|
|
" %lx = load i32, i32* %x\n"
|
|
" %ly = load i32, i32* %y\n"
|
|
" %sum = add i32 %lx, %ly\n"
|
|
" ret i32 %sum\n"
|
|
"}\n",
|
|
Err, C)) {
|
|
assert(M && "Failed to build the module!");
|
|
}
|
|
};
|
|
|
|
TEST_F(AAPassInfraTest, injectExternalAA) {
|
|
legacy::PassManager PM;
|
|
|
|
// Register our custom AA's wrapper pass manually.
|
|
bool IsCustomAAQueried = false;
|
|
PM.add(new TestCustomAAWrapperPass([&] { IsCustomAAQueried = true; }));
|
|
|
|
// Now add the external AA wrapper with a lambda which queries for the
|
|
// wrapper around our custom AA and adds it to the results.
|
|
PM.add(createExternalAAWrapperPass([](Pass &P, Function &, AAResults &AAR) {
|
|
if (auto *WrapperPass = P.getAnalysisIfAvailable<TestCustomAAWrapperPass>())
|
|
AAR.addAAResult(WrapperPass->getResult());
|
|
}));
|
|
|
|
// And run a pass that will make some alias queries. This will automatically
|
|
// trigger the rest of the alias analysis stack to be run. It is analagous to
|
|
// building a full pass pipeline with any of the existing pass manager
|
|
// builders.
|
|
PM.add(new AATestPass());
|
|
PM.run(*M);
|
|
|
|
// Finally, ensure that our custom AA was indeed queried.
|
|
EXPECT_TRUE(IsCustomAAQueried);
|
|
}
|
|
|
|
} // end anonymous namspace
|