mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-30 04:35:00 +00:00
[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
This commit is contained in:
parent
6345249972
commit
212226e114
@ -192,12 +192,35 @@ template <typename IRUnitT> 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 <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 : AnalysisResultConcept<IRUnitT> {
|
||||
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 : AnalysisPassConcept<typename PassT::IRUnitT> {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ public:
|
||||
|
||||
struct Result {
|
||||
Result(int Count) : InstructionCount(Count) {}
|
||||
bool invalidate(Function *) { return true; }
|
||||
int InstructionCount;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user