[PM/AA] Teach the new pass manager to use pass-by-lambda for registering

analysis passes, support pre-registering analyses, and use that to
implement parsing and pre-registering a custom alias analysis pipeline.

With this its possible to configure the particular alias analysis
pipeline used by the AAManager from the commandline of opt. I've updated
the test to show this effectively in use to build a pipeline including
basic-aa as part of it.

My big question for reviewers are around the APIs that are used to
expose this functionality. Are folks happy with pass-by-lambda to do
pass registration? Are folks happy with pre-registering analyses as
a way to inject customized instances of an analysis while still using
the registry for the general case?

Other thoughts of course welcome. The next round of patches will be to
add the rest of the alias analyses into the new pass manager and wire
them up here so that they can be used from opt. This will require
extending the (somewhate limited) functionality of AAManager w.r.t.
module passes.

Differential Revision: http://reviews.llvm.org/D17259

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@261197 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chandler Carruth 2016-02-18 09:45:17 +00:00
parent 20dee1f1c0
commit 67a41f0919
7 changed files with 124 additions and 32 deletions

View File

@ -342,14 +342,34 @@ public:
/// \brief Register an analysis pass with the manager.
///
/// This provides an initialized and set-up analysis pass to the analysis
/// manager. Whomever is setting up analysis passes must use this to populate
/// the manager with all of the analysis passes available.
template <typename PassT> void registerPass(PassT Pass) {
assert(!AnalysisPasses.count(PassT::ID()) &&
"Registered the same analysis pass twice!");
/// The argument is a callable whose result is a pass. This allows passing in
/// a lambda to construct the pass.
///
/// The pass type registered is the result type of calling the argument. If
/// that pass has already been registered, then the argument will not be
/// called and this function will return false. Otherwise, the pass type
/// becomes registered, with the instance provided by calling the argument
/// once, and this function returns true.
///
/// While this returns whether or not the pass type was already registered,
/// there in't an independent way to query that as that would be prone to
/// risky use when *querying* the analysis manager. Instead, the only
/// supported use case is avoiding duplicate registry of an analysis. This
/// interface also lends itself to minimizing the number of times we have to
/// do lookups for analyses or construct complex passes only to throw them
/// away.
template <typename PassBuilderT> bool registerPass(PassBuilderT PassBuilder) {
typedef decltype(PassBuilder()) PassT;
typedef detail::AnalysisPassModel<IRUnitT, PassT> PassModelT;
AnalysisPasses[PassT::ID()].reset(new PassModelT(std::move(Pass)));
auto &PassPtr = AnalysisPasses[PassT::ID()];
if (PassPtr)
// Already registered this pass type!
return false;
// Construct a new model around the instance returned by the builder.
PassPtr.reset(new PassModelT(PassBuilder()));
return true;
}
/// \brief Invalidate a specific analysis pass for an IR module.

View File

@ -21,6 +21,7 @@
#include "llvm/IR/PassManager.h"
namespace llvm {
class AAManager;
class TargetMachine;
/// \brief This class provides access to building LLVM's passes.
@ -39,21 +40,24 @@ public:
///
/// This is an interface that can be used to populate a \c
/// ModuleAnalysisManager with all registered module analyses. Callers can
/// still manually register any additional analyses.
/// still manually register any additional analyses. Callers can also
/// pre-register analyses and this will not override those.
void registerModuleAnalyses(ModuleAnalysisManager &MAM);
/// \brief Registers all available CGSCC analysis passes.
///
/// This is an interface that can be used to populate a \c CGSCCAnalysisManager
/// with all registered CGSCC analyses. Callers can still manually register any
/// additional analyses.
/// additional analyses. Callers can also pre-register analyses and this will
/// not override those.
void registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM);
/// \brief Registers all available function analysis passes.
///
/// This is an interface that can be used to populate a \c
/// FunctionAnalysisManager with all registered function analyses. Callers can
/// still manually register any additional analyses.
/// still manually register any additional analyses. Callers can also
/// pre-register analyses and this will not override those.
void registerFunctionAnalyses(FunctionAnalysisManager &FAM);
/// \brief Parse a textual pass pipeline description into a \c ModulePassManager.
@ -87,10 +91,28 @@ public:
bool parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText,
bool VerifyEachPass = true, bool DebugLogging = false);
/// Parse a textual alias analysis pipeline into the provided AA manager.
///
/// The format of the textual AA pipeline is a comma separated list of AA
/// pass names:
///
/// basic-aa,globals-aa,...
///
/// The AA manager is set up such that the provided alias analyses are tried
/// in the order specified. See the \c AAManaager documentation for details
/// about the logic used. This routine just provides the textual mapping
/// between AA names and the analyses to register with the manager.
///
/// Returns false if the text cannot be parsed cleanly. The specific state of
/// the \p AA manager is unspecified if such an error is encountered and this
/// returns false.
bool parseAAPipeline(AAManager &AA, StringRef PipelineText);
private:
bool parseModulePassName(ModulePassManager &MPM, StringRef Name);
bool parseCGSCCPassName(CGSCCPassManager &CGPM, StringRef Name);
bool parseFunctionPassName(FunctionPassManager &FPM, StringRef Name);
bool parseAAPassName(AAManager &AA, StringRef Name);
bool parseFunctionPassPipeline(FunctionPassManager &FPM,
StringRef &PipelineText, bool VerifyEachPass,
bool DebugLogging);

View File

@ -105,19 +105,19 @@ char NoOpFunctionAnalysis::PassID;
void PassBuilder::registerModuleAnalyses(ModuleAnalysisManager &MAM) {
#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
MAM.registerPass(CREATE_PASS);
MAM.registerPass([&] { return CREATE_PASS; });
#include "PassRegistry.def"
}
void PassBuilder::registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM) {
#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \
CGAM.registerPass(CREATE_PASS);
CGAM.registerPass([&] { return CREATE_PASS; });
#include "PassRegistry.def"
}
void PassBuilder::registerFunctionAnalyses(FunctionAnalysisManager &FAM) {
#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \
FAM.registerPass(CREATE_PASS);
FAM.registerPass([&] { return CREATE_PASS; });
#include "PassRegistry.def"
}
@ -214,6 +214,17 @@ bool PassBuilder::parseFunctionPassName(FunctionPassManager &FPM,
return false;
}
bool PassBuilder::parseAAPassName(AAManager &AA, StringRef Name) {
#define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS) \
if (Name == NAME) { \
AA.registerFunctionAnalysis<decltype(CREATE_PASS)>(); \
return true; \
}
#include "PassRegistry.def"
return false;
}
bool PassBuilder::parseFunctionPassPipeline(FunctionPassManager &FPM,
StringRef &PipelineText,
bool VerifyEachPass,
@ -418,3 +429,14 @@ bool PassBuilder::parsePassPipeline(ModulePassManager &MPM,
return false;
}
bool PassBuilder::parseAAPipeline(AAManager &AA, StringRef PipelineText) {
while (!PipelineText.empty()) {
StringRef Name;
std::tie(Name, PipelineText) = PipelineText.split(',');
if (!parseAAPassName(AA, Name))
return false;
}
return true;
}

View File

@ -55,7 +55,6 @@ CGSCC_PASS("no-op-cgscc", NoOpCGSCCPass())
#endif
FUNCTION_ANALYSIS("aa", AAManager())
FUNCTION_ANALYSIS("assumptions", AssumptionAnalysis())
FUNCTION_ANALYSIS("basic-aa", BasicAA())
FUNCTION_ANALYSIS("domtree", DominatorTreeAnalysis())
FUNCTION_ANALYSIS("loops", LoopAnalysis())
FUNCTION_ANALYSIS("no-op-function", NoOpFunctionAnalysis())
@ -63,6 +62,13 @@ FUNCTION_ANALYSIS("scalar-evolution", ScalarEvolutionAnalysis())
FUNCTION_ANALYSIS("targetlibinfo", TargetLibraryAnalysis())
FUNCTION_ANALYSIS("targetir",
TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis())
#ifndef FUNCTION_ALIAS_ANALYSIS
#define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS) \
FUNCTION_ANALYSIS(NAME, CREATE_PASS)
#endif
FUNCTION_ALIAS_ANALYSIS("basic-aa", BasicAA())
#undef FUNCTION_ALIAS_ANALYSIS
#undef FUNCTION_ANALYSIS
#ifndef FUNCTION_PASS

View File

@ -298,14 +298,6 @@
; CHECK-DT: Running analysis: DominatorTreeAnalysis
; CHECK-DT: Finished pass manager
; RUN: opt -disable-output -disable-verify -debug-pass-manager %s 2>&1 \
; RUN: -passes='require<aa>' \
; RUN: | FileCheck %s --check-prefix=CHECK-AA
; CHECK-AA: Starting pass manager
; CHECK-AA: Running pass: RequireAnalysisPass
; CHECK-AA: Running analysis: AAManager
; CHECK-AA: Finished pass manager
; RUN: opt -disable-output -disable-verify -debug-pass-manager %s 2>&1 \
; RUN: -passes='require<basic-aa>' \
; RUN: | FileCheck %s --check-prefix=CHECK-BASIC-AA
@ -314,6 +306,15 @@
; CHECK-BASIC-AA: Running analysis: BasicAA
; CHECK-BASIC-AA: Finished pass manager
; RUN: opt -disable-output -disable-verify -debug-pass-manager %s 2>&1 \
; RUN: -passes='require<aa>' -aa-pipeline='basic-aa' \
; RUN: | FileCheck %s --check-prefix=CHECK-AA
; CHECK-AA: Starting pass manager
; CHECK-AA: Running pass: RequireAnalysisPass
; CHECK-AA: Running analysis: AAManager
; CHECK-AA: Running analysis: BasicAA
; CHECK-AA: Finished pass manager
define void @foo() {
ret void
}

View File

@ -15,6 +15,7 @@
#include "NewPMDriver.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/CGSCCPassManager.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/IR/Dominators.h"
@ -36,6 +37,15 @@ static cl::opt<bool>
DebugPM("debug-pass-manager", cl::Hidden,
cl::desc("Print pass management debugging information"));
// This flag specifies a textual description of the alias analysis pipeline to
// use when querying for aliasing information. It only works in concert with
// the "passes" flag above.
static cl::opt<std::string>
AAPipeline("aa-pipeline",
cl::desc("A textual description of the alias analysis "
"pipeline for handling managed aliasing queries"),
cl::Hidden);
bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M,
TargetMachine *TM, tool_output_file *Out,
StringRef PassPipeline, OutputKind OK,
@ -44,22 +54,33 @@ bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M,
bool ShouldPreserveBitcodeUseListOrder) {
PassBuilder PB(TM);
// Specially handle the alias analysis manager so that we can register
// a custom pipeline of AA passes with it.
AAManager AA;
if (!PB.parseAAPipeline(AA, AAPipeline)) {
errs() << Arg0 << ": unable to parse AA pipeline description.\n";
return false;
}
FunctionAnalysisManager FAM(DebugPM);
CGSCCAnalysisManager CGAM(DebugPM);
ModuleAnalysisManager MAM(DebugPM);
// Register the AA manager first so that our version is the one used.
FAM.registerPass([&] { return std::move(AA); });
// Register all the basic analyses with the managers.
PB.registerModuleAnalyses(MAM);
PB.registerCGSCCAnalyses(CGAM);
PB.registerFunctionAnalyses(FAM);
// Cross register the analysis managers through their proxies.
MAM.registerPass(FunctionAnalysisManagerModuleProxy(FAM));
MAM.registerPass(CGSCCAnalysisManagerModuleProxy(CGAM));
CGAM.registerPass(FunctionAnalysisManagerCGSCCProxy(FAM));
CGAM.registerPass(ModuleAnalysisManagerCGSCCProxy(MAM));
FAM.registerPass(CGSCCAnalysisManagerFunctionProxy(CGAM));
FAM.registerPass(ModuleAnalysisManagerFunctionProxy(MAM));
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM); });
CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); });
FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
ModulePassManager MPM(DebugPM);
if (VK > VK_NoVerifier)

View File

@ -232,13 +232,13 @@ TEST_F(PassManagerTest, BasicPreservedAnalyses) {
TEST_F(PassManagerTest, Basic) {
FunctionAnalysisManager FAM;
int FunctionAnalysisRuns = 0;
FAM.registerPass(TestFunctionAnalysis(FunctionAnalysisRuns));
FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
ModuleAnalysisManager MAM;
int ModuleAnalysisRuns = 0;
MAM.registerPass(TestModuleAnalysis(ModuleAnalysisRuns));
MAM.registerPass(FunctionAnalysisManagerModuleProxy(FAM));
FAM.registerPass(ModuleAnalysisManagerFunctionProxy(MAM));
MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
ModulePassManager MPM;