[PM] Use a simpler technique to drop optional analysis manager arguments
authorChandler Carruth <chandlerc@gmail.com>
Wed, 27 May 2015 09:02:51 +0000 (09:02 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Wed, 27 May 2015 09:02:51 +0000 (09:02 +0000)
when invoking run methods.

This technique was suggested by Dinesh Dwivedi who also wrote the
original patch. During the code review, they explained to me that this
isn't a fully general technique as we need to know the signatures of the
method candidates. Since this is really a narrower utility, I switched
the names and structure to be more clearly a specialized run method
invoke helper and commented it accordingly. I still think this is
a pretty big win.

Very sorry to Dinesh for the extreme delay in landing this patch. I've
been far to busy poking at other things.

Original review: http://reviews.llvm.org/D3543

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238305 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/IR/PassManagerInternal.h

index 92de10b..ebc7374 100644 (file)
@@ -29,41 +29,56 @@ class PreservedAnalyses;
 /// \brief Implementation details of the pass manager interfaces.
 namespace detail {
 
+/// \brief Helper template to run a pass *with* an optional analysis manager.
+///
+/// This accepts the address of the run method as an argument to detect that it
+/// accepts the analysis manager and pass it through. This isn't (quite)
+/// a generic optional argument invocation tool, and couldn't be without making
+/// the calling syntax significantly more verbose.
+template <typename ResultT, typename IRUnitT, typename PassT>
+ResultT invokeRunMethod(PassT &Pass,
+                        ResultT (PassT::*run)(IRUnitT &,
+                                              AnalysisManager<IRUnitT> *),
+                        IRUnitT &IR, AnalysisManager<IRUnitT> *AM) {
+  return (Pass.*run)(IR, AM);
+}
+
+/// \brief Helper template to run a pass *without* an optional analysis manager.
+///
+/// This accepts the address of the run method as an argument to detect that it
+/// does not accept an analysis manager and drop it. This isn't (quite)
+/// a generic optional argument invocation tool, and couldn't be without making
+/// the calling syntax significantly more verbose.
+template <typename ResultT, typename IRUnitT, typename PassT>
+ResultT invokeRunMethod(
+    PassT &Pass,
+    ResultT (PassT::*run)(IRUnitT &),
+    IRUnitT &IR, AnalysisManager<IRUnitT> * /*AM*/) {
+  return (Pass.*run)(IR);
+}
+
 /// \brief Template for the abstract base class used to dispatch
 /// polymorphically over pass objects.
-template <typename IRUnitT> struct PassConcept {
-  // Boiler plate necessary for the container of derived classes.
-  virtual ~PassConcept() {}
+template <typename ResultT, typename IRUnitT> struct PassConceptBase {
+  virtual ~PassConceptBase() {}
 
   /// \brief The polymorphic API which runs the pass over a given IR entity.
   ///
   /// 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, AnalysisManager<IRUnitT> *AM) = 0;
+  virtual ResultT run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) = 0;
 
   /// \brief Polymorphic method to access the name of a pass.
   virtual StringRef name() = 0;
 };
 
-/// \brief SFINAE metafunction for computing whether \c PassT has a run method
-/// accepting an \c AnalysisManager<IRUnitT>.
-template <typename IRUnitT, typename PassT, typename ResultT>
-class PassRunAcceptsAnalysisManager {
-  typedef char SmallType;
-  struct BigType {
-    char a, b;
-  };
-
-  template <typename T, ResultT (T::*)(IRUnitT &, AnalysisManager<IRUnitT> *)>
-  struct Checker;
-
-  template <typename T> static SmallType f(Checker<T, &T::run> *);
-  template <typename T> static BigType f(...);
-
-public:
-  enum { Value = sizeof(f<PassT>(nullptr)) == sizeof(SmallType) };
-};
+/// \brief Abstract concept of an transform pass.
+///
+/// This concept is parameterized over the IR unit that it can run over and
+/// returns status of preserved analyses.
+template <typename IRUnitT>
+using PassConcept = PassConceptBase<PreservedAnalyses, IRUnitT>;
 
 /// \brief A template wrapper used to implement the polymorphic API.
 ///
@@ -72,42 +87,8 @@ public:
 /// \c run method also accepts an \c AnalysisManager<IRUnitT>*, we pass it
 /// along.
 template <typename IRUnitT, typename PassT,
-          typename PreservedAnalysesT = PreservedAnalyses,
-          bool AcceptsAnalysisManager = PassRunAcceptsAnalysisManager<
-              IRUnitT, PassT, PreservedAnalysesT>::Value>
-struct PassModel;
-
-/// \brief Specialization of \c PassModel for passes that accept an analyis
-/// manager.
-template <typename IRUnitT, typename PassT, typename PreservedAnalysesT>
-struct PassModel<IRUnitT, PassT, PreservedAnalysesT, true>
-    : PassConcept<IRUnitT> {
-  explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {}
-  // We have to explicitly define all the special member functions because MSVC
-  // refuses to generate them.
-  PassModel(const PassModel &Arg) : Pass(Arg.Pass) {}
-  PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
-  friend void swap(PassModel &LHS, PassModel &RHS) {
-    using std::swap;
-    swap(LHS.Pass, RHS.Pass);
-  }
-  PassModel &operator=(PassModel RHS) {
-    swap(*this, RHS);
-    return *this;
-  }
-
-  PreservedAnalysesT run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) override {
-    return Pass.run(IR, AM);
-  }
-  StringRef name() override { return PassT::name(); }
-  PassT Pass;
-};
-
-/// \brief Specialization of \c PassModel for passes that accept an analyis
-/// manager.
-template <typename IRUnitT, typename PassT, typename PreservedAnalysesT>
-struct PassModel<IRUnitT, PassT, PreservedAnalysesT, false>
-    : PassConcept<IRUnitT> {
+          typename PreservedAnalysesT = PreservedAnalyses>
+struct PassModel : PassConcept<IRUnitT> {
   explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {}
   // We have to explicitly define all the special member functions because MSVC
   // refuses to generate them.
@@ -122,8 +103,9 @@ struct PassModel<IRUnitT, PassT, PreservedAnalysesT, false>
     return *this;
   }
 
+  /// \brief The model delegates to the \c PassT::run method.
   PreservedAnalysesT run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) override {
-    return Pass.run(IR);
+    return invokeRunMethod<PreservedAnalysesT>(Pass, &PassT::run, IR, AM);
   }
   StringRef name() override { return PassT::name(); }
   PassT Pass;
@@ -245,33 +227,17 @@ struct AnalysisResultModel<IRUnitT, PassT, ResultT, PreservedAnalysesT, true>
 ///
 /// This concept is parameterized over the IR unit that it can run over and
 /// produce an analysis result.
-template <typename IRUnitT> struct AnalysisPassConcept {
-  virtual ~AnalysisPassConcept() {}
-
-  /// \brief Method to run this analysis over a unit of IR.
-  /// \returns A unique_ptr to the analysis result object to be queried by
-  /// users.
-  virtual std::unique_ptr<AnalysisResultConcept<IRUnitT>>
-  run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) = 0;
-
-  /// \brief Polymorphic method to access the name of a pass.
-  virtual StringRef name() = 0;
-};
+template <typename IRUnitT>
+using AnalysisPassConcept =
+    PassConceptBase<std::unique_ptr<AnalysisResultConcept<IRUnitT>>, IRUnitT>;
 
 /// \brief Wrapper to model the analysis pass concept.
 ///
 /// Can wrap any type which implements a suitable \c run method. The method
 /// must accept the IRUnitT as an argument and produce an object which can be
 /// wrapped in a \c AnalysisResultModel.
-template <typename IRUnitT, typename PassT,
-          bool AcceptsAnalysisManager = PassRunAcceptsAnalysisManager<
-              IRUnitT, PassT, typename PassT::Result>::Value>
-struct AnalysisPassModel;
-
-/// \brief Specialization of \c AnalysisPassModel which passes an
-/// \c AnalysisManager to PassT's run method.
 template <typename IRUnitT, typename PassT>
-struct AnalysisPassModel<IRUnitT, PassT, true> : AnalysisPassConcept<IRUnitT> {
+struct AnalysisPassModel : AnalysisPassConcept<IRUnitT> {
   explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {}
   // We have to explicitly define all the special member functions because MSVC
   // refuses to generate them.
@@ -287,53 +253,16 @@ struct AnalysisPassModel<IRUnitT, PassT, true> : AnalysisPassConcept<IRUnitT> {
   }
 
   // FIXME: Replace PassT::Result with type traits when we use C++11.
-  typedef AnalysisResultModel<IRUnitT, PassT, typename PassT::Result>
-      ResultModelT;
+  using ResultT = typename PassT::Result;
+  using ResultModelT = AnalysisResultModel<IRUnitT, PassT, ResultT>;
 
   /// \brief The model delegates to the \c PassT::run method.
   ///
   /// The return is wrapped in an \c AnalysisResultModel.
   std::unique_ptr<AnalysisResultConcept<IRUnitT>>
   run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) override {
-    return make_unique<ResultModelT>(Pass.run(IR, AM));
-  }
-
-  /// \brief The model delegates to a static \c PassT::name method.
-  ///
-  /// The returned string ref must point to constant immutable data!
-  StringRef name() override { return PassT::name(); }
-
-  PassT Pass;
-};
-
-/// \brief Specialization of \c AnalysisPassModel which does not pass an
-/// \c AnalysisManager to PassT's run method.
-template <typename IRUnitT, typename PassT>
-struct AnalysisPassModel<IRUnitT, PassT, false> : AnalysisPassConcept<IRUnitT> {
-  explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {}
-  // We have to explicitly define all the special member functions because MSVC
-  // refuses to generate them.
-  AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {}
-  AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
-  friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) {
-    using std::swap;
-    swap(LHS.Pass, RHS.Pass);
-  }
-  AnalysisPassModel &operator=(AnalysisPassModel RHS) {
-    swap(*this, RHS);
-    return *this;
-  }
-
-  // FIXME: Replace PassT::Result with type traits when we use C++11.
-  typedef AnalysisResultModel<IRUnitT, PassT, typename PassT::Result>
-      ResultModelT;
-
-  /// \brief The model delegates to the \c PassT::run method.
-  ///
-  /// The return is wrapped in an \c AnalysisResultModel.
-  std::unique_ptr<AnalysisResultConcept<IRUnitT>>
-  run(IRUnitT &IR, AnalysisManager<IRUnitT> *) override {
-    return make_unique<ResultModelT>(Pass.run(IR));
+    return make_unique<ResultModelT>(
+        invokeRunMethod<ResultT>(Pass, &PassT::run, IR, AM));
   }
 
   /// \brief The model delegates to a static \c PassT::name method.