Skip to content

Commit b361b53

Browse files
authored
Reland "[PassManager] Support MachineFunctionProperties (#83668)" (#87141)
Unfortunately GCC 9 rejects code in https://godbolt.org/z/zd9r5GM3e GCC 11 accepts this code.
1 parent 546dc22 commit b361b53

File tree

5 files changed

+143
-124
lines changed

5 files changed

+143
-124
lines changed

llvm/include/llvm/CodeGen/MachinePassManager.h

Lines changed: 86 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
// their respective analysis managers such as ModuleAnalysisManager and
1717
// FunctionAnalysisManager.
1818
//
19-
// TODO: Add MachineFunctionProperties support.
20-
//
2119
//===----------------------------------------------------------------------===//
2220

2321
#ifndef LLVM_CODEGEN_MACHINEPASSMANAGER_H
@@ -44,23 +42,67 @@ using MachineFunctionAnalysisManager = AnalysisManager<MachineFunction>;
4442
/// automatically mixes in \c PassInfoMixin.
4543
template <typename DerivedT>
4644
struct MachinePassInfoMixin : public PassInfoMixin<DerivedT> {
47-
// TODO: Add MachineFunctionProperties support.
45+
protected:
46+
class PropertyChanger {
47+
MachineFunction &MF;
48+
49+
template <typename T>
50+
using has_get_required_properties_t =
51+
decltype(std::declval<T &>().getRequiredProperties());
52+
53+
template <typename T>
54+
using has_get_set_properties_t =
55+
decltype(std::declval<T &>().getSetProperties());
56+
57+
template <typename T>
58+
using has_get_cleared_properties_t =
59+
decltype(std::declval<T &>().getClearedProperties());
60+
61+
public:
62+
PropertyChanger(MachineFunction &MF) : MF(MF) {
63+
#ifndef NDEBUG
64+
if constexpr (is_detected<has_get_required_properties_t,
65+
DerivedT>::value) {
66+
auto &MFProps = MF.getProperties();
67+
auto RequiredProperties = DerivedT::getRequiredProperties();
68+
if (!MFProps.verifyRequiredProperties(RequiredProperties)) {
69+
errs() << "MachineFunctionProperties required by " << DerivedT::name()
70+
<< " pass are not met by function " << MF.getName() << ".\n"
71+
<< "Required properties: ";
72+
RequiredProperties.print(errs());
73+
errs() << "\nCurrent properties: ";
74+
MFProps.print(errs());
75+
errs() << '\n';
76+
report_fatal_error("MachineFunctionProperties check failed");
77+
}
78+
}
79+
#endif
80+
}
81+
82+
~PropertyChanger() {
83+
if constexpr (is_detected<has_get_set_properties_t, DerivedT>::value)
84+
MF.getProperties().set(DerivedT::getSetProperties());
85+
if constexpr (is_detected<has_get_cleared_properties_t, DerivedT>::value)
86+
MF.getProperties().reset(DerivedT::getClearedProperties());
87+
}
88+
};
89+
90+
public:
91+
PreservedAnalyses runImpl(MachineFunction &MF,
92+
MachineFunctionAnalysisManager &MFAM) {
93+
PropertyChanger PC(MF);
94+
return static_cast<DerivedT *>(this)->run(MF, MFAM);
95+
}
4896
};
4997

5098
namespace detail {
51-
struct MachinePassConcept
52-
: PassConcept<MachineFunction, MachineFunctionAnalysisManager> {
53-
virtual MachineFunctionProperties getRequiredProperties() const = 0;
54-
virtual MachineFunctionProperties getSetProperties() const = 0;
55-
virtual MachineFunctionProperties getClearedProperties() const = 0;
56-
};
5799

58-
template <typename PassT> struct MachinePassModel : MachinePassConcept {
59-
explicit MachinePassModel(PassT &&Pass) : Pass(std::move(Pass)) {}
60-
// We have to explicitly define all the special member functions because MSVC
61-
// refuses to generate them.
62-
MachinePassModel(const MachinePassModel &Arg) : Pass(Arg.Pass) {}
63-
MachinePassModel(MachinePassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
100+
template <typename PassT>
101+
struct MachinePassModel
102+
: PassModel<MachineFunction, PassT, MachineFunctionAnalysisManager> {
103+
explicit MachinePassModel(PassT &&Pass)
104+
: PassModel<MachineFunction, PassT, MachineFunctionAnalysisManager>(
105+
std::move(Pass)) {}
64106

65107
friend void swap(MachinePassModel &LHS, MachinePassModel &RHS) {
66108
using std::swap;
@@ -75,89 +117,8 @@ template <typename PassT> struct MachinePassModel : MachinePassConcept {
75117
MachinePassModel &operator=(const MachinePassModel &) = delete;
76118
PreservedAnalyses run(MachineFunction &IR,
77119
MachineFunctionAnalysisManager &AM) override {
78-
return Pass.run(IR, AM);
79-
}
80-
81-
void printPipeline(
82-
raw_ostream &OS,
83-
function_ref<StringRef(StringRef)> MapClassName2PassName) override {
84-
Pass.printPipeline(OS, MapClassName2PassName);
85-
}
86-
87-
StringRef name() const override { return PassT::name(); }
88-
89-
template <typename T>
90-
using has_required_t = decltype(std::declval<T &>().isRequired());
91-
template <typename T>
92-
static std::enable_if_t<is_detected<has_required_t, T>::value, bool>
93-
passIsRequiredImpl() {
94-
return T::isRequired();
120+
return this->Pass.runImpl(IR, AM);
95121
}
96-
template <typename T>
97-
static std::enable_if_t<!is_detected<has_required_t, T>::value, bool>
98-
passIsRequiredImpl() {
99-
return false;
100-
}
101-
bool isRequired() const override { return passIsRequiredImpl<PassT>(); }
102-
103-
template <typename T>
104-
using has_get_required_properties_t =
105-
decltype(std::declval<T &>().getRequiredProperties());
106-
template <typename T>
107-
static std::enable_if_t<is_detected<has_get_required_properties_t, T>::value,
108-
MachineFunctionProperties>
109-
getRequiredPropertiesImpl() {
110-
return PassT::getRequiredProperties();
111-
}
112-
template <typename T>
113-
static std::enable_if_t<!is_detected<has_get_required_properties_t, T>::value,
114-
MachineFunctionProperties>
115-
getRequiredPropertiesImpl() {
116-
return MachineFunctionProperties();
117-
}
118-
MachineFunctionProperties getRequiredProperties() const override {
119-
return getRequiredPropertiesImpl<PassT>();
120-
}
121-
122-
template <typename T>
123-
using has_get_set_properties_t =
124-
decltype(std::declval<T &>().getSetProperties());
125-
template <typename T>
126-
static std::enable_if_t<is_detected<has_get_set_properties_t, T>::value,
127-
MachineFunctionProperties>
128-
getSetPropertiesImpl() {
129-
return PassT::getSetProperties();
130-
}
131-
template <typename T>
132-
static std::enable_if_t<!is_detected<has_get_set_properties_t, T>::value,
133-
MachineFunctionProperties>
134-
getSetPropertiesImpl() {
135-
return MachineFunctionProperties();
136-
}
137-
MachineFunctionProperties getSetProperties() const override {
138-
return getSetPropertiesImpl<PassT>();
139-
}
140-
141-
template <typename T>
142-
using has_get_cleared_properties_t =
143-
decltype(std::declval<T &>().getClearedProperties());
144-
template <typename T>
145-
static std::enable_if_t<is_detected<has_get_cleared_properties_t, T>::value,
146-
MachineFunctionProperties>
147-
getClearedPropertiesImpl() {
148-
return PassT::getClearedProperties();
149-
}
150-
template <typename T>
151-
static std::enable_if_t<!is_detected<has_get_cleared_properties_t, T>::value,
152-
MachineFunctionProperties>
153-
getClearedPropertiesImpl() {
154-
return MachineFunctionProperties();
155-
}
156-
MachineFunctionProperties getClearedProperties() const override {
157-
return getClearedPropertiesImpl<PassT>();
158-
}
159-
160-
PassT Pass;
161122
};
162123
} // namespace detail
163124

@@ -251,11 +212,12 @@ class FunctionAnalysisManagerMachineFunctionProxy
251212

252213
class ModuleToMachineFunctionPassAdaptor
253214
: public PassInfoMixin<ModuleToMachineFunctionPassAdaptor> {
254-
using MachinePassConcept = detail::MachinePassConcept;
255-
256215
public:
216+
using PassConceptT =
217+
detail::PassConcept<MachineFunction, MachineFunctionAnalysisManager>;
218+
257219
explicit ModuleToMachineFunctionPassAdaptor(
258-
std::unique_ptr<MachinePassConcept> Pass)
220+
std::unique_ptr<PassConceptT> Pass)
259221
: Pass(std::move(Pass)) {}
260222

261223
/// Runs the function pass across every function in the module.
@@ -266,20 +228,41 @@ class ModuleToMachineFunctionPassAdaptor
266228
static bool isRequired() { return true; }
267229

268230
private:
269-
std::unique_ptr<MachinePassConcept> Pass;
231+
std::unique_ptr<PassConceptT> Pass;
270232
};
271233

272234
template <typename MachineFunctionPassT>
273235
ModuleToMachineFunctionPassAdaptor
274236
createModuleToMachineFunctionPassAdaptor(MachineFunctionPassT &&Pass) {
275-
using PassModelT = detail::MachinePassModel<MachineFunctionPassT>;
237+
using PassModelT = detail::PassModel<MachineFunction, MachineFunctionPassT,
238+
MachineFunctionAnalysisManager>;
276239
// Do not use make_unique, it causes too many template instantiations,
277240
// causing terrible compile times.
278241
return ModuleToMachineFunctionPassAdaptor(
279-
std::unique_ptr<detail::MachinePassConcept>(
242+
std::unique_ptr<ModuleToMachineFunctionPassAdaptor::PassConceptT>(
280243
new PassModelT(std::forward<MachineFunctionPassT>(Pass))));
281244
}
282245

246+
template <>
247+
template <typename PassT>
248+
void PassManager<MachineFunction>::addPass(PassT &&Pass) {
249+
using PassModelT =
250+
detail::PassModel<MachineFunction, PassT, MachineFunctionAnalysisManager>;
251+
using MachinePassModelT = detail::MachinePassModel<PassT>;
252+
// Do not use make_unique or emplace_back, they cause too many template
253+
// instantiations, causing terrible compile times.
254+
if constexpr (std::is_base_of_v<MachinePassInfoMixin<PassT>, PassT>) {
255+
Passes.push_back(std::unique_ptr<PassConceptT>(
256+
new MachinePassModelT(std::forward<PassT>(Pass))));
257+
} else if constexpr (std::is_same_v<PassT, PassManager<MachineFunction>>) {
258+
for (auto &P : Pass.Passes)
259+
Passes.push_back(std::move(P));
260+
} else {
261+
Passes.push_back(std::unique_ptr<PassConceptT>(
262+
new PassModelT(std::forward<PassT>(Pass))));
263+
}
264+
}
265+
283266
template <>
284267
PreservedAnalyses
285268
PassManager<MachineFunction>::run(MachineFunction &,

llvm/include/llvm/IR/PassManager.h

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -267,29 +267,24 @@ class PassManager : public PassInfoMixin<
267267
return PA;
268268
}
269269

270-
template <typename PassT>
271-
LLVM_ATTRIBUTE_MINSIZE
272-
std::enable_if_t<!std::is_same<PassT, PassManager>::value>
273-
addPass(PassT &&Pass) {
270+
// FIXME: Revert to enable_if style when gcc >= 11.1
271+
template <typename PassT> LLVM_ATTRIBUTE_MINSIZE void addPass(PassT &&Pass) {
274272
using PassModelT =
275273
detail::PassModel<IRUnitT, PassT, AnalysisManagerT, ExtraArgTs...>;
276-
// Do not use make_unique or emplace_back, they cause too many template
277-
// instantiations, causing terrible compile times.
278-
Passes.push_back(std::unique_ptr<PassConceptT>(
279-
new PassModelT(std::forward<PassT>(Pass))));
280-
}
281-
282-
/// When adding a pass manager pass that has the same type as this pass
283-
/// manager, simply move the passes over. This is because we don't have use
284-
/// cases rely on executing nested pass managers. Doing this could reduce
285-
/// implementation complexity and avoid potential invalidation issues that may
286-
/// happen with nested pass managers of the same type.
287-
template <typename PassT>
288-
LLVM_ATTRIBUTE_MINSIZE
289-
std::enable_if_t<std::is_same<PassT, PassManager>::value>
290-
addPass(PassT &&Pass) {
291-
for (auto &P : Pass.Passes)
292-
Passes.push_back(std::move(P));
274+
if constexpr (!std::is_same_v<PassT, PassManager>) {
275+
// Do not use make_unique or emplace_back, they cause too many template
276+
// instantiations, causing terrible compile times.
277+
Passes.push_back(std::unique_ptr<PassConceptT>(
278+
new PassModelT(std::forward<PassT>(Pass))));
279+
} else {
280+
/// When adding a pass manager pass that has the same type as this pass
281+
/// manager, simply move the passes over. This is because we don't have
282+
/// use cases rely on executing nested pass managers. Doing this could
283+
/// reduce implementation complexity and avoid potential invalidation
284+
/// issues that may happen with nested pass managers of the same type.
285+
for (auto &P : Pass.Passes)
286+
Passes.push_back(std::move(P));
287+
}
293288
}
294289

295290
/// Returns if the pass manager contains any passes.

llvm/include/llvm/Passes/MachinePassRegistry.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ MACHINE_FUNCTION_PASS("dead-mi-elimination", DeadMachineInstructionElimPass())
127127
// MACHINE_FUNCTION_PASS("free-machine-function", FreeMachineFunctionPass())
128128
MACHINE_FUNCTION_PASS("no-op-machine-function", NoOpMachineFunctionPass())
129129
MACHINE_FUNCTION_PASS("print", PrintMIRPass())
130+
MACHINE_FUNCTION_PASS("require-all-machine-function-properties",
131+
RequireAllMachineFunctionPropertiesPass())
130132
#undef MACHINE_FUNCTION_PASS
131133

132134
// After a pass is converted to new pass manager, its entry should be moved from

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,33 @@ class TriggerVerifierErrorPass
365365
static StringRef name() { return "TriggerVerifierErrorPass"; }
366366
};
367367

368+
// A pass requires all MachineFunctionProperties.
369+
// DO NOT USE THIS EXCEPT FOR TESTING!
370+
class RequireAllMachineFunctionPropertiesPass
371+
: public MachinePassInfoMixin<RequireAllMachineFunctionPropertiesPass> {
372+
public:
373+
PreservedAnalyses run(MachineFunction &, MachineFunctionAnalysisManager &) {
374+
return PreservedAnalyses::none();
375+
}
376+
377+
static MachineFunctionProperties getRequiredProperties() {
378+
MachineFunctionProperties MFProps;
379+
MFProps.set(MachineFunctionProperties::Property::FailedISel);
380+
MFProps.set(MachineFunctionProperties::Property::FailsVerification);
381+
MFProps.set(MachineFunctionProperties::Property::IsSSA);
382+
MFProps.set(MachineFunctionProperties::Property::Legalized);
383+
MFProps.set(MachineFunctionProperties::Property::NoPHIs);
384+
MFProps.set(MachineFunctionProperties::Property::NoVRegs);
385+
MFProps.set(MachineFunctionProperties::Property::RegBankSelected);
386+
MFProps.set(MachineFunctionProperties::Property::Selected);
387+
MFProps.set(MachineFunctionProperties::Property::TiedOpsRewritten);
388+
MFProps.set(MachineFunctionProperties::Property::TracksDebugUserValues);
389+
MFProps.set(MachineFunctionProperties::Property::TracksLiveness);
390+
return MFProps;
391+
}
392+
static StringRef name() { return "RequireAllMachineFunctionPropertiesPass"; }
393+
};
394+
368395
} // namespace
369396

370397
PassBuilder::PassBuilder(TargetMachine *TM, PipelineTuningOptions PTO,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# REQUIRES: asserts
2+
# RUN: not --crash llc -mtriple=x86_64-pc-linux-gnu -passes=require-all-machine-function-properties -filetype=null %s 2>&1 | FileCheck %s
3+
4+
# CHECK: MachineFunctionProperties required by RequireAllMachineFunctionPropertiesPass pass are not met by function f.
5+
6+
---
7+
name: f
8+
selected: false
9+
body: |
10+
bb.0:
11+
RET 0
12+
...

0 commit comments

Comments
 (0)