diff --git a/llvm/include/llvm/Analysis/CGSCCPassManager.h b/llvm/include/llvm/Analysis/CGSCCPassManager.h index 15b7f226fd828..5df8ee8431b3b 100644 --- a/llvm/include/llvm/Analysis/CGSCCPassManager.h +++ b/llvm/include/llvm/Analysis/CGSCCPassManager.h @@ -311,7 +311,10 @@ struct CGSCCUpdateResult { /// pass over the module to enable a \c FunctionAnalysisManager to be used /// within this run safely. class ModuleToPostOrderCGSCCPassAdaptor - : public PassInfoMixin { + : public PassInfoMixin, + public AdaptorMixin { + friend AdaptorMixin; + public: using PassConceptT = detail::PassConcept { + : public PassInfoMixin, + public AdaptorMixin { + friend AdaptorMixin; + public: using PassConceptT = detail::PassConcept; diff --git a/llvm/include/llvm/CodeGen/MachinePassManager.h b/llvm/include/llvm/CodeGen/MachinePassManager.h index 69b5f6e92940c..f94bbcbb5d78c 100644 --- a/llvm/include/llvm/CodeGen/MachinePassManager.h +++ b/llvm/include/llvm/CodeGen/MachinePassManager.h @@ -191,7 +191,10 @@ class FunctionAnalysisManagerMachineFunctionProxy }; class FunctionToMachineFunctionPassAdaptor - : public PassInfoMixin { + : public PassInfoMixin, + public AdaptorMixin { + friend AdaptorMixin; + public: using PassConceptT = detail::PassConcept; diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h index d269221fac070..38c7658e84f8f 100644 --- a/llvm/include/llvm/IR/PassManager.h +++ b/llvm/include/llvm/IR/PassManager.h @@ -218,6 +218,22 @@ class PassManager : public PassInfoMixin< static bool isRequired() { return true; } + /// Erase all passes that satisfy the predicate \p Pred. + /// For internal use only! + void eraseIf(function_ref Pred) { + for (auto I = Passes.begin(); I != Passes.end();) { + auto &P = *I; + P->eraseIf(Pred); + bool IsSpecial = P->name().ends_with("PassAdaptor") || + P->name().contains("PassManager"); + bool PredResult = Pred(P->name()); + if ((!IsSpecial && PredResult) || (IsSpecial && P->isEmpty())) + I = Passes.erase(I); + else + ++I; + } + } + protected: using PassConceptT = detail::PassConcept; @@ -797,6 +813,28 @@ extern template class OuterAnalysisManagerProxy; +/// Simple mix-in for pass adaptor. If adaptor contains only a single pass +/// instance in it, then it can inherit this mix-in to get default `isEmpty()` +/// and `eraseIf` implementation. This mix-in must have access to the `Pass` +/// member in adaptor. +template struct AdaptorMixin { + bool isEmpty() const { return derived().Pass == nullptr; } + + void eraseIf(function_ref Pred) { + StringRef PassName = derived().Pass->name(); + if (PassName.contains("PassManager") || PassName.ends_with("PassAdaptor")) { + derived().Pass->eraseIf(Pred); + if (derived().Pass->isEmpty()) + derived().Pass.reset(); + } else if (Pred(PassName)) { + derived().Pass.reset(); + } + } + +private: + DerivedT &derived() { return *static_cast(this); } +}; + /// Trivial adaptor that maps from a module to its functions. /// /// Designed to allow composition of a FunctionPass(Manager) and @@ -821,7 +859,10 @@ using ModuleAnalysisManagerFunctionProxy = /// analyses are not invalidated while the function passes are running, so they /// may be stale. Function analyses will not be stale. class ModuleToFunctionPassAdaptor - : public PassInfoMixin { + : public PassInfoMixin, + public AdaptorMixin { + friend AdaptorMixin; + public: using PassConceptT = detail::PassConcept; diff --git a/llvm/include/llvm/IR/PassManagerInternal.h b/llvm/include/llvm/IR/PassManagerInternal.h index 4ada6ee5dd683..36caf7cd85a3d 100644 --- a/llvm/include/llvm/IR/PassManagerInternal.h +++ b/llvm/include/llvm/IR/PassManagerInternal.h @@ -59,6 +59,13 @@ struct PassConcept { /// To opt-in, pass should implement `static bool isRequired()`. It's no-op /// to have `isRequired` always return false since that is the default. virtual bool isRequired() const = 0; + + /// Polymorphic method to refurbish pass pipeline. + virtual void eraseIf(function_ref Pred) = 0; + + /// There may be some empty PassManager after erasing, + /// use it to remove them. + virtual bool isEmpty() const = 0; }; /// A template wrapper used to implement the polymorphic API. @@ -114,6 +121,33 @@ struct PassModel : PassConcept { bool isRequired() const override { return passIsRequiredImpl(); } + template + using has_erase_if_t = decltype(std::declval().eraseIf( + std::declval>())); + + template + std::enable_if_t::value> + eraseIfImpl(function_ref Pred) { + Pass.eraseIf(Pred); + } + + template + std::enable_if_t::value> + eraseIfImpl(function_ref) {} + + void eraseIf(function_ref Pred) override { + eraseIfImpl(Pred); + } + + template + using has_is_empty_t = decltype(std::declval().isEmpty()); + + bool isEmpty() const override { + if constexpr (is_detected::value) + return Pass.isEmpty(); + return false; + } + PassT Pass; }; diff --git a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h index f55022fbff07c..27d39985be261 100644 --- a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h +++ b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h @@ -134,6 +134,10 @@ class PassManager Pred); + size_t getNumLoopPasses() const { return LoopPasses.size(); } size_t getNumLoopNestPasses() const { return LoopNestPasses.size(); } @@ -399,7 +403,10 @@ std::optional LoopPassManager::runSinglePass( /// \fn createLoopFunctionToLoopPassAdaptor to see when loop mode and loop-nest /// mode are used. class FunctionToLoopPassAdaptor - : public PassInfoMixin { + : public PassInfoMixin, + public AdaptorMixin { + friend AdaptorMixin; + public: using PassConceptT = detail::PassConcept::eraseIf(function_ref Pred) { + assert(LoopPasses.size() + LoopNestPasses.size() == IsLoopNestPass.size() && + "Wrong precondition!"); + + std::vector IsLoopNestPassVec( + static_cast(IsLoopNestPass.size())); + for (unsigned Idx = 0, Sz = IsLoopNestPass.size(); Idx != Sz; ++Idx) + IsLoopNestPassVec[Idx] = IsLoopNestPass[Idx]; + + auto ILP = LoopPasses.begin(); + auto ILNP = LoopNestPasses.begin(); + for (auto I = IsLoopNestPassVec.begin(); I != IsLoopNestPassVec.end();) { + if (*I) { + if (Pred((*ILNP)->name())) { + I = IsLoopNestPassVec.erase(I); + ILNP = LoopNestPasses.erase(ILNP); + continue; + } + ++ILNP; + } else { + if (Pred((*ILP)->name())) { + I = IsLoopNestPassVec.erase(I); + ILP = LoopPasses.erase(ILP); + continue; + } + ++ILP; + } + ++I; + } + + IsLoopNestPass.clear(); + for (const auto I : IsLoopNestPassVec) + IsLoopNestPass.push_back(I); + + assert(LoopPasses.size() + LoopNestPasses.size() == IsLoopNestPass.size() && + "Wrong postcondition!"); +} + // Run both loop passes and loop-nest passes on top-level loop \p L. PreservedAnalyses LoopPassManager::runWithLoopNestPasses(Loop &L, LoopAnalysisManager &AM,