From edf5996b061b0fc046befdcf7a64740ea8197a99 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Thu, 18 Feb 2016 09:45:17 +0000 Subject: [PATCH] [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 llvm-svn: 261197 --- llvm/include/llvm/IR/PassManager.h | 34 +++++++++++++++++++++++++++------- llvm/include/llvm/Passes/PassBuilder.h | 28 +++++++++++++++++++++++++--- llvm/lib/Passes/PassBuilder.cpp | 28 +++++++++++++++++++++++++--- llvm/lib/Passes/PassRegistry.def | 8 +++++++- llvm/test/Other/new-pass-manager.ll | 17 +++++++++-------- llvm/tools/opt/NewPMDriver.cpp | 33 +++++++++++++++++++++++++++------ llvm/unittests/IR/PassManagerTest.cpp | 8 ++++---- 7 files changed, 124 insertions(+), 32 deletions(-) diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h index 2ceb53d..9b0301b 100644 --- a/llvm/include/llvm/IR/PassManager.h +++ b/llvm/include/llvm/IR/PassManager.h @@ -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 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 bool registerPass(PassBuilderT PassBuilder) { + typedef decltype(PassBuilder()) PassT; typedef detail::AnalysisPassModel 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. diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h index 1e605e3..8b182e1 100644 --- a/llvm/include/llvm/Passes/PassBuilder.h +++ b/llvm/include/llvm/Passes/PassBuilder.h @@ -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); diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 68ce41a..1a762df 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -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(); \ + 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; +} diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 1e48d6a..703032e 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -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 diff --git a/llvm/test/Other/new-pass-manager.ll b/llvm/test/Other/new-pass-manager.ll index 5bc3940..da5cff5 100644 --- a/llvm/test/Other/new-pass-manager.ll +++ b/llvm/test/Other/new-pass-manager.ll @@ -299,14 +299,6 @@ ; CHECK-DT: Finished pass manager ; RUN: opt -disable-output -disable-verify -debug-pass-manager %s 2>&1 \ -; RUN: -passes='require' \ -; 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' \ ; RUN: | FileCheck %s --check-prefix=CHECK-BASIC-AA ; CHECK-BASIC-AA: Starting pass manager @@ -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-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 } diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp index 3030d657..a95a4ed 100644 --- a/llvm/tools/opt/NewPMDriver.cpp +++ b/llvm/tools/opt/NewPMDriver.cpp @@ -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 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 + 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) diff --git a/llvm/unittests/IR/PassManagerTest.cpp b/llvm/unittests/IR/PassManagerTest.cpp index 41af0b0..37939768 100644 --- a/llvm/unittests/IR/PassManagerTest.cpp +++ b/llvm/unittests/IR/PassManagerTest.cpp @@ -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; -- 2.7.4