Skip to content

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
merged 1 commit into from
Mar 30, 2024

Conversation

paperchalice
Copy link
Contributor

Unfortunately GCC 9 rejects code in https://godbolt.org/z/zd9r5GM3e GCC 11 accepts this code.

@llvmbot
Copy link
Member

llvmbot commented Mar 30, 2024

@llvm/pr-subscribers-llvm-ir

Author: None (paperchalice)

Changes

Unfortunately 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:

  • (modified) llvm/include/llvm/CodeGen/MachinePassManager.h (+86-103)
  • (modified) llvm/include/llvm/IR/PassManager.h (+16-21)
  • (modified) llvm/include/llvm/Passes/MachinePassRegistry.def (+2)
  • (modified) llvm/lib/Passes/PassBuilder.cpp (+27)
  • (added) llvm/test/tools/llc/new-pm/machine-function-properties.mir (+12)
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
+...

@paperchalice paperchalice merged commit b361b53 into llvm:main Mar 30, 2024
@paperchalice paperchalice deleted the reland branch March 31, 2024 04:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants