Skip to content

[PassManager] Support MachineFunctionProperties #83668

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 84 additions & 103 deletions llvm/include/llvm/CodeGen/MachinePassManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
// their respective analysis managers such as ModuleAnalysisManager and
// FunctionAnalysisManager.
//
// TODO: Add MachineFunctionProperties support.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CODEGEN_MACHINEPASSMANAGER_H
Expand All @@ -44,23 +42,67 @@ using MachineFunctionAnalysisManager = AnalysisManager<MachineFunction>;
/// automatically mixes in \c PassInfoMixin.
template <typename DerivedT>
struct MachinePassInfoMixin : public PassInfoMixin<DerivedT> {
// TODO: Add MachineFunctionProperties support.
protected:
class PropertyChanger {
MachineFunction &MF;

template <typename T>
using has_get_required_properties_t =
decltype(std::declval<T &>().getRequiredProperties());

template <typename T>
using has_get_set_properties_t =
decltype(std::declval<T &>().getSetProperties());

template <typename T>
using has_get_cleared_properties_t =
decltype(std::declval<T &>().getClearedProperties());

public:
PropertyChanger(MachineFunction &MF) : MF(MF) {
#ifndef NDEBUG
if constexpr (is_detected<has_get_required_properties_t,
DerivedT>::value) {
auto &MFProps = MF.getProperties();
auto RequiredProperties = DerivedT::getRequiredProperties();
if (!MFProps.verifyRequiredProperties(RequiredProperties)) {
errs() << "MachineFunctionProperties required by " << DerivedT::name()
<< " pass are not met by function " << MF.getName() << ".\n"
<< "Required properties: ";
RequiredProperties.print(errs());
errs() << "\nCurrent properties: ";
MFProps.print(errs());
errs() << '\n';
report_fatal_error("MachineFunctionProperties check failed");
}
#endif
}
}

~PropertyChanger() {
if constexpr (is_detected<has_get_set_properties_t, DerivedT>::value)
MF.getProperties().set(DerivedT::getSetProperties());
if constexpr (is_detected<has_get_cleared_properties_t, DerivedT>::value)
MF.getProperties().reset(DerivedT::getClearedProperties());
}
};

public:
PreservedAnalyses runImpl(MachineFunction &MF,
MachineFunctionAnalysisManager &MFAM) {
PropertyChanger PC(MF);
return static_cast<DerivedT *>(this)->run(MF, MFAM);
}
};

namespace detail {
struct MachinePassConcept
: PassConcept<MachineFunction, MachineFunctionAnalysisManager> {
virtual MachineFunctionProperties getRequiredProperties() const = 0;
virtual MachineFunctionProperties getSetProperties() const = 0;
virtual MachineFunctionProperties getClearedProperties() const = 0;
};

template <typename PassT> struct MachinePassModel : MachinePassConcept {
explicit MachinePassModel(PassT &&Pass) : Pass(std::move(Pass)) {}
// We have to explicitly define all the special member functions because MSVC
// refuses to generate them.
MachinePassModel(const MachinePassModel &Arg) : Pass(Arg.Pass) {}
MachinePassModel(MachinePassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
template <typename PassT>
struct MachinePassModel
: PassModel<MachineFunction, PassT, MachineFunctionAnalysisManager> {
explicit MachinePassModel(PassT &&Pass)
: PassModel<MachineFunction, PassT, MachineFunctionAnalysisManager>(
std::move(Pass)) {}

friend void swap(MachinePassModel &LHS, MachinePassModel &RHS) {
using std::swap;
Expand All @@ -75,89 +117,8 @@ template <typename PassT> struct MachinePassModel : MachinePassConcept {
MachinePassModel &operator=(const MachinePassModel &) = delete;
PreservedAnalyses run(MachineFunction &IR,
MachineFunctionAnalysisManager &AM) override {
return Pass.run(IR, AM);
}

void printPipeline(
raw_ostream &OS,
function_ref<StringRef(StringRef)> MapClassName2PassName) override {
Pass.printPipeline(OS, MapClassName2PassName);
}

StringRef name() const override { return PassT::name(); }

template <typename T>
using has_required_t = decltype(std::declval<T &>().isRequired());
template <typename T>
static std::enable_if_t<is_detected<has_required_t, T>::value, bool>
passIsRequiredImpl() {
return T::isRequired();
return this->Pass.runImpl(IR, AM);
}
template <typename T>
static std::enable_if_t<!is_detected<has_required_t, T>::value, bool>
passIsRequiredImpl() {
return false;
}
bool isRequired() const override { return passIsRequiredImpl<PassT>(); }

template <typename T>
using has_get_required_properties_t =
decltype(std::declval<T &>().getRequiredProperties());
template <typename T>
static std::enable_if_t<is_detected<has_get_required_properties_t, T>::value,
MachineFunctionProperties>
getRequiredPropertiesImpl() {
return PassT::getRequiredProperties();
}
template <typename T>
static std::enable_if_t<!is_detected<has_get_required_properties_t, T>::value,
MachineFunctionProperties>
getRequiredPropertiesImpl() {
return MachineFunctionProperties();
}
MachineFunctionProperties getRequiredProperties() const override {
return getRequiredPropertiesImpl<PassT>();
}

template <typename T>
using has_get_set_properties_t =
decltype(std::declval<T &>().getSetProperties());
template <typename T>
static std::enable_if_t<is_detected<has_get_set_properties_t, T>::value,
MachineFunctionProperties>
getSetPropertiesImpl() {
return PassT::getSetProperties();
}
template <typename T>
static std::enable_if_t<!is_detected<has_get_set_properties_t, T>::value,
MachineFunctionProperties>
getSetPropertiesImpl() {
return MachineFunctionProperties();
}
MachineFunctionProperties getSetProperties() const override {
return getSetPropertiesImpl<PassT>();
}

template <typename T>
using has_get_cleared_properties_t =
decltype(std::declval<T &>().getClearedProperties());
template <typename T>
static std::enable_if_t<is_detected<has_get_cleared_properties_t, T>::value,
MachineFunctionProperties>
getClearedPropertiesImpl() {
return PassT::getClearedProperties();
}
template <typename T>
static std::enable_if_t<!is_detected<has_get_cleared_properties_t, T>::value,
MachineFunctionProperties>
getClearedPropertiesImpl() {
return MachineFunctionProperties();
}
MachineFunctionProperties getClearedProperties() const override {
return getClearedPropertiesImpl<PassT>();
}

PassT Pass;
};
} // namespace detail

Expand Down Expand Up @@ -251,11 +212,12 @@ class FunctionAnalysisManagerMachineFunctionProxy

class ModuleToMachineFunctionPassAdaptor
: public PassInfoMixin<ModuleToMachineFunctionPassAdaptor> {
using MachinePassConcept = detail::MachinePassConcept;

public:
using PassConceptT =
detail::PassConcept<MachineFunction, MachineFunctionAnalysisManager>;

explicit ModuleToMachineFunctionPassAdaptor(
std::unique_ptr<MachinePassConcept> Pass)
std::unique_ptr<PassConceptT> Pass)
: Pass(std::move(Pass)) {}

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

private:
std::unique_ptr<MachinePassConcept> Pass;
std::unique_ptr<PassConceptT> Pass;
};

template <typename MachineFunctionPassT>
ModuleToMachineFunctionPassAdaptor
createModuleToMachineFunctionPassAdaptor(MachineFunctionPassT &&Pass) {
using PassModelT = detail::MachinePassModel<MachineFunctionPassT>;
using PassModelT = detail::PassModel<MachineFunction, MachineFunctionPassT,
MachineFunctionAnalysisManager>;
// Do not use make_unique, it causes too many template instantiations,
// causing terrible compile times.
return ModuleToMachineFunctionPassAdaptor(
std::unique_ptr<detail::MachinePassConcept>(
std::unique_ptr<ModuleToMachineFunctionPassAdaptor::PassConceptT>(
new PassModelT(std::forward<MachineFunctionPassT>(Pass))));
}

template <>
template <typename PassT>
std::enable_if_t<!std::is_same<PassT, PassManager<MachineFunction>>::value>
PassManager<MachineFunction>::addPass(PassT &&Pass) {
using PassModelT =
detail::PassModel<MachineFunction, PassT, MachineFunctionAnalysisManager>;
using MachinePassModelT = detail::MachinePassModel<PassT>;
// Do not use make_unique or emplace_back, they cause too many template
// instantiations, causing terrible compile times.
if constexpr (std::is_base_of_v<MachinePassInfoMixin<PassT>, PassT>) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this always be true?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this always be true?

Try to use MachinePassModelT only, but InvalidateAnalysisPass<T> no longer works.

Passes.push_back(std::unique_ptr<PassConceptT>(
new MachinePassModelT(std::forward<PassT>(Pass))));
} else {
Passes.push_back(std::unique_ptr<PassConceptT>(
new PassModelT(std::forward<PassT>(Pass))));
}
}

template <>
PreservedAnalyses
PassManager<MachineFunction>::run(MachineFunction &,
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Passes/MachinePassRegistry.def
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ MACHINE_FUNCTION_PASS("dead-mi-elimination", DeadMachineInstructionElimPass())
// MACHINE_FUNCTION_PASS("free-machine-function", FreeMachineFunctionPass())
MACHINE_FUNCTION_PASS("no-op-machine-function", NoOpMachineFunctionPass())
MACHINE_FUNCTION_PASS("print", PrintMIRPass())
MACHINE_FUNCTION_PASS("require-all-machine-function-properties",
RequireAllMachineFunctionPropertiesPass())
#undef MACHINE_FUNCTION_PASS

// After a pass is converted to new pass manager, its entry should be moved from
Expand Down
27 changes: 27 additions & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,33 @@ class TriggerVerifierErrorPass
static StringRef name() { return "TriggerVerifierErrorPass"; }
};

// A pass requires all MachineFunctionProperties.
// DO NOT USE THIS EXCEPT FOR TESTING!
class RequireAllMachineFunctionPropertiesPass
: public MachinePassInfoMixin<RequireAllMachineFunctionPropertiesPass> {
public:
PreservedAnalyses run(MachineFunction &, MachineFunctionAnalysisManager &) {
return PreservedAnalyses::none();
}

static MachineFunctionProperties getRequiredProperties() {
MachineFunctionProperties MFProps;
MFProps.set(MachineFunctionProperties::Property::FailedISel);
MFProps.set(MachineFunctionProperties::Property::FailsVerification);
MFProps.set(MachineFunctionProperties::Property::IsSSA);
MFProps.set(MachineFunctionProperties::Property::Legalized);
MFProps.set(MachineFunctionProperties::Property::NoPHIs);
MFProps.set(MachineFunctionProperties::Property::NoVRegs);
MFProps.set(MachineFunctionProperties::Property::RegBankSelected);
MFProps.set(MachineFunctionProperties::Property::Selected);
MFProps.set(MachineFunctionProperties::Property::TiedOpsRewritten);
MFProps.set(MachineFunctionProperties::Property::TracksDebugUserValues);
MFProps.set(MachineFunctionProperties::Property::TracksLiveness);
return MFProps;
}
static StringRef name() { return "RequireAllMachineFunctionPropertiesPass"; }
};

} // namespace

PassBuilder::PassBuilder(TargetMachine *TM, PipelineTuningOptions PTO,
Expand Down
12 changes: 12 additions & 0 deletions llvm/test/tools/llc/new-pm/machine-function-properties.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# REQUIRES: asserts
# RUN: not --crash llc -mtriple=x86_64-pc-linux-gnu -passes=require-all-machine-function-properties -filetype=null %s 2>&1 | FileCheck %s

# CHECK: MachineFunctionProperties required by RequireAllMachineFunctionPropertiesPass pass are not met by function f.

---
name: f
selected: false
body: |
bb.0:
RET 0
...