diff --git a/llvm/include/llvm/Analysis/CGSCCPassManager.h b/llvm/include/llvm/Analysis/CGSCCPassManager.h --- a/llvm/include/llvm/Analysis/CGSCCPassManager.h +++ b/llvm/include/llvm/Analysis/CGSCCPassManager.h @@ -355,6 +355,10 @@ /// Runs the CGSCC pass across every SCC in the module. PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); + static bool isSkippable() { + return !std::is_base_of::value; + } + private: CGSCCPassT Pass; }; @@ -543,6 +547,10 @@ return PA; } + static bool isSkippable() { + return !std::is_base_of::value; + } + private: FunctionPassT Pass; }; diff --git a/llvm/include/llvm/IR/PassInstrumentation.h b/llvm/include/llvm/IR/PassInstrumentation.h --- a/llvm/include/llvm/IR/PassInstrumentation.h +++ b/llvm/include/llvm/IR/PassInstrumentation.h @@ -124,11 +124,41 @@ AfterAnalysisCallbacks; }; +// Template argument PassT of PassInstrumentation::runBeforePass could be two +// kinds: (1) a regular pass inherited from PassInfoMixin (happen when creating +// a adaptor pass for a regular pass); (2) a type-erased PassConcept created +// from (1). Here we want to make case (1) skippable unconditionally since they +// are regular passes. We call PassConcept::isSkippable to decide for case (2). +template struct MaybeSkippablePass { +private: + template + static constexpr auto check(T *) -> + typename std::is_same().isSkippable()), + bool>::type; + template static constexpr std::false_type check(...); + + typedef decltype(check(0)) type; + +public: + static constexpr bool value = type::value; +}; + /// This class provides instrumentation entry points for the Pass Manager, /// doing calls to callbacks registered in PassInstrumentationCallbacks. class PassInstrumentation { PassInstrumentationCallbacks *Callbacks; + template + static std::enable_if_t::value, bool> + isSkippable(const PassT &Pass) { + return Pass.isSkippable(); + } + template + static std::enable_if_t::value, bool> + isSkippable(const PassT &Pass) { + return true; + } + public: /// Callbacks object is not owned by PassInstrumentation, its life-time /// should at least match the life-time of corresponding @@ -148,6 +178,7 @@ bool ShouldRun = true; for (auto &C : Callbacks->BeforePassCallbacks) ShouldRun &= C(Pass.name(), llvm::Any(&IR)); + ShouldRun = ShouldRun || !isSkippable(Pass); return ShouldRun; } diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h --- a/llvm/include/llvm/IR/PassManager.h +++ b/llvm/include/llvm/IR/PassManager.h @@ -558,6 +558,8 @@ Passes.emplace_back(new PassModelT(std::move(Pass))); } + static bool isSkippable() { return false; } + private: using PassConceptT = detail::PassConcept; @@ -1259,6 +1261,10 @@ return PA; } + static bool isSkippable() { + return !std::is_base_of::value; + } + private: FunctionPassT Pass; }; diff --git a/llvm/include/llvm/IR/PassManagerInternal.h b/llvm/include/llvm/IR/PassManagerInternal.h --- a/llvm/include/llvm/IR/PassManagerInternal.h +++ b/llvm/include/llvm/IR/PassManagerInternal.h @@ -31,6 +31,20 @@ /// Implementation details of the pass manager interfaces. namespace detail { +template struct PassHasSkippableMethod { +private: + template + static constexpr auto check(T *) -> + typename std::is_same::type; + + template static constexpr std::false_type check(...); + + typedef decltype(check(0)) type; + +public: + static constexpr bool value = type::value; +}; + /// Template for the abstract base class used to dispatch /// polymorphically over pass objects. template @@ -48,6 +62,12 @@ /// Polymorphic method to access the name of a pass. virtual StringRef name() const = 0; + + /// Polymorphic method to to let a pass optionally exempted from skipping by + /// PassInstrumentation. + /// To opt-in, pass should implement `static bool isSkippable()`. It's no-op + /// to have `isSkippable` always return true since that is the default. + virtual bool isSkippable() const = 0; }; /// A template wrapper used to implement the polymorphic API. @@ -81,6 +101,19 @@ StringRef name() const override { return PassT::name(); } + template + static std::enable_if_t::value, bool> + PassIsSkippable() { + return T::isSkippable(); + } + template + static std::enable_if_t::value, bool> + PassIsSkippable() { + return true; + } + + bool isSkippable() const override { return PassIsSkippable(); } + PassT Pass; }; diff --git a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h --- a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h +++ b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h @@ -366,6 +366,10 @@ return PA; } + static bool isSkippable() { + return !std::is_base_of::value; + } + private: LoopPassT Pass;