//===- 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. // //===----------------------------------------------------------------------===// #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; namespace detail { template struct MachinePassModel : PassModel { explicit MachinePassModel(PassT &&Pass) : PassModel( std::move(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; } MachinePassModel &operator=(const MachinePassModel &) = delete; PreservedAnalyses run(MachineFunction &IR, MachineFunctionAnalysisManager &AM) override { #ifndef NDEBUG if constexpr (is_detected::value) { auto &MFProps = IR.getProperties(); auto RequiredProperties = PassT::getRequiredProperties(); if (!MFProps.verifyRequiredProperties(RequiredProperties)) { errs() << "MachineFunctionProperties required by " << PassT::name() << " pass are not met by function " << IR.getName() << ".\n" << "Required properties: "; RequiredProperties.print(errs()); errs() << "\nCurrent properties: "; MFProps.print(errs()); errs() << '\n'; report_fatal_error("MachineFunctionProperties check failed"); } } #endif auto PA = this->Pass.run(IR, AM); if constexpr (is_detected::value) IR.getProperties().set(PassT::getSetProperties()); if constexpr (is_detected::value) IR.getProperties().reset(PassT::getClearedProperties()); return PA; } private: 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()); }; } // namespace detail using MachineFunctionAnalysisManagerModuleProxy = InnerAnalysisManagerProxy; template <> bool MachineFunctionAnalysisManagerModuleProxy::Result::invalidate( Module &M, const PreservedAnalyses &PA, ModuleAnalysisManager::Invalidator &Inv); extern template class InnerAnalysisManagerProxy; using MachineFunctionAnalysisManagerFunctionProxy = InnerAnalysisManagerProxy; template <> bool MachineFunctionAnalysisManagerFunctionProxy::Result::invalidate( Function &F, const PreservedAnalyses &PA, FunctionAnalysisManager::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 &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 FunctionToMachineFunctionPassAdaptor : public PassInfoMixin { public: using PassConceptT = detail::PassConcept; explicit FunctionToMachineFunctionPassAdaptor( std::unique_ptr Pass) : Pass(std::move(Pass)) {} /// Runs the function pass across every function in the function. PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); void printPipeline(raw_ostream &OS, function_ref MapClassName2PassName); static bool isRequired() { return true; } private: std::unique_ptr Pass; }; template FunctionToMachineFunctionPassAdaptor createFunctionToMachineFunctionPassAdaptor(MachineFunctionPassT &&Pass) { using PassModelT = detail::PassModel; // Do not use make_unique, it causes too many template instantiations, // causing terrible compile times. return FunctionToMachineFunctionPassAdaptor( std::unique_ptr( new PassModelT(std::forward(Pass)))); } template <> template void PassManager::addPass(PassT &&Pass) { 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_same_v>) { for (auto &P : Pass.Passes) Passes.push_back(std::move(P)); } else { Passes.push_back(std::unique_ptr( new MachinePassModelT(std::forward(Pass)))); } } template <> PreservedAnalyses PassManager::run(MachineFunction &, AnalysisManager &); extern template class PassManager; /// Convenience typedef for a pass manager over functions. using MachineFunctionPassManager = PassManager; /// Returns the minimum set of Analyses that all machine function passes must /// preserve. PreservedAnalyses getMachineFunctionPassPreservedAnalyses(); } // end namespace llvm #endif // LLVM_CODEGEN_MACHINEPASSMANAGER_H