[llvm] r195747 - [PM] Factor the overwhelming majority of the interface boiler plate out

Chandler Carruth chandlerc at gmail.com
Tue Nov 26 03:24:37 PST 2013


Author: chandlerc
Date: Tue Nov 26 05:24:37 2013
New Revision: 195747

URL: http://llvm.org/viewvc/llvm-project?rev=195747&view=rev
Log:
[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.

Modified:
    llvm/trunk/include/llvm/IR/PassManager.h
    llvm/trunk/lib/IR/PassManager.cpp

Modified: llvm/trunk/include/llvm/IR/PassManager.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/PassManager.h?rev=195747&r1=195746&r2=195747&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/PassManager.h (original)
+++ llvm/trunk/include/llvm/IR/PassManager.h Tue Nov 26 05:24:37 2013
@@ -439,23 +439,43 @@ private:
   std::vector<polymorphic_ptr<FunctionPassConcept> > 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 <typename DerivedT, typename IRUnitT>
+class AnalysisManagerBase {
+  DerivedT *derived_this() { return static_cast<DerivedT *>(this); }
+  const DerivedT *derived_this() const { return static_cast<const DerivedT *>(this); }
+
+protected:
+  typedef detail::AnalysisResultConcept<IRUnitT> ResultConceptT;
+  typedef detail::AnalysisPassConcept<IRUnitT, DerivedT> 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 <typename PassT> const typename PassT::Result &getResult(Module *M) {
-    assert(ModuleAnalysisPasses.count(PassT::ID()) &&
+  template <typename PassT> 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<Module *> &ResultConcept =
-        getResultImpl(PassT::ID(), M);
-    typedef detail::AnalysisResultModel<Module *, PassT, typename PassT::Result>
+    const ResultConceptT &ResultConcept =
+        derived_this()->getResultImpl(PassT::ID(), IR);
+    typedef detail::AnalysisResultModel<IRUnitT, PassT, typename PassT::Result>
         ResultModelT;
     return static_cast<const ResultModelT &>(ResultConcept).Result;
   }
@@ -466,69 +486,100 @@ public:
   ///
   /// \returns null if there is no cached result.
   template <typename PassT>
-  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<Module *> *ResultConcept =
-        getCachedResultImpl(PassT::ID(), M);
+    const ResultConceptT *ResultConcept =
+        derived_this()->getCachedResultImpl(PassT::ID(), IR);
     if (!ResultConcept)
       return 0;
 
-    typedef detail::AnalysisResultModel<Module *, PassT, typename PassT::Result>
+    typedef detail::AnalysisResultModel<IRUnitT, PassT, typename PassT::Result>
         ResultModelT;
     return &static_cast<const ResultModelT *>(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 <typename PassT> 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<Module *, ModuleAnalysisManager, PassT>(
-            llvm_move(Pass));
+    typedef detail::AnalysisPassModel<IRUnitT, DerivedT, PassT> 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 <typename PassT> 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<void *, polymorphic_ptr<PassConceptT> > 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<ModuleAnalysisManager, Module *> {
+  friend class detail::AnalysisManagerBase<ModuleAnalysisManager, Module *>;
+  typedef detail::AnalysisManagerBase<ModuleAnalysisManager, Module *> 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<Module *> &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<Module *> *
-  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<void *, polymorphic_ptr<detail::AnalysisPassConcept<
-                               Module *, ModuleAnalysisManager> > >
-      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<void *,
@@ -541,75 +592,15 @@ private:
 
 /// \brief A function analysis manager to coordinate and cache analyses run over
 /// a module.
-class FunctionAnalysisManager {
-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 <typename PassT>
-  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<Function *> &ResultConcept =
-        getResultImpl(PassT::ID(), F);
-    typedef detail::AnalysisResultModel<Function *, PassT,
-                                        typename PassT::Result> ResultModelT;
-    return static_cast<const ResultModelT &>(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 <typename PassT>
-  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<Function *> *ResultConcept =
-        getCachedResultImpl(PassT::ID(), F);
-    if (!ResultConcept)
-      return 0;
-
-    typedef detail::AnalysisResultModel<Function *, PassT,
-                                        typename PassT::Result> ResultModelT;
-    return &static_cast<const ResultModelT *>(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 <typename PassT> 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));
-  }
+class FunctionAnalysisManager
+    : public detail::AnalysisManagerBase<FunctionAnalysisManager, Function *> {
+  friend class detail::AnalysisManagerBase<FunctionAnalysisManager, Function *>;
+  typedef detail::AnalysisManagerBase<FunctionAnalysisManager, Function *> BaseT;
+  typedef typename BaseT::ResultConceptT ResultConceptT;
+  typedef typename BaseT::PassConceptT PassConceptT;
 
-  /// \brief Invalidate a specific analysis pass for an IR module.
-  ///
-  /// Note that the analysis result can disregard invalidation.
-  template <typename PassT> 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);
+public:
+  // 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<Function *> &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<Function *> *
-  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<void *, polymorphic_ptr<detail::AnalysisPassConcept<
-                               Function *, FunctionAnalysisManager> > >
-      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.
   ///

Modified: llvm/trunk/lib/IR/PassManager.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/PassManager.cpp?rev=195747&r1=195746&r2=195747&view=diff
==============================================================================
--- llvm/trunk/lib/IR/PassManager.cpp (original)
+++ llvm/trunk/lib/IR/PassManager.cpp Tue Nov 26 05:24:37 2013
@@ -23,37 +23,22 @@ PreservedAnalyses ModulePassManager::run
   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<Module *> &
+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<detail::AnalysisResultConcept<Module *> >()));
 
-  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<Module *> *
+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::invalidateIm
   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,25 +70,6 @@ PreservedAnalyses FunctionPassManager::r
   return PA;
 }
 
-void FunctionAnalysisManager::invalidate(Function *F, const PreservedAnalyses &PA) {
-  // Clear all the invalidated results associated specifically with this
-  // function.
-  SmallVector<void *, 8> InvalidatedPassIDs;
-  FunctionAnalysisResultListT &ResultsList = FunctionAnalysisResultLists[F];
-  for (FunctionAnalysisResultListT::iterator I = ResultsList.begin(),
-                                             E = ResultsList.end();
-       I != E;)
-    if (I->second->invalidate(F, PA)) {
-      InvalidatedPassIDs.push_back(I->first);
-      I = ResultsList.erase(I);
-    } else {
-      ++I;
-    }
-  while (!InvalidatedPassIDs.empty())
-    FunctionAnalysisResults.erase(
-        std::make_pair(InvalidatedPassIDs.pop_back_val(), F));
-}
-
 bool FunctionAnalysisManager::empty() const {
   assert(FunctionAnalysisResults.empty() ==
              FunctionAnalysisResultLists.empty() &&
@@ -106,29 +83,25 @@ void FunctionAnalysisManager::clear() {
   FunctionAnalysisResultLists.clear();
 }
 
-const detail::AnalysisResultConcept<Function *> &
+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) {
-    // 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)));
+    ResultList.push_back(std::make_pair(PassID, lookupPass(PassID).run(F, this)));
     RI->second = llvm::prior(ResultList.end());
   }
 
   return *RI->second->second;
 }
 
-const detail::AnalysisResultConcept<Function *> *
+const FunctionAnalysisManager::ResultConceptT *
 FunctionAnalysisManager::getCachedResultImpl(void *PassID, Function *F) const {
   FunctionAnalysisResultMapT::const_iterator RI =
       FunctionAnalysisResults.find(std::make_pair(PassID, F));
@@ -144,6 +117,26 @@ void FunctionAnalysisManager::invalidate
   FunctionAnalysisResultLists[F].erase(RI->second);
 }
 
+void FunctionAnalysisManager::invalidateImpl(Function *F,
+                                             const PreservedAnalyses &PA) {
+  // Clear all the invalidated results associated specifically with this
+  // function.
+  SmallVector<void *, 8> InvalidatedPassIDs;
+  FunctionAnalysisResultListT &ResultsList = FunctionAnalysisResultLists[F];
+  for (FunctionAnalysisResultListT::iterator I = ResultsList.begin(),
+                                             E = ResultsList.end();
+       I != E;)
+    if (I->second->invalidate(F, PA)) {
+      InvalidatedPassIDs.push_back(I->first);
+      I = ResultsList.erase(I);
+    } else {
+      ++I;
+    }
+  while (!InvalidatedPassIDs.empty())
+    FunctionAnalysisResults.erase(
+        std::make_pair(InvalidatedPassIDs.pop_back_val(), F));
+}
+
 char FunctionAnalysisManagerModuleProxy::PassID;
 
 FunctionAnalysisManagerModuleProxy::Result





More information about the llvm-commits mailing list