257 lines
9.8 KiB
C
257 lines
9.8 KiB
C
|
//===- 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/Support/Error.h"
|
||
|
#include "llvm/Support/type_traits.h"
|
||
|
|
||
|
namespace llvm {
|
||
|
class Module;
|
||
|
|
||
|
extern template class AnalysisManager<MachineFunction>;
|
||
|
|
||
|
/// An AnalysisManager<MachineFunction> that also exposes IR analysis results.
|
||
|
class MachineFunctionAnalysisManager : public AnalysisManager<MachineFunction> {
|
||
|
public:
|
||
|
using Base = AnalysisManager<MachineFunction>;
|
||
|
|
||
|
MachineFunctionAnalysisManager() : Base(false), FAM(nullptr), MAM(nullptr) {}
|
||
|
MachineFunctionAnalysisManager(FunctionAnalysisManager &FAM,
|
||
|
ModuleAnalysisManager &MAM,
|
||
|
bool DebugLogging = false)
|
||
|
: Base(DebugLogging), 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> typename PassT::Result &getResult(Function &F) {
|
||
|
return FAM->getResult<PassT>(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>
|
||
|
typename PassT::Result *getCachedResult(Function &F) {
|
||
|
return FAM->getCachedResult<PassT>(F);
|
||
|
}
|
||
|
|
||
|
/// Get the result of an analysis pass for a Module.
|
||
|
///
|
||
|
/// Runs the analysis if a cached result is not available.
|
||
|
template <typename PassT> typename PassT::Result &getResult(Module &M) {
|
||
|
return MAM->getResult<PassT>(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> typename PassT::Result *getCachedResult(Module &M) {
|
||
|
return MAM->getCachedResult<PassT>(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<MachineFunction>;
|
||
|
|
||
|
/// 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<MachineFunction, MachineFunctionAnalysisManager> {
|
||
|
using Base = PassManager<MachineFunction, MachineFunctionAnalysisManager>;
|
||
|
|
||
|
public:
|
||
|
MachineFunctionPassManager(bool DebugLogging = false,
|
||
|
bool RequireCodeGenSCCOrder = false,
|
||
|
bool VerifyMachineFunction = false)
|
||
|
: Base(DebugLogging), 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 <typename PassT> void addPass(PassT &&Pass) {
|
||
|
Base::addPass(std::forward<PassT>(Pass));
|
||
|
PassConceptT *P = Passes.back().get();
|
||
|
addDoInitialization<PassT>(P);
|
||
|
addDoFinalization<PassT>(P);
|
||
|
|
||
|
// Add machine module pass.
|
||
|
addRunOnModule<PassT>(P);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
template <typename PassT>
|
||
|
using has_init_t = decltype(std::declval<PassT &>().doInitialization(
|
||
|
std::declval<Module &>(),
|
||
|
std::declval<MachineFunctionAnalysisManager &>()));
|
||
|
|
||
|
template <typename PassT>
|
||
|
std::enable_if_t<!is_detected<has_init_t, PassT>::value>
|
||
|
addDoInitialization(PassConceptT *Pass) {}
|
||
|
|
||
|
template <typename PassT>
|
||
|
std::enable_if_t<is_detected<has_init_t, PassT>::value>
|
||
|
addDoInitialization(PassConceptT *Pass) {
|
||
|
using PassModelT =
|
||
|
detail::PassModel<MachineFunction, PassT, PreservedAnalyses,
|
||
|
MachineFunctionAnalysisManager>;
|
||
|
auto *P = static_cast<PassModelT *>(Pass);
|
||
|
InitializationFuncs.emplace_back(
|
||
|
[=](Module &M, MachineFunctionAnalysisManager &MFAM) {
|
||
|
return P->Pass.doInitialization(M, MFAM);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
template <typename PassT>
|
||
|
using has_fini_t = decltype(std::declval<PassT &>().doFinalization(
|
||
|
std::declval<Module &>(),
|
||
|
std::declval<MachineFunctionAnalysisManager &>()));
|
||
|
|
||
|
template <typename PassT>
|
||
|
std::enable_if_t<!is_detected<has_fini_t, PassT>::value>
|
||
|
addDoFinalization(PassConceptT *Pass) {}
|
||
|
|
||
|
template <typename PassT>
|
||
|
std::enable_if_t<is_detected<has_fini_t, PassT>::value>
|
||
|
addDoFinalization(PassConceptT *Pass) {
|
||
|
using PassModelT =
|
||
|
detail::PassModel<MachineFunction, PassT, PreservedAnalyses,
|
||
|
MachineFunctionAnalysisManager>;
|
||
|
auto *P = static_cast<PassModelT *>(Pass);
|
||
|
FinalizationFuncs.emplace_back(
|
||
|
[=](Module &M, MachineFunctionAnalysisManager &MFAM) {
|
||
|
return P->Pass.doFinalization(M, MFAM);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
template <typename PassT>
|
||
|
using is_machine_module_pass_t = decltype(std::declval<PassT &>().run(
|
||
|
std::declval<Module &>(),
|
||
|
std::declval<MachineFunctionAnalysisManager &>()));
|
||
|
|
||
|
template <typename PassT>
|
||
|
using is_machine_function_pass_t = decltype(std::declval<PassT &>().run(
|
||
|
std::declval<MachineFunction &>(),
|
||
|
std::declval<MachineFunctionAnalysisManager &>()));
|
||
|
|
||
|
template <typename PassT>
|
||
|
std::enable_if_t<!is_detected<is_machine_module_pass_t, PassT>::value>
|
||
|
addRunOnModule(PassConceptT *Pass) {}
|
||
|
|
||
|
template <typename PassT>
|
||
|
std::enable_if_t<is_detected<is_machine_module_pass_t, PassT>::value>
|
||
|
addRunOnModule(PassConceptT *Pass) {
|
||
|
static_assert(is_detected<is_machine_function_pass_t, PassT>::value,
|
||
|
"machine module pass needs to define machine function pass "
|
||
|
"api. sorry.");
|
||
|
|
||
|
using PassModelT =
|
||
|
detail::PassModel<MachineFunction, PassT, PreservedAnalyses,
|
||
|
MachineFunctionAnalysisManager>;
|
||
|
auto *P = static_cast<PassModelT *>(Pass);
|
||
|
MachineModulePasses.emplace(
|
||
|
Passes.size() - 1,
|
||
|
[=](Module &M, MachineFunctionAnalysisManager &MFAM) {
|
||
|
return P->Pass.run(M, MFAM);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
using FuncTy = Error(Module &, MachineFunctionAnalysisManager &);
|
||
|
SmallVector<llvm::unique_function<FuncTy>, 4> InitializationFuncs;
|
||
|
SmallVector<llvm::unique_function<FuncTy>, 4> FinalizationFuncs;
|
||
|
|
||
|
using PassIndex = decltype(Passes)::size_type;
|
||
|
std::map<PassIndex, llvm::unique_function<FuncTy>> MachineModulePasses;
|
||
|
|
||
|
// Run codegen in the SCC order.
|
||
|
bool RequireCodeGenSCCOrder;
|
||
|
|
||
|
bool VerifyMachineFunction;
|
||
|
};
|
||
|
|
||
|
} // end namespace llvm
|
||
|
|
||
|
#endif // LLVM_CODEGEN_MACHINEPASSMANAGER_H
|