diff --git a/llvm/include/llvm/Analysis/CGSCCPassManager.h b/llvm/include/llvm/Analysis/CGSCCPassManager.h index 15b7f226fd828..f3cbfabe32719 100644 --- a/llvm/include/llvm/Analysis/CGSCCPassManager.h +++ b/llvm/include/llvm/Analysis/CGSCCPassManager.h @@ -311,17 +311,16 @@ 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 PassAdaptorMixin< + detail::PassConcept> { public: - using PassConceptT = - detail::PassConcept; - explicit ModuleToPostOrderCGSCCPassAdaptor(std::unique_ptr Pass) - : Pass(std::move(Pass)) {} + : PassAdaptorMixin(std::move(Pass)) {} ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor &&Arg) - : Pass(std::move(Arg.Pass)) {} + : PassAdaptorMixin(std::move(Arg.Pass)) {} friend void swap(ModuleToPostOrderCGSCCPassAdaptor &LHS, ModuleToPostOrderCGSCCPassAdaptor &RHS) { @@ -345,9 +344,6 @@ class ModuleToPostOrderCGSCCPassAdaptor } static bool isRequired() { return true; } - -private: - std::unique_ptr Pass; }; /// A function to deduce a function pass type and wrap it in the @@ -441,18 +437,18 @@ LazyCallGraph::SCC &updateCGAndAnalysisManagerForCGSCCPass( /// pass over the SCC to enable a \c FunctionAnalysisManager to be used /// within this run safely. class CGSCCToFunctionPassAdaptor - : public PassInfoMixin { + : public PassInfoMixin, + public PassAdaptorMixin< + detail::PassConcept> { public: - using PassConceptT = detail::PassConcept; - explicit CGSCCToFunctionPassAdaptor(std::unique_ptr Pass, bool EagerlyInvalidate, bool NoRerun) - : Pass(std::move(Pass)), EagerlyInvalidate(EagerlyInvalidate), + : PassAdaptorMixin(std::move(Pass)), EagerlyInvalidate(EagerlyInvalidate), NoRerun(NoRerun) {} CGSCCToFunctionPassAdaptor(CGSCCToFunctionPassAdaptor &&Arg) - : Pass(std::move(Arg.Pass)), EagerlyInvalidate(Arg.EagerlyInvalidate), - NoRerun(Arg.NoRerun) {} + : PassAdaptorMixin(std::move(Arg.Pass)), + EagerlyInvalidate(Arg.EagerlyInvalidate), NoRerun(Arg.NoRerun) {} friend void swap(CGSCCToFunctionPassAdaptor &LHS, CGSCCToFunctionPassAdaptor &RHS) { @@ -489,7 +485,6 @@ class CGSCCToFunctionPassAdaptor static bool isRequired() { return true; } private: - std::unique_ptr Pass; bool EagerlyInvalidate; bool NoRerun; }; diff --git a/llvm/include/llvm/CodeGen/MachinePassManager.h b/llvm/include/llvm/CodeGen/MachinePassManager.h index 69b5f6e92940c..aab2249a0a740 100644 --- a/llvm/include/llvm/CodeGen/MachinePassManager.h +++ b/llvm/include/llvm/CodeGen/MachinePassManager.h @@ -191,14 +191,13 @@ class FunctionAnalysisManagerMachineFunctionProxy }; class FunctionToMachineFunctionPassAdaptor - : public PassInfoMixin { + : public PassInfoMixin, + public PassAdaptorMixin> { public: - using PassConceptT = - detail::PassConcept; - explicit FunctionToMachineFunctionPassAdaptor( std::unique_ptr Pass) - : Pass(std::move(Pass)) {} + : PassAdaptorMixin(std::move(Pass)) {} /// Runs the function pass across every function in the function. PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); @@ -206,9 +205,6 @@ class FunctionToMachineFunctionPassAdaptor function_ref MapClassName2PassName); static bool isRequired() { return true; } - -private: - std::unique_ptr Pass; }; template diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h index 5dab9d0d0a797..8f3bcde89c4e6 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; @@ -801,6 +817,32 @@ 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 PassAdaptorMixin { + using PassConceptT = InternalConceptT; + + bool isEmpty() const { return Pass == nullptr; } + + void eraseIf(function_ref Pred) { + StringRef PassName = Pass->name(); + if (PassName.contains("PassManager") || PassName.ends_with("PassAdaptor")) { + Pass->eraseIf(Pred); + if (Pass->isEmpty()) + Pass.reset(); + } else if (Pred(PassName)) { + Pass.reset(); + } + } + +protected: + PassAdaptorMixin(std::unique_ptr Pass) + : Pass(std::move(Pass)) {} + std::unique_ptr Pass; +}; + /// Trivial adaptor that maps from a module to its functions. /// /// Designed to allow composition of a FunctionPass(Manager) and @@ -825,13 +867,14 @@ 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 PassAdaptorMixin< + detail::PassConcept> { public: - using PassConceptT = detail::PassConcept; - explicit ModuleToFunctionPassAdaptor(std::unique_ptr Pass, bool EagerlyInvalidate) - : Pass(std::move(Pass)), EagerlyInvalidate(EagerlyInvalidate) {} + : PassAdaptorMixin(std::move(Pass)), + EagerlyInvalidate(EagerlyInvalidate) {} /// Runs the function pass across every function in the module. PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); @@ -841,7 +884,6 @@ class ModuleToFunctionPassAdaptor static bool isRequired() { return true; } private: - std::unique_ptr Pass; bool EagerlyInvalidate; }; 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..42d00da93b31c 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,18 +403,17 @@ std::optional LoopPassManager::runSinglePass( /// \fn createLoopFunctionToLoopPassAdaptor to see when loop mode and loop-nest /// mode are used. class FunctionToLoopPassAdaptor - : public PassInfoMixin { + : public PassInfoMixin, + public PassAdaptorMixin< + detail::PassConcept> { public: - using PassConceptT = - detail::PassConcept; - explicit FunctionToLoopPassAdaptor(std::unique_ptr Pass, bool UseMemorySSA = false, bool UseBlockFrequencyInfo = false, bool UseBranchProbabilityInfo = false, bool LoopNestMode = false) - : Pass(std::move(Pass)), UseMemorySSA(UseMemorySSA), + : PassAdaptorMixin(std::move(Pass)), UseMemorySSA(UseMemorySSA), UseBlockFrequencyInfo(UseBlockFrequencyInfo), UseBranchProbabilityInfo(UseBranchProbabilityInfo), LoopNestMode(LoopNestMode) { @@ -428,8 +431,6 @@ class FunctionToLoopPassAdaptor bool isLoopNestMode() const { return LoopNestMode; } private: - std::unique_ptr Pass; - FunctionPassManager LoopCanonicalizationFPM; bool UseMemorySSA = false; diff --git a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp index 9f4270f5d62f5..edbe017dae35f 100644 --- a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp +++ b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp @@ -62,6 +62,45 @@ void PassManager::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,