#include "llvm/Testing/Support/Error.h"
#include <functional>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <llvm/ADT/Any.h>
#include <llvm/Analysis/CGSCCPassManager.h>
#include <llvm/Analysis/LoopAnalysisManager.h>
#include <llvm/AsmParser/Parser.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/PassInstrumentation.h>
#include <llvm/IR/PassManager.h>
#include <llvm/Passes/PassBuilder.h>
#include <llvm/Support/Regex.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Transforms/Scalar/LoopPassManager.h>
using namespace llvm;
namespace {
using testing::AnyNumber;
using testing::DoAll;
using testing::Not;
using testing::Return;
using testing::WithArgs;
using testing::_;
template <typename DerivedT, typename IRUnitT,
typename AnalysisManagerT = AnalysisManager<IRUnitT>,
typename... ExtraArgTs>
class MockAnalysisHandleBase {
public:
class Analysis : public AnalysisInfoMixin<Analysis> {
friend AnalysisInfoMixin<Analysis>;
friend MockAnalysisHandleBase;
static AnalysisKey Key;
DerivedT *Handle;
Analysis(DerivedT &Handle) : Handle(&Handle) {
static_assert(std::is_base_of<MockAnalysisHandleBase, DerivedT>::value,
"Must pass the derived type to this template!");
}
public:
class Result {
friend MockAnalysisHandleBase;
DerivedT *Handle;
Result(DerivedT &Handle) : Handle(&Handle) {}
public:
bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA,
typename AnalysisManagerT::Invalidator &Inv) {
return Handle->invalidate(IR, PA, Inv);
}
};
Result run(IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs... ExtraArgs) {
return Handle->run(IR, AM, ExtraArgs...);
}
};
Analysis getAnalysis() { return Analysis(static_cast<DerivedT &>(*this)); }
typename Analysis::Result getResult() {
return typename Analysis::Result(static_cast<DerivedT &>(*this));
}
static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
protected:
static bool invalidateCallback(IRUnitT &IR, const PreservedAnalyses &PA,
typename AnalysisManagerT::Invalidator &Inv) {
auto PAC = PA.template getChecker<Analysis>();
return !PAC.preserved() &&
!PAC.template preservedSet<AllAnalysesOn<IRUnitT>>();
}
void setDefaults() {
ON_CALL(static_cast<DerivedT &>(*this),
run(_, _, testing::Matcher<ExtraArgTs>(_)...))
.WillByDefault(Return(this->getResult()));
ON_CALL(static_cast<DerivedT &>(*this), invalidate(_, _, _))
.WillByDefault(&invalidateCallback);
}
};
template <typename DerivedT, typename IRUnitT, typename AnalysisManagerT,
typename... ExtraArgTs>
AnalysisKey MockAnalysisHandleBase<DerivedT, IRUnitT, AnalysisManagerT,
ExtraArgTs...>::Analysis::Key;
template <typename DerivedT, typename IRUnitT,
typename AnalysisManagerT = AnalysisManager<IRUnitT>,
typename... ExtraArgTs>
class MockPassHandleBase {
public:
class Pass : public PassInfoMixin<Pass> {
friend MockPassHandleBase;
DerivedT *Handle;
Pass(DerivedT &Handle) : Handle(&Handle) {
static_assert(std::is_base_of<MockPassHandleBase, DerivedT>::value,
"Must pass the derived type to this template!");
}
public:
PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
ExtraArgTs... ExtraArgs) {
return Handle->run(IR, AM, ExtraArgs...);
}
};
static StringRef getName() { return llvm::getTypeName<DerivedT>(); }
Pass getPass() { return Pass(static_cast<DerivedT &>(*this)); }
protected:
void setDefaults() {
ON_CALL(static_cast<DerivedT &>(*this),
run(_, _, testing::Matcher<ExtraArgTs>(_)...))
.WillByDefault(Return(PreservedAnalyses::all()));
}
};
template <typename IRUnitT> struct MockPassHandle;
template <>
struct MockPassHandle<Loop>
: MockPassHandleBase<MockPassHandle<Loop>, Loop, LoopAnalysisManager,
LoopStandardAnalysisResults &, LPMUpdater &> {
MOCK_METHOD4(run,
PreservedAnalyses(Loop &, LoopAnalysisManager &,
LoopStandardAnalysisResults &, LPMUpdater &));
static void invalidateLoop(Loop &L, LoopAnalysisManager &,
LoopStandardAnalysisResults &,
LPMUpdater &Updater) {
Updater.markLoopAsDeleted(L, L.getName());
}
MockPassHandle() { setDefaults(); }
};
template <>
struct MockPassHandle<LoopNest>
: MockPassHandleBase<MockPassHandle<LoopNest>, LoopNest,
LoopAnalysisManager, LoopStandardAnalysisResults &,
LPMUpdater &> {
MOCK_METHOD4(run,
PreservedAnalyses(LoopNest &, LoopAnalysisManager &,
LoopStandardAnalysisResults &, LPMUpdater &));
static void invalidateLoopNest(LoopNest &L, LoopAnalysisManager &,
LoopStandardAnalysisResults &,
LPMUpdater &Updater) {
Updater.markLoopAsDeleted(L.getOutermostLoop(), L.getName());
}
MockPassHandle() { setDefaults(); }
};
template <>
struct MockPassHandle<Function>
: MockPassHandleBase<MockPassHandle<Function>, Function> {
MOCK_METHOD2(run, PreservedAnalyses(Function &, FunctionAnalysisManager &));
MockPassHandle() { setDefaults(); }
};
template <>
struct MockPassHandle<LazyCallGraph::SCC>
: MockPassHandleBase<MockPassHandle<LazyCallGraph::SCC>, LazyCallGraph::SCC,
CGSCCAnalysisManager, LazyCallGraph &,
CGSCCUpdateResult &> {
MOCK_METHOD4(run,
PreservedAnalyses(LazyCallGraph::SCC &, CGSCCAnalysisManager &,
LazyCallGraph &G, CGSCCUpdateResult &UR));
static void invalidateSCC(LazyCallGraph::SCC &C, CGSCCAnalysisManager &,
LazyCallGraph &, CGSCCUpdateResult &UR) {
UR.InvalidatedSCCs.insert(&C);
}
MockPassHandle() { setDefaults(); }
};
template <>
struct MockPassHandle<Module>
: MockPassHandleBase<MockPassHandle<Module>, Module> {
MOCK_METHOD2(run, PreservedAnalyses(Module &, ModuleAnalysisManager &));
MockPassHandle() { setDefaults(); }
};
template <typename IRUnitT> struct MockAnalysisHandle;
template <>
struct MockAnalysisHandle<Loop>
: MockAnalysisHandleBase<MockAnalysisHandle<Loop>, Loop,
LoopAnalysisManager,
LoopStandardAnalysisResults &> {
MOCK_METHOD3_T(run, typename Analysis::Result(Loop &, LoopAnalysisManager &,
LoopStandardAnalysisResults &));
MOCK_METHOD3_T(invalidate, bool(Loop &, const PreservedAnalyses &,
LoopAnalysisManager::Invalidator &));
MockAnalysisHandle<Loop>() { this->setDefaults(); }
};
template <>
struct MockAnalysisHandle<Function>
: MockAnalysisHandleBase<MockAnalysisHandle<Function>, Function> {
MOCK_METHOD2(run, Analysis::Result(Function &, FunctionAnalysisManager &));
MOCK_METHOD3(invalidate, bool(Function &, const PreservedAnalyses &,
FunctionAnalysisManager::Invalidator &));
MockAnalysisHandle<Function>() { setDefaults(); }
};
template <>
struct MockAnalysisHandle<LazyCallGraph::SCC>
: MockAnalysisHandleBase<MockAnalysisHandle<LazyCallGraph::SCC>,
LazyCallGraph::SCC, CGSCCAnalysisManager,
LazyCallGraph &> {
MOCK_METHOD3(run, Analysis::Result(LazyCallGraph::SCC &,
CGSCCAnalysisManager &, LazyCallGraph &));
MOCK_METHOD3(invalidate, bool(LazyCallGraph::SCC &, const PreservedAnalyses &,
CGSCCAnalysisManager::Invalidator &));
MockAnalysisHandle<LazyCallGraph::SCC>() { setDefaults(); }
};
template <>
struct MockAnalysisHandle<Module>
: MockAnalysisHandleBase<MockAnalysisHandle<Module>, Module> {
MOCK_METHOD2(run, Analysis::Result(Module &, ModuleAnalysisManager &));
MOCK_METHOD3(invalidate, bool(Module &, const PreservedAnalyses &,
ModuleAnalysisManager::Invalidator &));
MockAnalysisHandle<Module>() { setDefaults(); }
};
static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
SMDiagnostic Err;
return parseAssemblyString(IR, Err, C);
}
template <typename IRUnitT> std::string getName(const IRUnitT &IR) {
return std::string(IR.getName());
}
template <> std::string getName(const StringRef &name) {
return std::string(name);
}
template <> std::string getName(const llvm::Any &WrappedIR) {
if (any_isa<const Module *>(WrappedIR))
return any_cast<const Module *>(WrappedIR)->getName().str();
if (any_isa<const Function *>(WrappedIR))
return any_cast<const Function *>(WrappedIR)->getName().str();
if (any_isa<const Loop *>(WrappedIR))
return any_cast<const Loop *>(WrappedIR)->getName().str();
if (any_isa<const LoopNest *>(WrappedIR))
return any_cast<const LoopNest *>(WrappedIR)->getName().str();
if (any_isa<const LazyCallGraph::SCC *>(WrappedIR))
return any_cast<const LazyCallGraph::SCC *>(WrappedIR)->getName();
return "<UNKNOWN>";
}
MATCHER_P(HasName, Name, "") {
*result_listener << "has name '" << getName(arg) << "'";
return Name == getName(arg);
}
MATCHER_P(HasNameRegex, Name, "") {
*result_listener << "has name '" << getName(arg) << "'";
llvm::Regex r(Name);
return r.match(getName(arg));
}
struct MockPassInstrumentationCallbacks {
PassInstrumentationCallbacks Callbacks;
MockPassInstrumentationCallbacks() {
ON_CALL(*this, runBeforePass(_, _)).WillByDefault(Return(true));
}
MOCK_METHOD2(runBeforePass, bool(StringRef PassID, llvm::Any));
MOCK_METHOD2(runBeforeSkippedPass, void(StringRef PassID, llvm::Any));
MOCK_METHOD2(runBeforeNonSkippedPass, void(StringRef PassID, llvm::Any));
MOCK_METHOD3(runAfterPass,
void(StringRef PassID, llvm::Any, const PreservedAnalyses &PA));
MOCK_METHOD2(runAfterPassInvalidated,
void(StringRef PassID, const PreservedAnalyses &PA));
MOCK_METHOD2(runBeforeAnalysis, void(StringRef PassID, llvm::Any));
MOCK_METHOD2(runAfterAnalysis, void(StringRef PassID, llvm::Any));
void registerPassInstrumentation() {
Callbacks.registerShouldRunOptionalPassCallback(
[this](StringRef P, llvm::Any IR) {
return this->runBeforePass(P, IR);
});
Callbacks.registerBeforeSkippedPassCallback(
[this](StringRef P, llvm::Any IR) {
this->runBeforeSkippedPass(P, IR);
});
Callbacks.registerBeforeNonSkippedPassCallback(
[this](StringRef P, llvm::Any IR) {
this->runBeforeNonSkippedPass(P, IR);
});
Callbacks.registerAfterPassCallback(
[this](StringRef P, llvm::Any IR, const PreservedAnalyses &PA) {
this->runAfterPass(P, IR, PA);
});
Callbacks.registerAfterPassInvalidatedCallback(
[this](StringRef P, const PreservedAnalyses &PA) {
this->runAfterPassInvalidated(P, PA);
});
Callbacks.registerBeforeAnalysisCallback([this](StringRef P, llvm::Any IR) {
return this->runBeforeAnalysis(P, IR);
});
Callbacks.registerAfterAnalysisCallback(
[this](StringRef P, llvm::Any IR) { this->runAfterAnalysis(P, IR); });
}
void ignoreNonMockPassInstrumentation(StringRef IRName) {
EXPECT_CALL(*this,
runBeforePass(Not(HasNameRegex("Mock")), HasName(IRName)))
.Times(AnyNumber());
EXPECT_CALL(
*this, runBeforeSkippedPass(Not(HasNameRegex("Mock")), HasName(IRName)))
.Times(AnyNumber());
EXPECT_CALL(*this, runBeforeNonSkippedPass(Not(HasNameRegex("Mock")),
HasName(IRName)))
.Times(AnyNumber());
EXPECT_CALL(*this,
runAfterPass(Not(HasNameRegex("Mock")), HasName(IRName), _))
.Times(AnyNumber());
EXPECT_CALL(*this,
runBeforeAnalysis(Not(HasNameRegex("Mock")), HasName(IRName)))
.Times(AnyNumber());
EXPECT_CALL(*this,
runAfterAnalysis(Not(HasNameRegex("Mock")), HasName(IRName)))
.Times(AnyNumber());
}
};
template <typename IRUnitT>
using ExtraMockPassHandle =
std::conditional_t<std::is_same<IRUnitT, Loop>::value,
MockPassHandle<LoopNest>, MockPassHandle<IRUnitT>>;
template <typename PassManagerT> class PassBuilderCallbacksTest;
template <typename TestIRUnitT, typename... ExtraPassArgTs,
typename... ExtraAnalysisArgTs>
class PassBuilderCallbacksTest<PassManager<
TestIRUnitT, AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>,
ExtraPassArgTs...>> : public testing::Test {
protected:
using IRUnitT = TestIRUnitT;
using AnalysisManagerT = AnalysisManager<TestIRUnitT, ExtraAnalysisArgTs...>;
using PassManagerT =
PassManager<TestIRUnitT, AnalysisManagerT, ExtraPassArgTs...>;
using AnalysisT = typename MockAnalysisHandle<IRUnitT>::Analysis;
LLVMContext Context;
std::unique_ptr<Module> M;
MockPassInstrumentationCallbacks CallbacksHandle;
PassBuilder PB;
ModulePassManager PM;
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
CGSCCAnalysisManager CGAM;
ModuleAnalysisManager AM;
MockPassHandle<IRUnitT> PassHandle;
ExtraMockPassHandle<IRUnitT> ExtraPassHandle;
MockAnalysisHandle<IRUnitT> AnalysisHandle;
static PreservedAnalyses getAnalysisResult(IRUnitT &U, AnalysisManagerT &AM,
ExtraAnalysisArgTs &&... Args) {
(void)AM.template getResult<AnalysisT>(
U, std::forward<ExtraAnalysisArgTs>(Args)...);
return PreservedAnalyses::all();
}
PassBuilderCallbacksTest()
: M(parseIR(Context,
"declare void @bar()\n"
"define void @foo(i32 %n) {\n"
"entry:\n"
" br label %loop\n"
"loop:\n"
" %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]\n"
" %iv.next = add i32 %iv, 1\n"
" tail call void @bar()\n"
" %cmp = icmp eq i32 %iv, %n\n"
" br i1 %cmp, label %exit, label %loop\n"
"exit:\n"
" ret void\n"
"}\n")),
CallbacksHandle(),
PB(nullptr, PipelineTuningOptions(), None, &CallbacksHandle.Callbacks),
PM(), LAM(), FAM(), CGAM(), AM() {
EXPECT_TRUE(&CallbacksHandle.Callbacks ==
PB.getPassInstrumentationCallbacks());
PB.registerAnalysisRegistrationCallback([this](AnalysisManagerT &AM) {
AM.registerPass([this] { return AnalysisHandle.getAnalysis(); });
});
PB.registerPipelineParsingCallback(
[this](StringRef Name, PassManagerT &PM,
ArrayRef<PassBuilder::PipelineElement> InnerPipeline) {
if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", Name, PM))
return true;
if (Name == "test-transform") {
PM.addPass(PassHandle.getPass());
if (std::is_same<IRUnitT, Loop>::value)
PM.addPass(ExtraPassHandle.getPass());
return true;
}
return false;
});
PB.registerModuleAnalyses(AM);
PB.registerCGSCCAnalyses(CGAM);
PB.registerFunctionAnalyses(FAM);
PB.registerLoopAnalyses(LAM);
PB.crossRegisterProxies(LAM, FAM, CGAM, AM);
}
};
using ModuleCallbacksTest = PassBuilderCallbacksTest<ModulePassManager>;
using CGSCCCallbacksTest = PassBuilderCallbacksTest<CGSCCPassManager>;
using FunctionCallbacksTest = PassBuilderCallbacksTest<FunctionPassManager>;
using LoopCallbacksTest = PassBuilderCallbacksTest<LoopPassManager>;
TEST_F(ModuleCallbacksTest, Passes) {
EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
.WillOnce(&getAnalysisResult);
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(ModuleCallbacksTest, InstrumentedPasses) {
EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
.WillOnce(&getAnalysisResult);
CallbacksHandle.registerPassInstrumentation();
CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
::testing::Sequence PISequence;
EXPECT_CALL(CallbacksHandle, runBeforePass(HasNameRegex("MockPassHandle"),
HasName("<string>")))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"),
HasName("<string>")))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"),
HasName("<string>")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("<string>")))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("MockPassHandle"),
HasName("<string>"), _))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("<string>")))
.Times(0);
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(ModuleCallbacksTest, InstrumentedSkippedPasses) {
CallbacksHandle.registerPassInstrumentation();
CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
EXPECT_CALL(CallbacksHandle, runBeforePass(_, _))
.WillRepeatedly(Return(false));
EXPECT_CALL(CallbacksHandle,
runBeforeSkippedPass(HasNameRegex("MockPassHandle"), _))
.Times(3);
EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _)).Times(0);
EXPECT_CALL(PassHandle, run(HasName("<string>"), _)).Times(0);
EXPECT_CALL(CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle"), _, _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("PassManager"), _))
.Times(5);
EXPECT_CALL(
CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("ModuleToFunctionPassAdaptor"), _))
.Times(1);
EXPECT_CALL(CallbacksHandle,
runBeforeNonSkippedPass(
HasNameRegex("ModuleToPostOrderCGSCCPassAdaptor"), _))
.Times(1);
EXPECT_CALL(
CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("CGSCCToFunctionPassAdaptor"), _))
.Times(1);
EXPECT_CALL(
CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("FunctionToLoopPassAdaptor"), _))
.Times(1);
EXPECT_CALL(CallbacksHandle, runAfterPass(HasNameRegex("PassManager"), _, _))
.Times(5);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("ModuleToFunctionPassAdaptor"), _, _))
.Times(1);
EXPECT_CALL(
CallbacksHandle,
runAfterPass(HasNameRegex("ModuleToPostOrderCGSCCPassAdaptor"), _, _))
.Times(1);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("CGSCCToFunctionPassAdaptor"), _, _))
.Times(1);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("FunctionToLoopPassAdaptor"), _, _))
.Times(1);
EXPECT_CALL(CallbacksHandle,
runBeforeAnalysis(Not(HasNameRegex("MockAnalysisHandle")), _))
.Times(AnyNumber());
EXPECT_CALL(CallbacksHandle,
runAfterAnalysis(Not(HasNameRegex("MockAnalysisHandle")), _))
.Times(AnyNumber());
PB.registerPipelineParsingCallback(
[](StringRef Name, FunctionPassManager &FPM,
ArrayRef<PassBuilder::PipelineElement>) {
if (Name == "test-transform") {
FPM.addPass(MockPassHandle<Function>().getPass());
return true;
}
return false;
});
PB.registerPipelineParsingCallback(
[](StringRef Name, LoopPassManager &LPM,
ArrayRef<PassBuilder::PipelineElement>) {
if (Name == "test-transform") {
LPM.addPass(MockPassHandle<Loop>().getPass());
return true;
}
return false;
});
StringRef PipelineText = "test-transform,function(test-transform),cgscc("
"function(loop(test-transform)))";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(FunctionCallbacksTest, Passes) {
EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
EXPECT_CALL(PassHandle, run(HasName("foo"), _)).WillOnce(&getAnalysisResult);
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(FunctionCallbacksTest, InstrumentedPasses) {
CallbacksHandle.registerPassInstrumentation();
CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
EXPECT_CALL(PassHandle, run(HasName("foo"), _)).WillOnce(&getAnalysisResult);
::testing::Sequence PISequence;
EXPECT_CALL(CallbacksHandle,
runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("foo")))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle"), HasName("foo"), _))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo")))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
.Times(0);
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(FunctionCallbacksTest, InstrumentedSkippedPasses) {
CallbacksHandle.registerPassInstrumentation();
CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
EXPECT_CALL(CallbacksHandle,
runBeforePass(HasNameRegex("MockPassHandle"), HasName("foo")))
.WillOnce(Return(false));
EXPECT_CALL(
CallbacksHandle,
runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("foo")))
.Times(1);
EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _)).Times(0);
EXPECT_CALL(PassHandle, run(HasName("foo"), _)).Times(0);
EXPECT_CALL(CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle"), _, _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle"), _, _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
.Times(0);
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(LoopCallbacksTest, Passes) {
EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
.WillOnce(WithArgs<0, 1, 2>(&getAnalysisResult));
EXPECT_CALL(ExtraPassHandle, run(HasName("loop"), _, _, _));
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(LoopCallbacksTest, InstrumentedPasses) {
CallbacksHandle.registerPassInstrumentation();
CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
.WillOnce(WithArgs<0, 1, 2>(&getAnalysisResult));
EXPECT_CALL(ExtraPassHandle, run(HasName("loop"), _, _, _));
::testing::Sequence PISequence;
EXPECT_CALL(CallbacksHandle,
runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"), _))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runBeforePass(HasNameRegex("MockPassHandle<.*LoopNest>"),
HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runBeforeNonSkippedPass(
HasNameRegex("MockPassHandle<.*LoopNest>"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle<.*LoopNest>"),
HasName("loop"), _))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
.Times(0);
EXPECT_CALL(
CallbacksHandle,
runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop")))
.Times(0);
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(LoopCallbacksTest, InstrumentedInvalidatingPasses) {
CallbacksHandle.registerPassInstrumentation();
CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
.WillOnce(DoAll(WithArgs<0, 1, 2, 3>(&PassHandle.invalidateLoop),
WithArgs<0, 1, 2>(&getAnalysisResult)));
::testing::Sequence PISequence;
EXPECT_CALL(CallbacksHandle,
runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPassInvalidated(HasNameRegex("^PassManager"), _))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"), _))
.Times(0);
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(LoopCallbacksTest, InstrumentedInvalidatingLoopNestPasses) {
CallbacksHandle.registerPassInstrumentation();
CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _))
.WillOnce(WithArgs<0, 1, 2>(&getAnalysisResult));
EXPECT_CALL(ExtraPassHandle, run(HasName("loop"), _, _, _))
.WillOnce(DoAll(&ExtraPassHandle.invalidateLoopNest,
[&](LoopNest &, LoopAnalysisManager &,
LoopStandardAnalysisResults &,
LPMUpdater &) { return PreservedAnalyses::all(); }));
::testing::Sequence PISequence;
EXPECT_CALL(CallbacksHandle,
runBeforePass(HasNameRegex("MockPassHandle"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle"), HasName("loop"), _))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runBeforePass(HasNameRegex("MockPassHandle<.*LoopNest>"),
HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runBeforeNonSkippedPass(
HasNameRegex("MockPassHandle<.*LoopNest>"), HasName("loop")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runAfterPassInvalidated(HasNameRegex("MockPassHandle<.*LoopNest>"), _))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPassInvalidated(HasNameRegex("^PassManager"), _))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle, runAfterPassInvalidated(
HasNameRegex("MockPassHandle<.*Loop>"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle<.*LoopNest>"),
HasName("loop"), _))
.Times(0);
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(LoopCallbacksTest, InstrumentedSkippedPasses) {
CallbacksHandle.registerPassInstrumentation();
CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
CallbacksHandle.ignoreNonMockPassInstrumentation("loop");
EXPECT_CALL(
CallbacksHandle,
runBeforePass(HasNameRegex("MockPassHandle<.*Loop>"), HasName("loop")))
.WillOnce(Return(false));
EXPECT_CALL(CallbacksHandle,
runBeforeSkippedPass(HasNameRegex("MockPassHandle<.*Loop>"),
HasName("loop")))
.Times(1);
EXPECT_CALL(CallbacksHandle,
runBeforePass(HasNameRegex("MockPassHandle<.*LoopNest>"),
HasName("loop")))
.WillOnce(Return(false));
EXPECT_CALL(CallbacksHandle,
runBeforeSkippedPass(HasNameRegex("MockPassHandle<.*LoopNest>"),
HasName("loop")))
.Times(1);
EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _)).Times(0);
EXPECT_CALL(PassHandle, run(HasName("loop"), _, _, _)).Times(0);
EXPECT_CALL(ExtraPassHandle, run(HasName("loop"), _, _, _)).Times(0);
EXPECT_CALL(CallbacksHandle, runBeforeNonSkippedPass(
HasNameRegex("MockPassHandle<.*Loop>"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle<.*Loop>"), _, _))
.Times(0);
EXPECT_CALL(CallbacksHandle, runAfterPassInvalidated(
HasNameRegex("MockPassHandle<.*Loop>"), _))
.Times(0);
EXPECT_CALL(
CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("MockPassHandle<.*LoopNest>"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle<.*LoopNest>"), _, _))
.Times(0);
EXPECT_CALL(
CallbacksHandle,
runAfterPassInvalidated(HasNameRegex("MockPassHandle<.*LoopNest>"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
.Times(0);
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(CGSCCCallbacksTest, Passes) {
EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
.WillOnce(WithArgs<0, 1, 2>(&getAnalysisResult));
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(CGSCCCallbacksTest, InstrumentedPasses) {
CallbacksHandle.registerPassInstrumentation();
CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
.WillOnce(WithArgs<0, 1, 2>(&getAnalysisResult));
::testing::Sequence PISequence;
EXPECT_CALL(CallbacksHandle,
runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"), _))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
.Times(0);
EXPECT_CALL(
CallbacksHandle,
runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
.Times(0);
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(CGSCCCallbacksTest, InstrumentedInvalidatingPasses) {
CallbacksHandle.registerPassInstrumentation();
CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _))
.WillOnce(DoAll(WithArgs<0, 1, 2, 3>(&PassHandle.invalidateSCC),
WithArgs<0, 1, 2>(&getAnalysisResult)));
::testing::Sequence PISequence;
EXPECT_CALL(CallbacksHandle,
runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
.InSequence(PISequence);
EXPECT_CALL(
CallbacksHandle,
runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), HasName("(foo)")))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPassInvalidated(HasNameRegex("^PassManager"), _))
.InSequence(PISequence);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle"), HasName("(foo)"), _))
.Times(0);
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(CGSCCCallbacksTest, InstrumentedSkippedPasses) {
CallbacksHandle.registerPassInstrumentation();
CallbacksHandle.ignoreNonMockPassInstrumentation("<string>");
CallbacksHandle.ignoreNonMockPassInstrumentation("foo");
CallbacksHandle.ignoreNonMockPassInstrumentation("(foo)");
EXPECT_CALL(CallbacksHandle,
runBeforePass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
.WillOnce(Return(false));
EXPECT_CALL(
CallbacksHandle,
runBeforeSkippedPass(HasNameRegex("MockPassHandle"), HasName("(foo)")))
.Times(1);
EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _)).Times(0);
EXPECT_CALL(PassHandle, run(HasName("(foo)"), _, _, _)).Times(0);
EXPECT_CALL(CallbacksHandle,
runBeforeNonSkippedPass(HasNameRegex("MockPassHandle"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterPass(HasNameRegex("MockPassHandle"), _, _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterPassInvalidated(HasNameRegex("MockPassHandle"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runBeforeAnalysis(HasNameRegex("MockAnalysisHandle"), _))
.Times(0);
EXPECT_CALL(CallbacksHandle,
runAfterAnalysis(HasNameRegex("MockAnalysisHandle"), _))
.Times(0);
StringRef PipelineText = "test-transform";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(ModuleCallbacksTest, AnalysisUtilities) {
EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));
StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(CGSCCCallbacksTest, PassUtilities) {
EXPECT_CALL(AnalysisHandle, run(HasName("(foo)"), _, _));
EXPECT_CALL(AnalysisHandle, invalidate(HasName("(foo)"), _, _));
StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(FunctionCallbacksTest, AnalysisUtilities) {
EXPECT_CALL(AnalysisHandle, run(HasName("foo"), _));
EXPECT_CALL(AnalysisHandle, invalidate(HasName("foo"), _, _));
StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(LoopCallbacksTest, PassUtilities) {
EXPECT_CALL(AnalysisHandle, run(HasName("loop"), _, _));
EXPECT_CALL(AnalysisHandle, invalidate(HasName("loop"), _, _));
StringRef PipelineText = "require<test-analysis>,invalidate<test-analysis>";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
}
TEST_F(ModuleCallbacksTest, ParseTopLevelPipeline) {
PB.registerParseTopLevelPipelineCallback(
[this](ModulePassManager &MPM,
ArrayRef<PassBuilder::PipelineElement> Pipeline) {
auto &FirstName = Pipeline.front().Name;
auto &InnerPipeline = Pipeline.front().InnerPipeline;
if (FirstName == "another-pipeline") {
for (auto &E : InnerPipeline) {
if (parseAnalysisUtilityPasses<AnalysisT>("test-analysis", E.Name,
PM))
continue;
if (E.Name == "test-transform") {
PM.addPass(PassHandle.getPass());
continue;
}
return false;
}
}
return true;
});
EXPECT_CALL(AnalysisHandle, run(HasName("<string>"), _));
EXPECT_CALL(PassHandle, run(HasName("<string>"), _))
.WillOnce(&getAnalysisResult);
EXPECT_CALL(AnalysisHandle, invalidate(HasName("<string>"), _, _));
StringRef PipelineText =
"another-pipeline(test-transform,invalidate<test-analysis>)";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded())
<< "Pipeline was: " << PipelineText;
PM.run(*M, AM);
PipelineText = "another-pipeline(instcombine)";
ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Failed())
<< "Pipeline was: " << PipelineText;
}
}