#include "llvm/IR/PassManager.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManagerImpl.h"
#include "llvm/Passes/StandardInstrumentations.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Transforms/Scalar/SimplifyCFG.h"
#include "gtest/gtest.h"
usingnamespacellvm;
namespace {
class TestFunctionAnalysis : public AnalysisInfoMixin<TestFunctionAnalysis> { … };
AnalysisKey TestFunctionAnalysis::Key;
class TestModuleAnalysis : public AnalysisInfoMixin<TestModuleAnalysis> { … };
AnalysisKey TestModuleAnalysis::Key;
struct TestModulePass : PassInfoMixin<TestModulePass> { … };
struct TestPreservingModulePass : PassInfoMixin<TestPreservingModulePass> { … };
struct TestFunctionPass : PassInfoMixin<TestFunctionPass> { … };
struct TestInvalidationFunctionPass
: PassInfoMixin<TestInvalidationFunctionPass> { … };
std::unique_ptr<Module> parseIR(LLVMContext &Context, const char *IR) { … }
class PassManagerTest : public ::testing::Test { … };
TEST(PreservedAnalysesTest, Basic) { … }
TEST(PreservedAnalysesTest, Preserve) { … }
TEST(PreservedAnalysesTest, PreserveSets) { … }
TEST(PreservedAnalysisTest, Intersect) { … }
TEST(PreservedAnalysisTest, Abandon) { … }
TEST_F(PassManagerTest, Basic) { … }
CustomizedAnalysisManager;
CustomizedPassManager;
class CustomizedAnalysis : public AnalysisInfoMixin<CustomizedAnalysis> { … };
AnalysisKey CustomizedAnalysis::Key;
struct CustomizedPass : PassInfoMixin<CustomizedPass> { … };
TEST_F(PassManagerTest, CustomizedPassManagerArgs) { … }
struct TestIndirectFunctionAnalysis
: public AnalysisInfoMixin<TestIndirectFunctionAnalysis> { … };
AnalysisKey TestIndirectFunctionAnalysis::Key;
struct TestDoublyIndirectFunctionAnalysis
: public AnalysisInfoMixin<TestDoublyIndirectFunctionAnalysis> { … };
AnalysisKey TestDoublyIndirectFunctionAnalysis::Key;
struct LambdaPass : public PassInfoMixin<LambdaPass> { … };
TEST_F(PassManagerTest, IndirectAnalysisInvalidation) { … }
TEST_F(PassManagerTest, FunctionPassCFGChecker) { … }
struct TestSimplifyCFGInvalidatingAnalysisPass
: PassInfoMixin<TestSimplifyCFGInvalidatingAnalysisPass> { … };
TEST_F(PassManagerTest, FunctionPassCFGCheckerInvalidateAnalysis) { … }
struct TestSimplifyCFGWrapperPass : PassInfoMixin<TestSimplifyCFGWrapperPass> { … };
TEST_F(PassManagerTest, FunctionPassCFGCheckerWrapped) { … }
#ifdef EXPENSIVE_CHECKS
struct WrongFunctionPass : PassInfoMixin<WrongFunctionPass> {
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
F.getEntryBlock().begin()->eraseFromParent();
return PreservedAnalyses::all();
}
static StringRef name() { return "WrongFunctionPass"; }
};
TEST_F(PassManagerTest, FunctionPassMissedFunctionAnalysisInvalidation) {
LLVMContext Context;
auto M = parseIR(Context, "define void @foo() {\n"
" %a = add i32 0, 0\n"
" ret void\n"
"}\n");
FunctionAnalysisManager FAM;
ModuleAnalysisManager MAM;
PassInstrumentationCallbacks PIC;
StandardInstrumentations SI(M->getContext(), false);
SI.registerCallbacks(PIC, &MAM);
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
FunctionPassManager FPM;
FPM.addPass(WrongFunctionPass());
auto *F = M->getFunction("foo");
EXPECT_DEATH(FPM.run(*F, FAM), "Function @foo changed by WrongFunctionPass without invalidating analyses");
}
struct WrongModulePass : PassInfoMixin<WrongModulePass> {
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {
for (Function &F : M)
F.getEntryBlock().begin()->eraseFromParent();
PreservedAnalyses PA;
PA.preserveSet<AllAnalysesOn<Function>>();
PA.preserve<FunctionAnalysisManagerModuleProxy>();
return PA;
}
static StringRef name() { return "WrongModulePass"; }
};
TEST_F(PassManagerTest, ModulePassMissedFunctionAnalysisInvalidation) {
LLVMContext Context;
auto M = parseIR(Context, "define void @foo() {\n"
" %a = add i32 0, 0\n"
" ret void\n"
"}\n");
FunctionAnalysisManager FAM;
ModuleAnalysisManager MAM;
PassInstrumentationCallbacks PIC;
StandardInstrumentations SI(M->getContext(), false);
SI.registerCallbacks(PIC, &MAM);
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
ModulePassManager MPM;
MPM.addPass(WrongModulePass());
EXPECT_DEATH(
MPM.run(*M, MAM),
"Function @foo changed by WrongModulePass without invalidating analyses");
}
struct WrongModulePass2 : PassInfoMixin<WrongModulePass2> {
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {
for (Function &F : M)
F.getEntryBlock().begin()->eraseFromParent();
PreservedAnalyses PA;
PA.preserveSet<AllAnalysesOn<Module>>();
PA.abandon<FunctionAnalysisManagerModuleProxy>();
return PA;
}
static StringRef name() { return "WrongModulePass2"; }
};
TEST_F(PassManagerTest, ModulePassMissedModuleAnalysisInvalidation) {
LLVMContext Context;
auto M = parseIR(Context, "define void @foo() {\n"
" %a = add i32 0, 0\n"
" ret void\n"
"}\n");
FunctionAnalysisManager FAM;
ModuleAnalysisManager MAM;
PassInstrumentationCallbacks PIC;
StandardInstrumentations SI(M->getContext(), false);
SI.registerCallbacks(PIC, &MAM);
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
MAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
FAM.registerPass([&] { return PassInstrumentationAnalysis(&PIC); });
FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
ModulePassManager MPM;
MPM.addPass(WrongModulePass2());
EXPECT_DEATH(
MPM.run(*M, MAM),
"Module changed by WrongModulePass2 without invalidating analyses");
}
#endif
}