//===- PassManager.h --- Pass management for CodeGen ------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This header defines the pass manager interface for codegen. The codegen // pipeline consists of only machine function passes. There is no container // relationship between IR module/function and machine function in terms of pass // manager organization. So there is no need for adaptor classes (for example // ModuleToMachineFunctionAdaptor). Since invalidation could only happen among // machine function passes, there is no proxy classes to handle cross-IR-unit // invalidation. IR analysis results are provided for machine function passes by // their respective analysis managers such as ModuleAnalysisManager and // FunctionAnalysisManager. // // TODO: Add MachineFunctionProperties support. // //===----------------------------------------------------------------------===// #ifndef LLVM_CODEGEN_MACHINEPASSMANAGER_H #define LLVM_CODEGEN_MACHINEPASSMANAGER_H #include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/PassManagerInternal.h" #include "llvm/Support/Error.h" namespace llvm { class Module; class Function; class MachineFunction; extern template class AnalysisManager; using MachineFunctionAnalysisManager = AnalysisManager; /// A CRTP mix-in that provides informational APIs needed for machine passes. /// /// This provides some boilerplate for types that are machine passes. It /// automatically mixes in \c PassInfoMixin. template struct MachinePassInfoMixin : public PassInfoMixin { // TODO: Add MachineFunctionProperties support. }; 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)) {} friend void swap(MachinePassModel &LHS, MachinePassModel &RHS) { using std::swap; swap(LHS.Pass, RHS.Pass); } MachinePassModel &operator=(MachinePassModel RHS) { swap(*this, RHS); return *this; } 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(); } 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 using MachineFunctionAnalysisManagerModuleProxy = InnerAnalysisManagerProxy; template <> bool MachineFunctionAnalysisManagerModuleProxy::Result::invalidate( Module &M, const PreservedAnalyses &PA, ModuleAnalysisManager::Invalidator &Inv); extern template class InnerAnalysisManagerProxy; extern template class OuterAnalysisManagerProxy; /// Provide the \c ModuleAnalysisManager to \c Function proxy. using ModuleAnalysisManagerMachineFunctionProxy = OuterAnalysisManagerProxy; class FunctionAnalysisManagerMachineFunctionProxy : public AnalysisInfoMixin { public: class Result { public: explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {} Result(Result &&Arg) : FAM(std::move(Arg.FAM)) { // We have to null out the analysis manager in the moved-from state // because we are taking ownership of the responsibilty to clear the // analysis state. Arg.FAM = nullptr; } ~Result() { // FAM is cleared in a moved from state where there is nothing to do. if (!FAM) return; // Clear out the analysis manager if we're being destroyed -- it means we // didn't even see an invalidate call when we got invalidated. FAM->clear(); } Result &operator=(Result &&RHS) { FAM = RHS.FAM; // We have to null out the analysis manager in the moved-from state // because we are taking ownership of the responsibilty to clear the // analysis state. RHS.FAM = nullptr; return *this; } /// Accessor for the analysis manager. FunctionAnalysisManager &getManager() { return *FAM; } /// Handler for invalidation of the outer IR unit, \c IRUnitT. /// /// If the proxy analysis itself is not preserved, we assume that the set of /// inner IR objects contained in IRUnit may have changed. In this case, /// we have to call \c clear() on the inner analysis manager, as it may now /// have stale pointers to its inner IR objects. /// /// Regardless of whether the proxy analysis is marked as preserved, all of /// the analyses in the inner analysis manager are potentially invalidated /// based on the set of preserved analyses. bool invalidate(MachineFunction &IR, const PreservedAnalyses &PA, MachineFunctionAnalysisManager::Invalidator &Inv); private: FunctionAnalysisManager *FAM; }; explicit FunctionAnalysisManagerMachineFunctionProxy( FunctionAnalysisManager &FAM) : FAM(&FAM) {} /// Run the analysis pass and create our proxy result object. /// /// This doesn't do any interesting work; it is primarily used to insert our /// proxy result object into the outer analysis cache so that we can proxy /// invalidation to the inner analysis manager. Result run(MachineFunction &, MachineFunctionAnalysisManager &) { return Result(*FAM); } static AnalysisKey Key; private: FunctionAnalysisManager *FAM; }; class ModuleToMachineFunctionPassAdaptor : public PassInfoMixin { using MachinePassConcept = detail::MachinePassConcept; public: explicit ModuleToMachineFunctionPassAdaptor( std::unique_ptr Pass) : Pass(std::move(Pass)) {} /// Runs the function pass across every function in the module. PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); void printPipeline(raw_ostream &OS, function_ref MapClassName2PassName); static bool isRequired() { return true; } private: std::unique_ptr Pass; }; template ModuleToMachineFunctionPassAdaptor createModuleToMachineFunctionPassAdaptor(MachineFunctionPassT &&Pass) { using PassModelT = detail::MachinePassModel; // Do not use make_unique, it causes too many template instantiations, // causing terrible compile times. return ModuleToMachineFunctionPassAdaptor( std::unique_ptr( new PassModelT(std::forward(Pass)))); } template <> PreservedAnalyses PassManager::run(MachineFunction &, AnalysisManager &); extern template class PassManager; /// Convenience typedef for a pass manager over functions. using MachineFunctionPassManager = PassManager; } // end namespace llvm #endif // LLVM_CODEGEN_MACHINEPASSMANAGER_H