diff --git a/llvm/include/llvm/CodeGen/MachinePassManager.h b/llvm/include/llvm/CodeGen/MachinePassManager.h index 3faffe5c4cab2..965e8282ccaba 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; /// automatically mixes in \c PassInfoMixin. template struct MachinePassInfoMixin : public PassInfoMixin { - // TODO: Add MachineFunctionProperties support. +protected: + class PropertyChanger { + MachineFunction &MF; + + template + using has_get_required_properties_t = + decltype(std::declval().getRequiredProperties()); + + template + using has_get_set_properties_t = + decltype(std::declval().getSetProperties()); + + template + using has_get_cleared_properties_t = + decltype(std::declval().getClearedProperties()); + + public: + PropertyChanger(MachineFunction &MF) : MF(MF) { +#ifndef NDEBUG + if constexpr (is_detected::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::value) + MF.getProperties().set(DerivedT::getSetProperties()); + if constexpr (is_detected::value) + MF.getProperties().reset(DerivedT::getClearedProperties()); + } + }; + +public: + PreservedAnalyses runImpl(MachineFunction &MF, + MachineFunctionAnalysisManager &MFAM) { + PropertyChanger PC(MF); + return static_cast(this)->run(MF, MFAM); + } }; namespace detail { -struct MachinePassConcept - : PassConcept { - virtual MachineFunctionProperties getRequiredProperties() const = 0; - virtual MachineFunctionProperties getSetProperties() const = 0; - virtual MachineFunctionProperties getClearedProperties() const = 0; -}; -template 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 +struct MachinePassModel + : PassModel { + explicit MachinePassModel(PassT &&Pass) + : PassModel( + std::move(Pass)) {} friend void swap(MachinePassModel &LHS, MachinePassModel &RHS) { using std::swap; @@ -75,89 +117,8 @@ template 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 MapClassName2PassName) override { - Pass.printPipeline(OS, MapClassName2PassName); - } - - StringRef name() const override { return PassT::name(); } - - template - using has_required_t = decltype(std::declval().isRequired()); - template - static std::enable_if_t::value, bool> - passIsRequiredImpl() { - return T::isRequired(); + return this->Pass.runImpl(IR, AM); } - template - static std::enable_if_t::value, bool> - passIsRequiredImpl() { - return false; - } - bool isRequired() const override { return passIsRequiredImpl(); } - - template - using has_get_required_properties_t = - decltype(std::declval().getRequiredProperties()); - template - static std::enable_if_t::value, - MachineFunctionProperties> - getRequiredPropertiesImpl() { - return PassT::getRequiredProperties(); - } - template - static std::enable_if_t::value, - MachineFunctionProperties> - getRequiredPropertiesImpl() { - return MachineFunctionProperties(); - } - MachineFunctionProperties getRequiredProperties() const override { - return getRequiredPropertiesImpl(); - } - - template - using has_get_set_properties_t = - decltype(std::declval().getSetProperties()); - template - static std::enable_if_t::value, - MachineFunctionProperties> - getSetPropertiesImpl() { - return PassT::getSetProperties(); - } - template - static std::enable_if_t::value, - MachineFunctionProperties> - getSetPropertiesImpl() { - return MachineFunctionProperties(); - } - MachineFunctionProperties getSetProperties() const override { - return getSetPropertiesImpl(); - } - - template - using has_get_cleared_properties_t = - decltype(std::declval().getClearedProperties()); - template - static std::enable_if_t::value, - MachineFunctionProperties> - getClearedPropertiesImpl() { - return PassT::getClearedProperties(); - } - template - static std::enable_if_t::value, - MachineFunctionProperties> - getClearedPropertiesImpl() { - return MachineFunctionProperties(); - } - MachineFunctionProperties getClearedProperties() const override { - return getClearedPropertiesImpl(); - } - - PassT Pass; }; } // namespace detail @@ -251,11 +212,12 @@ class FunctionAnalysisManagerMachineFunctionProxy class ModuleToMachineFunctionPassAdaptor : public PassInfoMixin { - using MachinePassConcept = detail::MachinePassConcept; - public: + using PassConceptT = + detail::PassConcept; + explicit ModuleToMachineFunctionPassAdaptor( - std::unique_ptr Pass) + std::unique_ptr Pass) : Pass(std::move(Pass)) {} /// Runs the function pass across every function in the module. @@ -266,20 +228,39 @@ class ModuleToMachineFunctionPassAdaptor static bool isRequired() { return true; } private: - std::unique_ptr Pass; + std::unique_ptr Pass; }; template ModuleToMachineFunctionPassAdaptor createModuleToMachineFunctionPassAdaptor(MachineFunctionPassT &&Pass) { - using PassModelT = detail::MachinePassModel; + using PassModelT = detail::PassModel; // Do not use make_unique, it causes too many template instantiations, // causing terrible compile times. return ModuleToMachineFunctionPassAdaptor( - std::unique_ptr( + std::unique_ptr( new PassModelT(std::forward(Pass)))); } +template <> +template +std::enable_if_t>::value> +PassManager::addPass(PassT &&Pass) { + using PassModelT = + detail::PassModel; + using MachinePassModelT = detail::MachinePassModel; + // 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, PassT>) { + Passes.push_back(std::unique_ptr( + new MachinePassModelT(std::forward(Pass)))); + } else { + Passes.push_back(std::unique_ptr( + new PassModelT(std::forward(Pass)))); + } +} + template <> PreservedAnalyses PassManager::run(MachineFunction &, diff --git a/llvm/include/llvm/Passes/MachinePassRegistry.def b/llvm/include/llvm/Passes/MachinePassRegistry.def index 016602730e0e9..2f77ae655d9b2 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 f60f4eb3f0ef8..57975e34d4265 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 { +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 0000000000000..a9eb88ec69884 --- /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 +...