diff --git a/include/llvm/IR/PassManager.h b/include/llvm/IR/PassManager.h index b86b03e053f..66e5703af5b 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -154,24 +154,69 @@ 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() {} virtual PassConcept *clone() = 0; /// \brief The polymorphic API which runs the pass over a given IR entity. - virtual PreservedAnalyses run(T Arg) = 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) = 0; +}; + +/// \brief SFINAE metafunction for computing whether \c PassT has a run method +/// accepting an \c AnalysisManagerT. +template +class PassRunAcceptsAnalysisManager { + typedef char SmallType; + struct BigType { char a, b; }; + + template + struct Checker; + + template static SmallType f(Checker *); + template static BigType f(...); + +public: + enum { Value = sizeof(f(0)) == sizeof(SmallType) }; }; /// \brief A template wrapper used to implement the polymorphic API. /// -/// Can be instantiated for any object which provides a \c run method -/// accepting a \c T. It requires the pass to be a copyable -/// object. -template struct PassModel : PassConcept { +/// Can be instantiated for any object which provides a \c run method accepting +/// an \c IRUnitT. It requires the pass to be a copyable object. When the +/// \c run method also accepts an \c AnalysisManagerT*, we pass it along. +template ::Value> +struct PassModel; + +/// \brief Specialization of \c PassModel for passes that accept an analyis +/// manager. +template +struct PassModel : PassConcept { PassModel(PassT Pass) : Pass(llvm_move(Pass)) {} virtual PassModel *clone() { return new PassModel(Pass); } - virtual PreservedAnalyses run(T Arg) { return Pass.run(Arg); } + virtual PreservedAnalyses run(IRUnitT IR, AnalysisManagerT *AM) { + return Pass.run(IR, AM); + } + PassT Pass; +}; + +/// \brief Specialization of \c PassModel for passes that accept an analyis +/// manager. +template +struct PassModel : PassConcept { + PassModel(PassT Pass) : Pass(llvm_move(Pass)) {} + virtual PassModel *clone() { return new PassModel(Pass); } + virtual PreservedAnalyses run(IRUnitT IR, AnalysisManagerT *AM) { + return Pass.run(IR); + } PassT Pass; }; @@ -307,14 +352,14 @@ class ModuleAnalysisManager; class ModulePassManager { public: - explicit ModulePassManager(ModuleAnalysisManager *AM = 0) : AM(AM) {} + explicit ModulePassManager() {} /// \brief Run all of the module passes in this module pass manager over /// a module. /// /// This method should only be called for a single module as there is the /// expectation that the lifetime of a pass is bounded to that of a module. - PreservedAnalyses run(Module *M); + PreservedAnalyses run(Module *M, ModuleAnalysisManager *AM = 0); template void addPass(ModulePassT Pass) { Passes.push_back(new ModulePassModel(llvm_move(Pass))); @@ -322,13 +367,14 @@ public: private: // Pull in the concept type and model template specialized for modules. - typedef detail::PassConcept ModulePassConcept; + typedef detail::PassConcept ModulePassConcept; template - struct ModulePassModel : detail::PassModel { - ModulePassModel(PassT Pass) : detail::PassModel(Pass) {} + struct ModulePassModel + : detail::PassModel { + ModulePassModel(PassT Pass) + : detail::PassModel(Pass) {} }; - ModuleAnalysisManager *AM; std::vector > Passes; }; @@ -336,24 +382,25 @@ class FunctionAnalysisManager; class FunctionPassManager { public: - explicit FunctionPassManager(FunctionAnalysisManager *AM = 0) : AM(AM) {} + explicit FunctionPassManager() {} template void addPass(FunctionPassT Pass) { Passes.push_back(new FunctionPassModel(llvm_move(Pass))); } - PreservedAnalyses run(Function *F); + PreservedAnalyses run(Function *F, FunctionAnalysisManager *AM = 0); private: // Pull in the concept type and model template specialized for functions. - typedef detail::PassConcept FunctionPassConcept; + typedef detail::PassConcept + FunctionPassConcept; template - struct FunctionPassModel : detail::PassModel { + struct FunctionPassModel + : detail::PassModel { FunctionPassModel(PassT Pass) - : detail::PassModel(Pass) {} + : detail::PassModel(Pass) {} }; - FunctionAnalysisManager *AM; std::vector > Passes; }; @@ -569,14 +616,14 @@ private: /// FIXME: It might be really nice to "enforce" this (softly) by making this /// proxy the API path to access a function analysis manager within a module /// pass. -class FunctionAnalysisModuleProxy { +class FunctionAnalysisManagerModuleProxy { public: typedef Module IRUnitT; class Result; static void *ID() { return (void *)&PassID; } - FunctionAnalysisModuleProxy(FunctionAnalysisManager &FAM) : FAM(FAM) {} + FunctionAnalysisManagerModuleProxy(FunctionAnalysisManager &FAM) : FAM(FAM) {} /// \brief Run the analysis pass and create our proxy result object. /// @@ -595,14 +642,18 @@ private: FunctionAnalysisManager &FAM; }; -/// \brief The result proxy object for the \c FunctionAnalysisModuleProxy. +/// \brief The result proxy object for the +/// \c FunctionAnalysisManagerModuleProxy. /// /// See its documentation for more information. -class FunctionAnalysisModuleProxy::Result { +class FunctionAnalysisManagerModuleProxy::Result { public: Result(FunctionAnalysisManager &FAM) : FAM(FAM) {} ~Result(); + /// \brief Accessor for the \c FunctionAnalysisManager. + FunctionAnalysisManager &getManager() const { return FAM; } + /// \brief Handler for invalidation of the module. /// /// If this analysis itself is preserved, then we assume that the set of \c @@ -621,52 +672,46 @@ private: /// \brief Trivial adaptor that maps from a module to its functions. /// -/// Designed to allow composition of a FunctionPass(Manager) and a -/// ModulePassManager. Note that if this pass is constructed with a pointer to -/// a \c ModuleAnalysisManager it will run the \c FunctionAnalysisModuleProxy -/// analysis prior to running the function pass over the module to enable a \c -/// FunctionAnalysisManager to be used within this run safely. +/// Designed to allow composition of a FunctionPass(Manager) and +/// a ModulePassManager. Note that if this pass is constructed with a pointer +/// to a \c ModuleAnalysisManager it will run the +/// \c FunctionAnalysisManagerModuleProxy analysis prior to running the function +/// pass over the module to enable a \c FunctionAnalysisManager to be used +/// within this run safely. template class ModuleToFunctionPassAdaptor { public: - explicit ModuleToFunctionPassAdaptor(FunctionPassT Pass, - ModuleAnalysisManager *MAM = 0) - : Pass(llvm_move(Pass)), MAM(MAM) {} + explicit ModuleToFunctionPassAdaptor(FunctionPassT Pass) + : Pass(llvm_move(Pass)) {} /// \brief Runs the function pass across every function in the module. - PreservedAnalyses run(Module *M) { - if (MAM) - // Pull in the analysis proxy so that the function analysis manager is - // appropriately set up. - (void)MAM->getResult(M); + PreservedAnalyses run(Module *M, ModuleAnalysisManager *AM) { + FunctionAnalysisManager *FAM = 0; + if (AM) + // Setup the function analysis manager from its proxy. + FAM = &AM->getResult(M).getManager(); PreservedAnalyses PA = PreservedAnalyses::all(); for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) { - PreservedAnalyses PassPA = Pass.run(I); + PreservedAnalyses PassPA = Pass.run(I, FAM); PA.intersect(llvm_move(PassPA)); } // By definition we preserve the proxy. - PA.preserve(); + PA.preserve(); return PA; } private: FunctionPassT Pass; - ModuleAnalysisManager *MAM; }; /// \brief A function to deduce a function pass type and wrap it in the /// templated adaptor. -/// -/// \param MAM is an optional \c ModuleAnalysisManager which (if provided) will -/// be queried for a \c FunctionAnalysisModuleProxy to enable the function -/// pass(es) to safely interact with a \c FunctionAnalysisManager. template ModuleToFunctionPassAdaptor -createModuleToFunctionPassAdaptor(FunctionPassT Pass, - ModuleAnalysisManager *MAM = 0) { - return ModuleToFunctionPassAdaptor(llvm_move(Pass), MAM); +createModuleToFunctionPassAdaptor(FunctionPassT Pass) { + return ModuleToFunctionPassAdaptor(llvm_move(Pass)); } } diff --git a/lib/IR/PassManager.cpp b/lib/IR/PassManager.cpp index 18388dc0c5a..c4c2d1471f7 100644 --- a/lib/IR/PassManager.cpp +++ b/lib/IR/PassManager.cpp @@ -12,10 +12,10 @@ using namespace llvm; -PreservedAnalyses ModulePassManager::run(Module *M) { +PreservedAnalyses ModulePassManager::run(Module *M, ModuleAnalysisManager *AM) { PreservedAnalyses PA = PreservedAnalyses::all(); for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) { - PreservedAnalyses PassPA = Passes[Idx]->run(M); + PreservedAnalyses PassPA = Passes[Idx]->run(M, AM); if (AM) AM->invalidate(M, PassPA); PA.intersect(llvm_move(PassPA)); @@ -57,10 +57,10 @@ void ModuleAnalysisManager::invalidateImpl(void *PassID, Module *M) { ModuleAnalysisResults.erase(PassID); } -PreservedAnalyses FunctionPassManager::run(Function *F) { +PreservedAnalyses FunctionPassManager::run(Function *F, FunctionAnalysisManager *AM) { PreservedAnalyses PA = PreservedAnalyses::all(); for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) { - PreservedAnalyses PassPA = Passes[Idx]->run(F); + PreservedAnalyses PassPA = Passes[Idx]->run(F, AM); if (AM) AM->invalidate(F, PassPA); PA.intersect(llvm_move(PassPA)); @@ -131,21 +131,22 @@ void FunctionAnalysisManager::invalidateImpl(void *PassID, Function *F) { FunctionAnalysisResultLists[F].erase(RI->second); } -char FunctionAnalysisModuleProxy::PassID; +char FunctionAnalysisManagerModuleProxy::PassID; -FunctionAnalysisModuleProxy::Result -FunctionAnalysisModuleProxy::run(Module *M) { +FunctionAnalysisManagerModuleProxy::Result +FunctionAnalysisManagerModuleProxy::run(Module *M) { assert(FAM.empty() && "Function analyses ran prior to the module proxy!"); return Result(FAM); } -FunctionAnalysisModuleProxy::Result::~Result() { +FunctionAnalysisManagerModuleProxy::Result::~Result() { // Clear out the analysis manager if we're being destroyed -- it means we // didn't even see an invalidate call when we got invalidated. FAM.clear(); } -bool FunctionAnalysisModuleProxy::Result::invalidate(Module *M, const PreservedAnalyses &PA) { +bool FunctionAnalysisManagerModuleProxy::Result::invalidate( + Module *M, const PreservedAnalyses &PA) { // If this proxy isn't marked as preserved, then it is has an invalid set of // Function objects in the cache making it impossible to incrementally // preserve them. Just clear the entire manager. diff --git a/unittests/IR/PassManagerTest.cpp b/unittests/IR/PassManagerTest.cpp index d23d85b8828..94fe99a3aa0 100644 --- a/unittests/IR/PassManagerTest.cpp +++ b/unittests/IR/PassManagerTest.cpp @@ -73,26 +73,24 @@ struct TestPreservingModulePass { struct TestMinPreservingModulePass { PreservedAnalyses run(Module *M) { PreservedAnalyses PA; - PA.preserve(); + PA.preserve(); return PA; } }; struct TestFunctionPass { - TestFunctionPass(FunctionAnalysisManager &AM, int &RunCount, - int &AnalyzedInstrCount) - : AM(AM), RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount) {} + TestFunctionPass(int &RunCount, int &AnalyzedInstrCount) + : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount) {} - PreservedAnalyses run(Function *F) { + PreservedAnalyses run(Function *F, FunctionAnalysisManager *AM) { ++RunCount; - const TestAnalysisPass::Result &AR = AM.getResult(F); + const TestAnalysisPass::Result &AR = AM->getResult(F); AnalyzedInstrCount += AR.InstructionCount; return PreservedAnalyses::all(); } - FunctionAnalysisManager &AM; int &RunCount; int &AnalyzedInstrCount; }; @@ -129,45 +127,45 @@ TEST_F(PassManagerTest, Basic) { FAM.registerPass(TestAnalysisPass(AnalysisRuns)); ModuleAnalysisManager MAM; - MAM.registerPass(FunctionAnalysisModuleProxy(FAM)); + MAM.registerPass(FunctionAnalysisManagerModuleProxy(FAM)); - ModulePassManager MPM(&MAM); + ModulePassManager MPM; // Count the runs over a Function. - FunctionPassManager FPM1(&FAM); + FunctionPassManager FPM1; int FunctionPassRunCount1 = 0; int AnalyzedInstrCount1 = 0; - FPM1.addPass(TestFunctionPass(FAM, FunctionPassRunCount1, AnalyzedInstrCount1)); - MPM.addPass(createModuleToFunctionPassAdaptor(FPM1, &MAM)); + FPM1.addPass(TestFunctionPass(FunctionPassRunCount1, AnalyzedInstrCount1)); + MPM.addPass(createModuleToFunctionPassAdaptor(FPM1)); // Count the runs over a module. int ModulePassRunCount = 0; MPM.addPass(TestModulePass(ModulePassRunCount)); // Count the runs over a Function in a separate manager. - FunctionPassManager FPM2(&FAM); + FunctionPassManager FPM2; int FunctionPassRunCount2 = 0; int AnalyzedInstrCount2 = 0; - FPM2.addPass(TestFunctionPass(FAM, FunctionPassRunCount2, AnalyzedInstrCount2)); - MPM.addPass(createModuleToFunctionPassAdaptor(FPM2, &MAM)); + FPM2.addPass(TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2)); + MPM.addPass(createModuleToFunctionPassAdaptor(FPM2)); // A third function pass manager but with only preserving intervening passes. MPM.addPass(TestPreservingModulePass()); - FunctionPassManager FPM3(&FAM); + FunctionPassManager FPM3; int FunctionPassRunCount3 = 0; int AnalyzedInstrCount3 = 0; - FPM3.addPass(TestFunctionPass(FAM, FunctionPassRunCount3, AnalyzedInstrCount3)); - MPM.addPass(createModuleToFunctionPassAdaptor(FPM3, &MAM)); + FPM3.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3)); + MPM.addPass(createModuleToFunctionPassAdaptor(FPM3)); // A fourth function pass manager but with a minimal intervening passes. MPM.addPass(TestMinPreservingModulePass()); - FunctionPassManager FPM4(&FAM); + FunctionPassManager FPM4; int FunctionPassRunCount4 = 0; int AnalyzedInstrCount4 = 0; - FPM4.addPass(TestFunctionPass(FAM, FunctionPassRunCount4, AnalyzedInstrCount4)); - MPM.addPass(createModuleToFunctionPassAdaptor(FPM4, &MAM)); + FPM4.addPass(TestFunctionPass(FunctionPassRunCount4, AnalyzedInstrCount4)); + MPM.addPass(createModuleToFunctionPassAdaptor(FPM4)); - MPM.run(M.get()); + MPM.run(M.get(), &MAM); // Validate module pass counters. EXPECT_EQ(1, ModulePassRunCount);