From 0dd9c5f9e4e1eb23d0aa1b703007be0911606ffd Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Tue, 26 Nov 2013 11:24:37 +0000 Subject: [PATCH] [PM] Factor the overwhelming majority of the interface boiler plate out of the two analysis managers into a CRTP base class that can be shared and re-used in building any analysis manager. This will in turn simplify adding yet another analysis manager to the system. The base class provides all of the interface sugar for the analysis manager delegating the functionality back through DerivedT methods which operate on simple pass IDs. It also provides the pass registration, storage, and lookup system which is common across the various formulations of analysis managers. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@195747 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/PassManager.h | 218 ++++++++++++++++------------------ lib/IR/PassManager.cpp | 139 ++++++++++------------ 2 files changed, 167 insertions(+), 190 deletions(-) diff --git a/include/llvm/IR/PassManager.h b/include/llvm/IR/PassManager.h index 3c9414986e6..ddb9ea8f7f9 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -439,23 +439,43 @@ private: std::vector > Passes; }; -/// \brief A module analysis pass manager with lazy running and caching of -/// results. -class ModuleAnalysisManager { -public: - ModuleAnalysisManager() {} +namespace detail { +/// \brief A CRTP base used to implement analysis managers. +/// +/// This class template serves as the boiler plate of an analysis manager. Any +/// analysis manager can be implemented on top of this base class. Any +/// implementation will be required to provide specific hooks: +/// +/// - getResultImpl +/// - getCachedResultImpl +/// - invalidateImpl +/// +/// The details of the call pattern are within. +template +class AnalysisManagerBase { + DerivedT *derived_this() { return static_cast(this); } + const DerivedT *derived_this() const { return static_cast(this); } + +protected: + typedef detail::AnalysisResultConcept ResultConceptT; + typedef detail::AnalysisPassConcept PassConceptT; + + // FIXME: Provide template aliases for the models when we're using C++11 in + // a mode supporting them. + +public: /// \brief Get the result of an analysis pass for this module. /// /// If there is not a valid cached result in the manager already, this will /// re-run the analysis to produce a valid result. - template const typename PassT::Result &getResult(Module *M) { - assert(ModuleAnalysisPasses.count(PassT::ID()) && + template const typename PassT::Result &getResult(IRUnitT IR) { + assert(AnalysisPasses.count(PassT::ID()) && "This analysis pass was not registered prior to being queried"); - const detail::AnalysisResultConcept &ResultConcept = - getResultImpl(PassT::ID(), M); - typedef detail::AnalysisResultModel + const ResultConceptT &ResultConcept = + derived_this()->getResultImpl(PassT::ID(), IR); + typedef detail::AnalysisResultModel ResultModelT; return static_cast(ResultConcept).Result; } @@ -466,69 +486,100 @@ public: /// /// \returns null if there is no cached result. template - const typename PassT::Result *getCachedResult(Module *M) const { - assert(ModuleAnalysisPasses.count(PassT::ID()) && + const typename PassT::Result *getCachedResult(IRUnitT IR) const { + assert(AnalysisPasses.count(PassT::ID()) && "This analysis pass was not registered prior to being queried"); - const detail::AnalysisResultConcept *ResultConcept = - getCachedResultImpl(PassT::ID(), M); + const ResultConceptT *ResultConcept = + derived_this()->getCachedResultImpl(PassT::ID(), IR); if (!ResultConcept) return 0; - typedef detail::AnalysisResultModel + typedef detail::AnalysisResultModel ResultModelT; return &static_cast(ResultConcept)->Result; } /// \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 + /// 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(!ModuleAnalysisPasses.count(PassT::ID()) && + assert(!AnalysisPasses.count(PassT::ID()) && "Registered the same analysis pass twice!"); - ModuleAnalysisPasses[PassT::ID()] = - new detail::AnalysisPassModel( - llvm_move(Pass)); + typedef detail::AnalysisPassModel PassModelT; + AnalysisPasses[PassT::ID()] = new PassModelT(llvm_move(Pass)); } /// \brief Invalidate a specific analysis pass for an IR module. /// /// Note that the analysis result can disregard invalidation. template void invalidate(Module *M) { - assert(ModuleAnalysisPasses.count(PassT::ID()) && + assert(AnalysisPasses.count(PassT::ID()) && "This analysis pass was not registered prior to being invalidated"); - invalidateImpl(PassT::ID(), M); + derived_this()->invalidateImpl(PassT::ID(), M); } - /// \brief Invalidate analyses cached for an IR Module. + /// \brief Invalidate analyses cached for an IR unit. /// /// Walk through all of the analyses pertaining to this module and invalidate /// them unless they are preserved by the PreservedAnalyses set. - void invalidate(Module *M, const PreservedAnalyses &PA); + void invalidate(IRUnitT IR, const PreservedAnalyses &PA) { + derived_this()->invalidateImpl(IR, PA); + } + +protected: + /// \brief Lookup a registered analysis pass. + PassConceptT &lookupPass(void *PassID) { + typename AnalysisPassMapT::iterator PI = AnalysisPasses.find(PassID); + assert(PI != AnalysisPasses.end() && + "Analysis passes must be registered prior to being queried!"); + return *PI->second; + } + + /// \brief Lookup a registered analysis pass. + const PassConceptT &lookupPass(void *PassID) const { + typename AnalysisPassMapT::const_iterator PI = AnalysisPasses.find(PassID); + assert(PI != AnalysisPasses.end() && + "Analysis passes must be registered prior to being queried!"); + return *PI->second; + } + +private: + /// \brief Map type from module analysis pass ID to pass concept pointer. + typedef DenseMap > AnalysisPassMapT; + + /// \brief Collection of module analysis passes, indexed by ID. + AnalysisPassMapT AnalysisPasses; +}; + +} + +/// \brief A module analysis pass manager with lazy running and caching of +/// results. +class ModuleAnalysisManager + : public detail::AnalysisManagerBase { + friend class detail::AnalysisManagerBase; + typedef detail::AnalysisManagerBase BaseT; + typedef typename BaseT::ResultConceptT ResultConceptT; + typedef typename BaseT::PassConceptT PassConceptT; + +public: + // Public methods provided by the base class. private: /// \brief Get a module pass result, running the pass if necessary. - const detail::AnalysisResultConcept &getResultImpl(void *PassID, - Module *M); + const ResultConceptT &getResultImpl(void *PassID, Module *M); /// \brief Get a cached module pass result or return null. - const detail::AnalysisResultConcept * - getCachedResultImpl(void *PassID, Module *M) const; + const ResultConceptT *getCachedResultImpl(void *PassID, Module *M) const; /// \brief Invalidate a module pass result. void invalidateImpl(void *PassID, Module *M); - /// \brief Map type from module analysis pass ID to pass concept pointer. - typedef DenseMap > > - ModuleAnalysisPassMapT; - - /// \brief Collection of module analysis passes, indexed by ID. - ModuleAnalysisPassMapT ModuleAnalysisPasses; + /// \brief Invalidate results across a module. + void invalidateImpl(Module *M, const PreservedAnalyses &PA); /// \brief Map type from module analysis pass ID to pass result concept pointer. typedef DenseMap { + friend class detail::AnalysisManagerBase; + typedef detail::AnalysisManagerBase BaseT; + typedef typename BaseT::ResultConceptT ResultConceptT; + typedef typename BaseT::PassConceptT PassConceptT; + public: - FunctionAnalysisManager() {} - - /// \brief Get the result of an analysis pass for a function. - /// - /// If there is not a valid cached result in the manager already, this will - /// re-run the analysis to produce a valid result. - template - const typename PassT::Result &getResult(Function *F) { - assert(FunctionAnalysisPasses.count(PassT::ID()) && - "This analysis pass was not registered prior to being queried"); - - const detail::AnalysisResultConcept &ResultConcept = - getResultImpl(PassT::ID(), F); - typedef detail::AnalysisResultModel ResultModelT; - return static_cast(ResultConcept).Result; - } - - /// \brief Get the cached result of an analysis pass for a function if - /// available. - /// - /// Does not run the analysis ever. - /// \returns null if a cached result is not available. - template - const typename PassT::Result *getCachedResult(Function *F) { - assert(FunctionAnalysisPasses.count(PassT::ID()) && - "This analysis pass was not registered prior to being queried"); - - const detail::AnalysisResultConcept *ResultConcept = - getCachedResultImpl(PassT::ID(), F); - if (!ResultConcept) - return 0; - - typedef detail::AnalysisResultModel ResultModelT; - return &static_cast(ResultConcept)->Result; - } - - /// \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(!FunctionAnalysisPasses.count(PassT::ID()) && - "Registered the same analysis pass twice!"); - FunctionAnalysisPasses[PassT::ID()] = new detail::AnalysisPassModel< - Function *, FunctionAnalysisManager, PassT>(llvm_move(Pass)); - } - - /// \brief Invalidate a specific analysis pass for an IR module. - /// - /// Note that the analysis result can disregard invalidation. - template void invalidate(Function *F) { - assert(FunctionAnalysisPasses.count(PassT::ID()) && - "This analysis pass was not registered prior to being invalidated"); - invalidateImpl(PassT::ID(), F); - } - - /// \brief Invalidate analyses cached for an IR Function. - /// - /// Walk through all of the analyses cache for this IR function and - /// invalidate them unless they are preserved by the provided - /// PreservedAnalyses set. - void invalidate(Function *F, const PreservedAnalyses &PA); + // Most public APIs are inherited from the CRTP base class. /// \brief Returns true if the analysis manager has an empty results cache. bool empty() const; @@ -624,23 +615,16 @@ public: private: /// \brief Get a function pass result, running the pass if necessary. - const detail::AnalysisResultConcept &getResultImpl(void *PassID, - Function *F); + const ResultConceptT &getResultImpl(void *PassID, Function *F); /// \brief Get a cached function pass result or return null. - const detail::AnalysisResultConcept * - getCachedResultImpl(void *PassID, Function *F) const; + const ResultConceptT *getCachedResultImpl(void *PassID, Function *F) const; /// \brief Invalidate a function pass result. void invalidateImpl(void *PassID, Function *F); - /// \brief Map type from function analysis pass ID to pass concept pointer. - typedef DenseMap > > - FunctionAnalysisPassMapT; - - /// \brief Collection of function analysis passes, indexed by ID. - FunctionAnalysisPassMapT FunctionAnalysisPasses; + /// \brief Invalidate the results for a function.. + void invalidateImpl(Function *F, const PreservedAnalyses &PA); /// \brief List of function analysis pass IDs and associated concept pointers. /// diff --git a/lib/IR/PassManager.cpp b/lib/IR/PassManager.cpp index 05aea0743ae..30b46b01c1d 100644 --- a/lib/IR/PassManager.cpp +++ b/lib/IR/PassManager.cpp @@ -23,37 +23,22 @@ PreservedAnalyses ModulePassManager::run(Module *M, ModuleAnalysisManager *AM) { return PA; } -void ModuleAnalysisManager::invalidate(Module *M, const PreservedAnalyses &PA) { - // FIXME: This is a total hack based on the fact that erasure doesn't - // invalidate iteration for DenseMap. - for (ModuleAnalysisResultMapT::iterator I = ModuleAnalysisResults.begin(), - E = ModuleAnalysisResults.end(); - I != E; ++I) - if (I->second->invalidate(M, PA)) - ModuleAnalysisResults.erase(I); -} - -const detail::AnalysisResultConcept & +const ModuleAnalysisManager::ResultConceptT & ModuleAnalysisManager::getResultImpl(void *PassID, Module *M) { ModuleAnalysisResultMapT::iterator RI; bool Inserted; llvm::tie(RI, Inserted) = ModuleAnalysisResults.insert(std::make_pair( PassID, polymorphic_ptr >())); - if (Inserted) { - // We don't have a cached result for this result. Look up the pass and run - // it to produce a result, which we then add to the cache. - ModuleAnalysisPassMapT::const_iterator PI = - ModuleAnalysisPasses.find(PassID); - assert(PI != ModuleAnalysisPasses.end() && - "Analysis passes must be registered prior to being queried!"); - RI->second = PI->second->run(M, this); - } + // If we don't have a cached result for this module, look up the pass and run + // it to produce a result, which we then add to the cache. + if (Inserted) + RI->second = lookupPass(PassID).run(M, this); return *RI->second; } -const detail::AnalysisResultConcept * +const ModuleAnalysisManager::ResultConceptT * ModuleAnalysisManager::getCachedResultImpl(void *PassID, Module *M) const { ModuleAnalysisResultMapT::const_iterator RI = ModuleAnalysisResults.find(PassID); return RI == ModuleAnalysisResults.end() ? 0 : &*RI->second; @@ -63,6 +48,17 @@ void ModuleAnalysisManager::invalidateImpl(void *PassID, Module *M) { ModuleAnalysisResults.erase(PassID); } +void ModuleAnalysisManager::invalidateImpl(Module *M, + const PreservedAnalyses &PA) { + // FIXME: This is a total hack based on the fact that erasure doesn't + // invalidate iteration for DenseMap. + for (ModuleAnalysisResultMapT::iterator I = ModuleAnalysisResults.begin(), + E = ModuleAnalysisResults.end(); + I != E; ++I) + if (I->second->invalidate(M, PA)) + ModuleAnalysisResults.erase(I); +} + PreservedAnalyses FunctionPassManager::run(Function *F, FunctionAnalysisManager *AM) { PreservedAnalyses PA = PreservedAnalyses::all(); for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) { @@ -74,7 +70,55 @@ PreservedAnalyses FunctionPassManager::run(Function *F, FunctionAnalysisManager return PA; } -void FunctionAnalysisManager::invalidate(Function *F, const PreservedAnalyses &PA) { +bool FunctionAnalysisManager::empty() const { + assert(FunctionAnalysisResults.empty() == + FunctionAnalysisResultLists.empty() && + "The storage and index of analysis results disagree on how many there " + "are!"); + return FunctionAnalysisResults.empty(); +} + +void FunctionAnalysisManager::clear() { + FunctionAnalysisResults.clear(); + FunctionAnalysisResultLists.clear(); +} + +const FunctionAnalysisManager::ResultConceptT & +FunctionAnalysisManager::getResultImpl(void *PassID, Function *F) { + FunctionAnalysisResultMapT::iterator RI; + bool Inserted; + llvm::tie(RI, Inserted) = FunctionAnalysisResults.insert(std::make_pair( + std::make_pair(PassID, F), FunctionAnalysisResultListT::iterator())); + + // If we don't have a cached result for this function, look up the pass and + // run it to produce a result, which we then add to the cache. + if (Inserted) { + FunctionAnalysisResultListT &ResultList = FunctionAnalysisResultLists[F]; + ResultList.push_back(std::make_pair(PassID, lookupPass(PassID).run(F, this))); + RI->second = llvm::prior(ResultList.end()); + } + + return *RI->second->second; +} + +const FunctionAnalysisManager::ResultConceptT * +FunctionAnalysisManager::getCachedResultImpl(void *PassID, Function *F) const { + FunctionAnalysisResultMapT::const_iterator RI = + FunctionAnalysisResults.find(std::make_pair(PassID, F)); + return RI == FunctionAnalysisResults.end() ? 0 : &*RI->second->second; +} + +void FunctionAnalysisManager::invalidateImpl(void *PassID, Function *F) { + FunctionAnalysisResultMapT::iterator RI = + FunctionAnalysisResults.find(std::make_pair(PassID, F)); + if (RI == FunctionAnalysisResults.end()) + return; + + FunctionAnalysisResultLists[F].erase(RI->second); +} + +void FunctionAnalysisManager::invalidateImpl(Function *F, + const PreservedAnalyses &PA) { // Clear all the invalidated results associated specifically with this // function. SmallVector InvalidatedPassIDs; @@ -93,57 +137,6 @@ void FunctionAnalysisManager::invalidate(Function *F, const PreservedAnalyses &P std::make_pair(InvalidatedPassIDs.pop_back_val(), F)); } -bool FunctionAnalysisManager::empty() const { - assert(FunctionAnalysisResults.empty() == - FunctionAnalysisResultLists.empty() && - "The storage and index of analysis results disagree on how many there " - "are!"); - return FunctionAnalysisResults.empty(); -} - -void FunctionAnalysisManager::clear() { - FunctionAnalysisResults.clear(); - FunctionAnalysisResultLists.clear(); -} - -const detail::AnalysisResultConcept & -FunctionAnalysisManager::getResultImpl(void *PassID, Function *F) { - FunctionAnalysisResultMapT::iterator RI; - bool Inserted; - llvm::tie(RI, Inserted) = FunctionAnalysisResults.insert(std::make_pair( - std::make_pair(PassID, F), FunctionAnalysisResultListT::iterator())); - - if (Inserted) { - // We don't have a cached result for this result. Look up the pass and run - // it to produce a result, which we then add to the cache. - FunctionAnalysisPassMapT::const_iterator PI = - FunctionAnalysisPasses.find(PassID); - assert(PI != FunctionAnalysisPasses.end() && - "Analysis passes must be registered prior to being queried!"); - FunctionAnalysisResultListT &ResultList = FunctionAnalysisResultLists[F]; - ResultList.push_back(std::make_pair(PassID, PI->second->run(F, this))); - RI->second = llvm::prior(ResultList.end()); - } - - return *RI->second->second; -} - -const detail::AnalysisResultConcept * -FunctionAnalysisManager::getCachedResultImpl(void *PassID, Function *F) const { - FunctionAnalysisResultMapT::const_iterator RI = - FunctionAnalysisResults.find(std::make_pair(PassID, F)); - return RI == FunctionAnalysisResults.end() ? 0 : &*RI->second->second; -} - -void FunctionAnalysisManager::invalidateImpl(void *PassID, Function *F) { - FunctionAnalysisResultMapT::iterator RI = - FunctionAnalysisResults.find(std::make_pair(PassID, F)); - if (RI == FunctionAnalysisResults.end()) - return; - - FunctionAnalysisResultLists[F].erase(RI->second); -} - char FunctionAnalysisManagerModuleProxy::PassID; FunctionAnalysisManagerModuleProxy::Result