-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Reland "[PassManager] Support MachineFunctionProperties (#83668)" #87141
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
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
…llvm#87137) Unfortunately GCC 9 rejects code in https://godbolt.org/z/zd9r5GM3e GCC 11 accepts this code.
@llvm/pr-subscribers-llvm-ir Author: None (paperchalice) ChangesUnfortunately GCC 9 rejects code in https://godbolt.org/z/zd9r5GM3e GCC 11 accepts this code. Full diff: https://github.com/llvm/llvm-project/pull/87141.diff 5 Files Affected:
diff --git a/llvm/include/llvm/CodeGen/MachinePassManager.h b/llvm/include/llvm/CodeGen/MachinePassManager.h
index 3faffe5c4cab29..8689fd19030f90 100644
--- a/llvm/include/llvm/CodeGen/MachinePassManager.h
+++ b/llvm/include/llvm/CodeGen/MachinePassManager.h
@@ -16,8 +16,6 @@
// their respective analysis managers such as ModuleAnalysisManager and
// FunctionAnalysisManager.
//
-// TODO: Add MachineFunctionProperties support.
-//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_MACHINEPASSMANAGER_H
@@ -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;
@@ -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
@@ -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.
@@ -266,20 +228,41 @@ 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>
+void 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>) {
+ Passes.push_back(std::unique_ptr<PassConceptT>(
+ new MachinePassModelT(std::forward<PassT>(Pass))));
+ } else if constexpr (std::is_same_v<PassT, PassManager<MachineFunction>>) {
+ for (auto &P : Pass.Passes)
+ Passes.push_back(std::move(P));
+ } else {
+ Passes.push_back(std::unique_ptr<PassConceptT>(
+ new PassModelT(std::forward<PassT>(Pass))));
+ }
+}
+
template <>
PreservedAnalyses
PassManager<MachineFunction>::run(MachineFunction &,
diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h
index ec8b809d40bfbc..108465478d3779 100644
--- a/llvm/include/llvm/IR/PassManager.h
+++ b/llvm/include/llvm/IR/PassManager.h
@@ -267,29 +267,24 @@ class PassManager : public PassInfoMixin<
return PA;
}
- template <typename PassT>
- LLVM_ATTRIBUTE_MINSIZE
- std::enable_if_t<!std::is_same<PassT, PassManager>::value>
- addPass(PassT &&Pass) {
+ // FIXME: Revert to enable_if style when gcc >= 11.1
+ template <typename PassT> LLVM_ATTRIBUTE_MINSIZE void addPass(PassT &&Pass) {
using PassModelT =
detail::PassModel<IRUnitT, PassT, AnalysisManagerT, ExtraArgTs...>;
- // Do not use make_unique or emplace_back, they cause too many template
- // instantiations, causing terrible compile times.
- Passes.push_back(std::unique_ptr<PassConceptT>(
- new PassModelT(std::forward<PassT>(Pass))));
- }
-
- /// When adding a pass manager pass that has the same type as this pass
- /// manager, simply move the passes over. This is because we don't have use
- /// cases rely on executing nested pass managers. Doing this could reduce
- /// implementation complexity and avoid potential invalidation issues that may
- /// happen with nested pass managers of the same type.
- template <typename PassT>
- LLVM_ATTRIBUTE_MINSIZE
- std::enable_if_t<std::is_same<PassT, PassManager>::value>
- addPass(PassT &&Pass) {
- for (auto &P : Pass.Passes)
- Passes.push_back(std::move(P));
+ if constexpr (!std::is_same_v<PassT, PassManager>) {
+ // Do not use make_unique or emplace_back, they cause too many template
+ // instantiations, causing terrible compile times.
+ Passes.push_back(std::unique_ptr<PassConceptT>(
+ new PassModelT(std::forward<PassT>(Pass))));
+ } else {
+ /// When adding a pass manager pass that has the same type as this pass
+ /// manager, simply move the passes over. This is because we don't have
+ /// use cases rely on executing nested pass managers. Doing this could
+ /// reduce implementation complexity and avoid potential invalidation
+ /// issues that may happen with nested pass managers of the same type.
+ for (auto &P : Pass.Passes)
+ Passes.push_back(std::move(P));
+ }
}
/// Returns if the pass manager contains any passes.
diff --git a/llvm/include/llvm/Passes/MachinePassRegistry.def b/llvm/include/llvm/Passes/MachinePassRegistry.def
index 016602730e0e97..2f77ae655d9b22 100644
--- a/llvm/include/llvm/Passes/MachinePassRegistry.def
+++ b/llvm/include/llvm/Passes/MachinePassRegistry.def
@@ -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
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index f60f4eb3f0ef8c..57975e34d4265b 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -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,
diff --git a/llvm/test/tools/llc/new-pm/machine-function-properties.mir b/llvm/test/tools/llc/new-pm/machine-function-properties.mir
new file mode 100644
index 00000000000000..a9eb88ec698841
--- /dev/null
+++ b/llvm/test/tools/llc/new-pm/machine-function-properties.mir
@@ -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
+...
|
arsenm
approved these changes
Mar 30, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Unfortunately GCC 9 rejects code in https://godbolt.org/z/zd9r5GM3e GCC 11 accepts this code.