[llvm] r195400 - [PM] Switch analysis managers to be threaded through the run methods

Chandler Carruth chandlerc at gmail.com
Thu Nov 21 16:43:29 PST 2013


Author: chandlerc
Date: Thu Nov 21 18:43:29 2013
New Revision: 195400

URL: http://llvm.org/viewvc/llvm-project?rev=195400&view=rev
Log:
[PM] Switch analysis managers to be threaded through the run methods
rather than the constructors of passes.

This simplifies the APIs of passes significantly and removes an error
prone pattern where the *same* manager had to be given to every
different layer. With the new API the analysis managers themselves will
have to be cross connected with proxy analyses that allow a pass at one
layer to query for the analysis manager of another layer. The proxy will
both expose a handle to the other layer's manager and it will provide
the invalidation hooks to ensure things remain consistent across layers.
Finally, the outer-most analysis manager has to be passed to the run
method of the outer-most pass manager. The rest of the propagation is
automatic.

I've used SFINAE again to allow passes to completely disregard the
analysis manager if they don't need or want to care. This helps keep
simple things simple for users of the new pass manager.

Also, the system specifically supports passing a null pointer into the
outer-most run method if your pass pipeline neither needs nor wants to
deal with analyses. I find this of dubious utility as while some
*passes* don't care about analysis, I'm not sure there are any
real-world users of the pass manager itself that need to avoid even
creating an analysis manager. But it is easy to support, so there we go.

Finally I renamed the module proxy for the function analysis manager to
the more verbose but less confusing name of
FunctionAnalysisManagerModuleProxy. I hate this name, but I have no idea
what else to name these things. I'm expecting in the fullness of time to
potentially have the complete cross product of types at the proxy layer:

{Module,SCC,Function,Loop,Region}AnalysisManager{Module,SCC,Function,Loop,Region}Proxy

(except for XAnalysisManagerXProxy which doesn't make any sense)

This should make it somewhat easier to do the next phases which is to
build the upward proxy and get its invalidation correct, as well as to
make the invalidation within the Module -> Function mapping pass be more
fine grained so as to invalidate fewer fuction analyses.

After all of the proxy analyses are done and the invalidation working,
I'll finally be able to start working on the next two fun fronts: how to
adapt an existing pass to work in both the legacy pass world and the new
one, and building the SCC, Loop, and Region counterparts. Fun times!

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

Modified: llvm/trunk/include/llvm/IR/PassManager.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/PassManager.h?rev=195400&r1=195399&r2=195400&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/PassManager.h (original)
+++ llvm/trunk/include/llvm/IR/PassManager.h Thu Nov 21 18:43:29 2013
@@ -154,24 +154,69 @@ namespace detail {
 
 /// \brief Template for the abstract base class used to dispatch
 /// polymorphically over pass objects.
-template <typename T> struct PassConcept {
+template <typename IRUnitT, typename AnalysisManagerT> 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 <typename IRUnitT, typename PassT, typename AnalysisManagerT>
+class PassRunAcceptsAnalysisManager {
+  typedef char SmallType;
+  struct BigType { char a, b; };
+
+  template <typename T, PreservedAnalyses (T::*)(IRUnitT, AnalysisManagerT *)>
+  struct Checker;
+
+  template <typename T> static SmallType f(Checker<T, &T::run> *);
+  template <typename T> static BigType f(...);
+
+public:
+  enum { Value = sizeof(f<PassT>(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 <typename T, typename PassT> struct PassModel : PassConcept<T> {
+/// 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 <typename IRUnitT, typename PassT, typename AnalysisManagerT,
+          bool AcceptsAnalysisManager = PassRunAcceptsAnalysisManager<
+              IRUnitT, PassT, AnalysisManagerT>::Value>
+struct PassModel;
+
+/// \brief Specialization of \c PassModel for passes that accept an analyis
+/// manager.
+template <typename IRUnitT, typename PassT, typename AnalysisManagerT>
+struct PassModel<IRUnitT, PassT, AnalysisManagerT,
+                 true> : PassConcept<IRUnitT, AnalysisManagerT> {
   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 <typename IRUnitT, typename PassT, typename AnalysisManagerT>
+struct PassModel<IRUnitT, PassT, AnalysisManagerT,
+                 false> : PassConcept<IRUnitT, AnalysisManagerT> {
+  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 <typename ModulePassT> void addPass(ModulePassT Pass) {
     Passes.push_back(new ModulePassModel<ModulePassT>(llvm_move(Pass)));
@@ -322,13 +367,14 @@ public:
 
 private:
   // Pull in the concept type and model template specialized for modules.
-  typedef detail::PassConcept<Module *> ModulePassConcept;
+  typedef detail::PassConcept<Module *, ModuleAnalysisManager> ModulePassConcept;
   template <typename PassT>
-  struct ModulePassModel : detail::PassModel<Module *, PassT> {
-    ModulePassModel(PassT Pass) : detail::PassModel<Module *, PassT>(Pass) {}
+  struct ModulePassModel
+      : detail::PassModel<Module *, PassT, ModuleAnalysisManager> {
+    ModulePassModel(PassT Pass)
+        : detail::PassModel<Module *, PassT, ModuleAnalysisManager>(Pass) {}
   };
 
-  ModuleAnalysisManager *AM;
   std::vector<polymorphic_ptr<ModulePassConcept> > Passes;
 };
 
@@ -336,24 +382,25 @@ class FunctionAnalysisManager;
 
 class FunctionPassManager {
 public:
-  explicit FunctionPassManager(FunctionAnalysisManager *AM = 0) : AM(AM) {}
+  explicit FunctionPassManager() {}
 
   template <typename FunctionPassT> void addPass(FunctionPassT Pass) {
     Passes.push_back(new FunctionPassModel<FunctionPassT>(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<Function *> FunctionPassConcept;
+  typedef detail::PassConcept<Function *, FunctionAnalysisManager>
+      FunctionPassConcept;
   template <typename PassT>
-  struct FunctionPassModel : detail::PassModel<Function *, PassT> {
+  struct FunctionPassModel
+      : detail::PassModel<Function *, PassT, FunctionAnalysisManager> {
     FunctionPassModel(PassT Pass)
-        : detail::PassModel<Function *, PassT>(Pass) {}
+        : detail::PassModel<Function *, PassT, FunctionAnalysisManager>(Pass) {}
   };
 
-  FunctionAnalysisManager *AM;
   std::vector<polymorphic_ptr<FunctionPassConcept> > 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 <typename FunctionPassT>
 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<FunctionAnalysisModuleProxy>(M);
+  PreservedAnalyses run(Module *M, ModuleAnalysisManager *AM) {
+    FunctionAnalysisManager *FAM = 0;
+    if (AM)
+      // Setup the function analysis manager from its proxy.
+      FAM = &AM->getResult<FunctionAnalysisManagerModuleProxy>(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<FunctionAnalysisModuleProxy>();
+    PA.preserve<FunctionAnalysisManagerModuleProxy>();
     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 <typename FunctionPassT>
 ModuleToFunctionPassAdaptor<FunctionPassT>
-createModuleToFunctionPassAdaptor(FunctionPassT Pass,
-                                  ModuleAnalysisManager *MAM = 0) {
-  return ModuleToFunctionPassAdaptor<FunctionPassT>(llvm_move(Pass), MAM);
+createModuleToFunctionPassAdaptor(FunctionPassT Pass) {
+  return ModuleToFunctionPassAdaptor<FunctionPassT>(llvm_move(Pass));
 }
 
 }

Modified: llvm/trunk/lib/IR/PassManager.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/PassManager.cpp?rev=195400&r1=195399&r2=195400&view=diff
==============================================================================
--- llvm/trunk/lib/IR/PassManager.cpp (original)
+++ llvm/trunk/lib/IR/PassManager.cpp Thu Nov 21 18:43:29 2013
@@ -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::invalidateIm
   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::invalidate
   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.

Modified: llvm/trunk/unittests/IR/PassManagerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/PassManagerTest.cpp?rev=195400&r1=195399&r2=195400&view=diff
==============================================================================
--- llvm/trunk/unittests/IR/PassManagerTest.cpp (original)
+++ llvm/trunk/unittests/IR/PassManagerTest.cpp Thu Nov 21 18:43:29 2013
@@ -73,26 +73,24 @@ struct TestPreservingModulePass {
 struct TestMinPreservingModulePass {
   PreservedAnalyses run(Module *M) {
     PreservedAnalyses PA;
-    PA.preserve<FunctionAnalysisModuleProxy>();
+    PA.preserve<FunctionAnalysisManagerModuleProxy>();
     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<TestAnalysisPass>(F);
+    const TestAnalysisPass::Result &AR = AM->getResult<TestAnalysisPass>(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);





More information about the llvm-commits mailing list