[llvm] r195332 - [PM] Add support for using SFINAE to reflect on an analysis's result

Chandler Carruth chandlerc at gmail.com
Thu Nov 21 01:10:22 PST 2013


Author: chandlerc
Date: Thu Nov 21 03:10:21 2013
New Revision: 195332

URL: http://llvm.org/viewvc/llvm-project?rev=195332&view=rev
Log:
[PM] Add support for using SFINAE to reflect on an analysis's result
type and detect whether or not it provides an 'invalidate' member the
analysis manager should use.

This lets the overwhelming common case of *not* caring about custom
behavior when an analysis is invalidated be the the obvious default
behavior with no code written by the author of an analysis. Only when
they write code specifically to handle invalidation does it get used.

Both cases are actually covered by tests here. The test analysis uses
the default behavior, and the proxy module analysis actually has custom
behavior on invalidation that is firing correctly. (In fact, this is the
analysis which was the primary motivation for having custom invalidation
behavior in the first place.)

Modified:
    llvm/trunk/include/llvm/IR/PassManager.h
    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=195332&r1=195331&r2=195332&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/PassManager.h (original)
+++ llvm/trunk/include/llvm/IR/PassManager.h Thu Nov 21 03:10:21 2013
@@ -194,10 +194,33 @@ template <typename IRUnitT> struct Analy
 
 /// \brief Wrapper to model the analysis result concept.
 ///
+/// By default, this will implement the invalidate method with a trivial
+/// implementation so that the actual analysis result doesn't need to provide
+/// an invalidation handler. It is only selected when the invalidation handler
+/// is not part of the ResultT's interface.
+template <typename IRUnitT, typename ResultT, bool HasInvalidateHandler = false>
+struct AnalysisResultModel : AnalysisResultConcept<IRUnitT> {
+  AnalysisResultModel(ResultT Result) : Result(llvm_move(Result)) {}
+  virtual AnalysisResultModel *clone() {
+    return new AnalysisResultModel(Result);
+  }
+
+  /// \brief The model returns true to allow the invalidation.
+  //
+  // FIXME: We should actually use two different concepts for analysis results
+  // rather than two different models, and avoid the indirect function call for
+  // ones that use the trivial behavior.
+  virtual bool invalidate(IRUnitT *) { return true; }
+
+  ResultT Result;
+};
+
+/// \brief Wrapper to model the analysis result concept.
+///
 /// Can wrap any type which implements a suitable invalidate member and model
 /// the AnalysisResultConcept for the AnalysisManager.
 template <typename IRUnitT, typename ResultT>
-struct AnalysisResultModel : AnalysisResultConcept<IRUnitT> {
+struct AnalysisResultModel<IRUnitT, ResultT, true> : AnalysisResultConcept<IRUnitT> {
   AnalysisResultModel(ResultT Result) : Result(llvm_move(Result)) {}
   virtual AnalysisResultModel *clone() {
     return new AnalysisResultModel(Result);
@@ -209,6 +232,19 @@ struct AnalysisResultModel : AnalysisRes
   ResultT Result;
 };
 
+/// \brief SFINAE metafunction for computing whether \c ResultT provides an
+/// \c invalidate member function.
+template <typename IRUnitT, typename ResultT> class ResultHasInvalidateMethod {
+  typedef char SmallType;
+  struct BigType { char a, b; };
+  template <typename T, bool (T::*)(IRUnitT *)> struct Checker;
+  template <typename T> static SmallType f(Checker<T, &T::invalidate> *);
+  template <typename T> static BigType f(...);
+
+public:
+  enum { Value = sizeof(f<ResultT>(0)) == sizeof(SmallType) };
+};
+
 /// \brief Abstract concept of an analysis pass.
 ///
 /// This concept is parameterized over the IR unit that it can run over and
@@ -237,7 +273,10 @@ struct AnalysisPassModel : AnalysisPassC
   typedef typename PassT::IRUnitT IRUnitT;
 
   // FIXME: Replace PassT::Result with type traits when we use C++11.
-  typedef AnalysisResultModel<IRUnitT, typename PassT::Result> ResultModelT;
+  typedef AnalysisResultModel<
+      IRUnitT, typename PassT::Result,
+      ResultHasInvalidateMethod<IRUnitT, typename PassT::Result>::Value>
+          ResultModelT;
 
   /// \brief The model delegates to the \c PassT::run method.
   ///
@@ -323,8 +362,10 @@ public:
 
     const detail::AnalysisResultConcept<Module> &ResultConcept =
         getResultImpl(PassT::ID(), M);
-    typedef detail::AnalysisResultModel<Module, typename PassT::Result>
-        ResultModelT;
+    typedef detail::AnalysisResultModel<
+        Module, typename PassT::Result,
+        detail::ResultHasInvalidateMethod<
+            Module, typename PassT::Result>::Value> ResultModelT;
     return static_cast<const ResultModelT &>(ResultConcept).Result;
   }
 
@@ -405,8 +446,10 @@ public:
 
     const detail::AnalysisResultConcept<Function> &ResultConcept =
         getResultImpl(PassT::ID(), F);
-    typedef detail::AnalysisResultModel<Function, typename PassT::Result>
-        ResultModelT;
+    typedef detail::AnalysisResultModel<
+        Function, typename PassT::Result,
+        detail::ResultHasInvalidateMethod<
+            Function, typename PassT::Result>::Value> ResultModelT;
     return static_cast<const ResultModelT &>(ResultConcept).Result;
   }
 

Modified: llvm/trunk/unittests/IR/PassManagerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/PassManagerTest.cpp?rev=195332&r1=195331&r2=195332&view=diff
==============================================================================
--- llvm/trunk/unittests/IR/PassManagerTest.cpp (original)
+++ llvm/trunk/unittests/IR/PassManagerTest.cpp Thu Nov 21 03:10:21 2013
@@ -25,7 +25,6 @@ public:
 
   struct Result {
     Result(int Count) : InstructionCount(Count) {}
-    bool invalidate(Function *) { return true; }
     int InstructionCount;
   };
 





More information about the llvm-commits mailing list