From 212226e11498bc25af8b80375a3e0a49b13bdd03 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Thu, 21 Nov 2013 09:10:21 +0000 Subject: [PATCH] [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.) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@195332 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/PassManager.h | 55 ++++++++++++++++++++++++++++---- unittests/IR/PassManagerTest.cpp | 1 - 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/include/llvm/IR/PassManager.h b/include/llvm/IR/PassManager.h index 368ebaeb178..a37fc8f2f93 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -192,12 +192,35 @@ template struct AnalysisResultConcept { virtual bool invalidate(IRUnitT *IR) = 0; }; +/// \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 +struct AnalysisResultModel : AnalysisResultConcept { + 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 -struct AnalysisResultModel : AnalysisResultConcept { +struct AnalysisResultModel : AnalysisResultConcept { AnalysisResultModel(ResultT Result) : Result(llvm_move(Result)) {} virtual AnalysisResultModel *clone() { return new AnalysisResultModel(Result); @@ -209,6 +232,19 @@ struct AnalysisResultModel : AnalysisResultConcept { ResultT Result; }; +/// \brief SFINAE metafunction for computing whether \c ResultT provides an +/// \c invalidate member function. +template class ResultHasInvalidateMethod { + typedef char SmallType; + struct BigType { char a, b; }; + template struct Checker; + template static SmallType f(Checker *); + template static BigType f(...); + +public: + enum { Value = sizeof(f(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 : AnalysisPassConcept { typedef typename PassT::IRUnitT IRUnitT; // FIXME: Replace PassT::Result with type traits when we use C++11. - typedef AnalysisResultModel ResultModelT; + typedef AnalysisResultModel< + IRUnitT, typename PassT::Result, + ResultHasInvalidateMethod::Value> + ResultModelT; /// \brief The model delegates to the \c PassT::run method. /// @@ -323,8 +362,10 @@ public: const detail::AnalysisResultConcept &ResultConcept = getResultImpl(PassT::ID(), M); - typedef detail::AnalysisResultModel - ResultModelT; + typedef detail::AnalysisResultModel< + Module, typename PassT::Result, + detail::ResultHasInvalidateMethod< + Module, typename PassT::Result>::Value> ResultModelT; return static_cast(ResultConcept).Result; } @@ -405,8 +446,10 @@ public: const detail::AnalysisResultConcept &ResultConcept = getResultImpl(PassT::ID(), F); - typedef detail::AnalysisResultModel - ResultModelT; + typedef detail::AnalysisResultModel< + Function, typename PassT::Result, + detail::ResultHasInvalidateMethod< + Function, typename PassT::Result>::Value> ResultModelT; return static_cast(ResultConcept).Result; } diff --git a/unittests/IR/PassManagerTest.cpp b/unittests/IR/PassManagerTest.cpp index 7cb4f8d8b03..38ef1a43290 100644 --- a/unittests/IR/PassManagerTest.cpp +++ b/unittests/IR/PassManagerTest.cpp @@ -25,7 +25,6 @@ public: struct Result { Result(int Count) : InstructionCount(Count) {} - bool invalidate(Function *) { return true; } int InstructionCount; }; -- 2.34.1