Index: include/llvm/IR/IRPrintingPasses.h =================================================================== --- include/llvm/IR/IRPrintingPasses.h +++ 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: include/llvm/IR/PassManager.h =================================================================== --- include/llvm/IR/PassManager.h +++ 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; @@ -321,7 +328,8 @@ /// managing analyses. This base class is factored so that if you need to /// customize the handling of a specific IR unit, you can do so without /// replicating *all* of the boilerplate. -template class AnalysisManagerBase { +template +class AnalysisManagerBase { DerivedT *derived_this() { return static_cast(this); } const DerivedT *derived_this() const { return static_cast(this); @@ -332,7 +340,7 @@ protected: typedef detail::AnalysisResultConcept ResultConceptT; - typedef detail::AnalysisPassConcept PassConceptT; + typedef detail::AnalysisPassConcept PassConceptT; // FIXME: Provide template aliases for the models when we're using C++11 in // a mode supporting them. @@ -352,12 +360,13 @@ /// /// 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 = - derived_this()->getResultImpl(PassT::ID(), IR); + derived_this()->getResultImpl(PassT::ID(), IR, ExtraArgs...); typedef detail::AnalysisResultModel ResultModelT; return static_cast(ResultConcept).Result; @@ -403,7 +412,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) @@ -468,11 +477,15 @@ /// 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 - : public detail::AnalysisManagerBase, IRUnitT> { - friend class detail::AnalysisManagerBase, IRUnitT>; - typedef detail::AnalysisManagerBase, IRUnitT> BaseT; + : public detail::AnalysisManagerBase< + AnalysisManager, IRUnitT, ExtraArgTs...> { + friend class detail::AnalysisManagerBase< + AnalysisManager, IRUnitT, ExtraArgTs...>; + typedef detail::AnalysisManagerBase, + IRUnitT, ExtraArgTs...> + BaseT; typedef typename BaseT::ResultConceptT ResultConceptT; typedef typename BaseT::PassConceptT PassConceptT; @@ -522,7 +535,8 @@ AnalysisManager &operator=(const AnalysisManager &) = delete; /// \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( @@ -535,7 +549,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. @@ -668,7 +682,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> { @@ -750,7 +764,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< @@ -760,8 +777,9 @@ AnalysisManagerT *AM; }; -template -char InnerAnalysisManagerProxy::PassID; +template +char + InnerAnalysisManagerProxy::PassID; extern template class InnerAnalysisManagerProxy; @@ -781,7 +799,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> { @@ -823,7 +841,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< @@ -833,8 +854,9 @@ const AnalysisManagerT *AM; }; -template -char OuterAnalysisManagerProxy::PassID; +template +char + OuterAnalysisManagerProxy::PassID; extern template class OuterAnalysisManagerProxy; @@ -935,15 +957,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 arguements 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); @@ -965,8 +1002,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); @@ -981,8 +1018,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: include/llvm/IR/PassManagerInternal.h =================================================================== --- include/llvm/IR/PassManagerInternal.h +++ 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,7 +31,8 @@ /// \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() {} @@ -40,7 +41,8 @@ /// 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, AnalysisManager &AM) = 0; + virtual PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM, + ExtraArgTs... ExtraArgs) = 0; /// \brief Polymorphic method to access the name of a pass. virtual StringRef name() = 0; @@ -51,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. When the -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. @@ -68,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; @@ -191,14 +194,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; @@ -209,8 +213,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. @@ -233,8 +237,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: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -334,8 +334,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 ">") { \ @@ -357,7 +358,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 ">") { \ @@ -379,8 +381,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 ">") { \ @@ -402,7 +405,7 @@ #define LOOP_ANALYSIS(NAME, CREATE_PASS) \ if (Name == "require<" NAME ">") { \ FPM.addPass(RequireAnalysisPass< \ - std::remove_reference::type>()); \ + std::remove_reference::type, Loop>()); \ return true; \ } \ if (Name == "invalidate<" NAME ">") { \ Index: unittests/IR/PassManagerTest.cpp =================================================================== --- unittests/IR/PassManagerTest.cpp +++ 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); +} }