diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/libs/llvm12/include/llvm/CodeGen/CodeGenPassBuilder.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/libs/llvm12/include/llvm/CodeGen/CodeGenPassBuilder.h')
-rw-r--r-- | contrib/libs/llvm12/include/llvm/CodeGen/CodeGenPassBuilder.h | 1155 |
1 files changed, 1155 insertions, 0 deletions
diff --git a/contrib/libs/llvm12/include/llvm/CodeGen/CodeGenPassBuilder.h b/contrib/libs/llvm12/include/llvm/CodeGen/CodeGenPassBuilder.h new file mode 100644 index 0000000000..cf1633258f --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/CodeGen/CodeGenPassBuilder.h @@ -0,0 +1,1155 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- Construction of codegen pass pipelines ------------------*- 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// Interfaces for registering analysis passes, producing common pass manager +/// configurations, and parsing of pass pipelines. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_CODEGENPASSBUILDER_H +#define LLVM_CODEGEN_CODEGENPASSBUILDER_H + +#include "llvm/ADT/FunctionExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/Analysis/CFLAndersAliasAnalysis.h" +#include "llvm/Analysis/CFLSteensAliasAnalysis.h" +#include "llvm/Analysis/ScopedNoAliasAA.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/Analysis/TypeBasedAliasAnalysis.h" +#include "llvm/CodeGen/ExpandReductions.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachinePassManager.h" +#include "llvm/CodeGen/PreISelIntrinsicLowering.h" +#include "llvm/CodeGen/UnreachableBlockElim.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Verifier.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCTargetOptions.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/CGPassBuilderOption.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/ConstantHoisting.h" +#include "llvm/Transforms/Scalar/LoopPassManager.h" +#include "llvm/Transforms/Scalar/LoopStrengthReduce.h" +#include "llvm/Transforms/Scalar/LowerConstantIntrinsics.h" +#include "llvm/Transforms/Scalar/MergeICmps.h" +#include "llvm/Transforms/Scalar/PartiallyInlineLibCalls.h" +#include "llvm/Transforms/Scalar/ScalarizeMaskedMemIntrin.h" +#include "llvm/Transforms/Utils.h" +#include "llvm/Transforms/Utils/EntryExitInstrumenter.h" +#include "llvm/Transforms/Utils/LowerInvoke.h" +#include <cassert> +#include <string> +#include <type_traits> +#include <utility> + +namespace llvm { + +// FIXME: Dummy target independent passes definitions that have not yet been +// ported to new pass manager. Once they do, remove these. +#define DUMMY_FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR) \ + struct PASS_NAME : public PassInfoMixin<PASS_NAME> { \ + template <typename... Ts> PASS_NAME(Ts &&...) {} \ + PreservedAnalyses run(Function &, FunctionAnalysisManager &) { \ + return PreservedAnalyses::all(); \ + } \ + }; +#define DUMMY_MODULE_PASS(NAME, PASS_NAME, CONSTRUCTOR) \ + struct PASS_NAME : public PassInfoMixin<PASS_NAME> { \ + template <typename... Ts> PASS_NAME(Ts &&...) {} \ + PreservedAnalyses run(Module &, ModuleAnalysisManager &) { \ + return PreservedAnalyses::all(); \ + } \ + }; +#define DUMMY_MACHINE_MODULE_PASS(NAME, PASS_NAME, CONSTRUCTOR) \ + struct PASS_NAME : public PassInfoMixin<PASS_NAME> { \ + template <typename... Ts> PASS_NAME(Ts &&...) {} \ + Error run(Module &, MachineFunctionAnalysisManager &) { \ + return Error::success(); \ + } \ + PreservedAnalyses run(MachineFunction &, \ + MachineFunctionAnalysisManager &) { \ + llvm_unreachable("this api is to make new PM api happy"); \ + } \ + static AnalysisKey Key; \ + }; +#define DUMMY_MACHINE_FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR) \ + struct PASS_NAME : public PassInfoMixin<PASS_NAME> { \ + template <typename... Ts> PASS_NAME(Ts &&...) {} \ + PreservedAnalyses run(MachineFunction &, \ + MachineFunctionAnalysisManager &) { \ + return PreservedAnalyses::all(); \ + } \ + static AnalysisKey Key; \ + }; +#include "MachinePassRegistry.def" + +/// This class provides access to building LLVM's passes. +/// +/// Its members provide the baseline state available to passes during their +/// construction. The \c MachinePassRegistry.def file specifies how to construct +/// all of the built-in passes, and those may reference these members during +/// construction. +template <typename DerivedT> class CodeGenPassBuilder { +public: + explicit CodeGenPassBuilder(LLVMTargetMachine &TM, CGPassBuilderOption Opts, + PassInstrumentationCallbacks *PIC) + : TM(TM), Opt(Opts), PIC(PIC) { + // Target could set CGPassBuilderOption::MISchedPostRA to true to achieve + // substitutePass(&PostRASchedulerID, &PostMachineSchedulerID) + + // Target should override TM.Options.EnableIPRA in their target-specific + // LLVMTM ctor. See TargetMachine::setGlobalISel for example. + if (Opt.EnableIPRA) + TM.Options.EnableIPRA = *Opt.EnableIPRA; + + if (Opt.EnableGlobalISelAbort) + TM.Options.GlobalISelAbort = *Opt.EnableGlobalISelAbort; + + if (!Opt.OptimizeRegAlloc) + Opt.OptimizeRegAlloc = getOptLevel() != CodeGenOpt::None; + } + + Error buildPipeline(ModulePassManager &MPM, MachineFunctionPassManager &MFPM, + raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut, + CodeGenFileType FileType) const; + + void registerModuleAnalyses(ModuleAnalysisManager &) const; + void registerFunctionAnalyses(FunctionAnalysisManager &) const; + void registerMachineFunctionAnalyses(MachineFunctionAnalysisManager &) const; + std::pair<StringRef, bool> getPassNameFromLegacyName(StringRef) const; + + void registerAnalyses(MachineFunctionAnalysisManager &MFAM) const { + registerModuleAnalyses(*MFAM.MAM); + registerFunctionAnalyses(*MFAM.FAM); + registerMachineFunctionAnalyses(MFAM); + } + + PassInstrumentationCallbacks *getPassInstrumentationCallbacks() const { + return PIC; + } + +protected: + template <typename PassT> using has_key_t = decltype(PassT::Key); + + template <typename PassT> + using is_module_pass_t = decltype(std::declval<PassT &>().run( + std::declval<Module &>(), std::declval<ModuleAnalysisManager &>())); + + template <typename PassT> + using is_function_pass_t = decltype(std::declval<PassT &>().run( + std::declval<Function &>(), std::declval<FunctionAnalysisManager &>())); + + // Function object to maintain state while adding codegen IR passes. + class AddIRPass { + public: + AddIRPass(ModulePassManager &MPM, bool DebugPM, bool Check = true) + : MPM(MPM), FPM(DebugPM) { + if (Check) + AddingFunctionPasses = false; + } + ~AddIRPass() { + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + } + + // Add Function Pass + template <typename PassT> + std::enable_if_t<is_detected<is_function_pass_t, PassT>::value> + operator()(PassT &&Pass) { + if (AddingFunctionPasses && !*AddingFunctionPasses) + AddingFunctionPasses = true; + FPM.addPass(std::forward<PassT>(Pass)); + } + + // Add Module Pass + template <typename PassT> + std::enable_if_t<is_detected<is_module_pass_t, PassT>::value && + !is_detected<is_function_pass_t, PassT>::value> + operator()(PassT &&Pass) { + assert((!AddingFunctionPasses || !*AddingFunctionPasses) && + "could not add module pass after adding function pass"); + MPM.addPass(std::forward<PassT>(Pass)); + } + + private: + ModulePassManager &MPM; + FunctionPassManager FPM; + // The codegen IR pipeline are mostly function passes with the exceptions of + // a few loop and module passes. `AddingFunctionPasses` make sures that + // we could only add module passes at the beginning of the pipeline. Once + // we begin adding function passes, we could no longer add module passes. + // This special-casing introduces less adaptor passes. If we have the need + // of adding module passes after function passes, we could change the + // implementation to accommodate that. + Optional<bool> AddingFunctionPasses; + }; + + // Function object to maintain state while adding codegen machine passes. + class AddMachinePass { + public: + AddMachinePass(MachineFunctionPassManager &PM) : PM(PM) {} + + template <typename PassT> void operator()(PassT &&Pass) { + static_assert( + is_detected<has_key_t, PassT>::value, + "Machine function pass must define a static member variable `Key`."); + for (auto &C : BeforeCallbacks) + if (!C(&PassT::Key)) + return; + PM.addPass(std::forward<PassT>(Pass)); + for (auto &C : AfterCallbacks) + C(&PassT::Key); + } + + template <typename PassT> void insertPass(AnalysisKey *ID, PassT Pass) { + AfterCallbacks.emplace_back( + [this, ID, Pass = std::move(Pass)](AnalysisKey *PassID) { + if (PassID == ID) + this->PM.addPass(std::move(Pass)); + }); + } + + void disablePass(AnalysisKey *ID) { + BeforeCallbacks.emplace_back( + [ID](AnalysisKey *PassID) { return PassID != ID; }); + } + + MachineFunctionPassManager releasePM() { return std::move(PM); } + + private: + MachineFunctionPassManager &PM; + SmallVector<llvm::unique_function<bool(AnalysisKey *)>, 4> BeforeCallbacks; + SmallVector<llvm::unique_function<void(AnalysisKey *)>, 4> AfterCallbacks; + }; + + LLVMTargetMachine &TM; + CGPassBuilderOption Opt; + PassInstrumentationCallbacks *PIC; + + /// Target override these hooks to parse target-specific analyses. + void registerTargetAnalysis(ModuleAnalysisManager &) const {} + void registerTargetAnalysis(FunctionAnalysisManager &) const {} + void registerTargetAnalysis(MachineFunctionAnalysisManager &) const {} + std::pair<StringRef, bool> getTargetPassNameFromLegacyName(StringRef) const { + return {"", false}; + } + + template <typename TMC> TMC &getTM() const { return static_cast<TMC &>(TM); } + CodeGenOpt::Level getOptLevel() const { return TM.getOptLevel(); } + + /// Check whether or not GlobalISel should abort on error. + /// When this is disabled, GlobalISel will fall back on SDISel instead of + /// erroring out. + bool isGlobalISelAbortEnabled() const { + return TM.Options.GlobalISelAbort == GlobalISelAbortMode::Enable; + } + + /// Check whether or not a diagnostic should be emitted when GlobalISel + /// uses the fallback path. In other words, it will emit a diagnostic + /// when GlobalISel failed and isGlobalISelAbortEnabled is false. + bool reportDiagnosticWhenGlobalISelFallback() const { + return TM.Options.GlobalISelAbort == GlobalISelAbortMode::DisableWithDiag; + } + + /// addInstSelector - This method should install an instruction selector pass, + /// which converts from LLVM code to machine instructions. + Error addInstSelector(AddMachinePass &) const { + return make_error<StringError>("addInstSelector is not overridden", + inconvertibleErrorCode()); + } + + /// Add passes that optimize instruction level parallelism for out-of-order + /// targets. These passes are run while the machine code is still in SSA + /// form, so they can use MachineTraceMetrics to control their heuristics. + /// + /// All passes added here should preserve the MachineDominatorTree, + /// MachineLoopInfo, and MachineTraceMetrics analyses. + void addILPOpts(AddMachinePass &) const {} + + /// This method may be implemented by targets that want to run passes + /// immediately before register allocation. + void addPreRegAlloc(AddMachinePass &) const {} + + /// addPreRewrite - Add passes to the optimized register allocation pipeline + /// after register allocation is complete, but before virtual registers are + /// rewritten to physical registers. + /// + /// These passes must preserve VirtRegMap and LiveIntervals, and when running + /// after RABasic or RAGreedy, they should take advantage of LiveRegMatrix. + /// When these passes run, VirtRegMap contains legal physreg assignments for + /// all virtual registers. + /// + /// Note if the target overloads addRegAssignAndRewriteOptimized, this may not + /// be honored. This is also not generally used for the the fast variant, + /// where the allocation and rewriting are done in one pass. + void addPreRewrite(AddMachinePass &) const {} + + /// Add passes to be run immediately after virtual registers are rewritten + /// to physical registers. + void addPostRewrite(AddMachinePass &) const {} + + /// This method may be implemented by targets that want to run passes after + /// register allocation pass pipeline but before prolog-epilog insertion. + void addPostRegAlloc(AddMachinePass &) const {} + + /// This method may be implemented by targets that want to run passes after + /// prolog-epilog insertion and before the second instruction scheduling pass. + void addPreSched2(AddMachinePass &) const {} + + /// This pass may be implemented by targets that want to run passes + /// immediately before machine code is emitted. + void addPreEmitPass(AddMachinePass &) const {} + + /// Targets may add passes immediately before machine code is emitted in this + /// callback. This is called even later than `addPreEmitPass`. + // FIXME: Rename `addPreEmitPass` to something more sensible given its actual + // position and remove the `2` suffix here as this callback is what + // `addPreEmitPass` *should* be but in reality isn't. + void addPreEmitPass2(AddMachinePass &) const {} + + /// {{@ For GlobalISel + /// + + /// addPreISel - This method should add any "last minute" LLVM->LLVM + /// passes (which are run just before instruction selector). + void addPreISel(AddIRPass &) const { + llvm_unreachable("addPreISel is not overridden"); + } + + /// This method should install an IR translator pass, which converts from + /// LLVM code to machine instructions with possibly generic opcodes. + Error addIRTranslator(AddMachinePass &) const { + return make_error<StringError>("addIRTranslator is not overridden", + inconvertibleErrorCode()); + } + + /// This method may be implemented by targets that want to run passes + /// immediately before legalization. + void addPreLegalizeMachineIR(AddMachinePass &) const {} + + /// This method should install a legalize pass, which converts the instruction + /// sequence into one that can be selected by the target. + Error addLegalizeMachineIR(AddMachinePass &) const { + return make_error<StringError>("addLegalizeMachineIR is not overridden", + inconvertibleErrorCode()); + } + + /// This method may be implemented by targets that want to run passes + /// immediately before the register bank selection. + void addPreRegBankSelect(AddMachinePass &) const {} + + /// This method should install a register bank selector pass, which + /// assigns register banks to virtual registers without a register + /// class or register banks. + Error addRegBankSelect(AddMachinePass &) const { + return make_error<StringError>("addRegBankSelect is not overridden", + inconvertibleErrorCode()); + } + + /// This method may be implemented by targets that want to run passes + /// immediately before the (global) instruction selection. + void addPreGlobalInstructionSelect(AddMachinePass &) const {} + + /// This method should install a (global) instruction selector pass, which + /// converts possibly generic instructions to fully target-specific + /// instructions, thereby constraining all generic virtual registers to + /// register classes. + Error addGlobalInstructionSelect(AddMachinePass &) const { + return make_error<StringError>( + "addGlobalInstructionSelect is not overridden", + inconvertibleErrorCode()); + } + /// @}} + + /// High level function that adds all passes necessary to go from llvm IR + /// representation to the MI representation. + /// Adds IR based lowering and target specific optimization passes and finally + /// the core instruction selection passes. + /// \returns true if an error occurred, false otherwise. + void addISelPasses(AddIRPass &) const; + + /// Add the actual instruction selection passes. This does not include + /// preparation passes on IR. + Error addCoreISelPasses(AddMachinePass &) const; + + /// Add the complete, standard set of LLVM CodeGen passes. + /// Fully developed targets will not generally override this. + Error addMachinePasses(AddMachinePass &) const; + + /// Add passes to lower exception handling for the code generator. + void addPassesToHandleExceptions(AddIRPass &) const; + + /// Add common target configurable passes that perform LLVM IR to IR + /// transforms following machine independent optimization. + void addIRPasses(AddIRPass &) const; + + /// Add pass to prepare the LLVM IR for code generation. This should be done + /// before exception handling preparation passes. + void addCodeGenPrepare(AddIRPass &) const; + + /// Add common passes that perform LLVM IR to IR transforms in preparation for + /// instruction selection. + void addISelPrepare(AddIRPass &) const; + + /// Methods with trivial inline returns are convenient points in the common + /// codegen pass pipeline where targets may insert passes. Methods with + /// out-of-line standard implementations are major CodeGen stages called by + /// addMachinePasses. Some targets may override major stages when inserting + /// passes is insufficient, but maintaining overriden stages is more work. + /// + + /// addMachineSSAOptimization - Add standard passes that optimize machine + /// instructions in SSA form. + void addMachineSSAOptimization(AddMachinePass &) const; + + /// addFastRegAlloc - Add the minimum set of target-independent passes that + /// are required for fast register allocation. + Error addFastRegAlloc(AddMachinePass &) const; + + /// addOptimizedRegAlloc - Add passes related to register allocation. + /// LLVMTargetMachine provides standard regalloc passes for most targets. + void addOptimizedRegAlloc(AddMachinePass &) const; + + /// Add passes that optimize machine instructions after register allocation. + void addMachineLateOptimization(AddMachinePass &) const; + + /// addGCPasses - Add late codegen passes that analyze code for garbage + /// collection. This should return true if GC info should be printed after + /// these passes. + void addGCPasses(AddMachinePass &) const {} + + /// Add standard basic block placement passes. + void addBlockPlacement(AddMachinePass &) const; + + using CreateMCStreamer = + std::function<Expected<std::unique_ptr<MCStreamer>>(MCContext &)>; + void addAsmPrinter(AddMachinePass &, CreateMCStreamer) const { + llvm_unreachable("addAsmPrinter is not overridden"); + } + + /// Utilities for targets to add passes to the pass manager. + /// + + /// createTargetRegisterAllocator - Create the register allocator pass for + /// this target at the current optimization level. + void addTargetRegisterAllocator(AddMachinePass &, bool Optimized) const; + + /// addMachinePasses helper to create the target-selected or overriden + /// regalloc pass. + void addRegAllocPass(AddMachinePass &, bool Optimized) const; + + /// Add core register alloator passes which do the actual register assignment + /// and rewriting. \returns true if any passes were added. + Error addRegAssignmentFast(AddMachinePass &) const; + Error addRegAssignmentOptimized(AddMachinePass &) const; + +private: + DerivedT &derived() { return static_cast<DerivedT &>(*this); } + const DerivedT &derived() const { + return static_cast<const DerivedT &>(*this); + } +}; + +template <typename Derived> +Error CodeGenPassBuilder<Derived>::buildPipeline( + ModulePassManager &MPM, MachineFunctionPassManager &MFPM, + raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut, + CodeGenFileType FileType) const { + AddIRPass addIRPass(MPM, Opt.DebugPM); + addISelPasses(addIRPass); + + AddMachinePass addPass(MFPM); + if (auto Err = addCoreISelPasses(addPass)) + return std::move(Err); + + if (auto Err = derived().addMachinePasses(addPass)) + return std::move(Err); + + derived().addAsmPrinter( + addPass, [this, &Out, DwoOut, FileType](MCContext &Ctx) { + return this->TM.createMCStreamer(Out, DwoOut, FileType, Ctx); + }); + + addPass(FreeMachineFunctionPass()); + return Error::success(); +} + +static inline AAManager registerAAAnalyses(CFLAAType UseCFLAA) { + AAManager AA; + + // The order in which these are registered determines their priority when + // being queried. + + switch (UseCFLAA) { + case CFLAAType::Steensgaard: + AA.registerFunctionAnalysis<CFLSteensAA>(); + break; + case CFLAAType::Andersen: + AA.registerFunctionAnalysis<CFLAndersAA>(); + break; + case CFLAAType::Both: + AA.registerFunctionAnalysis<CFLAndersAA>(); + AA.registerFunctionAnalysis<CFLSteensAA>(); + break; + default: + break; + } + + // Basic AliasAnalysis support. + // Add TypeBasedAliasAnalysis before BasicAliasAnalysis so that + // BasicAliasAnalysis wins if they disagree. This is intended to help + // support "obvious" type-punning idioms. + AA.registerFunctionAnalysis<TypeBasedAA>(); + AA.registerFunctionAnalysis<ScopedNoAliasAA>(); + AA.registerFunctionAnalysis<BasicAA>(); + + return AA; +} + +template <typename Derived> +void CodeGenPassBuilder<Derived>::registerModuleAnalyses( + ModuleAnalysisManager &MAM) const { +#define MODULE_ANALYSIS(NAME, PASS_NAME, CONSTRUCTOR) \ + MAM.registerPass([&] { return PASS_NAME CONSTRUCTOR; }); +#include "MachinePassRegistry.def" + derived().registerTargetAnalysis(MAM); +} + +template <typename Derived> +void CodeGenPassBuilder<Derived>::registerFunctionAnalyses( + FunctionAnalysisManager &FAM) const { + FAM.registerPass([this] { return registerAAAnalyses(this->Opt.UseCFLAA); }); + +#define FUNCTION_ANALYSIS(NAME, PASS_NAME, CONSTRUCTOR) \ + FAM.registerPass([&] { return PASS_NAME CONSTRUCTOR; }); +#include "MachinePassRegistry.def" + derived().registerTargetAnalysis(FAM); +} + +template <typename Derived> +void CodeGenPassBuilder<Derived>::registerMachineFunctionAnalyses( + MachineFunctionAnalysisManager &MFAM) const { +#define MACHINE_FUNCTION_ANALYSIS(NAME, PASS_NAME, CONSTRUCTOR) \ + MFAM.registerPass([&] { return PASS_NAME CONSTRUCTOR; }); +#include "MachinePassRegistry.def" + derived().registerTargetAnalysis(MFAM); +} + +// FIXME: For new PM, use pass name directly in commandline seems good. +// Translate stringfied pass name to its old commandline name. Returns the +// matching legacy name and a boolean value indicating if the pass is a machine +// pass. +template <typename Derived> +std::pair<StringRef, bool> +CodeGenPassBuilder<Derived>::getPassNameFromLegacyName(StringRef Name) const { + std::pair<StringRef, bool> Ret; + if (Name.empty()) + return Ret; + +#define FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR) \ + if (Name == NAME) \ + Ret = {#PASS_NAME, false}; +#define DUMMY_FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR) \ + if (Name == NAME) \ + Ret = {#PASS_NAME, false}; +#define MODULE_PASS(NAME, PASS_NAME, CONSTRUCTOR) \ + if (Name == NAME) \ + Ret = {#PASS_NAME, false}; +#define DUMMY_MODULE_PASS(NAME, PASS_NAME, CONSTRUCTOR) \ + if (Name == NAME) \ + Ret = {#PASS_NAME, false}; +#define MACHINE_MODULE_PASS(NAME, PASS_NAME, CONSTRUCTOR) \ + if (Name == NAME) \ + Ret = {#PASS_NAME, true}; +#define DUMMY_MACHINE_MODULE_PASS(NAME, PASS_NAME, CONSTRUCTOR) \ + if (Name == NAME) \ + Ret = {#PASS_NAME, true}; +#define MACHINE_FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR) \ + if (Name == NAME) \ + Ret = {#PASS_NAME, true}; +#define DUMMY_MACHINE_FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR) \ + if (Name == NAME) \ + Ret = {#PASS_NAME, true}; +#include "llvm/CodeGen/MachinePassRegistry.def" + + if (Ret.first.empty()) + Ret = derived().getTargetPassNameFromLegacyName(Name); + + if (Ret.first.empty()) + report_fatal_error(Twine('\"') + Twine(Name) + + Twine("\" pass could not be found.")); + + return Ret; +} + +template <typename Derived> +void CodeGenPassBuilder<Derived>::addISelPasses(AddIRPass &addPass) const { + if (TM.useEmulatedTLS()) + addPass(LowerEmuTLSPass()); + + addPass(PreISelIntrinsicLoweringPass()); + + derived().addIRPasses(addPass); + derived().addCodeGenPrepare(addPass); + addPassesToHandleExceptions(addPass); + derived().addISelPrepare(addPass); +} + +/// Add common target configurable passes that perform LLVM IR to IR transforms +/// following machine independent optimization. +template <typename Derived> +void CodeGenPassBuilder<Derived>::addIRPasses(AddIRPass &addPass) const { + // Before running any passes, run the verifier to determine if the input + // coming from the front-end and/or optimizer is valid. + if (!Opt.DisableVerify) + addPass(VerifierPass()); + + // Run loop strength reduction before anything else. + if (getOptLevel() != CodeGenOpt::None && !Opt.DisableLSR) { + addPass(createFunctionToLoopPassAdaptor( + LoopStrengthReducePass(), /*UseMemorySSA*/ true, Opt.DebugPM)); + // FIXME: use -stop-after so we could remove PrintLSR + if (Opt.PrintLSR) + addPass(PrintFunctionPass(dbgs(), "\n\n*** Code after LSR ***\n")); + } + + if (getOptLevel() != CodeGenOpt::None) { + // The MergeICmpsPass tries to create memcmp calls by grouping sequences of + // loads and compares. ExpandMemCmpPass then tries to expand those calls + // into optimally-sized loads and compares. The transforms are enabled by a + // target lowering hook. + if (!Opt.DisableMergeICmps) + addPass(MergeICmpsPass()); + addPass(ExpandMemCmpPass()); + } + + // Run GC lowering passes for builtin collectors + // TODO: add a pass insertion point here + addPass(GCLoweringPass()); + addPass(ShadowStackGCLoweringPass()); + addPass(LowerConstantIntrinsicsPass()); + + // Make sure that no unreachable blocks are instruction selected. + addPass(UnreachableBlockElimPass()); + + // Prepare expensive constants for SelectionDAG. + if (getOptLevel() != CodeGenOpt::None && !Opt.DisableConstantHoisting) + addPass(ConstantHoistingPass()); + + if (getOptLevel() != CodeGenOpt::None && !Opt.DisablePartialLibcallInlining) + addPass(PartiallyInlineLibCallsPass()); + + // Instrument function entry and exit, e.g. with calls to mcount(). + addPass(EntryExitInstrumenterPass(/*PostInlining=*/true)); + + // Add scalarization of target's unsupported masked memory intrinsics pass. + // the unsupported intrinsic will be replaced with a chain of basic blocks, + // that stores/loads element one-by-one if the appropriate mask bit is set. + addPass(ScalarizeMaskedMemIntrinPass()); + + // Expand reduction intrinsics into shuffle sequences if the target wants to. + addPass(ExpandReductionsPass()); +} + +/// Turn exception handling constructs into something the code generators can +/// handle. +template <typename Derived> +void CodeGenPassBuilder<Derived>::addPassesToHandleExceptions( + AddIRPass &addPass) const { + const MCAsmInfo *MCAI = TM.getMCAsmInfo(); + assert(MCAI && "No MCAsmInfo"); + switch (MCAI->getExceptionHandlingType()) { + case ExceptionHandling::SjLj: + // SjLj piggy-backs on dwarf for this bit. The cleanups done apply to both + // Dwarf EH prepare needs to be run after SjLj prepare. Otherwise, + // catch info can get misplaced when a selector ends up more than one block + // removed from the parent invoke(s). This could happen when a landing + // pad is shared by multiple invokes and is also a target of a normal + // edge from elsewhere. + addPass(SjLjEHPreparePass()); + LLVM_FALLTHROUGH; + case ExceptionHandling::DwarfCFI: + case ExceptionHandling::ARM: + case ExceptionHandling::AIX: + addPass(DwarfEHPass(getOptLevel())); + break; + case ExceptionHandling::WinEH: + // We support using both GCC-style and MSVC-style exceptions on Windows, so + // add both preparation passes. Each pass will only actually run if it + // recognizes the personality function. + addPass(WinEHPass()); + addPass(DwarfEHPass(getOptLevel())); + break; + case ExceptionHandling::Wasm: + // Wasm EH uses Windows EH instructions, but it does not need to demote PHIs + // on catchpads and cleanuppads because it does not outline them into + // funclets. Catchswitch blocks are not lowered in SelectionDAG, so we + // should remove PHIs there. + addPass(WinEHPass(/*DemoteCatchSwitchPHIOnly=*/false)); + addPass(WasmEHPass()); + break; + case ExceptionHandling::None: + addPass(LowerInvokePass()); + + // The lower invoke pass may create unreachable code. Remove it. + addPass(UnreachableBlockElimPass()); + break; + } +} + +/// Add pass to prepare the LLVM IR for code generation. This should be done +/// before exception handling preparation passes. +template <typename Derived> +void CodeGenPassBuilder<Derived>::addCodeGenPrepare(AddIRPass &addPass) const { + if (getOptLevel() != CodeGenOpt::None && !Opt.DisableCGP) + addPass(CodeGenPreparePass()); + // TODO: Default ctor'd RewriteSymbolPass is no-op. + // addPass(RewriteSymbolPass()); +} + +/// Add common passes that perform LLVM IR to IR transforms in preparation for +/// instruction selection. +template <typename Derived> +void CodeGenPassBuilder<Derived>::addISelPrepare(AddIRPass &addPass) const { + derived().addPreISel(addPass); + + // Add both the safe stack and the stack protection passes: each of them will + // only protect functions that have corresponding attributes. + addPass(SafeStackPass()); + addPass(StackProtectorPass()); + + if (Opt.PrintISelInput) + addPass(PrintFunctionPass(dbgs(), + "\n\n*** Final LLVM Code input to ISel ***\n")); + + // All passes which modify the LLVM IR are now complete; run the verifier + // to ensure that the IR is valid. + if (!Opt.DisableVerify) + addPass(VerifierPass()); +} + +template <typename Derived> +Error CodeGenPassBuilder<Derived>::addCoreISelPasses( + AddMachinePass &addPass) const { + // Enable FastISel with -fast-isel, but allow that to be overridden. + TM.setO0WantsFastISel(Opt.EnableFastISelOption.getValueOr(true)); + + // Determine an instruction selector. + enum class SelectorType { SelectionDAG, FastISel, GlobalISel }; + SelectorType Selector; + + if (Opt.EnableFastISelOption && *Opt.EnableFastISelOption == true) + Selector = SelectorType::FastISel; + else if ((Opt.EnableGlobalISelOption && + *Opt.EnableGlobalISelOption == true) || + (TM.Options.EnableGlobalISel && + (!Opt.EnableGlobalISelOption || + *Opt.EnableGlobalISelOption == false))) + Selector = SelectorType::GlobalISel; + else if (TM.getOptLevel() == CodeGenOpt::None && TM.getO0WantsFastISel()) + Selector = SelectorType::FastISel; + else + Selector = SelectorType::SelectionDAG; + + // Set consistently TM.Options.EnableFastISel and EnableGlobalISel. + if (Selector == SelectorType::FastISel) { + TM.setFastISel(true); + TM.setGlobalISel(false); + } else if (Selector == SelectorType::GlobalISel) { + TM.setFastISel(false); + TM.setGlobalISel(true); + } + + // Add instruction selector passes. + if (Selector == SelectorType::GlobalISel) { + if (auto Err = derived().addIRTranslator(addPass)) + return std::move(Err); + + derived().addPreLegalizeMachineIR(addPass); + + if (auto Err = derived().addLegalizeMachineIR(addPass)) + return std::move(Err); + + // Before running the register bank selector, ask the target if it + // wants to run some passes. + derived().addPreRegBankSelect(addPass); + + if (auto Err = derived().addRegBankSelect(addPass)) + return std::move(Err); + + derived().addPreGlobalInstructionSelect(addPass); + + if (auto Err = derived().addGlobalInstructionSelect(addPass)) + return std::move(Err); + + // Pass to reset the MachineFunction if the ISel failed. + addPass(ResetMachineFunctionPass(reportDiagnosticWhenGlobalISelFallback(), + isGlobalISelAbortEnabled())); + + // Provide a fallback path when we do not want to abort on + // not-yet-supported input. + if (!isGlobalISelAbortEnabled()) + if (auto Err = derived().addInstSelector(addPass)) + return std::move(Err); + + } else if (auto Err = derived().addInstSelector(addPass)) + return std::move(Err); + + // Expand pseudo-instructions emitted by ISel. Don't run the verifier before + // FinalizeISel. + addPass(FinalizeISelPass()); + + // // Print the instruction selected machine code... + // printAndVerify("After Instruction Selection"); + + return Error::success(); +} + +/// Add the complete set of target-independent postISel code generator passes. +/// +/// This can be read as the standard order of major LLVM CodeGen stages. Stages +/// with nontrivial configuration or multiple passes are broken out below in +/// add%Stage routines. +/// +/// Any CodeGenPassBuilder<Derived>::addXX routine may be overriden by the +/// Target. The addPre/Post methods with empty header implementations allow +/// injecting target-specific fixups just before or after major stages. +/// Additionally, targets have the flexibility to change pass order within a +/// stage by overriding default implementation of add%Stage routines below. Each +/// technique has maintainability tradeoffs because alternate pass orders are +/// not well supported. addPre/Post works better if the target pass is easily +/// tied to a common pass. But if it has subtle dependencies on multiple passes, +/// the target should override the stage instead. +template <typename Derived> +Error CodeGenPassBuilder<Derived>::addMachinePasses( + AddMachinePass &addPass) const { + // Add passes that optimize machine instructions in SSA form. + if (getOptLevel() != CodeGenOpt::None) { + derived().addMachineSSAOptimization(addPass); + } else { + // If the target requests it, assign local variables to stack slots relative + // to one another and simplify frame index references where possible. + addPass(LocalStackSlotPass()); + } + + if (TM.Options.EnableIPRA) + addPass(RegUsageInfoPropagationPass()); + + // Run pre-ra passes. + derived().addPreRegAlloc(addPass); + + // Run register allocation and passes that are tightly coupled with it, + // including phi elimination and scheduling. + if (*Opt.OptimizeRegAlloc) { + derived().addOptimizedRegAlloc(addPass); + } else { + if (auto Err = derived().addFastRegAlloc(addPass)) + return Err; + } + + // Run post-ra passes. + derived().addPostRegAlloc(addPass); + + // Insert prolog/epilog code. Eliminate abstract frame index references... + if (getOptLevel() != CodeGenOpt::None) { + addPass(PostRAMachineSinkingPass()); + addPass(ShrinkWrapPass()); + } + + addPass(PrologEpilogInserterPass()); + + /// Add passes that optimize machine instructions after register allocation. + if (getOptLevel() != CodeGenOpt::None) + derived().addMachineLateOptimization(addPass); + + // Expand pseudo instructions before second scheduling pass. + addPass(ExpandPostRAPseudosPass()); + + // Run pre-sched2 passes. + derived().addPreSched2(addPass); + + if (Opt.EnableImplicitNullChecks) + addPass(ImplicitNullChecksPass()); + + // Second pass scheduler. + // Let Target optionally insert this pass by itself at some other + // point. + if (getOptLevel() != CodeGenOpt::None && + !TM.targetSchedulesPostRAScheduling()) { + if (Opt.MISchedPostRA) + addPass(PostMachineSchedulerPass()); + else + addPass(PostRASchedulerPass()); + } + + // GC + derived().addGCPasses(addPass); + + // Basic block placement. + if (getOptLevel() != CodeGenOpt::None) + derived().addBlockPlacement(addPass); + + // Insert before XRay Instrumentation. + addPass(FEntryInserterPass()); + + addPass(XRayInstrumentationPass()); + addPass(PatchableFunctionPass()); + + derived().addPreEmitPass(addPass); + + if (TM.Options.EnableIPRA) + // Collect register usage information and produce a register mask of + // clobbered registers, to be used to optimize call sites. + addPass(RegUsageInfoCollectorPass()); + + addPass(FuncletLayoutPass()); + + addPass(StackMapLivenessPass()); + addPass(LiveDebugValuesPass()); + + if (TM.Options.EnableMachineOutliner && getOptLevel() != CodeGenOpt::None && + Opt.EnableMachineOutliner != RunOutliner::NeverOutline) { + bool RunOnAllFunctions = + (Opt.EnableMachineOutliner == RunOutliner::AlwaysOutline); + bool AddOutliner = RunOnAllFunctions || TM.Options.SupportsDefaultOutlining; + if (AddOutliner) + addPass(MachineOutlinerPass(RunOnAllFunctions)); + } + + // Add passes that directly emit MI after all other MI passes. + derived().addPreEmitPass2(addPass); + + return Error::success(); +} + +/// Add passes that optimize machine instructions in SSA form. +template <typename Derived> +void CodeGenPassBuilder<Derived>::addMachineSSAOptimization( + AddMachinePass &addPass) const { + // Pre-ra tail duplication. + addPass(EarlyTailDuplicatePass()); + + // Optimize PHIs before DCE: removing dead PHI cycles may make more + // instructions dead. + addPass(OptimizePHIsPass()); + + // This pass merges large allocas. StackSlotColoring is a different pass + // which merges spill slots. + addPass(StackColoringPass()); + + // If the target requests it, assign local variables to stack slots relative + // to one another and simplify frame index references where possible. + addPass(LocalStackSlotPass()); + + // With optimization, dead code should already be eliminated. However + // there is one known exception: lowered code for arguments that are only + // used by tail calls, where the tail calls reuse the incoming stack + // arguments directly (see t11 in test/CodeGen/X86/sibcall.ll). + addPass(DeadMachineInstructionElimPass()); + + // Allow targets to insert passes that improve instruction level parallelism, + // like if-conversion. Such passes will typically need dominator trees and + // loop info, just like LICM and CSE below. + derived().addILPOpts(addPass); + + addPass(EarlyMachineLICMPass()); + addPass(MachineCSEPass()); + + addPass(MachineSinkingPass()); + + addPass(PeepholeOptimizerPass()); + // Clean-up the dead code that may have been generated by peephole + // rewriting. + addPass(DeadMachineInstructionElimPass()); +} + +//===---------------------------------------------------------------------===// +/// Register Allocation Pass Configuration +//===---------------------------------------------------------------------===// + +/// Instantiate the default register allocator pass for this target for either +/// the optimized or unoptimized allocation path. This will be added to the pass +/// manager by addFastRegAlloc in the unoptimized case or addOptimizedRegAlloc +/// in the optimized case. +/// +/// A target that uses the standard regalloc pass order for fast or optimized +/// allocation may still override this for per-target regalloc +/// selection. But -regalloc=... always takes precedence. +template <typename Derived> +void CodeGenPassBuilder<Derived>::addTargetRegisterAllocator( + AddMachinePass &addPass, bool Optimized) const { + if (Optimized) + addPass(RAGreedyPass()); + else + addPass(RAFastPass()); +} + +/// Find and instantiate the register allocation pass requested by this target +/// at the current optimization level. Different register allocators are +/// defined as separate passes because they may require different analysis. +template <typename Derived> +void CodeGenPassBuilder<Derived>::addRegAllocPass(AddMachinePass &addPass, + bool Optimized) const { + if (Opt.RegAlloc == RegAllocType::Default) + // With no -regalloc= override, ask the target for a regalloc pass. + derived().addTargetRegisterAllocator(addPass, Optimized); + else if (Opt.RegAlloc == RegAllocType::Basic) + addPass(RABasicPass()); + else if (Opt.RegAlloc == RegAllocType::Fast) + addPass(RAFastPass()); + else if (Opt.RegAlloc == RegAllocType::Greedy) + addPass(RAGreedyPass()); + else if (Opt.RegAlloc == RegAllocType::PBQP) + addPass(RAPBQPPass()); + else + llvm_unreachable("unknonwn register allocator type"); +} + +template <typename Derived> +Error CodeGenPassBuilder<Derived>::addRegAssignmentFast( + AddMachinePass &addPass) const { + if (Opt.RegAlloc != RegAllocType::Default && + Opt.RegAlloc != RegAllocType::Fast) + return make_error<StringError>( + "Must use fast (default) register allocator for unoptimized regalloc.", + inconvertibleErrorCode()); + + addRegAllocPass(addPass, false); + return Error::success(); +} + +template <typename Derived> +Error CodeGenPassBuilder<Derived>::addRegAssignmentOptimized( + AddMachinePass &addPass) const { + // Add the selected register allocation pass. + addRegAllocPass(addPass, true); + + // Allow targets to change the register assignments before rewriting. + derived().addPreRewrite(addPass); + + // Finally rewrite virtual registers. + addPass(VirtRegRewriterPass()); + // Perform stack slot coloring and post-ra machine LICM. + // + // FIXME: Re-enable coloring with register when it's capable of adding + // kill markers. + addPass(StackSlotColoringPass()); + + return Error::success(); +} + +/// Add the minimum set of target-independent passes that are required for +/// register allocation. No coalescing or scheduling. +template <typename Derived> +Error CodeGenPassBuilder<Derived>::addFastRegAlloc( + AddMachinePass &addPass) const { + addPass(PHIEliminationPass()); + addPass(TwoAddressInstructionPass()); + return derived().addRegAssignmentFast(addPass); +} + +/// Add standard target-independent passes that are tightly coupled with +/// optimized register allocation, including coalescing, machine instruction +/// scheduling, and register allocation itself. +template <typename Derived> +void CodeGenPassBuilder<Derived>::addOptimizedRegAlloc( + AddMachinePass &addPass) const { + addPass(DetectDeadLanesPass()); + + addPass(ProcessImplicitDefsPass()); + + // Edge splitting is smarter with machine loop info. + addPass(PHIEliminationPass()); + + // Eventually, we want to run LiveIntervals before PHI elimination. + if (Opt.EarlyLiveIntervals) + addPass(LiveIntervalsPass()); + + addPass(TwoAddressInstructionPass()); + addPass(RegisterCoalescerPass()); + + // The machine scheduler may accidentally create disconnected components + // when moving subregister definitions around, avoid this by splitting them to + // separate vregs before. Splitting can also improve reg. allocation quality. + addPass(RenameIndependentSubregsPass()); + + // PreRA instruction scheduling. + addPass(MachineSchedulerPass()); + + if (derived().addRegAssignmentOptimized(addPass)) { + // Allow targets to expand pseudo instructions depending on the choice of + // registers before MachineCopyPropagation. + derived().addPostRewrite(addPass); + + // Copy propagate to forward register uses and try to eliminate COPYs that + // were not coalesced. + addPass(MachineCopyPropagationPass()); + + // Run post-ra machine LICM to hoist reloads / remats. + // + // FIXME: can this move into MachineLateOptimization? + addPass(MachineLICMPass()); + } +} + +//===---------------------------------------------------------------------===// +/// Post RegAlloc Pass Configuration +//===---------------------------------------------------------------------===// + +/// Add passes that optimize machine instructions after register allocation. +template <typename Derived> +void CodeGenPassBuilder<Derived>::addMachineLateOptimization( + AddMachinePass &addPass) const { + // Branch folding must be run after regalloc and prolog/epilog insertion. + addPass(BranchFolderPass()); + + // Tail duplication. + // Note that duplicating tail just increases code size and degrades + // performance for targets that require Structured Control Flow. + // In addition it can also make CFG irreducible. Thus we disable it. + if (!TM.requiresStructuredCFG()) + addPass(TailDuplicatePass()); + + // Copy propagation. + addPass(MachineCopyPropagationPass()); +} + +/// Add standard basic block placement passes. +template <typename Derived> +void CodeGenPassBuilder<Derived>::addBlockPlacement( + AddMachinePass &addPass) const { + addPass(MachineBlockPlacementPass()); + // Run a separate pass to collect block placement statistics. + if (Opt.EnableBlockPlacementStats) + addPass(MachineBlockPlacementStatsPass()); +} + +} // namespace llvm + +#endif // LLVM_CODEGEN_CODEGENPASSBUILDER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif |