Skip to content

Commit 7ca2eed

Browse files
committed
Support eraseIf in pass manager
1 parent 3f9d02a commit 7ca2eed

File tree

6 files changed

+135
-5
lines changed

6 files changed

+135
-5
lines changed

llvm/include/llvm/Analysis/CGSCCPassManager.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,10 @@ struct CGSCCUpdateResult {
311311
/// pass over the module to enable a \c FunctionAnalysisManager to be used
312312
/// within this run safely.
313313
class ModuleToPostOrderCGSCCPassAdaptor
314-
: public PassInfoMixin<ModuleToPostOrderCGSCCPassAdaptor> {
314+
: public PassInfoMixin<ModuleToPostOrderCGSCCPassAdaptor>,
315+
public AdaptorMixin<ModuleToPostOrderCGSCCPassAdaptor> {
316+
friend AdaptorMixin<ModuleToPostOrderCGSCCPassAdaptor>;
317+
315318
public:
316319
using PassConceptT =
317320
detail::PassConcept<LazyCallGraph::SCC, CGSCCAnalysisManager,
@@ -441,7 +444,10 @@ LazyCallGraph::SCC &updateCGAndAnalysisManagerForCGSCCPass(
441444
/// pass over the SCC to enable a \c FunctionAnalysisManager to be used
442445
/// within this run safely.
443446
class CGSCCToFunctionPassAdaptor
444-
: public PassInfoMixin<CGSCCToFunctionPassAdaptor> {
447+
: public PassInfoMixin<CGSCCToFunctionPassAdaptor>,
448+
public AdaptorMixin<CGSCCToFunctionPassAdaptor> {
449+
friend AdaptorMixin<CGSCCToFunctionPassAdaptor>;
450+
445451
public:
446452
using PassConceptT = detail::PassConcept<Function, FunctionAnalysisManager>;
447453

llvm/include/llvm/CodeGen/MachinePassManager.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,10 @@ class FunctionAnalysisManagerMachineFunctionProxy
191191
};
192192

193193
class FunctionToMachineFunctionPassAdaptor
194-
: public PassInfoMixin<FunctionToMachineFunctionPassAdaptor> {
194+
: public PassInfoMixin<FunctionToMachineFunctionPassAdaptor>,
195+
public AdaptorMixin<FunctionToMachineFunctionPassAdaptor> {
196+
friend AdaptorMixin<FunctionToMachineFunctionPassAdaptor>;
197+
195198
public:
196199
using PassConceptT =
197200
detail::PassConcept<MachineFunction, MachineFunctionAnalysisManager>;

llvm/include/llvm/IR/PassManager.h

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,22 @@ class PassManager : public PassInfoMixin<
218218

219219
static bool isRequired() { return true; }
220220

221+
/// Erase all passes that satisfy the predicate \p Pred.
222+
/// For internal use only!
223+
void eraseIf(function_ref<bool(StringRef)> Pred) {
224+
for (auto I = Passes.begin(); I != Passes.end();) {
225+
auto &P = *I;
226+
P->eraseIf(Pred);
227+
bool IsSpecial = P->name().ends_with("PassAdaptor") ||
228+
P->name().contains("PassManager");
229+
bool PredResult = Pred(P->name());
230+
if ((!IsSpecial && PredResult) || (IsSpecial && P->isEmpty()))
231+
I = Passes.erase(I);
232+
else
233+
++I;
234+
}
235+
}
236+
221237
protected:
222238
using PassConceptT =
223239
detail::PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...>;
@@ -797,6 +813,28 @@ extern template class OuterAnalysisManagerProxy<ModuleAnalysisManager,
797813
using ModuleAnalysisManagerFunctionProxy =
798814
OuterAnalysisManagerProxy<ModuleAnalysisManager, Function>;
799815

816+
/// Simple mix-in for pass adaptor. If adaptor contains only a single pass
817+
/// instance in it, then it can inherit this mix-in to get default `isEmpty()`
818+
/// and `eraseIf` implementation. This mix-in must have access to the `Pass`
819+
/// member in adaptor.
820+
template <typename DerivedT> struct AdaptorMixin {
821+
bool isEmpty() const { return derived().Pass == nullptr; }
822+
823+
void eraseIf(function_ref<bool(StringRef)> Pred) {
824+
StringRef PassName = derived().Pass->name();
825+
if (PassName.contains("PassManager") || PassName.ends_with("PassAdaptor")) {
826+
derived().Pass->eraseIf(Pred);
827+
if (derived().Pass->isEmpty())
828+
derived().Pass.reset();
829+
} else if (Pred(PassName)) {
830+
derived().Pass.reset();
831+
}
832+
}
833+
834+
private:
835+
DerivedT &derived() { return *static_cast<Derived *>(this); }
836+
};
837+
800838
/// Trivial adaptor that maps from a module to its functions.
801839
///
802840
/// Designed to allow composition of a FunctionPass(Manager) and
@@ -821,7 +859,10 @@ using ModuleAnalysisManagerFunctionProxy =
821859
/// analyses are not invalidated while the function passes are running, so they
822860
/// may be stale. Function analyses will not be stale.
823861
class ModuleToFunctionPassAdaptor
824-
: public PassInfoMixin<ModuleToFunctionPassAdaptor> {
862+
: public PassInfoMixin<ModuleToFunctionPassAdaptor>,
863+
public AdaptorMixin<ModuleToFunctionPassAdaptor> {
864+
friend AdaptorMixin<ModuleToFunctionPassAdaptor>;
865+
825866
public:
826867
using PassConceptT = detail::PassConcept<Function, FunctionAnalysisManager>;
827868

llvm/include/llvm/IR/PassManagerInternal.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ struct PassConcept {
5959
/// To opt-in, pass should implement `static bool isRequired()`. It's no-op
6060
/// to have `isRequired` always return false since that is the default.
6161
virtual bool isRequired() const = 0;
62+
63+
/// Polymorphic method to refurbish pass pipeline.
64+
virtual void eraseIf(function_ref<bool(StringRef)> Pred) = 0;
65+
66+
/// There may be some empty PassManager after erasing,
67+
/// use it to remove them.
68+
virtual bool isEmpty() const = 0;
6269
};
6370

6471
/// A template wrapper used to implement the polymorphic API.
@@ -114,6 +121,33 @@ struct PassModel : PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...> {
114121

115122
bool isRequired() const override { return passIsRequiredImpl<PassT>(); }
116123

124+
template <typename T>
125+
using has_erase_if_t = decltype(std::declval<T &>().eraseIf(
126+
std::declval<function_ref<bool(StringRef)>>()));
127+
128+
template <typename T>
129+
std::enable_if_t<is_detected<has_erase_if_t, T>::value>
130+
eraseIfImpl(function_ref<bool(StringRef)> Pred) {
131+
Pass.eraseIf(Pred);
132+
}
133+
134+
template <typename T>
135+
std::enable_if_t<!is_detected<has_erase_if_t, T>::value>
136+
eraseIfImpl(function_ref<bool(StringRef)>) {}
137+
138+
void eraseIf(function_ref<bool(StringRef)> Pred) override {
139+
eraseIfImpl<PassT>(Pred);
140+
}
141+
142+
template <typename T>
143+
using has_is_empty_t = decltype(std::declval<T &>().isEmpty());
144+
145+
bool isEmpty() const override {
146+
if constexpr (is_detected<has_is_empty_t, PassT>::value)
147+
return Pass.isEmpty();
148+
return false;
149+
}
150+
117151
PassT Pass;
118152
};
119153

llvm/include/llvm/Transforms/Scalar/LoopPassManager.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ class PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
134134

135135
static bool isRequired() { return true; }
136136

137+
/// Erase all passes that satisfy the predicate \p Pred.
138+
/// For internal use only!
139+
void eraseIf(function_ref<bool(StringRef)> Pred);
140+
137141
size_t getNumLoopPasses() const { return LoopPasses.size(); }
138142
size_t getNumLoopNestPasses() const { return LoopNestPasses.size(); }
139143

@@ -399,7 +403,10 @@ std::optional<PreservedAnalyses> LoopPassManager::runSinglePass(
399403
/// \fn createLoopFunctionToLoopPassAdaptor to see when loop mode and loop-nest
400404
/// mode are used.
401405
class FunctionToLoopPassAdaptor
402-
: public PassInfoMixin<FunctionToLoopPassAdaptor> {
406+
: public PassInfoMixin<FunctionToLoopPassAdaptor>,
407+
public AdaptorMixin<FunctionToLoopPassAdaptor> {
408+
friend AdaptorMixin<FunctionToLoopPassAdaptor>;
409+
403410
public:
404411
using PassConceptT =
405412
detail::PassConcept<Loop, LoopAnalysisManager,

llvm/lib/Transforms/Scalar/LoopPassManager.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,45 @@ void PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
6262
}
6363
}
6464

65+
void PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
66+
LPMUpdater &>::eraseIf(function_ref<bool(StringRef)> Pred) {
67+
assert(LoopPasses.size() + LoopNestPasses.size() == IsLoopNestPass.size() &&
68+
"Wrong precondition!");
69+
70+
std::vector<char> IsLoopNestPassVec(
71+
static_cast<size_t>(IsLoopNestPass.size()));
72+
for (unsigned Idx = 0, Sz = IsLoopNestPass.size(); Idx != Sz; ++Idx)
73+
IsLoopNestPassVec[Idx] = IsLoopNestPass[Idx];
74+
75+
auto ILP = LoopPasses.begin();
76+
auto ILNP = LoopNestPasses.begin();
77+
for (auto I = IsLoopNestPassVec.begin(); I != IsLoopNestPassVec.end();) {
78+
if (*I) {
79+
if (Pred((*ILNP)->name())) {
80+
I = IsLoopNestPassVec.erase(I);
81+
ILNP = LoopNestPasses.erase(ILNP);
82+
continue;
83+
}
84+
++ILNP;
85+
} else {
86+
if (Pred((*ILP)->name())) {
87+
I = IsLoopNestPassVec.erase(I);
88+
ILP = LoopPasses.erase(ILP);
89+
continue;
90+
}
91+
++ILP;
92+
}
93+
++I;
94+
}
95+
96+
IsLoopNestPass.clear();
97+
for (const auto I : IsLoopNestPassVec)
98+
IsLoopNestPass.push_back(I);
99+
100+
assert(LoopPasses.size() + LoopNestPasses.size() == IsLoopNestPass.size() &&
101+
"Wrong postcondition!");
102+
}
103+
65104
// Run both loop passes and loop-nest passes on top-level loop \p L.
66105
PreservedAnalyses
67106
LoopPassManager::runWithLoopNestPasses(Loop &L, LoopAnalysisManager &AM,

0 commit comments

Comments
 (0)