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 0000000000000..efe0bec35d72a --- /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; +}  | 
