[llvm] [Pass] Add `eraseIf` in pass managers and adaptors (PR #116912)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 19 19:36:26 PST 2024
https://github.com/paperchalice created https://github.com/llvm/llvm-project/pull/116912
`llc` need thses methods to implement start stop options
>From c2c2ccbdf55eb0af7ebfed98a88b3ba4ce6e0d49 Mon Sep 17 00:00:00 2001
From: PaperChalice <liujunchang97 at outlook.com>
Date: Wed, 20 Nov 2024 11:30:20 +0800
Subject: [PATCH] [Pass] Add `eraseIf` in pass managers and adaptors
`llc` need thses methods to implement start stop options
---
llvm/include/llvm/Analysis/CGSCCPassManager.h | 29 +++++------
.../include/llvm/CodeGen/MachinePassManager.h | 12 ++---
llvm/include/llvm/IR/PassManager.h | 52 +++++++++++++++++--
llvm/include/llvm/IR/PassManagerInternal.h | 34 ++++++++++++
.../llvm/Transforms/Scalar/LoopPassManager.h | 17 +++---
.../lib/Transforms/Scalar/LoopPassManager.cpp | 39 ++++++++++++++
6 files changed, 145 insertions(+), 38 deletions(-)
diff --git a/llvm/include/llvm/Analysis/CGSCCPassManager.h b/llvm/include/llvm/Analysis/CGSCCPassManager.h
index 15b7f226fd8283..f3cbfabe32719e 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<ModuleToPostOrderCGSCCPassAdaptor> {
+ : public PassInfoMixin<ModuleToPostOrderCGSCCPassAdaptor>,
+ public PassAdaptorMixin<
+ detail::PassConcept<LazyCallGraph::SCC, CGSCCAnalysisManager,
+ LazyCallGraph &, CGSCCUpdateResult &>> {
public:
- using PassConceptT =
- detail::PassConcept<LazyCallGraph::SCC, CGSCCAnalysisManager,
- LazyCallGraph &, CGSCCUpdateResult &>;
-
explicit ModuleToPostOrderCGSCCPassAdaptor(std::unique_ptr<PassConceptT> 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<PassConceptT> 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<CGSCCToFunctionPassAdaptor> {
+ : public PassInfoMixin<CGSCCToFunctionPassAdaptor>,
+ public PassAdaptorMixin<
+ detail::PassConcept<Function, FunctionAnalysisManager>> {
public:
- using PassConceptT = detail::PassConcept<Function, FunctionAnalysisManager>;
-
explicit CGSCCToFunctionPassAdaptor(std::unique_ptr<PassConceptT> 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<PassConceptT> Pass;
bool EagerlyInvalidate;
bool NoRerun;
};
diff --git a/llvm/include/llvm/CodeGen/MachinePassManager.h b/llvm/include/llvm/CodeGen/MachinePassManager.h
index 69b5f6e92940c4..aab2249a0a740e 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<FunctionToMachineFunctionPassAdaptor> {
+ : public PassInfoMixin<FunctionToMachineFunctionPassAdaptor>,
+ public PassAdaptorMixin<detail::PassConcept<
+ MachineFunction, MachineFunctionAnalysisManager>> {
public:
- using PassConceptT =
- detail::PassConcept<MachineFunction, MachineFunctionAnalysisManager>;
-
explicit FunctionToMachineFunctionPassAdaptor(
std::unique_ptr<PassConceptT> 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<StringRef(StringRef)> MapClassName2PassName);
static bool isRequired() { return true; }
-
-private:
- std::unique_ptr<PassConceptT> Pass;
};
template <typename MachineFunctionPassT>
diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h
index 5dab9d0d0a7979..8f3bcde89c4e65 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<bool(StringRef)> 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<IRUnitT, AnalysisManagerT, ExtraArgTs...>;
@@ -801,6 +817,32 @@ extern template class OuterAnalysisManagerProxy<ModuleAnalysisManager,
using ModuleAnalysisManagerFunctionProxy =
OuterAnalysisManagerProxy<ModuleAnalysisManager, Function>;
+/// 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 <typename InternalConceptT> struct PassAdaptorMixin {
+ using PassConceptT = InternalConceptT;
+
+ bool isEmpty() const { return Pass == nullptr; }
+
+ void eraseIf(function_ref<bool(StringRef)> 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<PassConceptT> Pass)
+ : Pass(std::move(Pass)) {}
+ std::unique_ptr<PassConceptT> 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<ModuleToFunctionPassAdaptor> {
+ : public PassInfoMixin<ModuleToFunctionPassAdaptor>,
+ public PassAdaptorMixin<
+ detail::PassConcept<Function, FunctionAnalysisManager>> {
public:
- using PassConceptT = detail::PassConcept<Function, FunctionAnalysisManager>;
-
explicit ModuleToFunctionPassAdaptor(std::unique_ptr<PassConceptT> 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<PassConceptT> Pass;
bool EagerlyInvalidate;
};
diff --git a/llvm/include/llvm/IR/PassManagerInternal.h b/llvm/include/llvm/IR/PassManagerInternal.h
index 4ada6ee5dd6831..36caf7cd85a3d5 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<bool(StringRef)> 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<IRUnitT, AnalysisManagerT, ExtraArgTs...> {
bool isRequired() const override { return passIsRequiredImpl<PassT>(); }
+ template <typename T>
+ using has_erase_if_t = decltype(std::declval<T &>().eraseIf(
+ std::declval<function_ref<bool(StringRef)>>()));
+
+ template <typename T>
+ std::enable_if_t<is_detected<has_erase_if_t, T>::value>
+ eraseIfImpl(function_ref<bool(StringRef)> Pred) {
+ Pass.eraseIf(Pred);
+ }
+
+ template <typename T>
+ std::enable_if_t<!is_detected<has_erase_if_t, T>::value>
+ eraseIfImpl(function_ref<bool(StringRef)>) {}
+
+ void eraseIf(function_ref<bool(StringRef)> Pred) override {
+ eraseIfImpl<PassT>(Pred);
+ }
+
+ template <typename T>
+ using has_is_empty_t = decltype(std::declval<T &>().isEmpty());
+
+ bool isEmpty() const override {
+ if constexpr (is_detected<has_is_empty_t, PassT>::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 f55022fbff07c1..42d00da93b31ca 100644
--- a/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
+++ b/llvm/include/llvm/Transforms/Scalar/LoopPassManager.h
@@ -134,6 +134,10 @@ class PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
static bool isRequired() { return true; }
+ /// Erase all passes that satisfy the predicate \p Pred.
+ /// For internal use only!
+ void eraseIf(function_ref<bool(StringRef)> Pred);
+
size_t getNumLoopPasses() const { return LoopPasses.size(); }
size_t getNumLoopNestPasses() const { return LoopNestPasses.size(); }
@@ -399,18 +403,17 @@ std::optional<PreservedAnalyses> LoopPassManager::runSinglePass(
/// \fn createLoopFunctionToLoopPassAdaptor to see when loop mode and loop-nest
/// mode are used.
class FunctionToLoopPassAdaptor
- : public PassInfoMixin<FunctionToLoopPassAdaptor> {
+ : public PassInfoMixin<FunctionToLoopPassAdaptor>,
+ public PassAdaptorMixin<
+ detail::PassConcept<Loop, LoopAnalysisManager,
+ LoopStandardAnalysisResults &, LPMUpdater &>> {
public:
- using PassConceptT =
- detail::PassConcept<Loop, LoopAnalysisManager,
- LoopStandardAnalysisResults &, LPMUpdater &>;
-
explicit FunctionToLoopPassAdaptor(std::unique_ptr<PassConceptT> 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<PassConceptT> Pass;
-
FunctionPassManager LoopCanonicalizationFPM;
bool UseMemorySSA = false;
diff --git a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
index 9f4270f5d62f5c..edbe017dae35f4 100644
--- a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
@@ -62,6 +62,45 @@ void PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
}
}
+void PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
+ LPMUpdater &>::eraseIf(function_ref<bool(StringRef)> Pred) {
+ assert(LoopPasses.size() + LoopNestPasses.size() == IsLoopNestPass.size() &&
+ "Wrong precondition!");
+
+ std::vector<char> IsLoopNestPassVec(
+ static_cast<size_t>(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,
More information about the llvm-commits
mailing list