//===- 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/IR/PassManager.h" #include "llvm/Support/Error.h" #include namespace llvm { class Module; class Function; class MachineFunction; extern template class AnalysisManager; /// Like \c AnalysisKey, but only for machine passes. struct alignas(8) MachinePassKey {}; /// 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 { static MachinePassKey *ID() { static_assert(std::is_base_of::value, "Must pass the derived type as the template argument!"); return &DerivedT::Key; } }; /// An AnalysisManager that also exposes IR analysis results. class MachineFunctionAnalysisManager : public AnalysisManager { public: using Base = AnalysisManager; MachineFunctionAnalysisManager() : FAM(nullptr), MAM(nullptr) {} MachineFunctionAnalysisManager(FunctionAnalysisManager &FAM, ModuleAnalysisManager &MAM) : FAM(&FAM), MAM(&MAM) {} MachineFunctionAnalysisManager(MachineFunctionAnalysisManager &&) = default; MachineFunctionAnalysisManager & operator=(MachineFunctionAnalysisManager &&) = default; /// Get the result of an analysis pass for a Function. /// /// Runs the analysis if a cached result is not available. template typename PassT::Result &getResult(Function &F) { return FAM->getResult(F); } /// Get the cached result of an analysis pass for a Function. /// /// This method never runs the analysis. /// /// \returns null if there is no cached result. template typename PassT::Result *getCachedResult(Function &F) { return FAM->getCachedResult(F); } /// Get the result of an analysis pass for a Module. /// /// Runs the analysis if a cached result is not available. template typename PassT::Result &getResult(Module &M) { return MAM->getResult(M); } /// Get the cached result of an analysis pass for a Module. /// /// This method never runs the analysis. /// /// \returns null if there is no cached result. template typename PassT::Result *getCachedResult(Module &M) { return MAM->getCachedResult(M); } /// Get the result of an analysis pass for a MachineFunction. /// /// Runs the analysis if a cached result is not available. using Base::getResult; /// Get the cached result of an analysis pass for a MachineFunction. /// /// This method never runs the analysis. /// /// returns null if there is no cached result. using Base::getCachedResult; // FIXME: Add LoopAnalysisManager or CGSCCAnalysisManager if needed. FunctionAnalysisManager *FAM; ModuleAnalysisManager *MAM; }; extern template class PassManager; /// MachineFunctionPassManager adds/removes below features to/from the base /// PassManager template instantiation. /// /// - Support passes that implement doInitialization/doFinalization. This is for /// machine function passes to work on module level constructs. One such pass /// is AsmPrinter. /// /// - Support machine module pass which runs over the module (for example, /// MachineOutliner). A machine module pass needs to define the method: /// /// ```Error run(Module &, MachineFunctionAnalysisManager &)``` /// /// FIXME: machine module passes still need to define the usual machine /// function pass interface, namely, /// `PreservedAnalyses run(MachineFunction &, /// MachineFunctionAnalysisManager &)` /// But this interface wouldn't be executed. It is just a placeholder /// to satisfy the pass manager type-erased inteface. This /// special-casing of machine module pass is due to its limited use /// cases and the unnecessary complexity it may bring to the machine /// pass manager. /// /// - The base class `run` method is replaced by an alternative `run` method. /// See details below. /// /// - Support codegening in the SCC order. Users include interprocedural /// register allocation (IPRA). class MachineFunctionPassManager : public PassManager { using Base = PassManager; public: MachineFunctionPassManager(bool RequireCodeGenSCCOrder = false, bool VerifyMachineFunction = false) : RequireCodeGenSCCOrder(RequireCodeGenSCCOrder), VerifyMachineFunction(VerifyMachineFunction) {} MachineFunctionPassManager(MachineFunctionPassManager &&) = default; MachineFunctionPassManager & operator=(MachineFunctionPassManager &&) = default; /// Run machine passes for a Module. /// /// The intended use is to start the codegen pipeline for a Module. The base /// class's `run` method is deliberately hidden by this due to the observation /// that we don't yet have the use cases of compositing two instances of /// machine pass managers, or compositing machine pass managers with other /// types of pass managers. Error run(Module &M, MachineFunctionAnalysisManager &MFAM); template void addPass(PassT &&Pass) { Base::addPass(std::forward(Pass)); PassConceptT *P = Passes.back().get(); addDoInitialization(P); addDoFinalization(P); // Add machine module pass. addRunOnModule(P); } private: template using has_init_t = decltype(std::declval().doInitialization( std::declval(), std::declval())); template std::enable_if_t::value> addDoInitialization(PassConceptT *Pass) {} template std::enable_if_t::value> addDoInitialization(PassConceptT *Pass) { using PassModelT = detail::PassModel; auto *P = static_cast(Pass); InitializationFuncs.emplace_back( [=](Module &M, MachineFunctionAnalysisManager &MFAM) { return P->Pass.doInitialization(M, MFAM); }); } template using has_fini_t = decltype(std::declval().doFinalization( std::declval(), std::declval())); template std::enable_if_t::value> addDoFinalization(PassConceptT *Pass) {} template std::enable_if_t::value> addDoFinalization(PassConceptT *Pass) { using PassModelT = detail::PassModel; auto *P = static_cast(Pass); FinalizationFuncs.emplace_back( [=](Module &M, MachineFunctionAnalysisManager &MFAM) { return P->Pass.doFinalization(M, MFAM); }); } template using is_machine_module_pass_t = decltype(std::declval().run( std::declval(), std::declval())); template using is_machine_function_pass_t = decltype(std::declval().run( std::declval(), std::declval())); template std::enable_if_t::value> addRunOnModule(PassConceptT *Pass) {} template std::enable_if_t::value> addRunOnModule(PassConceptT *Pass) { static_assert(is_detected::value, "machine module pass needs to define machine function pass " "api. sorry."); using PassModelT = detail::PassModel; auto *P = static_cast(Pass); MachineModulePasses.emplace( Passes.size() - 1, [=](Module &M, MachineFunctionAnalysisManager &MFAM) { return P->Pass.run(M, MFAM); }); } using FuncTy = Error(Module &, MachineFunctionAnalysisManager &); SmallVector, 4> InitializationFuncs; SmallVector, 4> FinalizationFuncs; using PassIndex = decltype(Passes)::size_type; std::map> MachineModulePasses; // Run codegen in the SCC order. bool RequireCodeGenSCCOrder; bool VerifyMachineFunction; }; } // end namespace llvm #endif // LLVM_CODEGEN_MACHINEPASSMANAGER_H