From 92d3c7e8e226344ed4d63e17617cb414ee7e3d7b Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Fri, 19 Aug 2016 07:49:23 +0000 Subject: [PATCH] [PM] Redesign how the new PM detects whether an analysis result provides its own invalidate method. Previously, the technique would assume that if a result didn't have an invalidate method that didn't exactly match the expected signature it didn't have one at all. This is in fact not the case. And we had analyses with incorrect signatures for the invalidate method in the tree that would be erroneously invalidated in certain cases! Yikes. Moreover a result might legitimately want to have multiple overloads for the invalidate method, and if one changes or a new one is needed we again really want a compiler error. For example in the tree we had not added the overload for a *function* IR unit to the invalidate routine for TLI. Doh. So a new techique for the SFINAE detection here: if the result has *any* member spelled "invalidate" we turn off the synthesis of a default version. We don't care if it is a member function or a member variable or how many overloads there are. Once a result has something by that name it must provide suitable overloads for the contexts in which it is used. This seems much more resilient and durable. Huge props to Richard Smith who helped me figure out how on earth we could even do this in C++. It took quite some doing. The technique is remarkably clean however, and merely requires that the analysis results are not *final* classes. I think that's a requirement we can live with even if it is a bit odd. I've fixed the two bad in-tree analysis results. And this will make my next change which changes the API for invalidate much easier to validate as correct. llvm-svn: 279217 --- llvm/include/llvm/Analysis/TargetLibraryInfo.h | 3 ++- llvm/include/llvm/IR/PassManager.h | 2 +- llvm/include/llvm/IR/PassManagerInternal.h | 25 +++++++++++++++++-------- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h index 2cbf6f7..41e4241 100644 --- a/llvm/include/llvm/Analysis/TargetLibraryInfo.h +++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.h @@ -271,8 +271,9 @@ public: /// Handle invalidation from the pass manager. /// /// If we try to invalidate this info, just return false. It cannot become - /// invalid even if the module changes. + /// invalid even if the module or function changes. bool invalidate(Module &, const PreservedAnalyses &) { return false; } + bool invalidate(Function &, const PreservedAnalyses &) { return false; } }; /// Analysis pass providing the \c TargetLibraryInfo. diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h index 44bef21..c485c06 100644 --- a/llvm/include/llvm/IR/PassManager.h +++ b/llvm/include/llvm/IR/PassManager.h @@ -802,7 +802,7 @@ public: const AnalysisManagerT &getManager() const { return *AM; } /// \brief Handle invalidation by ignoring it, this pass is immutable. - bool invalidate(IRUnitT &) { return false; } + bool invalidate(IRUnitT &, const PreservedAnalyses &) { return false; } private: const AnalysisManagerT *AM; diff --git a/llvm/include/llvm/IR/PassManagerInternal.h b/llvm/include/llvm/IR/PassManagerInternal.h index a88e3cc..a498d39 100644 --- a/llvm/include/llvm/IR/PassManagerInternal.h +++ b/llvm/include/llvm/IR/PassManagerInternal.h @@ -94,19 +94,28 @@ template struct AnalysisResultConcept { /// \brief SFINAE metafunction for computing whether \c ResultT provides an /// \c invalidate member function. template class ResultHasInvalidateMethod { - typedef char SmallType; - struct BigType { + typedef char EnabledType; + struct DisabledType { char a, b; }; - template - struct Checker; - - template static SmallType f(Checker *); - template static BigType f(...); + // First we define an overload that can only be taken if there is no + // invalidate member. We do this by taking the address of an invalidate + // member in an adjacent base class of a derived class. This would be + // ambiguous if there were an invalidate member in the result type. + template static DisabledType NonceFunction(T U::*); + struct CheckerBase { int invalidate; }; + template struct Checker : CheckerBase, T {}; + template + static decltype(NonceFunction(&Checker::invalidate)) check(rank<1>); + + // Now we have the fallback that will only be reached when there is an + // invalidate member, and enables the trait. + template + static EnabledType check(rank<0>); public: - enum { Value = sizeof(f(nullptr)) == sizeof(SmallType) }; + enum { Value = sizeof(check(rank<1>())) == sizeof(EnabledType) }; }; /// \brief Wrapper to model the analysis result concept. -- 2.7.4