From 8c28aa1da865fcc14a79c5017099cf3b1bec69ba Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Fri, 19 Aug 2016 18:36:06 +0000 Subject: [PATCH] [PM] Re-instate r279227 and r279228 with a fix to the way the templating was done to hopefully appease MSVC. As an upside, this also implements the suggestion Sanjoy made in code review, so two for one! =] I'll be watching the bots to see if there are still issues. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@279295 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/IRPrintingPasses.h | 2 +- include/llvm/IR/PassManager.h | 103 +++++++++++++++++++++------------- include/llvm/IR/PassManagerInternal.h | 37 +++++++----- lib/Passes/PassBuilder.cpp | 15 +++-- unittests/IR/PassManagerTest.cpp | 57 +++++++++++++++++++ 5 files changed, 154 insertions(+), 60 deletions(-) diff --git a/include/llvm/IR/IRPrintingPasses.h b/include/llvm/IR/IRPrintingPasses.h index bc6de19a6c3..0825e0696ca 100644 --- a/include/llvm/IR/IRPrintingPasses.h +++ b/include/llvm/IR/IRPrintingPasses.h @@ -30,7 +30,7 @@ class Module; 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. diff --git a/include/llvm/IR/PassManager.h b/include/llvm/IR/PassManager.h index e2d4d990143..aac03f0bac7 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -171,7 +171,7 @@ private: }; // 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 @@ struct AnalysisInfoMixin : PassInfoMixin { /// 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 @@ public: } /// \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 @@ public: 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 @@ public: } 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,9 @@ typedef PassManager FunctionPassManager; /// 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 -class AnalysisManager { +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 +364,12 @@ public: /// /// 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 @@ public: /// 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 @@ private: } /// \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 @@ private: 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 @@ typedef AnalysisManager FunctionAnalysisManager; /// 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 @@ public: /// 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 @@ private: AnalysisManagerT *AM; }; -template -char InnerAnalysisManagerProxy::PassID; +template +char + InnerAnalysisManagerProxy::PassID; extern template class InnerAnalysisManagerProxy; @@ -720,7 +732,7 @@ typedef InnerAnalysisManagerProxy /// 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 @@ public: /// \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 @@ private: const AnalysisManagerT *AM; }; -template -char OuterAnalysisManagerProxy::PassID; +template +char + OuterAnalysisManagerProxy::PassID; extern template class OuterAnalysisManagerProxy; @@ -872,19 +888,29 @@ createModuleToFunctionPassAdaptor(FunctionPassT Pass) { /// \brief A template utility pass to force an analysis result to be available. /// -/// 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> { +/// 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 +/// this specialization just ignores them. +/// +/// Specific patterns of run-method extra arguments and analysis manager extra +/// arguments will have to be defined as appropriate specializations. +template , + typename... ExtraArgTs> +struct RequireAnalysisPass + : PassInfoMixin> { /// \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); + PreservedAnalyses run(IRUnitT &Arg, AnalysisManagerT &AM, + ExtraArgTs &&... Args) { + (void)AM.template getResult(Arg, + std::forward(Args)...); return PreservedAnalyses::all(); } @@ -904,8 +930,8 @@ struct InvalidateAnalysisPass /// 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 +946,8 @@ struct InvalidateAnalysisPass /// 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(); } }; @@ -948,12 +974,11 @@ public: return *this; } - template - PreservedAnalyses run(IRUnitT &Arg, AnalysisManager &AM, - Ts... Args) { + template + PreservedAnalyses run(IRUnitT &Arg, AnalysisManagerT &AM, Ts &&... Args) { auto PA = PreservedAnalyses::all(); for (int i = 0; i < Count; ++i) - PA.intersect(P.run(Arg, AM, Args...)); + PA.intersect(P.run(Arg, AM, std::forward(Args)...)); return PA; } diff --git a/include/llvm/IR/PassManagerInternal.h b/include/llvm/IR/PassManagerInternal.h index 2ffd55225fb..dcc0a1cb2d9 100644 --- a/include/llvm/IR/PassManagerInternal.h +++ b/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 @@ namespace detail { /// \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 @@ template struct PassConcept { /// 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 @@ struct PassModel : PassConcept { 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 @@ struct AnalysisResultModel /// /// 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 @@ template struct AnalysisPassConcept { /// 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 @@ struct AnalysisPassModel : AnalysisPassConcept { /// /// 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. diff --git a/lib/Passes/PassBuilder.cpp b/lib/Passes/PassBuilder.cpp index cdbc2a24bf3..df4702653cf 100644 --- a/lib/Passes/PassBuilder.cpp +++ b/lib/Passes/PassBuilder.cpp @@ -516,8 +516,9 @@ bool PassBuilder::parseModulePass(ModulePassManager &MPM, } #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 @@ bool PassBuilder::parseCGSCCPass(CGSCCPassManager &CGPM, #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 @@ bool PassBuilder::parseFunctionPass(FunctionPassManager &FPM, } #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 @@ bool PassBuilder::parseLoopPass(LoopPassManager &LPM, const PipelineElement &E, #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 ">") { \ diff --git a/unittests/IR/PassManagerTest.cpp b/unittests/IR/PassManagerTest.cpp index c2ac863260a..47fb8b70f1b 100644 --- a/unittests/IR/PassManagerTest.cpp +++ b/unittests/IR/PassManagerTest.cpp @@ -331,4 +331,61 @@ TEST_F(PassManagerTest, Basic) { 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([](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); +} } -- 2.11.0