diff options
Diffstat (limited to 'llvm/tools/opt/NewPMDriver.cpp')
-rw-r--r-- | llvm/tools/opt/NewPMDriver.cpp | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp new file mode 100644 index 000000000000..efe0bec35d72 --- /dev/null +++ b/llvm/tools/opt/NewPMDriver.cpp @@ -0,0 +1,372 @@ +//===- NewPMDriver.cpp - Driver for opt with new PM -----------------------===// +// +// 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 +/// +/// This file is just a split of the code that logically belongs in opt.cpp but +/// that includes the new pass manager headers. +/// +//===----------------------------------------------------------------------===// + +#include "NewPMDriver.h" +#include "Debugify.h" +#include "PassPrinters.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/CGSCCPassManager.h" +#include "llvm/Bitcode/BitcodeWriterPass.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/PassPlugin.h" +#include "llvm/Passes/StandardInstrumentations.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" +#include "llvm/Transforms/Scalar/LoopPassManager.h" + +using namespace llvm; +using namespace opt_tool; + +static cl::opt<bool> + DebugPM("debug-pass-manager", cl::Hidden, + cl::desc("Print pass management debugging information")); + +static cl::list<std::string> + PassPlugins("load-pass-plugin", + cl::desc("Load passes from plugin library")); + +// This flag specifies a textual description of the alias analysis pipeline to +// use when querying for aliasing information. It only works in concert with +// the "passes" flag above. +static cl::opt<std::string> + AAPipeline("aa-pipeline", + cl::desc("A textual description of the alias analysis " + "pipeline for handling managed aliasing queries"), + cl::Hidden); + +/// {{@ These options accept textual pipeline descriptions which will be +/// inserted into default pipelines at the respective extension points +static cl::opt<std::string> PeepholeEPPipeline( + "passes-ep-peephole", + cl::desc("A textual description of the function pass pipeline inserted at " + "the Peephole extension points into default pipelines"), + cl::Hidden); +static cl::opt<std::string> LateLoopOptimizationsEPPipeline( + "passes-ep-late-loop-optimizations", + cl::desc( + "A textual description of the loop pass pipeline inserted at " + "the LateLoopOptimizations extension point into default pipelines"), + cl::Hidden); +static cl::opt<std::string> LoopOptimizerEndEPPipeline( + "passes-ep-loop-optimizer-end", + cl::desc("A textual description of the loop pass pipeline inserted at " + "the LoopOptimizerEnd extension point into default pipelines"), + cl::Hidden); +static cl::opt<std::string> ScalarOptimizerLateEPPipeline( + "passes-ep-scalar-optimizer-late", + cl::desc("A textual description of the function pass pipeline inserted at " + "the ScalarOptimizerLate extension point into default pipelines"), + cl::Hidden); +static cl::opt<std::string> CGSCCOptimizerLateEPPipeline( + "passes-ep-cgscc-optimizer-late", + cl::desc("A textual description of the cgscc pass pipeline inserted at " + "the CGSCCOptimizerLate extension point into default pipelines"), + cl::Hidden); +static cl::opt<std::string> VectorizerStartEPPipeline( + "passes-ep-vectorizer-start", + cl::desc("A textual description of the function pass pipeline inserted at " + "the VectorizerStart extension point into default pipelines"), + cl::Hidden); +static cl::opt<std::string> PipelineStartEPPipeline( + "passes-ep-pipeline-start", + cl::desc("A textual description of the function pass pipeline inserted at " + "the PipelineStart extension point into default pipelines"), + cl::Hidden); +static cl::opt<std::string> OptimizerLastEPPipeline( + "passes-ep-optimizer-last", + cl::desc("A textual description of the function pass pipeline inserted at " + "the OptimizerLast extension point into default pipelines"), + cl::Hidden); + +extern cl::opt<PGOKind> PGOKindFlag; +extern cl::opt<std::string> ProfileFile; +extern cl::opt<CSPGOKind> CSPGOKindFlag; +extern cl::opt<std::string> CSProfileGenFile; + +static cl::opt<std::string> + ProfileRemappingFile("profile-remapping-file", + cl::desc("Path to the profile remapping file."), + cl::Hidden); +static cl::opt<bool> DebugInfoForProfiling( + "new-pm-debug-info-for-profiling", cl::init(false), cl::Hidden, + cl::desc("Emit special debug info to enable PGO profile generation.")); +/// @}} + +template <typename PassManagerT> +bool tryParsePipelineText(PassBuilder &PB, + const cl::opt<std::string> &PipelineOpt) { + if (PipelineOpt.empty()) + return false; + + // Verify the pipeline is parseable: + PassManagerT PM; + if (auto Err = PB.parsePassPipeline(PM, PipelineOpt)) { + errs() << "Could not parse -" << PipelineOpt.ArgStr + << " pipeline: " << toString(std::move(Err)) + << "... I'm going to ignore it.\n"; + return false; + } + return true; +} + +/// If one of the EPPipeline command line options was given, register callbacks +/// for parsing and inserting the given pipeline +static void registerEPCallbacks(PassBuilder &PB, bool VerifyEachPass, + bool DebugLogging) { + if (tryParsePipelineText<FunctionPassManager>(PB, PeepholeEPPipeline)) + PB.registerPeepholeEPCallback( + [&PB, VerifyEachPass, DebugLogging]( + FunctionPassManager &PM, PassBuilder::OptimizationLevel Level) { + ExitOnError Err("Unable to parse PeepholeEP pipeline: "); + Err(PB.parsePassPipeline(PM, PeepholeEPPipeline, VerifyEachPass, + DebugLogging)); + }); + if (tryParsePipelineText<LoopPassManager>(PB, + LateLoopOptimizationsEPPipeline)) + PB.registerLateLoopOptimizationsEPCallback( + [&PB, VerifyEachPass, DebugLogging]( + LoopPassManager &PM, PassBuilder::OptimizationLevel Level) { + ExitOnError Err("Unable to parse LateLoopOptimizationsEP pipeline: "); + Err(PB.parsePassPipeline(PM, LateLoopOptimizationsEPPipeline, + VerifyEachPass, DebugLogging)); + }); + if (tryParsePipelineText<LoopPassManager>(PB, LoopOptimizerEndEPPipeline)) + PB.registerLoopOptimizerEndEPCallback( + [&PB, VerifyEachPass, DebugLogging]( + LoopPassManager &PM, PassBuilder::OptimizationLevel Level) { + ExitOnError Err("Unable to parse LoopOptimizerEndEP pipeline: "); + Err(PB.parsePassPipeline(PM, LoopOptimizerEndEPPipeline, + VerifyEachPass, DebugLogging)); + }); + if (tryParsePipelineText<FunctionPassManager>(PB, + ScalarOptimizerLateEPPipeline)) + PB.registerScalarOptimizerLateEPCallback( + [&PB, VerifyEachPass, DebugLogging]( + FunctionPassManager &PM, PassBuilder::OptimizationLevel Level) { + ExitOnError Err("Unable to parse ScalarOptimizerLateEP pipeline: "); + Err(PB.parsePassPipeline(PM, ScalarOptimizerLateEPPipeline, + VerifyEachPass, DebugLogging)); + }); + if (tryParsePipelineText<CGSCCPassManager>(PB, CGSCCOptimizerLateEPPipeline)) + PB.registerCGSCCOptimizerLateEPCallback( + [&PB, VerifyEachPass, DebugLogging]( + CGSCCPassManager &PM, PassBuilder::OptimizationLevel Level) { + ExitOnError Err("Unable to parse CGSCCOptimizerLateEP pipeline: "); + Err(PB.parsePassPipeline(PM, CGSCCOptimizerLateEPPipeline, + VerifyEachPass, DebugLogging)); + }); + if (tryParsePipelineText<FunctionPassManager>(PB, VectorizerStartEPPipeline)) + PB.registerVectorizerStartEPCallback( + [&PB, VerifyEachPass, DebugLogging]( + FunctionPassManager &PM, PassBuilder::OptimizationLevel Level) { + ExitOnError Err("Unable to parse VectorizerStartEP pipeline: "); + Err(PB.parsePassPipeline(PM, VectorizerStartEPPipeline, + VerifyEachPass, DebugLogging)); + }); + if (tryParsePipelineText<ModulePassManager>(PB, PipelineStartEPPipeline)) + PB.registerPipelineStartEPCallback( + [&PB, VerifyEachPass, DebugLogging](ModulePassManager &PM) { + ExitOnError Err("Unable to parse PipelineStartEP pipeline: "); + Err(PB.parsePassPipeline(PM, PipelineStartEPPipeline, VerifyEachPass, + DebugLogging)); + }); + if (tryParsePipelineText<FunctionPassManager>(PB, OptimizerLastEPPipeline)) + PB.registerOptimizerLastEPCallback( + [&PB, VerifyEachPass, DebugLogging](FunctionPassManager &PM, + PassBuilder::OptimizationLevel) { + ExitOnError Err("Unable to parse OptimizerLastEP pipeline: "); + Err(PB.parsePassPipeline(PM, OptimizerLastEPPipeline, VerifyEachPass, + DebugLogging)); + }); +} + +#ifdef LINK_POLLY_INTO_TOOLS +namespace polly { +void RegisterPollyPasses(PassBuilder &); +} +#endif + +bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM, + ToolOutputFile *Out, ToolOutputFile *ThinLTOLinkOut, + ToolOutputFile *OptRemarkFile, + StringRef PassPipeline, OutputKind OK, + VerifierKind VK, + bool ShouldPreserveAssemblyUseListOrder, + bool ShouldPreserveBitcodeUseListOrder, + bool EmitSummaryIndex, bool EmitModuleHash, + bool EnableDebugify) { + bool VerifyEachPass = VK == VK_VerifyEachPass; + + Optional<PGOOptions> P; + switch (PGOKindFlag) { + case InstrGen: + P = PGOOptions(ProfileFile, "", "", PGOOptions::IRInstr); + break; + case InstrUse: + P = PGOOptions(ProfileFile, "", ProfileRemappingFile, PGOOptions::IRUse); + break; + case SampleUse: + P = PGOOptions(ProfileFile, "", ProfileRemappingFile, + PGOOptions::SampleUse); + break; + case NoPGO: + if (DebugInfoForProfiling) + P = PGOOptions("", "", "", PGOOptions::NoAction, PGOOptions::NoCSAction, + true); + else + P = None; + } + if (CSPGOKindFlag != NoCSPGO) { + if (P && (P->Action == PGOOptions::IRInstr || + P->Action == PGOOptions::SampleUse)) + errs() << "CSPGOKind cannot be used with IRInstr or SampleUse"; + if (CSPGOKindFlag == CSInstrGen) { + if (CSProfileGenFile.empty()) + errs() << "CSInstrGen needs to specify CSProfileGenFile"; + if (P) { + P->CSAction = PGOOptions::CSIRInstr; + P->CSProfileGenFile = CSProfileGenFile; + } else + P = PGOOptions("", CSProfileGenFile, ProfileRemappingFile, + PGOOptions::NoAction, PGOOptions::CSIRInstr); + } else /* CSPGOKindFlag == CSInstrUse */ { + if (!P) + errs() << "CSInstrUse needs to be together with InstrUse"; + P->CSAction = PGOOptions::CSIRUse; + } + } + PassInstrumentationCallbacks PIC; + StandardInstrumentations SI; + SI.registerCallbacks(PIC); + + PassBuilder PB(TM, PipelineTuningOptions(), P, &PIC); + registerEPCallbacks(PB, VerifyEachPass, DebugPM); + + // Load requested pass plugins and let them register pass builder callbacks + for (auto &PluginFN : PassPlugins) { + auto PassPlugin = PassPlugin::Load(PluginFN); + if (!PassPlugin) { + errs() << "Failed to load passes from '" << PluginFN + << "'. Request ignored.\n"; + continue; + } + + PassPlugin->registerPassBuilderCallbacks(PB); + } + + // Register a callback that creates the debugify passes as needed. + PB.registerPipelineParsingCallback( + [](StringRef Name, ModulePassManager &MPM, + ArrayRef<PassBuilder::PipelineElement>) { + if (Name == "debugify") { + MPM.addPass(NewPMDebugifyPass()); + return true; + } else if (Name == "check-debugify") { + MPM.addPass(NewPMCheckDebugifyPass()); + return true; + } + return false; + }); + +#ifdef LINK_POLLY_INTO_TOOLS + polly::RegisterPollyPasses(PB); +#endif + + // Specially handle the alias analysis manager so that we can register + // a custom pipeline of AA passes with it. + AAManager AA; + if (auto Err = PB.parseAAPipeline(AA, AAPipeline)) { + errs() << Arg0 << ": " << toString(std::move(Err)) << "\n"; + return false; + } + + LoopAnalysisManager LAM(DebugPM); + FunctionAnalysisManager FAM(DebugPM); + CGSCCAnalysisManager CGAM(DebugPM); + ModuleAnalysisManager MAM(DebugPM); + + // Register the AA manager first so that our version is the one used. + FAM.registerPass([&] { return std::move(AA); }); + + // Register all the basic analyses with the managers. + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + ModulePassManager MPM(DebugPM); + if (VK > VK_NoVerifier) + MPM.addPass(VerifierPass()); + if (EnableDebugify) + MPM.addPass(NewPMDebugifyPass()); + + if (auto Err = + PB.parsePassPipeline(MPM, PassPipeline, VerifyEachPass, DebugPM)) { + errs() << Arg0 << ": " << toString(std::move(Err)) << "\n"; + return false; + } + + if (VK > VK_NoVerifier) + MPM.addPass(VerifierPass()); + if (EnableDebugify) + MPM.addPass(NewPMCheckDebugifyPass()); + + // Add any relevant output pass at the end of the pipeline. + switch (OK) { + case OK_NoOutput: + break; // No output pass needed. + case OK_OutputAssembly: + MPM.addPass( + PrintModulePass(Out->os(), "", ShouldPreserveAssemblyUseListOrder)); + break; + case OK_OutputBitcode: + MPM.addPass(BitcodeWriterPass(Out->os(), ShouldPreserveBitcodeUseListOrder, + EmitSummaryIndex, EmitModuleHash)); + break; + case OK_OutputThinLTOBitcode: + MPM.addPass(ThinLTOBitcodeWriterPass( + Out->os(), ThinLTOLinkOut ? &ThinLTOLinkOut->os() : nullptr)); + break; + } + + // Before executing passes, print the final values of the LLVM options. + cl::PrintOptionValues(); + + // Now that we have all of the passes ready, run them. + MPM.run(M, MAM); + + // Declare success. + if (OK != OK_NoOutput) { + Out->keep(); + if (OK == OK_OutputThinLTOBitcode && ThinLTOLinkOut) + ThinLTOLinkOut->keep(); + } + + if (OptRemarkFile) + OptRemarkFile->keep(); + + return true; +} |