Index: llvm/trunk/include/llvm/IR/IRPrintingPasses.h =================================================================== --- llvm/trunk/include/llvm/IR/IRPrintingPasses.h +++ llvm/trunk/include/llvm/IR/IRPrintingPasses.h @@ -30,7 +30,7 @@ class ModulePass; class PreservedAnalyses; class raw_ostream; -template class AnalysisManager; +template class AnalysisManager; /// \brief Create and return a pass that writes the module to the specified /// \c raw_ostream. Index: llvm/trunk/include/llvm/IR/PassManager.h =================================================================== --- llvm/trunk/include/llvm/IR/PassManager.h +++ llvm/trunk/include/llvm/IR/PassManager.h @@ -171,7 +171,7 @@ }; // Forward declare the analysis manager template. -template class AnalysisManager; +template class AnalysisManager; /// A CRTP mix-in to automatically provide informational APIs needed for /// passes. @@ -222,8 +222,11 @@ /// that analysis manager to each pass it runs, as well as calling the analysis /// manager's invalidation routine with the PreservedAnalyses of each pass it /// runs. -template -class PassManager : public PassInfoMixin> { +template , + typename... ExtraArgTs> +class PassManager : public PassInfoMixin< + PassManager> { public: /// \brief Construct a pass manager. /// @@ -241,7 +244,8 @@ } /// \brief Run all of the passes in this manager over the IR. - PreservedAnalyses run(IRUnitT &IR, AnalysisManager &AM) { + PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM, + ExtraArgTs... ExtraArgs) { PreservedAnalyses PA = PreservedAnalyses::all(); if (DebugLogging) @@ -252,7 +256,7 @@ dbgs() << "Running pass: " << Passes[Idx]->name() << " on " << IR.getName() << "\n"; - PreservedAnalyses PassPA = Passes[Idx]->run(IR, AM); + PreservedAnalyses PassPA = Passes[Idx]->run(IR, AM, ExtraArgs...); // Update the analysis manager as each pass runs and potentially // invalidates analyses. We also update the preserved set of analyses @@ -278,12 +282,15 @@ } template void addPass(PassT Pass) { - typedef detail::PassModel PassModelT; + typedef detail::PassModel + PassModelT; Passes.emplace_back(new PassModelT(std::move(Pass))); } private: - typedef detail::PassConcept PassConceptT; + typedef detail::PassConcept + PassConceptT; PassManager(const PassManager &) = delete; PassManager &operator=(const PassManager &) = delete; @@ -308,10 +315,10 @@ /// This analysis manager can be used for any IR unit where the address of the /// IR unit sufficies as its identity. It manages the cache for a unit of IR via /// the address of each unit of IR cached. -template +template class AnalysisManager { typedef detail::AnalysisResultConcept ResultConceptT; - typedef detail::AnalysisPassConcept PassConceptT; + typedef detail::AnalysisPassConcept PassConceptT; public: // Most public APIs are inherited from the CRTP base class. @@ -358,11 +365,11 @@ /// /// If there is not a valid cached result in the manager already, this will /// re-run the analysis to produce a valid result. - template typename PassT::Result &getResult(IRUnitT &IR) { + template + typename PassT::Result &getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs) { assert(AnalysisPasses.count(PassT::ID()) && "This analysis pass was not registered prior to being queried"); - - ResultConceptT &ResultConcept = getResultImpl(PassT::ID(), IR); + ResultConceptT &ResultConcept = getResultImpl(PassT::ID(), IR, ExtraArgs...); typedef detail::AnalysisResultModel ResultModelT; return static_cast(ResultConcept).Result; @@ -407,7 +414,7 @@ /// away. template bool registerPass(PassBuilderT PassBuilder) { typedef decltype(PassBuilder()) PassT; - typedef detail::AnalysisPassModel PassModelT; + typedef detail::AnalysisPassModel PassModelT; auto &PassPtr = AnalysisPasses[PassT::ID()]; if (PassPtr) @@ -502,7 +509,8 @@ } /// \brief Get an analysis result, running the pass if necessary. - ResultConceptT &getResultImpl(void *PassID, IRUnitT &IR) { + ResultConceptT &getResultImpl(void *PassID, IRUnitT &IR, + ExtraArgTs... ExtraArgs) { typename AnalysisResultMapT::iterator RI; bool Inserted; std::tie(RI, Inserted) = AnalysisResults.insert(std::make_pair( @@ -515,7 +523,7 @@ if (DebugLogging) dbgs() << "Running analysis: " << P.name() << "\n"; AnalysisResultListT &ResultList = AnalysisResultLists[&IR]; - ResultList.emplace_back(PassID, P.run(IR, *this)); + ResultList.emplace_back(PassID, P.run(IR, *this, ExtraArgs...)); // P.run may have inserted elements into AnalysisResults and invalidated // RI. @@ -607,7 +615,7 @@ /// Note that the proxy's result is a move-only object and represents ownership /// of the validity of the analyses in the \c FunctionAnalysisManager it /// provides. -template +template class InnerAnalysisManagerProxy : public AnalysisInfoMixin< InnerAnalysisManagerProxy> { @@ -689,7 +697,10 @@ /// In debug builds, it will also assert that the analysis manager is empty /// as no queries should arrive at the function analysis manager prior to /// this analysis being requested. - Result run(IRUnitT &IR, AnalysisManager &) { return Result(*AM); } + Result run(IRUnitT &IR, AnalysisManager &, + ExtraArgTs...) { + return Result(*AM); + } private: friend AnalysisInfoMixin< @@ -699,8 +710,9 @@ AnalysisManagerT *AM; }; -template -char InnerAnalysisManagerProxy::PassID; +template +char + InnerAnalysisManagerProxy::PassID; extern template class InnerAnalysisManagerProxy; @@ -720,7 +732,7 @@ /// This proxy *doesn't* manage the invalidation in any way. That is handled by /// the recursive return path of each layer of the pass manager and the /// returned PreservedAnalysis set. -template +template class OuterAnalysisManagerProxy : public AnalysisInfoMixin< OuterAnalysisManagerProxy> { @@ -762,7 +774,10 @@ /// \brief Run the analysis pass and create our proxy result object. /// Nothing to see here, it just forwards the \c AM reference into the /// result. - Result run(IRUnitT &, AnalysisManager &) { return Result(*AM); } + Result run(IRUnitT &, AnalysisManager &, + ExtraArgTs...) { + return Result(*AM); + } private: friend AnalysisInfoMixin< @@ -772,8 +787,9 @@ const AnalysisManagerT *AM; }; -template -char OuterAnalysisManagerProxy::PassID; +template +char + OuterAnalysisManagerProxy::PassID; extern template class OuterAnalysisManagerProxy; @@ -874,15 +890,30 @@ /// /// This is a no-op pass which simply forces a specific analysis pass's result /// to be available when it is run. -template -struct RequireAnalysisPass : PassInfoMixin> { +template , + typename... ExtraArgTs> +struct RequireAnalysisPass; + +/// A specialization of the RequireAnalysisPass for generic IR unit analysis +/// managers and pass managers that have no extra arguments. +/// +/// If there are extra arguments at the pass's run level there may also be +/// extra arguments to the analysis manager's \c getResult routine. We can't +/// guess how to effectively map the arguments from one to the other, and so +/// only the specialization with no extra arguments is provided generically. +/// Specific patterns of run-method extra arguments and analysis manager extra +/// arguments will have to be defined as appropriate for those patterns. +template +struct RequireAnalysisPass> + : PassInfoMixin< + RequireAnalysisPass>> { /// \brief Run this pass over some unit of IR. /// /// This pass can be run over any unit of IR and use any analysis manager /// provided they satisfy the basic API requirements. When this pass is /// created, these methods can be instantiated to satisfy whatever the /// context requires. - template PreservedAnalyses run(IRUnitT &Arg, AnalysisManager &AM) { (void)AM.template getResult(Arg); @@ -904,8 +935,8 @@ /// provided they satisfy the basic API requirements. When this pass is /// created, these methods can be instantiated to satisfy whatever the /// context requires. - template - PreservedAnalyses run(IRUnitT &Arg, AnalysisManager &AM) { + template + PreservedAnalyses run(IRUnitT &Arg, AnalysisManagerT &AM, ExtraArgTs &&...) { // We have to directly invalidate the analysis result as we can't // enumerate all other analyses and use the preserved set to control it. AM.template invalidate(Arg); @@ -920,8 +951,8 @@ /// analysis passes to be re-run to produce fresh results if any are needed. struct InvalidateAllAnalysesPass : PassInfoMixin { /// \brief Run this pass over some unit of IR. - template - PreservedAnalyses run(IRUnitT &, AnalysisManager &) { + template + PreservedAnalyses run(IRUnitT &, AnalysisManagerT &, ExtraArgTs &&...) { return PreservedAnalyses::none(); } }; Index: llvm/trunk/include/llvm/IR/PassManagerInternal.h =================================================================== --- llvm/trunk/include/llvm/IR/PassManagerInternal.h +++ llvm/trunk/include/llvm/IR/PassManagerInternal.h @@ -23,7 +23,7 @@ namespace llvm { -template class AnalysisManager; +template class AnalysisManager; class PreservedAnalyses; /// \brief Implementation details of the pass manager interfaces. @@ -31,12 +31,18 @@ /// \brief Template for the abstract base class used to dispatch /// polymorphically over pass objects. -template struct PassConcept { +template +struct PassConcept { // Boiler plate necessary for the container of derived classes. virtual ~PassConcept() {} /// \brief The polymorphic API which runs the pass over a given IR entity. - virtual PreservedAnalyses run(IRUnitT &IR, AnalysisManager &AM) = 0; + /// + /// Note that actual pass object can omit the analysis manager argument if + /// desired. Also that the analysis manager may be null if there is no + /// analysis manager in the pass pipeline. + virtual PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM, + ExtraArgTs... ExtraArgs) = 0; /// \brief Polymorphic method to access the name of a pass. virtual StringRef name() = 0; @@ -47,9 +53,9 @@ /// Can be instantiated for any object which provides a \c run method accepting /// an \c IRUnitT& and an \c AnalysisManager&. It requires the pass to /// be a copyable object. -template -struct PassModel : PassConcept { +template +struct PassModel : PassConcept { explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. @@ -64,8 +70,9 @@ return *this; } - PreservedAnalysesT run(IRUnitT &IR, AnalysisManager &AM) override { - return Pass.run(IR, AM); + PreservedAnalysesT run(IRUnitT &IR, AnalysisManagerT &AM, + ExtraArgTs... ExtraArgs) override { + return Pass.run(IR, AM, ExtraArgs...); } StringRef name() override { return PassT::name(); } PassT Pass; @@ -205,14 +212,15 @@ /// /// This concept is parameterized over the IR unit that it can run over and /// produce an analysis result. -template struct AnalysisPassConcept { +template struct AnalysisPassConcept { virtual ~AnalysisPassConcept() {} /// \brief Method to run this analysis over a unit of IR. /// \returns A unique_ptr to the analysis result object to be queried by /// users. virtual std::unique_ptr> - run(IRUnitT &IR, AnalysisManager &AM) = 0; + run(IRUnitT &IR, AnalysisManager &AM, + ExtraArgTs... ExtraArgs) = 0; /// \brief Polymorphic method to access the name of a pass. virtual StringRef name() = 0; @@ -223,8 +231,8 @@ /// Can wrap any type which implements a suitable \c run method. The method /// must accept an \c IRUnitT& and an \c AnalysisManager& as arguments /// and produce an object which can be wrapped in a \c AnalysisResultModel. -template -struct AnalysisPassModel : AnalysisPassConcept { +template +struct AnalysisPassModel : AnalysisPassConcept { explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {} // We have to explicitly define all the special member functions because MSVC // refuses to generate them. @@ -247,8 +255,9 @@ /// /// The return is wrapped in an \c AnalysisResultModel. std::unique_ptr> - run(IRUnitT &IR, AnalysisManager &AM) override { - return make_unique(Pass.run(IR, AM)); + run(IRUnitT &IR, AnalysisManager &AM, + ExtraArgTs... ExtraArgs) override { + return make_unique(Pass.run(IR, AM, ExtraArgs...)); } /// \brief The model delegates to a static \c PassT::name method. Index: llvm/trunk/lib/Passes/PassBuilder.cpp =================================================================== --- llvm/trunk/lib/Passes/PassBuilder.cpp +++ llvm/trunk/lib/Passes/PassBuilder.cpp @@ -516,8 +516,9 @@ } #define MODULE_ANALYSIS(NAME, CREATE_PASS) \ if (Name == "require<" NAME ">") { \ - MPM.addPass(RequireAnalysisPass< \ - std::remove_reference::type>()); \ + MPM.addPass( \ + RequireAnalysisPass< \ + std::remove_reference::type, Module>()); \ return true; \ } \ if (Name == "invalidate<" NAME ">") { \ @@ -578,7 +579,8 @@ #define CGSCC_ANALYSIS(NAME, CREATE_PASS) \ if (Name == "require<" NAME ">") { \ CGPM.addPass(RequireAnalysisPass< \ - std::remove_reference::type>()); \ + std::remove_reference::type, \ + LazyCallGraph::SCC>()); \ return true; \ } \ if (Name == "invalidate<" NAME ">") { \ @@ -637,8 +639,9 @@ } #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ if (Name == "require<" NAME ">") { \ - FPM.addPass(RequireAnalysisPass< \ - std::remove_reference::type>()); \ + FPM.addPass( \ + RequireAnalysisPass< \ + std::remove_reference::type, Function>()); \ return true; \ } \ if (Name == "invalidate<" NAME ">") { \ @@ -688,7 +691,7 @@ #define LOOP_ANALYSIS(NAME, CREATE_PASS) \ if (Name == "require<" NAME ">") { \ LPM.addPass(RequireAnalysisPass< \ - std::remove_reference::type>()); \ + std::remove_reference::type, Loop>()); \ return true; \ } \ if (Name == "invalidate<" NAME ">") { \ Index: llvm/trunk/unittests/IR/PassManagerTest.cpp =================================================================== --- llvm/trunk/unittests/IR/PassManagerTest.cpp +++ llvm/trunk/unittests/IR/PassManagerTest.cpp @@ -331,4 +331,61 @@ EXPECT_EQ(1, ModuleAnalysisRuns); } + +// A customized pass manager that passes extra arguments through the +// infrastructure. +typedef AnalysisManager CustomizedAnalysisManager; +typedef PassManager + CustomizedPassManager; + +class CustomizedAnalysis : public AnalysisInfoMixin { +public: + struct Result { + Result(int I) : I(I) {} + int I; + }; + + Result run(Function &F, CustomizedAnalysisManager &AM, int I) { + return Result(I); + } + +private: + friend AnalysisInfoMixin; + static char PassID; +}; + +char CustomizedAnalysis::PassID; + +struct CustomizedPass : PassInfoMixin { + std::function Callback; + + template + CustomizedPass(CallbackT Callback) : Callback(Callback) {} + + PreservedAnalyses run(Function &F, CustomizedAnalysisManager &AM, int I, + int &O) { + Callback(AM.getResult(F, I), O); + return PreservedAnalyses::none(); + } +}; + +TEST_F(PassManagerTest, CustomizedPassManagerArgs) { + CustomizedAnalysisManager AM; + AM.registerPass([&] { return CustomizedAnalysis(); }); + + CustomizedPassManager PM; + + // Add an instance of the customized pass that just accumulates the input + // after it is round-tripped through the analysis. + int Result = 0; + PM.addPass(CustomizedPass::CustomizedPass( + [](CustomizedAnalysis::Result &R, int &O) { O += R.I; })); + + // Run this over every function with the input of 42. + for (Function &F : *M) + PM.run(F, AM, 42, Result); + + // And ensure that we accumulated the correct result. + EXPECT_EQ(42 * (int)M->size(), Result); +} }