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