Index: include/llvm/IR/PassManager.h =================================================================== --- include/llvm/IR/PassManager.h +++ include/llvm/IR/PassManager.h @@ -342,14 +342,34 @@ /// \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. Index: include/llvm/Passes/PassBuilder.h =================================================================== --- include/llvm/Passes/PassBuilder.h +++ 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 @@ /// /// 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 @@ 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); Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -105,19 +105,19 @@ 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 @@ 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 @@ 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; +} Index: lib/Passes/PassRegistry.def =================================================================== --- lib/Passes/PassRegistry.def +++ lib/Passes/PassRegistry.def @@ -55,7 +55,6 @@ #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("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 Index: test/Other/new-pass-manager.ll =================================================================== --- test/Other/new-pass-manager.ll +++ 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 } Index: tools/opt/NewPMDriver.cpp =================================================================== --- tools/opt/NewPMDriver.cpp +++ 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 @@ 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 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) Index: unittests/IR/PassManagerTest.cpp =================================================================== --- unittests/IR/PassManagerTest.cpp +++ unittests/IR/PassManagerTest.cpp @@ -232,13 +232,13 @@ 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;