[llvm] [WIP][llc] Add a reusable LLVMLlcDriver library (PR #221896)

Anutosh Bhat via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 22:57:17 PDT 2026


https://github.com/anutosh491 updated https://github.com/llvm/llvm-project/pull/221896

>From bfb3a1afaff556eae9de0da8e551ac890837cc0b Mon Sep 17 00:00:00 2001
From: anutosh491 <andersonbhat491 at gmail.com>
Date: Sat, 5 Sep 2026 10:43:18 +0530
Subject: [PATCH] [llc] Add a reusable LLVMLlcDriver library

---
 llvm/tools/llc/CMakeLists.txt                 |  15 +-
 llvm/tools/llc/llc.cpp                        | 907 +----------------
 llvm/tools/llc/llcdriver.cpp                  | 912 ++++++++++++++++++
 .../llvm-project-overlay/llvm/BUILD.bazel     |  23 +-
 4 files changed, 948 insertions(+), 909 deletions(-)
 create mode 100644 llvm/tools/llc/llcdriver.cpp

diff --git a/llvm/tools/llc/CMakeLists.txt b/llvm/tools/llc/CMakeLists.txt
index 5038a69bf4206..e6f3cf0e1e2fa 100644
--- a/llvm/tools/llc/CMakeLists.txt
+++ b/llvm/tools/llc/CMakeLists.txt
@@ -25,13 +25,26 @@ set(LLVM_LINK_COMPONENTS
   Vectorize
   )
 
+# Keep the command-line implementation in a separate library so other LLVM
+# tools can reuse the llc driver without compiling or rewriting llc.cpp.
+add_llvm_library(LLVMLlcDriver
+  STATIC
+  llcdriver.cpp
+  NewPMDriver.cpp
+
+  PARTIAL_SOURCES_INTENDED
+  DEPENDS
+  intrinsics_gen
+  )
+
 add_llvm_tool(llc
+  PARTIAL_SOURCES_INTENDED
   llc.cpp
-  NewPMDriver.cpp
 
   DEPENDS
   intrinsics_gen
   SUPPORT_PLUGINS
   )
+target_link_libraries(llc PRIVATE LLVMLlcDriver)
 
 export_executable_symbols_for_plugins(llc)
diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp
index 28cf80ee096e9..3b4a6ca4ab775 100644
--- a/llvm/tools/llc/llc.cpp
+++ b/llvm/tools/llc/llc.cpp
@@ -1,915 +1,16 @@
-//===-- llc.cpp - Implement the LLVM Native Code Generator ----------------===//
+//===-- llc.cpp - LLVM Native Code Generator entry point -----------------===//
 //
 // 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 is the llc code generator driver. It provides a convenient
-// command-line interface for generating an assembly file or a relocatable file,
-// given LLVM bitcode.
-//
-//===----------------------------------------------------------------------===//
 
-#include "NewPMDriver.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/ScopeExit.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/Analysis/RuntimeLibcallInfo.h"
-#include "llvm/Analysis/TargetLibraryInfo.h"
-#include "llvm/CodeGen/CommandFlags.h"
-#include "llvm/CodeGen/LinkAllAsmWriterComponents.h"
-#include "llvm/CodeGen/LinkAllCodegenComponents.h"
-#include "llvm/CodeGen/MIRParser/MIRParser.h"
-#include "llvm/CodeGen/MachineFunctionPass.h"
-#include "llvm/CodeGen/MachineModuleInfo.h"
-#include "llvm/CodeGen/TargetPassConfig.h"
-#include "llvm/CodeGen/TargetSubtargetInfo.h"
-#include "llvm/IR/AutoUpgrade.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/DiagnosticInfo.h"
-#include "llvm/IR/DiagnosticPrinter.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/LLVMRemarkStreamer.h"
-#include "llvm/IR/LegacyPassManager.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/IRReader/IRReader.h"
-#include "llvm/InitializePasses.h"
-#include "llvm/MC/MCTargetOptionsCommandFlags.h"
-#include "llvm/MC/TargetRegistry.h"
-#include "llvm/Pass.h"
-#include "llvm/Plugins/PassPlugin.h"
-#include "llvm/Remarks/HotnessThresholdParser.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/FormattedStream.h"
 #include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/PGOOptions.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetSelect.h"
-#include "llvm/Support/TimeProfiler.h"
-#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Support/WithColor.h"
-#include "llvm/Target/TargetLoweringObjectFile.h"
-#include "llvm/Target/TargetMachine.h"
-#include "llvm/TargetParser/Host.h"
-#include "llvm/TargetParser/SubtargetFeature.h"
-#include "llvm/TargetParser/Triple.h"
-#include "llvm/Transforms/Utils/Cloning.h"
-#include <cassert>
-#include <memory>
-#include <optional>
-using namespace llvm;
-
-static codegen::RegisterCodeGenFlags CGF;
-static codegen::RegisterMTuneFlag MTF;
-static codegen::RegisterSaveStatsFlag SSF;
-
-// General options for llc.  Other pass-specific options are specified
-// within the corresponding llc passes, and target-specific options
-// and back-end code generation options are specified with the target machine.
-//
-static cl::opt<std::string>
-    InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
-
-static cl::list<std::string>
-    InstPrinterOptions("M", cl::desc("InstPrinter options"));
-
-static cl::opt<std::string>
-    InputLanguage("x", cl::desc("Input language ('ir' or 'mir')"));
-
-static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
-                                           cl::value_desc("filename"));
-
-static cl::opt<std::string>
-    SplitDwarfOutputFile("split-dwarf-output", cl::desc(".dwo output filename"),
-                         cl::value_desc("filename"));
-
-static cl::opt<unsigned>
-    TimeCompilations("time-compilations", cl::Hidden, cl::init(1u),
-                     cl::value_desc("N"),
-                     cl::desc("Repeat compilation N times for timing"));
-
-static cl::opt<bool> TimeTrace("time-trace", cl::desc("Record time trace"));
-
-static cl::opt<unsigned> TimeTraceGranularity(
-    "time-trace-granularity",
-    cl::desc(
-        "Minimum time granularity (in microseconds) traced by time profiler"),
-    cl::init(500), cl::Hidden);
-
-static cl::opt<std::string>
-    TimeTraceFile("time-trace-file",
-                  cl::desc("Specify time trace file destination"),
-                  cl::value_desc("filename"));
-
-static cl::opt<std::string>
-    BinutilsVersion("binutils-version", cl::Hidden,
-                    cl::desc("Produced object files can use all ELF features "
-                             "supported by this binutils version and newer."
-                             "If -no-integrated-as is specified, the generated "
-                             "assembly will consider GNU as support."
-                             "'none' means that all ELF features can be used, "
-                             "regardless of binutils support"));
-
-static cl::opt<bool>
-    PreserveComments("preserve-as-comments", cl::Hidden,
-                     cl::desc("Preserve Comments in outputted assembly"),
-                     cl::init(true));
-
-// Determine optimization level.
-static cl::opt<char>
-    OptLevel("O",
-             cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
-                      "(default = '-O2')"),
-             cl::Prefix, cl::init('2'));
-
-static cl::opt<std::string>
-    TargetTriple("mtriple", cl::desc("Override target triple for module"));
-
-static cl::opt<std::string> SplitDwarfFile(
-    "split-dwarf-file",
-    cl::desc(
-        "Specify the name of the .dwo file to encode in the DWARF output"));
-
-static cl::opt<bool> NoVerify("disable-verify", cl::Hidden,
-                              cl::desc("Do not verify input module"));
-
-static cl::opt<bool> VerifyEach("verify-each",
-                                cl::desc("Verify after each transform"));
-
-static cl::opt<bool>
-    DisableSimplifyLibCalls("disable-simplify-libcalls",
-                            cl::desc("Disable simplify-libcalls"));
-
-static cl::opt<bool> ShowMCEncoding("show-mc-encoding", cl::Hidden,
-                                    cl::desc("Show encoding in .s output"));
-
-static cl::opt<unsigned>
-    OutputAsmVariant("output-asm-variant",
-                     cl::desc("Syntax variant to use for output printing"));
-
-static cl::opt<bool>
-    DwarfDirectory("dwarf-directory", cl::Hidden,
-                   cl::desc("Use .file directives with an explicit directory"),
-                   cl::init(true));
-
-static cl::opt<bool> AsmVerbose("asm-verbose",
-                                cl::desc("Add comments to directives."),
-                                cl::init(true));
-
-static cl::opt<bool>
-    CompileTwice("compile-twice", cl::Hidden,
-                 cl::desc("Run everything twice, re-using the same pass "
-                          "manager and verify the result is the same."),
-                 cl::init(false));
-
-static cl::opt<bool> DiscardValueNames(
-    "discard-value-names",
-    cl::desc("Discard names from Value (other than GlobalValue)."),
-    cl::init(false), cl::Hidden);
-
-static cl::opt<bool>
-    PrintMIR2VecVocab("print-mir2vec-vocab", cl::Hidden,
-                      cl::desc("Print MIR2Vec vocabulary contents"),
-                      cl::init(false));
-
-static cl::opt<bool>
-    PrintMIR2Vec("print-mir2vec", cl::Hidden,
-                 cl::desc("Print MIR2Vec embeddings for functions"),
-                 cl::init(false));
-
-static cl::list<std::string> IncludeDirs("I", cl::desc("include search path"));
-
-static cl::opt<bool> RemarksWithHotness(
-    "pass-remarks-with-hotness",
-    cl::desc("With PGO, include profile count in optimization remarks"),
-    cl::Hidden);
-
-static cl::opt<std::optional<uint64_t>, false, remarks::HotnessThresholdParser>
-    RemarksHotnessThreshold(
-        "pass-remarks-hotness-threshold",
-        cl::desc("Minimum profile count required for "
-                 "an optimization remark to be output. "
-                 "Use 'auto' to apply the threshold from profile summary."),
-        cl::value_desc("N or 'auto'"), cl::init(0), cl::Hidden);
-
-static cl::opt<std::string>
-    RemarksFilename("pass-remarks-output",
-                    cl::desc("Output filename for pass remarks"),
-                    cl::value_desc("filename"));
-
-static cl::opt<std::string>
-    RemarksPasses("pass-remarks-filter",
-                  cl::desc("Only record optimization remarks from passes whose "
-                           "names match the given regular expression"),
-                  cl::value_desc("regex"));
 
-static cl::opt<std::string> RemarksFormat(
-    "pass-remarks-format",
-    cl::desc("The format used for serializing remarks (default: YAML)"),
-    cl::value_desc("format"), cl::init("yaml"));
+extern "C" int llcMain(int argc, char **argv);
 
-static cl::list<std::string> PassPlugins("load-pass-plugin",
-                                         cl::desc("Load plugin library"));
-
-static cl::opt<bool> EnableNewPassManager(
-    "enable-new-pm", cl::desc("Enable the new pass manager"), cl::init(false));
-
-// This flag specifies a textual description of the optimization pass pipeline
-// to run over the module. This flag switches opt to use the new pass manager
-// infrastructure, completely disabling all of the flags specific to the old
-// pass management.
-static cl::opt<std::string> PassPipeline(
-    "passes",
-    cl::desc(
-        "A textual description of the pass pipeline. To have analysis passes "
-        "available before a certain pass, add 'require<foo-analysis>'."));
-static cl::alias PassPipeline2("p", cl::aliasopt(PassPipeline),
-                               cl::desc("Alias for -passes"));
-
-static std::vector<std::string> &getRunPassNames() {
-  static std::vector<std::string> RunPassNames;
-  return RunPassNames;
-}
-
-namespace {
-struct RunPassOption {
-  void operator=(const std::string &Val) const {
-    if (Val.empty())
-      return;
-    SmallVector<StringRef, 8> PassNames;
-    StringRef(Val).split(PassNames, ',', -1, false);
-    for (auto PassName : PassNames)
-      getRunPassNames().push_back(std::string(PassName));
-  }
-};
-} // namespace
-
-static RunPassOption RunPassOpt;
-
-static cl::opt<RunPassOption, true, cl::parser<std::string>> RunPass(
-    "run-pass",
-    cl::desc("Run compiler only for specified passes (comma separated list)"),
-    cl::value_desc("pass-name"), cl::location(RunPassOpt));
-
-// PGO command line options
-enum PGOKind {
-  NoPGO,
-  SampleUse,
-};
-
-static cl::opt<PGOKind>
-    PGOKindFlag("pgo-kind", cl::init(NoPGO), cl::Hidden,
-                cl::desc("The kind of profile guided optimization"),
-                cl::values(clEnumValN(NoPGO, "nopgo", "Do not use PGO."),
-                           clEnumValN(SampleUse, "pgo-sample-use-pipeline",
-                                      "Use sampled profile to guide PGO.")));
-
-// Function to set PGO options on TargetMachine based on command line flags.
-static void setPGOOptions(TargetMachine &TM) {
-  std::optional<PGOOptions> PGOOpt;
-
-  switch (PGOKindFlag) {
-  case SampleUse:
-    // Use default values for other PGOOptions parameters. This parameter
-    // is used to test that PGO data is preserved at -O0.
-    PGOOpt = PGOOptions("", "", "", "", PGOOptions::SampleUse,
-                        PGOOptions::NoCSAction);
-    break;
-  case NoPGO:
-    PGOOpt = std::nullopt;
-    break;
-  }
-
-  if (PGOOpt)
-    TM.setPGOOption(PGOOpt);
-}
-
-static int compileModule(char **argv, SmallVectorImpl<PassPlugin> &,
-                         LLVMContext &Context, std::string &OutputFilename);
-
-[[noreturn]] static void reportError(Twine Msg, StringRef Filename = "") {
-  SmallString<256> Prefix;
-  if (!Filename.empty()) {
-    if (Filename == "-")
-      Filename = "<stdin>";
-    ("'" + Twine(Filename) + "': ").toStringRef(Prefix);
-  }
-  WithColor::error(errs(), "llc") << Prefix << Msg << "\n";
-  exit(1);
-}
-
-[[noreturn]] static void reportError(Error Err, StringRef Filename) {
-  assert(Err);
-  handleAllErrors(createFileError(Filename, std::move(Err)),
-                  [&](const ErrorInfoBase &EI) { reportError(EI.message()); });
-  llvm_unreachable("reportError() should not return");
-}
-
-static std::unique_ptr<ToolOutputFile> GetOutputStream(Triple::OSType OS) {
-  // If we don't yet have an output filename, make one.
-  if (OutputFilename.empty()) {
-    if (InputFilename == "-")
-      OutputFilename = "-";
-    else {
-      // If InputFilename ends in .bc or .ll, remove it.
-      StringRef IFN = InputFilename;
-      if (IFN.ends_with(".bc") || IFN.ends_with(".ll"))
-        OutputFilename = std::string(IFN.drop_back(3));
-      else if (IFN.ends_with(".mir"))
-        OutputFilename = std::string(IFN.drop_back(4));
-      else
-        OutputFilename = std::string(IFN);
-
-      switch (codegen::getFileType()) {
-      case CodeGenFileType::AssemblyFile:
-        OutputFilename += ".s";
-        break;
-      case CodeGenFileType::ObjectFile:
-        if (OS == Triple::Win32)
-          OutputFilename += ".obj";
-        else
-          OutputFilename += ".o";
-        break;
-      case CodeGenFileType::Null:
-        OutputFilename = "-";
-        break;
-      }
-    }
-  }
-
-  // Decide if we need "binary" output.
-  bool Binary = false;
-  switch (codegen::getFileType()) {
-  case CodeGenFileType::AssemblyFile:
-    break;
-  case CodeGenFileType::ObjectFile:
-  case CodeGenFileType::Null:
-    Binary = true;
-    break;
-  }
-
-  // Open the file.
-  std::error_code EC;
-  sys::fs::OpenFlags OpenFlags = sys::fs::OF_None;
-  if (!Binary)
-    OpenFlags |= sys::fs::OF_TextWithCRLF;
-  auto FDOut = std::make_unique<ToolOutputFile>(OutputFilename, EC, OpenFlags);
-  if (EC)
-    reportError(EC.message());
-  return FDOut;
-}
-
-// main - Entry point for the llc compiler.
-//
 int main(int argc, char **argv) {
-  InitLLVM X(argc, argv);
-
-  // Enable debug stream buffering.
-  EnableDebugBuffering = true;
-
-  // Initialize targets first, so that --version shows registered targets.
-  InitializeAllTargets();
-  InitializeAllTargetMCs();
-  InitializeAllAsmPrinters();
-  InitializeAllAsmParsers();
-
-  // Initialize codegen and IR passes used by llc so that the -print-after,
-  // -print-before, and -stop-after options work.
-  PassRegistry *Registry = PassRegistry::getPassRegistry();
-  initializeCore(*Registry);
-  initializeCodeGen(*Registry);
-  initializeLoopStrengthReducePass(*Registry);
-  initializePostInlineEntryExitInstrumenterPass(*Registry);
-  initializeUnreachableBlockElimLegacyPassPass(*Registry);
-  initializeConstantHoistingLegacyPassPass(*Registry);
-  initializeScalarOpts(*Registry);
-  initializeIPO(*Registry);
-  initializeVectorization(*Registry);
-  initializeScalarizeMaskedMemIntrinLegacyPassPass(*Registry);
-  initializeTransformUtils(*Registry);
-
-  // Initialize debugging passes.
-  initializeScavengerTestPass(*Registry);
-
-  SmallVector<PassPlugin, 1> PluginList;
-  PassPlugins.setCallback([&](const std::string &PluginPath) {
-    auto Plugin = PassPlugin::Load(PluginPath);
-    if (!Plugin)
-      reportFatalUsageError(Plugin.takeError());
-    PluginList.emplace_back(Plugin.get());
-  });
-
-  // Register the Target and CPU printer for --version.
-  cl::AddExtraVersionPrinter(sys::printDefaultTargetAndDetectedCPU);
-  // Register the target printer for --version.
-  cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
-
-  cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n");
-
-  if (!PassPipeline.empty() && !getRunPassNames().empty()) {
-    errs() << "The `llc -run-pass=...` syntax for the new pass manager is "
-              "not supported, please use `llc -passes=<pipeline>` (or the `-p` "
-              "alias for a more concise version).\n";
-    return 1;
-  }
-
-  if (TimeTrace)
-    timeTraceProfilerInitialize(TimeTraceGranularity, argv[0]);
-  llvm::scope_exit TimeTraceScopeExit([]() {
-    if (TimeTrace) {
-      if (auto E = timeTraceProfilerWrite(TimeTraceFile, OutputFilename)) {
-        handleAllErrors(std::move(E), [&](const StringError &SE) {
-          errs() << SE.getMessage() << "\n";
-        });
-        return;
-      }
-      timeTraceProfilerCleanup();
-    }
-  });
-
-  LLVMContext Context;
-  Context.setDiscardValueNames(DiscardValueNames);
-
-  // Set a diagnostic handler that doesn't exit on the first error
-  Context.setDiagnosticHandler(std::make_unique<LLCDiagnosticHandler>());
-
-  Expected<LLVMRemarkFileHandle> RemarksFileOrErr =
-      setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses,
-                                   RemarksFormat, RemarksWithHotness,
-                                   RemarksHotnessThreshold);
-  if (Error E = RemarksFileOrErr.takeError())
-    reportError(std::move(E), RemarksFilename);
-  LLVMRemarkFileHandle RemarksFile = std::move(*RemarksFileOrErr);
-
-  codegen::MaybeEnableStatistics();
-  std::string OutputFilename;
-
-  if (InputLanguage != "" && InputLanguage != "ir" && InputLanguage != "mir")
-    reportError("input language must be '', 'IR' or 'MIR'");
-
-  // Compile the module TimeCompilations times to give better compile time
-  // metrics.
-  for (unsigned I = TimeCompilations; I; --I)
-    if (int RetVal = compileModule(argv, PluginList, Context, OutputFilename))
-      return RetVal;
-
-  if (RemarksFile)
-    RemarksFile->keep();
-
-  return codegen::MaybeSaveStatistics(OutputFilename, "llc");
-}
-
-static bool addPass(PassManagerBase &PM, const char *argv0, StringRef PassName,
-                    TargetPassConfig &TPC) {
-  if (PassName == "none")
-    return false;
-
-  const PassRegistry *PR = PassRegistry::getPassRegistry();
-  const PassInfo *PI = PR->getPassInfo(PassName);
-  if (!PI) {
-    WithColor::error(errs(), argv0)
-        << "run-pass " << PassName << " is not registered.\n";
-    return true;
-  }
-
-  Pass *P;
-  if (PI->getNormalCtor())
-    P = PI->getNormalCtor()();
-  else {
-    WithColor::error(errs(), argv0)
-        << "cannot create pass: " << PI->getPassName() << "\n";
-    return true;
-  }
-  std::string Banner = std::string("After ") + std::string(P->getPassName());
-  TPC.addMachinePrePasses();
-  PM.add(P);
-  TPC.addMachinePostPasses(Banner);
-
-  return false;
-}
-
-static int compileModule(char **argv, SmallVectorImpl<PassPlugin> &PluginList,
-                         LLVMContext &Context, std::string &OutputFilename) {
-  // Load the module to be compiled...
-  SMDiagnostic Err;
-  std::unique_ptr<Module> M;
-  std::unique_ptr<MIRParser> MIR;
-  Triple TheTriple;
-  std::string CPUStr = codegen::getCPUStr();
-  std::string TuneCPUStr = codegen::getTuneCPUStr();
-  std::string FeaturesStr = codegen::getFeaturesStr();
-
-  // Set attributes on functions as loaded from MIR from command line arguments.
-  auto setMIRFunctionAttributes = [&CPUStr, &TuneCPUStr,
-                                   &FeaturesStr](Function &F) {
-    codegen::setFunctionAttributes(F, CPUStr, FeaturesStr, TuneCPUStr);
-  };
-
-  CodeGenOptLevel OLvl;
-  if (auto Level = CodeGenOpt::parseLevel(OptLevel)) {
-    OLvl = *Level;
-  } else {
-    WithColor::error(errs(), argv[0]) << "invalid optimization level.\n";
-    return 1;
-  }
-
-  // Parse 'none' or '$major.$minor'. Disallow -binutils-version=0 because we
-  // use that to indicate the MC default.
-  if (!BinutilsVersion.empty() && BinutilsVersion != "none") {
-    StringRef V = BinutilsVersion.getValue();
-    unsigned Num;
-    if (V.consumeInteger(10, Num) || Num == 0 ||
-        !(V.empty() ||
-          (V.consume_front(".") && !V.consumeInteger(10, Num) && V.empty()))) {
-      WithColor::error(errs(), argv[0])
-          << "invalid -binutils-version, accepting 'none' or major.minor\n";
-      return 1;
-    }
-  }
-  TargetOptions Options;
-  auto InitializeOptions = [&](const Triple &TheTriple) {
-    Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple);
-
-    if (Options.XCOFFReadOnlyPointers) {
-      if (!TheTriple.isOSAIX())
-        reportError("-mxcoff-roptr option is only supported on AIX",
-                    InputFilename);
-
-      // Since the storage mapping class is specified per csect,
-      // without using data sections, it is less effective to use read-only
-      // pointers. Using read-only pointers may cause other RO variables in the
-      // same csect to become RW when the linker acts upon `-bforceimprw`;
-      // therefore, we require that separate data sections are used in the
-      // presence of ReadOnlyPointers. We respect the setting of data-sections
-      // since we have not found reasons to do otherwise that overcome the user
-      // surprise of not respecting the setting.
-      if (!Options.DataSections)
-        reportError("-mxcoff-roptr option must be used with -data-sections",
-                    InputFilename);
-    }
-
-    if (TheTriple.isX86() &&
-        codegen::getFuseFPOps() != FPOpFusion::FPOpFusionMode::Standard)
-      WithColor::warning(errs(), argv[0])
-          << "X86 backend ignores --fp-contract setting; use IR fast-math "
-             "flags instead.";
-
-    Options.MCOptions.BinutilsVersion =
-        MCTargetOptions::parseBinutilsVersion(BinutilsVersion);
-    Options.MCOptions.ShowMCEncoding = ShowMCEncoding;
-    Options.MCOptions.AsmVerbose = AsmVerbose;
-    Options.MCOptions.PreserveAsmComments = PreserveComments;
-    if (OutputAsmVariant.getNumOccurrences())
-      Options.MCOptions.OutputAsmVariant = OutputAsmVariant;
-    Options.MCOptions.IASSearchPaths = IncludeDirs;
-    Options.MCOptions.InstPrinterOptions = InstPrinterOptions;
-    Options.MCOptions.SplitDwarfFile = SplitDwarfFile;
-    if (DwarfDirectory.getPosition()) {
-      Options.MCOptions.MCUseDwarfDirectory =
-          DwarfDirectory ? MCTargetOptions::EnableDwarfDirectory
-                         : MCTargetOptions::DisableDwarfDirectory;
-    } else {
-      // -dwarf-directory is not set explicitly. Some assemblers
-      // (e.g. GNU as or ptxas) do not support `.file directory'
-      // syntax prior to DWARFv5. Let the target decide the default
-      // value.
-      Options.MCOptions.MCUseDwarfDirectory =
-          MCTargetOptions::DefaultDwarfDirectory;
-    }
-  };
-
-  std::optional<Reloc::Model> RM = codegen::getExplicitRelocModel();
-  std::optional<CodeModel::Model> CM = codegen::getExplicitCodeModel();
-
-  const Target *TheTarget = nullptr;
-  std::unique_ptr<TargetMachine> Target;
-
-  // If user just wants to list available options, skip module loading
-  auto MAttrs = codegen::getMAttrs();
-  bool SkipModule =
-      CPUStr == "help" || TuneCPUStr == "help" || is_contained(MAttrs, "help");
-  if (SkipModule) {
-    if (!TargetTriple.empty())
-      TheTriple = Triple(Triple::normalize(TargetTriple));
-    else
-      TheTriple = Triple(sys::getDefaultTargetTriple());
-
-    // Get the target specific parser.
-    std::string Error;
-    TheTarget =
-        TargetRegistry::lookupTarget(codegen::getMArch(), TheTriple, Error);
-    if (!TheTarget) {
-      WithColor::error(errs(), argv[0]) << Error << "\n";
-      return 1;
-    }
-
-    InitializeOptions(TheTriple);
-    // Pass "help" as CPU for -mtune=help
-    std::string SkipModuleCPU = (TuneCPUStr == "help" ? "help" : CPUStr);
-    // Create the target machine just to print the help info. Use unique_ptr
-    // to avoid a memory leak.
-    Target = std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
-        TheTriple, SkipModuleCPU, FeaturesStr, Options, RM, CM, OLvl));
-    if (!Target) {
-      WithColor::error(errs(), argv[0])
-          << "could not allocate target machine\n";
-      return 1;
-    }
-
-    // If we don't have a module then just exit now. We do this down
-    // here since the CPU/Feature help is underneath the target machine
-    // creation.
-    return 0;
-  }
-
-  auto SetDataLayout = [&](StringRef DataLayoutTargetTriple,
-                           StringRef OldDLStr) -> std::optional<std::string> {
-    // If we are supposed to override the target triple, do so now.
-    std::string IRTargetTriple = DataLayoutTargetTriple.str();
-    if (!TargetTriple.empty())
-      IRTargetTriple = Triple::normalize(TargetTriple);
-    TheTriple = Triple(IRTargetTriple);
-    if (TheTriple.getTriple().empty())
-      TheTriple.setTriple(sys::getDefaultTargetTriple());
-
-    std::string Error;
-    TheTarget =
-        TargetRegistry::lookupTarget(codegen::getMArch(), TheTriple, Error);
-    if (!TheTarget) {
-      WithColor::error(errs(), argv[0]) << Error << "\n";
-      exit(1);
-    }
-
-    InitializeOptions(TheTriple);
-    Target = std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
-        TheTriple, CPUStr, FeaturesStr, Options, RM, CM, OLvl));
-    if (!Target) {
-      WithColor::error(errs(), argv[0])
-          << "could not allocate target machine\n";
-      exit(1);
-    }
-
-    // Set PGO options based on command line flags
-    setPGOOptions(*Target);
-
-    return Target->createDataLayout().getStringRepresentation();
-  };
-  if (InputLanguage == "mir" ||
-      (InputLanguage == "" && StringRef(InputFilename).ends_with(".mir"))) {
-    MIR = createMIRParserFromFile(InputFilename, Err, Context,
-                                  setMIRFunctionAttributes);
-    if (MIR)
-      M = MIR->parseIRModule(SetDataLayout);
-  } else {
-    M = parseIRFile(InputFilename, Err, Context,
-                    ParserCallbacks(SetDataLayout));
-  }
-  if (!M) {
-    Err.print(argv[0], WithColor::error(errs(), argv[0]));
-    return 1;
-  }
-
-  M->setTargetTriple(TheTriple);
-
-  std::optional<CodeModel::Model> CM_IR = M->getCodeModel();
-  if (!CM && CM_IR)
-    Target->setCodeModel(*CM_IR);
-  if (std::optional<uint64_t> LDT = codegen::getExplicitLargeDataThreshold())
-    Target->setLargeDataThreshold(*LDT);
-
-  // Figure out where we are going to send the output.
-  std::unique_ptr<ToolOutputFile> Out = GetOutputStream(TheTriple.getOS());
-  if (!Out)
-    return 1;
-
-  // Ensure the filename is passed down to CodeViewDebug.
-  Target->Options.ObjectFilenameForDebug = Out->outputFilename();
-
-  // Return a copy of the output filename via the output param
-  OutputFilename = Out->outputFilename();
-
-  // Tell target that this tool is not necessarily used with argument ABI
-  // compliance (i.e. narrow integer argument extensions).
-  Target->Options.VerifyArgABICompliance = 0;
-
-  std::unique_ptr<ToolOutputFile> DwoOut;
-  if (!SplitDwarfOutputFile.empty()) {
-    std::error_code EC;
-    DwoOut = std::make_unique<ToolOutputFile>(SplitDwarfOutputFile, EC,
-                                              sys::fs::OF_None);
-    if (EC)
-      reportError(EC.message(), SplitDwarfOutputFile);
-  }
-
-  // Add an appropriate TargetLibraryInfo pass for the module's triple.
-  TargetLibraryInfoImpl TLII(M->getTargetTriple(), Target->Options.VecLib);
-
-  // The -disable-simplify-libcalls flag actually disables all builtin optzns.
-  if (DisableSimplifyLibCalls)
-    TLII.disableAllFunctions();
-
-  // Verify module immediately to catch problems before doInitialization() is
-  // called on any passes.
-  if (!NoVerify && verifyModule(*M, &errs()))
-    reportError("input module cannot be verified", InputFilename);
-
-  // Override function attributes based on CPUStr, TuneCPUStr, FeaturesStr, and
-  // command line flags.
-  codegen::setFunctionAttributes(*M, CPUStr, FeaturesStr, TuneCPUStr);
-
-  for (auto &Plugin : PluginList) {
-    CodeGenFileType CGFT = codegen::getFileType();
-    if (Plugin.invokePreCodeGenCallback(*M, *Target, CGFT, Out->os())) {
-      // TODO: Deduplicate code with below and the NewPMDriver.
-      if (Context.getDiagHandlerPtr()->HasErrors)
-        exit(1);
-      Out->keep();
-      return 0;
-    }
-  }
-
-  if (mc::getExplicitRelaxAll() &&
-      codegen::getFileType() != CodeGenFileType::ObjectFile)
-    WithColor::warning(errs(), argv[0])
-        << ": warning: ignoring -mc-relax-all because filetype != obj";
-
-  VerifierKind VK = VerifierKind::InputOutput;
-  if (NoVerify)
-    VK = VerifierKind::None;
-  else if (VerifyEach)
-    VK = VerifierKind::EachPass;
-
-  // Use the NewPM if the user specifies -passes (NewPM specific), specifically
-  // requests the NewPM with -enable-new-pm, or the target defaults to the
-  // NewPM, the user has not explicitly disabled the NewPM with
-  // -enable-new-pm=false, and the user has not specified -run-pass.
-  if (!PassPipeline.empty() ||
-      (EnableNewPassManager.getNumOccurrences() > 0 && EnableNewPassManager) ||
-      (Target->shouldDefaultToNewPM() &&
-       !(EnableNewPassManager.getNumOccurrences() && !EnableNewPassManager) &&
-       getRunPassNames().empty())) {
-    return compileModuleWithNewPM(
-        argv[0], std::move(M), std::move(MIR), std::move(Target),
-        std::move(Out), std::move(DwoOut), Context, TLII, VK, PassPipeline,
-        PluginList, codegen::getFileType());
-  }
-
-  // Build up all of the passes that we want to do to the module.
-  legacy::PassManager PM;
-  PM.add(new TargetLibraryInfoWrapperPass(TLII));
-  PM.add(new RuntimeLibraryInfoWrapper(
-      Target->Options.ExceptionModel, Target->Options.EABIVersion,
-      Options.MCOptions.ABIName, Target->Options.VecLib));
-
-  {
-    raw_pwrite_stream *OS = &Out->os();
-
-    // Manually do the buffering rather than using buffer_ostream,
-    // so we can memcmp the contents in CompileTwice mode
-    SmallVector<char, 0> Buffer;
-    std::unique_ptr<raw_svector_ostream> BOS;
-    if ((codegen::getFileType() != CodeGenFileType::AssemblyFile &&
-         !Out->os().supportsSeeking()) ||
-        CompileTwice) {
-      BOS = std::make_unique<raw_svector_ostream>(Buffer);
-      OS = BOS.get();
-    }
-
-    const char *argv0 = argv[0];
-    MachineModuleInfoWrapperPass *MMIWP =
-        new MachineModuleInfoWrapperPass(Target.get());
-
-    // Set a temporary diagnostic handler. This is used before
-    // MachineModuleInfoWrapperPass::doInitialization for features like -M.
-    bool HasMCErrors = false;
-    MCContext &MCCtx = MMIWP->getMMI().getContext();
-    MCCtx.setDiagnosticHandler([&](const SMDiagnostic &SMD, bool IsInlineAsm,
-                                   const SourceMgr &SrcMgr,
-                                   std::vector<const MDNode *> &LocInfos) {
-      WithColor::error(errs(), argv0) << SMD.getMessage() << '\n';
-      HasMCErrors = true;
-    });
-
-    // Construct a custom pass pipeline that starts after instruction
-    // selection.
-    if (!getRunPassNames().empty()) {
-      if (!MIR) {
-        WithColor::error(errs(), argv[0])
-            << "run-pass is for .mir file only.\n";
-        delete MMIWP;
-        return 1;
-      }
-      TargetPassConfig *PTPC = Target->createPassConfig(PM);
-      TargetPassConfig &TPC = *PTPC;
-      if (TPC.hasLimitedCodeGenPipeline()) {
-        WithColor::error(errs(), argv[0])
-            << "run-pass cannot be used with "
-            << TPC.getLimitedCodeGenPipelineReason() << ".\n";
-        delete PTPC;
-        delete MMIWP;
-        return 1;
-      }
-
-      TPC.setDisableVerify(NoVerify);
-      PM.add(&TPC);
-      PM.add(MMIWP);
-      TPC.printAndVerify("");
-      for (const std::string &RunPassName : getRunPassNames()) {
-        if (addPass(PM, argv0, RunPassName, TPC))
-          return 1;
-      }
-      TPC.setInitialized();
-      PM.add(createPrintMIRPass(*OS));
-
-      // Add MIR2Vec vocabulary printer if requested
-      if (PrintMIR2VecVocab) {
-        PM.add(createMIR2VecVocabPrinterLegacyPass(errs()));
-      }
-
-      // Add MIR2Vec printer if requested
-      if (PrintMIR2Vec) {
-        PM.add(createMIR2VecPrinterLegacyPass(errs()));
-      }
-
-      PM.add(createFreeMachineFunctionPass());
-    } else {
-      if (Target->addPassesToEmitFile(PM, *OS, DwoOut ? &DwoOut->os() : nullptr,
-                                      codegen::getFileType(), NoVerify,
-                                      MMIWP)) {
-        if (!HasMCErrors)
-          reportError("target does not support generation of this file type");
-      }
-
-      // Add MIR2Vec vocabulary printer if requested
-      if (PrintMIR2VecVocab) {
-        PM.add(createMIR2VecVocabPrinterLegacyPass(errs()));
-      }
-
-      // Add MIR2Vec printer if requested
-      if (PrintMIR2Vec) {
-        PM.add(createMIR2VecPrinterLegacyPass(errs()));
-      }
-    }
-
-    Target->getObjFileLowering()->Initialize(MMIWP->getMMI().getContext(),
-                                             *Target);
-    if (MIR) {
-      assert(MMIWP && "Forgot to create MMIWP?");
-      if (MIR->parseMachineFunctions(*M, MMIWP->getMMI()))
-        return 1;
-    }
-
-    // Before executing passes, print the final values of the LLVM options.
-    cl::PrintOptionValues();
-
-    // If requested, run the pass manager over the same module again,
-    // to catch any bugs due to persistent state in the passes. Note that
-    // opt has the same functionality, so it may be worth abstracting this out
-    // in the future.
-    SmallVector<char, 0> CompileTwiceBuffer;
-    if (CompileTwice) {
-      std::unique_ptr<Module> M2(llvm::CloneModule(*M));
-      PM.run(*M2);
-      CompileTwiceBuffer = Buffer;
-      Buffer.clear();
-    }
-
-    PM.run(*M);
-
-    if (Context.getDiagHandlerPtr()->HasErrors || HasMCErrors)
-      return 1;
-
-    // Compare the two outputs and make sure they're the same
-    if (CompileTwice) {
-      if (Buffer.size() != CompileTwiceBuffer.size() ||
-          (memcmp(Buffer.data(), CompileTwiceBuffer.data(), Buffer.size()) !=
-           0)) {
-        errs()
-            << "Running the pass manager twice changed the output.\n"
-               "Writing the result of the second run to the specified output\n"
-               "To generate the one-run comparison binary, just run without\n"
-               "the compile-twice option\n";
-        Out->os() << Buffer;
-        Out->keep();
-        return 1;
-      }
-    }
-
-    if (BOS) {
-      Out->os() << Buffer;
-    }
-  }
-
-  // Declare success.
-  Out->keep();
-  if (DwoOut)
-    DwoOut->keep();
-
-  return 0;
+  llvm::InitLLVM X(argc, argv);
+  return llcMain(argc, argv);
 }
diff --git a/llvm/tools/llc/llcdriver.cpp b/llvm/tools/llc/llcdriver.cpp
new file mode 100644
index 0000000000000..051e977c7549a
--- /dev/null
+++ b/llvm/tools/llc/llcdriver.cpp
@@ -0,0 +1,912 @@
+//===-- llcdriver.cpp - Implement the LLVM Native Code Generator ----------===//
+//
+// 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 is the llc code generator driver. It provides a convenient
+// command-line interface for generating an assembly file or a relocatable file,
+// given LLVM bitcode.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NewPMDriver.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/RuntimeLibcallInfo.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/CodeGen/LinkAllAsmWriterComponents.h"
+#include "llvm/CodeGen/LinkAllCodegenComponents.h"
+#include "llvm/CodeGen/MIRParser/MIRParser.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/IR/AutoUpgrade.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LLVMRemarkStreamer.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/MC/MCTargetOptionsCommandFlags.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Pass.h"
+#include "llvm/Plugins/PassPlugin.h"
+#include "llvm/Remarks/HotnessThresholdParser.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/PGOOptions.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/TimeProfiler.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/TargetParser/Host.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
+#include "llvm/TargetParser/Triple.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+#include <cassert>
+#include <memory>
+#include <optional>
+using namespace llvm;
+
+static codegen::RegisterCodeGenFlags CGF;
+static codegen::RegisterMTuneFlag MTF;
+static codegen::RegisterSaveStatsFlag SSF;
+
+// General options for llc.  Other pass-specific options are specified
+// within the corresponding llc passes, and target-specific options
+// and back-end code generation options are specified with the target machine.
+//
+static cl::opt<std::string>
+    InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
+
+static cl::list<std::string>
+    InstPrinterOptions("M", cl::desc("InstPrinter options"));
+
+static cl::opt<std::string>
+    InputLanguage("x", cl::desc("Input language ('ir' or 'mir')"));
+
+static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
+                                           cl::value_desc("filename"));
+
+static cl::opt<std::string>
+    SplitDwarfOutputFile("split-dwarf-output", cl::desc(".dwo output filename"),
+                         cl::value_desc("filename"));
+
+static cl::opt<unsigned>
+    TimeCompilations("time-compilations", cl::Hidden, cl::init(1u),
+                     cl::value_desc("N"),
+                     cl::desc("Repeat compilation N times for timing"));
+
+static cl::opt<bool> TimeTrace("time-trace", cl::desc("Record time trace"));
+
+static cl::opt<unsigned> TimeTraceGranularity(
+    "time-trace-granularity",
+    cl::desc(
+        "Minimum time granularity (in microseconds) traced by time profiler"),
+    cl::init(500), cl::Hidden);
+
+static cl::opt<std::string>
+    TimeTraceFile("time-trace-file",
+                  cl::desc("Specify time trace file destination"),
+                  cl::value_desc("filename"));
+
+static cl::opt<std::string>
+    BinutilsVersion("binutils-version", cl::Hidden,
+                    cl::desc("Produced object files can use all ELF features "
+                             "supported by this binutils version and newer."
+                             "If -no-integrated-as is specified, the generated "
+                             "assembly will consider GNU as support."
+                             "'none' means that all ELF features can be used, "
+                             "regardless of binutils support"));
+
+static cl::opt<bool>
+    PreserveComments("preserve-as-comments", cl::Hidden,
+                     cl::desc("Preserve Comments in outputted assembly"),
+                     cl::init(true));
+
+// Determine optimization level.
+static cl::opt<char>
+    OptLevel("O",
+             cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
+                      "(default = '-O2')"),
+             cl::Prefix, cl::init('2'));
+
+static cl::opt<std::string>
+    TargetTriple("mtriple", cl::desc("Override target triple for module"));
+
+static cl::opt<std::string> SplitDwarfFile(
+    "split-dwarf-file",
+    cl::desc(
+        "Specify the name of the .dwo file to encode in the DWARF output"));
+
+static cl::opt<bool> NoVerify("disable-verify", cl::Hidden,
+                              cl::desc("Do not verify input module"));
+
+static cl::opt<bool> VerifyEach("verify-each",
+                                cl::desc("Verify after each transform"));
+
+static cl::opt<bool>
+    DisableSimplifyLibCalls("disable-simplify-libcalls",
+                            cl::desc("Disable simplify-libcalls"));
+
+static cl::opt<bool> ShowMCEncoding("show-mc-encoding", cl::Hidden,
+                                    cl::desc("Show encoding in .s output"));
+
+static cl::opt<unsigned>
+    OutputAsmVariant("output-asm-variant",
+                     cl::desc("Syntax variant to use for output printing"));
+
+static cl::opt<bool>
+    DwarfDirectory("dwarf-directory", cl::Hidden,
+                   cl::desc("Use .file directives with an explicit directory"),
+                   cl::init(true));
+
+static cl::opt<bool> AsmVerbose("asm-verbose",
+                                cl::desc("Add comments to directives."),
+                                cl::init(true));
+
+static cl::opt<bool>
+    CompileTwice("compile-twice", cl::Hidden,
+                 cl::desc("Run everything twice, re-using the same pass "
+                          "manager and verify the result is the same."),
+                 cl::init(false));
+
+static cl::opt<bool> DiscardValueNames(
+    "discard-value-names",
+    cl::desc("Discard names from Value (other than GlobalValue)."),
+    cl::init(false), cl::Hidden);
+
+static cl::opt<bool>
+    PrintMIR2VecVocab("print-mir2vec-vocab", cl::Hidden,
+                      cl::desc("Print MIR2Vec vocabulary contents"),
+                      cl::init(false));
+
+static cl::opt<bool>
+    PrintMIR2Vec("print-mir2vec", cl::Hidden,
+                 cl::desc("Print MIR2Vec embeddings for functions"),
+                 cl::init(false));
+
+static cl::list<std::string> IncludeDirs("I", cl::desc("include search path"));
+
+static cl::opt<bool> RemarksWithHotness(
+    "pass-remarks-with-hotness",
+    cl::desc("With PGO, include profile count in optimization remarks"),
+    cl::Hidden);
+
+static cl::opt<std::optional<uint64_t>, false, remarks::HotnessThresholdParser>
+    RemarksHotnessThreshold(
+        "pass-remarks-hotness-threshold",
+        cl::desc("Minimum profile count required for "
+                 "an optimization remark to be output. "
+                 "Use 'auto' to apply the threshold from profile summary."),
+        cl::value_desc("N or 'auto'"), cl::init(0), cl::Hidden);
+
+static cl::opt<std::string>
+    RemarksFilename("pass-remarks-output",
+                    cl::desc("Output filename for pass remarks"),
+                    cl::value_desc("filename"));
+
+static cl::opt<std::string>
+    RemarksPasses("pass-remarks-filter",
+                  cl::desc("Only record optimization remarks from passes whose "
+                           "names match the given regular expression"),
+                  cl::value_desc("regex"));
+
+static cl::opt<std::string> RemarksFormat(
+    "pass-remarks-format",
+    cl::desc("The format used for serializing remarks (default: YAML)"),
+    cl::value_desc("format"), cl::init("yaml"));
+
+static cl::list<std::string> PassPlugins("load-pass-plugin",
+                                         cl::desc("Load plugin library"));
+
+static cl::opt<bool> EnableNewPassManager(
+    "enable-new-pm", cl::desc("Enable the new pass manager"), cl::init(false));
+
+// This flag specifies a textual description of the optimization pass pipeline
+// to run over the module. This flag switches opt to use the new pass manager
+// infrastructure, completely disabling all of the flags specific to the old
+// pass management.
+static cl::opt<std::string> PassPipeline(
+    "passes",
+    cl::desc(
+        "A textual description of the pass pipeline. To have analysis passes "
+        "available before a certain pass, add 'require<foo-analysis>'."));
+static cl::alias PassPipeline2("p", cl::aliasopt(PassPipeline),
+                               cl::desc("Alias for -passes"));
+
+static std::vector<std::string> &getRunPassNames() {
+  static std::vector<std::string> RunPassNames;
+  return RunPassNames;
+}
+
+namespace {
+struct RunPassOption {
+  void operator=(const std::string &Val) const {
+    if (Val.empty())
+      return;
+    SmallVector<StringRef, 8> PassNames;
+    StringRef(Val).split(PassNames, ',', -1, false);
+    for (auto PassName : PassNames)
+      getRunPassNames().push_back(std::string(PassName));
+  }
+};
+} // namespace
+
+static RunPassOption RunPassOpt;
+
+static cl::opt<RunPassOption, true, cl::parser<std::string>> RunPass(
+    "run-pass",
+    cl::desc("Run compiler only for specified passes (comma separated list)"),
+    cl::value_desc("pass-name"), cl::location(RunPassOpt));
+
+// PGO command line options
+enum PGOKind {
+  NoPGO,
+  SampleUse,
+};
+
+static cl::opt<PGOKind>
+    PGOKindFlag("pgo-kind", cl::init(NoPGO), cl::Hidden,
+                cl::desc("The kind of profile guided optimization"),
+                cl::values(clEnumValN(NoPGO, "nopgo", "Do not use PGO."),
+                           clEnumValN(SampleUse, "pgo-sample-use-pipeline",
+                                      "Use sampled profile to guide PGO.")));
+
+// Function to set PGO options on TargetMachine based on command line flags.
+static void setPGOOptions(TargetMachine &TM) {
+  std::optional<PGOOptions> PGOOpt;
+
+  switch (PGOKindFlag) {
+  case SampleUse:
+    // Use default values for other PGOOptions parameters. This parameter
+    // is used to test that PGO data is preserved at -O0.
+    PGOOpt = PGOOptions("", "", "", "", PGOOptions::SampleUse,
+                        PGOOptions::NoCSAction);
+    break;
+  case NoPGO:
+    PGOOpt = std::nullopt;
+    break;
+  }
+
+  if (PGOOpt)
+    TM.setPGOOption(PGOOpt);
+}
+
+static int compileModule(char **argv, SmallVectorImpl<PassPlugin> &,
+                         LLVMContext &Context, std::string &OutputFilename);
+
+[[noreturn]] static void reportError(Twine Msg, StringRef Filename = "") {
+  SmallString<256> Prefix;
+  if (!Filename.empty()) {
+    if (Filename == "-")
+      Filename = "<stdin>";
+    ("'" + Twine(Filename) + "': ").toStringRef(Prefix);
+  }
+  WithColor::error(errs(), "llc") << Prefix << Msg << "\n";
+  exit(1);
+}
+
+[[noreturn]] static void reportError(Error Err, StringRef Filename) {
+  assert(Err);
+  handleAllErrors(createFileError(Filename, std::move(Err)),
+                  [&](const ErrorInfoBase &EI) { reportError(EI.message()); });
+  llvm_unreachable("reportError() should not return");
+}
+
+static std::unique_ptr<ToolOutputFile> GetOutputStream(Triple::OSType OS) {
+  // If we don't yet have an output filename, make one.
+  if (OutputFilename.empty()) {
+    if (InputFilename == "-")
+      OutputFilename = "-";
+    else {
+      // If InputFilename ends in .bc or .ll, remove it.
+      StringRef IFN = InputFilename;
+      if (IFN.ends_with(".bc") || IFN.ends_with(".ll"))
+        OutputFilename = std::string(IFN.drop_back(3));
+      else if (IFN.ends_with(".mir"))
+        OutputFilename = std::string(IFN.drop_back(4));
+      else
+        OutputFilename = std::string(IFN);
+
+      switch (codegen::getFileType()) {
+      case CodeGenFileType::AssemblyFile:
+        OutputFilename += ".s";
+        break;
+      case CodeGenFileType::ObjectFile:
+        if (OS == Triple::Win32)
+          OutputFilename += ".obj";
+        else
+          OutputFilename += ".o";
+        break;
+      case CodeGenFileType::Null:
+        OutputFilename = "-";
+        break;
+      }
+    }
+  }
+
+  // Decide if we need "binary" output.
+  bool Binary = false;
+  switch (codegen::getFileType()) {
+  case CodeGenFileType::AssemblyFile:
+    break;
+  case CodeGenFileType::ObjectFile:
+  case CodeGenFileType::Null:
+    Binary = true;
+    break;
+  }
+
+  // Open the file.
+  std::error_code EC;
+  sys::fs::OpenFlags OpenFlags = sys::fs::OF_None;
+  if (!Binary)
+    OpenFlags |= sys::fs::OF_TextWithCRLF;
+  auto FDOut = std::make_unique<ToolOutputFile>(OutputFilename, EC, OpenFlags);
+  if (EC)
+    reportError(EC.message());
+  return FDOut;
+}
+
+// Entry point for the llc compiler.
+//
+extern "C" int llcMain(int argc, char **argv) {
+  // Enable debug stream buffering.
+  EnableDebugBuffering = true;
+
+  // Initialize targets first, so that --version shows registered targets.
+  InitializeAllTargets();
+  InitializeAllTargetMCs();
+  InitializeAllAsmPrinters();
+  InitializeAllAsmParsers();
+
+  // Initialize codegen and IR passes used by llc so that the -print-after,
+  // -print-before, and -stop-after options work.
+  PassRegistry *Registry = PassRegistry::getPassRegistry();
+  initializeCore(*Registry);
+  initializeCodeGen(*Registry);
+  initializeLoopStrengthReducePass(*Registry);
+  initializePostInlineEntryExitInstrumenterPass(*Registry);
+  initializeUnreachableBlockElimLegacyPassPass(*Registry);
+  initializeConstantHoistingLegacyPassPass(*Registry);
+  initializeScalarOpts(*Registry);
+  initializeIPO(*Registry);
+  initializeVectorization(*Registry);
+  initializeScalarizeMaskedMemIntrinLegacyPassPass(*Registry);
+  initializeTransformUtils(*Registry);
+
+  // Initialize debugging passes.
+  initializeScavengerTestPass(*Registry);
+
+  SmallVector<PassPlugin, 1> PluginList;
+  PassPlugins.setCallback([&](const std::string &PluginPath) {
+    auto Plugin = PassPlugin::Load(PluginPath);
+    if (!Plugin)
+      reportFatalUsageError(Plugin.takeError());
+    PluginList.emplace_back(Plugin.get());
+  });
+
+  // Register the Target and CPU printer for --version.
+  cl::AddExtraVersionPrinter(sys::printDefaultTargetAndDetectedCPU);
+  // Register the target printer for --version.
+  cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
+
+  cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n");
+
+  if (!PassPipeline.empty() && !getRunPassNames().empty()) {
+    errs() << "The `llc -run-pass=...` syntax for the new pass manager is "
+              "not supported, please use `llc -passes=<pipeline>` (or the `-p` "
+              "alias for a more concise version).\n";
+    return 1;
+  }
+
+  if (TimeTrace)
+    timeTraceProfilerInitialize(TimeTraceGranularity, argv[0]);
+  llvm::scope_exit TimeTraceScopeExit([]() {
+    if (TimeTrace) {
+      if (auto E = timeTraceProfilerWrite(TimeTraceFile, OutputFilename)) {
+        handleAllErrors(std::move(E), [&](const StringError &SE) {
+          errs() << SE.getMessage() << "\n";
+        });
+        return;
+      }
+      timeTraceProfilerCleanup();
+    }
+  });
+
+  LLVMContext Context;
+  Context.setDiscardValueNames(DiscardValueNames);
+
+  // Set a diagnostic handler that doesn't exit on the first error
+  Context.setDiagnosticHandler(std::make_unique<LLCDiagnosticHandler>());
+
+  Expected<LLVMRemarkFileHandle> RemarksFileOrErr =
+      setupLLVMOptimizationRemarks(Context, RemarksFilename, RemarksPasses,
+                                   RemarksFormat, RemarksWithHotness,
+                                   RemarksHotnessThreshold);
+  if (Error E = RemarksFileOrErr.takeError())
+    reportError(std::move(E), RemarksFilename);
+  LLVMRemarkFileHandle RemarksFile = std::move(*RemarksFileOrErr);
+
+  codegen::MaybeEnableStatistics();
+  std::string OutputFilename;
+
+  if (InputLanguage != "" && InputLanguage != "ir" && InputLanguage != "mir")
+    reportError("input language must be '', 'IR' or 'MIR'");
+
+  // Compile the module TimeCompilations times to give better compile time
+  // metrics.
+  for (unsigned I = TimeCompilations; I; --I)
+    if (int RetVal = compileModule(argv, PluginList, Context, OutputFilename))
+      return RetVal;
+
+  if (RemarksFile)
+    RemarksFile->keep();
+
+  return codegen::MaybeSaveStatistics(OutputFilename, "llc");
+}
+
+static bool addPass(PassManagerBase &PM, const char *argv0, StringRef PassName,
+                    TargetPassConfig &TPC) {
+  if (PassName == "none")
+    return false;
+
+  const PassRegistry *PR = PassRegistry::getPassRegistry();
+  const PassInfo *PI = PR->getPassInfo(PassName);
+  if (!PI) {
+    WithColor::error(errs(), argv0)
+        << "run-pass " << PassName << " is not registered.\n";
+    return true;
+  }
+
+  Pass *P;
+  if (PI->getNormalCtor())
+    P = PI->getNormalCtor()();
+  else {
+    WithColor::error(errs(), argv0)
+        << "cannot create pass: " << PI->getPassName() << "\n";
+    return true;
+  }
+  std::string Banner = std::string("After ") + std::string(P->getPassName());
+  TPC.addMachinePrePasses();
+  PM.add(P);
+  TPC.addMachinePostPasses(Banner);
+
+  return false;
+}
+
+static int compileModule(char **argv, SmallVectorImpl<PassPlugin> &PluginList,
+                         LLVMContext &Context, std::string &OutputFilename) {
+  // Load the module to be compiled...
+  SMDiagnostic Err;
+  std::unique_ptr<Module> M;
+  std::unique_ptr<MIRParser> MIR;
+  Triple TheTriple;
+  std::string CPUStr = codegen::getCPUStr();
+  std::string TuneCPUStr = codegen::getTuneCPUStr();
+  std::string FeaturesStr = codegen::getFeaturesStr();
+
+  // Set attributes on functions as loaded from MIR from command line arguments.
+  auto setMIRFunctionAttributes = [&CPUStr, &TuneCPUStr,
+                                   &FeaturesStr](Function &F) {
+    codegen::setFunctionAttributes(F, CPUStr, FeaturesStr, TuneCPUStr);
+  };
+
+  CodeGenOptLevel OLvl;
+  if (auto Level = CodeGenOpt::parseLevel(OptLevel)) {
+    OLvl = *Level;
+  } else {
+    WithColor::error(errs(), argv[0]) << "invalid optimization level.\n";
+    return 1;
+  }
+
+  // Parse 'none' or '$major.$minor'. Disallow -binutils-version=0 because we
+  // use that to indicate the MC default.
+  if (!BinutilsVersion.empty() && BinutilsVersion != "none") {
+    StringRef V = BinutilsVersion.getValue();
+    unsigned Num;
+    if (V.consumeInteger(10, Num) || Num == 0 ||
+        !(V.empty() ||
+          (V.consume_front(".") && !V.consumeInteger(10, Num) && V.empty()))) {
+      WithColor::error(errs(), argv[0])
+          << "invalid -binutils-version, accepting 'none' or major.minor\n";
+      return 1;
+    }
+  }
+  TargetOptions Options;
+  auto InitializeOptions = [&](const Triple &TheTriple) {
+    Options = codegen::InitTargetOptionsFromCodeGenFlags(TheTriple);
+
+    if (Options.XCOFFReadOnlyPointers) {
+      if (!TheTriple.isOSAIX())
+        reportError("-mxcoff-roptr option is only supported on AIX",
+                    InputFilename);
+
+      // Since the storage mapping class is specified per csect,
+      // without using data sections, it is less effective to use read-only
+      // pointers. Using read-only pointers may cause other RO variables in the
+      // same csect to become RW when the linker acts upon `-bforceimprw`;
+      // therefore, we require that separate data sections are used in the
+      // presence of ReadOnlyPointers. We respect the setting of data-sections
+      // since we have not found reasons to do otherwise that overcome the user
+      // surprise of not respecting the setting.
+      if (!Options.DataSections)
+        reportError("-mxcoff-roptr option must be used with -data-sections",
+                    InputFilename);
+    }
+
+    if (TheTriple.isX86() &&
+        codegen::getFuseFPOps() != FPOpFusion::FPOpFusionMode::Standard)
+      WithColor::warning(errs(), argv[0])
+          << "X86 backend ignores --fp-contract setting; use IR fast-math "
+             "flags instead.";
+
+    Options.MCOptions.BinutilsVersion =
+        MCTargetOptions::parseBinutilsVersion(BinutilsVersion);
+    Options.MCOptions.ShowMCEncoding = ShowMCEncoding;
+    Options.MCOptions.AsmVerbose = AsmVerbose;
+    Options.MCOptions.PreserveAsmComments = PreserveComments;
+    if (OutputAsmVariant.getNumOccurrences())
+      Options.MCOptions.OutputAsmVariant = OutputAsmVariant;
+    Options.MCOptions.IASSearchPaths = IncludeDirs;
+    Options.MCOptions.InstPrinterOptions = InstPrinterOptions;
+    Options.MCOptions.SplitDwarfFile = SplitDwarfFile;
+    if (DwarfDirectory.getPosition()) {
+      Options.MCOptions.MCUseDwarfDirectory =
+          DwarfDirectory ? MCTargetOptions::EnableDwarfDirectory
+                         : MCTargetOptions::DisableDwarfDirectory;
+    } else {
+      // -dwarf-directory is not set explicitly. Some assemblers
+      // (e.g. GNU as or ptxas) do not support `.file directory'
+      // syntax prior to DWARFv5. Let the target decide the default
+      // value.
+      Options.MCOptions.MCUseDwarfDirectory =
+          MCTargetOptions::DefaultDwarfDirectory;
+    }
+  };
+
+  std::optional<Reloc::Model> RM = codegen::getExplicitRelocModel();
+  std::optional<CodeModel::Model> CM = codegen::getExplicitCodeModel();
+
+  const Target *TheTarget = nullptr;
+  std::unique_ptr<TargetMachine> Target;
+
+  // If user just wants to list available options, skip module loading
+  auto MAttrs = codegen::getMAttrs();
+  bool SkipModule =
+      CPUStr == "help" || TuneCPUStr == "help" || is_contained(MAttrs, "help");
+  if (SkipModule) {
+    if (!TargetTriple.empty())
+      TheTriple = Triple(Triple::normalize(TargetTriple));
+    else
+      TheTriple = Triple(sys::getDefaultTargetTriple());
+
+    // Get the target specific parser.
+    std::string Error;
+    TheTarget =
+        TargetRegistry::lookupTarget(codegen::getMArch(), TheTriple, Error);
+    if (!TheTarget) {
+      WithColor::error(errs(), argv[0]) << Error << "\n";
+      return 1;
+    }
+
+    InitializeOptions(TheTriple);
+    // Pass "help" as CPU for -mtune=help
+    std::string SkipModuleCPU = (TuneCPUStr == "help" ? "help" : CPUStr);
+    // Create the target machine just to print the help info. Use unique_ptr
+    // to avoid a memory leak.
+    Target = std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
+        TheTriple, SkipModuleCPU, FeaturesStr, Options, RM, CM, OLvl));
+    if (!Target) {
+      WithColor::error(errs(), argv[0])
+          << "could not allocate target machine\n";
+      return 1;
+    }
+
+    // If we don't have a module then just exit now. We do this down
+    // here since the CPU/Feature help is underneath the target machine
+    // creation.
+    return 0;
+  }
+
+  auto SetDataLayout = [&](StringRef DataLayoutTargetTriple,
+                           StringRef OldDLStr) -> std::optional<std::string> {
+    // If we are supposed to override the target triple, do so now.
+    std::string IRTargetTriple = DataLayoutTargetTriple.str();
+    if (!TargetTriple.empty())
+      IRTargetTriple = Triple::normalize(TargetTriple);
+    TheTriple = Triple(IRTargetTriple);
+    if (TheTriple.getTriple().empty())
+      TheTriple.setTriple(sys::getDefaultTargetTriple());
+
+    std::string Error;
+    TheTarget =
+        TargetRegistry::lookupTarget(codegen::getMArch(), TheTriple, Error);
+    if (!TheTarget) {
+      WithColor::error(errs(), argv[0]) << Error << "\n";
+      exit(1);
+    }
+
+    InitializeOptions(TheTriple);
+    Target = std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
+        TheTriple, CPUStr, FeaturesStr, Options, RM, CM, OLvl));
+    if (!Target) {
+      WithColor::error(errs(), argv[0])
+          << "could not allocate target machine\n";
+      exit(1);
+    }
+
+    // Set PGO options based on command line flags
+    setPGOOptions(*Target);
+
+    return Target->createDataLayout().getStringRepresentation();
+  };
+  if (InputLanguage == "mir" ||
+      (InputLanguage == "" && StringRef(InputFilename).ends_with(".mir"))) {
+    MIR = createMIRParserFromFile(InputFilename, Err, Context,
+                                  setMIRFunctionAttributes);
+    if (MIR)
+      M = MIR->parseIRModule(SetDataLayout);
+  } else {
+    M = parseIRFile(InputFilename, Err, Context,
+                    ParserCallbacks(SetDataLayout));
+  }
+  if (!M) {
+    Err.print(argv[0], WithColor::error(errs(), argv[0]));
+    return 1;
+  }
+
+  M->setTargetTriple(TheTriple);
+
+  std::optional<CodeModel::Model> CM_IR = M->getCodeModel();
+  if (!CM && CM_IR)
+    Target->setCodeModel(*CM_IR);
+  if (std::optional<uint64_t> LDT = codegen::getExplicitLargeDataThreshold())
+    Target->setLargeDataThreshold(*LDT);
+
+  // Figure out where we are going to send the output.
+  std::unique_ptr<ToolOutputFile> Out = GetOutputStream(TheTriple.getOS());
+  if (!Out)
+    return 1;
+
+  // Ensure the filename is passed down to CodeViewDebug.
+  Target->Options.ObjectFilenameForDebug = Out->outputFilename();
+
+  // Return a copy of the output filename via the output param
+  OutputFilename = Out->outputFilename();
+
+  // Tell target that this tool is not necessarily used with argument ABI
+  // compliance (i.e. narrow integer argument extensions).
+  Target->Options.VerifyArgABICompliance = 0;
+
+  std::unique_ptr<ToolOutputFile> DwoOut;
+  if (!SplitDwarfOutputFile.empty()) {
+    std::error_code EC;
+    DwoOut = std::make_unique<ToolOutputFile>(SplitDwarfOutputFile, EC,
+                                              sys::fs::OF_None);
+    if (EC)
+      reportError(EC.message(), SplitDwarfOutputFile);
+  }
+
+  // Add an appropriate TargetLibraryInfo pass for the module's triple.
+  TargetLibraryInfoImpl TLII(M->getTargetTriple(), Target->Options.VecLib);
+
+  // The -disable-simplify-libcalls flag actually disables all builtin optzns.
+  if (DisableSimplifyLibCalls)
+    TLII.disableAllFunctions();
+
+  // Verify module immediately to catch problems before doInitialization() is
+  // called on any passes.
+  if (!NoVerify && verifyModule(*M, &errs()))
+    reportError("input module cannot be verified", InputFilename);
+
+  // Override function attributes based on CPUStr, TuneCPUStr, FeaturesStr, and
+  // command line flags.
+  codegen::setFunctionAttributes(*M, CPUStr, FeaturesStr, TuneCPUStr);
+
+  for (auto &Plugin : PluginList) {
+    CodeGenFileType CGFT = codegen::getFileType();
+    if (Plugin.invokePreCodeGenCallback(*M, *Target, CGFT, Out->os())) {
+      // TODO: Deduplicate code with below and the NewPMDriver.
+      if (Context.getDiagHandlerPtr()->HasErrors)
+        exit(1);
+      Out->keep();
+      return 0;
+    }
+  }
+
+  if (mc::getExplicitRelaxAll() &&
+      codegen::getFileType() != CodeGenFileType::ObjectFile)
+    WithColor::warning(errs(), argv[0])
+        << ": warning: ignoring -mc-relax-all because filetype != obj";
+
+  VerifierKind VK = VerifierKind::InputOutput;
+  if (NoVerify)
+    VK = VerifierKind::None;
+  else if (VerifyEach)
+    VK = VerifierKind::EachPass;
+
+  // Use the NewPM if the user specifies -passes (NewPM specific), specifically
+  // requests the NewPM with -enable-new-pm, or the target defaults to the
+  // NewPM, the user has not explicitly disabled the NewPM with
+  // -enable-new-pm=false, and the user has not specified -run-pass.
+  if (!PassPipeline.empty() ||
+      (EnableNewPassManager.getNumOccurrences() > 0 && EnableNewPassManager) ||
+      (Target->shouldDefaultToNewPM() &&
+       !(EnableNewPassManager.getNumOccurrences() && !EnableNewPassManager) &&
+       getRunPassNames().empty())) {
+    return compileModuleWithNewPM(
+        argv[0], std::move(M), std::move(MIR), std::move(Target),
+        std::move(Out), std::move(DwoOut), Context, TLII, VK, PassPipeline,
+        PluginList, codegen::getFileType());
+  }
+
+  // Build up all of the passes that we want to do to the module.
+  legacy::PassManager PM;
+  PM.add(new TargetLibraryInfoWrapperPass(TLII));
+  PM.add(new RuntimeLibraryInfoWrapper(
+      Target->Options.ExceptionModel, Target->Options.EABIVersion,
+      Options.MCOptions.ABIName, Target->Options.VecLib));
+
+  {
+    raw_pwrite_stream *OS = &Out->os();
+
+    // Manually do the buffering rather than using buffer_ostream,
+    // so we can memcmp the contents in CompileTwice mode
+    SmallVector<char, 0> Buffer;
+    std::unique_ptr<raw_svector_ostream> BOS;
+    if ((codegen::getFileType() != CodeGenFileType::AssemblyFile &&
+         !Out->os().supportsSeeking()) ||
+        CompileTwice) {
+      BOS = std::make_unique<raw_svector_ostream>(Buffer);
+      OS = BOS.get();
+    }
+
+    const char *argv0 = argv[0];
+    MachineModuleInfoWrapperPass *MMIWP =
+        new MachineModuleInfoWrapperPass(Target.get());
+
+    // Set a temporary diagnostic handler. This is used before
+    // MachineModuleInfoWrapperPass::doInitialization for features like -M.
+    bool HasMCErrors = false;
+    MCContext &MCCtx = MMIWP->getMMI().getContext();
+    MCCtx.setDiagnosticHandler([&](const SMDiagnostic &SMD, bool IsInlineAsm,
+                                   const SourceMgr &SrcMgr,
+                                   std::vector<const MDNode *> &LocInfos) {
+      WithColor::error(errs(), argv0) << SMD.getMessage() << '\n';
+      HasMCErrors = true;
+    });
+
+    // Construct a custom pass pipeline that starts after instruction
+    // selection.
+    if (!getRunPassNames().empty()) {
+      if (!MIR) {
+        WithColor::error(errs(), argv[0])
+            << "run-pass is for .mir file only.\n";
+        delete MMIWP;
+        return 1;
+      }
+      TargetPassConfig *PTPC = Target->createPassConfig(PM);
+      TargetPassConfig &TPC = *PTPC;
+      if (TPC.hasLimitedCodeGenPipeline()) {
+        WithColor::error(errs(), argv[0])
+            << "run-pass cannot be used with "
+            << TPC.getLimitedCodeGenPipelineReason() << ".\n";
+        delete PTPC;
+        delete MMIWP;
+        return 1;
+      }
+
+      TPC.setDisableVerify(NoVerify);
+      PM.add(&TPC);
+      PM.add(MMIWP);
+      TPC.printAndVerify("");
+      for (const std::string &RunPassName : getRunPassNames()) {
+        if (addPass(PM, argv0, RunPassName, TPC))
+          return 1;
+      }
+      TPC.setInitialized();
+      PM.add(createPrintMIRPass(*OS));
+
+      // Add MIR2Vec vocabulary printer if requested
+      if (PrintMIR2VecVocab) {
+        PM.add(createMIR2VecVocabPrinterLegacyPass(errs()));
+      }
+
+      // Add MIR2Vec printer if requested
+      if (PrintMIR2Vec) {
+        PM.add(createMIR2VecPrinterLegacyPass(errs()));
+      }
+
+      PM.add(createFreeMachineFunctionPass());
+    } else {
+      if (Target->addPassesToEmitFile(PM, *OS, DwoOut ? &DwoOut->os() : nullptr,
+                                      codegen::getFileType(), NoVerify,
+                                      MMIWP)) {
+        if (!HasMCErrors)
+          reportError("target does not support generation of this file type");
+      }
+
+      // Add MIR2Vec vocabulary printer if requested
+      if (PrintMIR2VecVocab) {
+        PM.add(createMIR2VecVocabPrinterLegacyPass(errs()));
+      }
+
+      // Add MIR2Vec printer if requested
+      if (PrintMIR2Vec) {
+        PM.add(createMIR2VecPrinterLegacyPass(errs()));
+      }
+    }
+
+    Target->getObjFileLowering()->Initialize(MMIWP->getMMI().getContext(),
+                                             *Target);
+    if (MIR) {
+      assert(MMIWP && "Forgot to create MMIWP?");
+      if (MIR->parseMachineFunctions(*M, MMIWP->getMMI()))
+        return 1;
+    }
+
+    // Before executing passes, print the final values of the LLVM options.
+    cl::PrintOptionValues();
+
+    // If requested, run the pass manager over the same module again,
+    // to catch any bugs due to persistent state in the passes. Note that
+    // opt has the same functionality, so it may be worth abstracting this out
+    // in the future.
+    SmallVector<char, 0> CompileTwiceBuffer;
+    if (CompileTwice) {
+      std::unique_ptr<Module> M2(llvm::CloneModule(*M));
+      PM.run(*M2);
+      CompileTwiceBuffer = Buffer;
+      Buffer.clear();
+    }
+
+    PM.run(*M);
+
+    if (Context.getDiagHandlerPtr()->HasErrors || HasMCErrors)
+      return 1;
+
+    // Compare the two outputs and make sure they're the same
+    if (CompileTwice) {
+      if (Buffer.size() != CompileTwiceBuffer.size() ||
+          (memcmp(Buffer.data(), CompileTwiceBuffer.data(), Buffer.size()) !=
+           0)) {
+        errs()
+            << "Running the pass manager twice changed the output.\n"
+               "Writing the result of the second run to the specified output\n"
+               "To generate the one-run comparison binary, just run without\n"
+               "the compile-twice option\n";
+        Out->os() << Buffer;
+        Out->keep();
+        return 1;
+      }
+    }
+
+    if (BOS) {
+      Out->os() << Buffer;
+    }
+  }
+
+  // Declare success.
+  Out->keep();
+  if (DwoOut)
+    DwoOut->keep();
+
+  return 0;
+}
diff --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
index 30e7693a2563e..11e80ee03cbae 100644
--- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
@@ -4988,14 +4988,16 @@ llvm_driver_cc_binary(
     deps = [":dsymutil-lib"],
 )
 
-cc_binary(
-    name = "llc",
-    srcs = glob([
-        "tools/llc/*.cpp",
+cc_library(
+    name = "llc-driver",
+    srcs = [
+        "tools/llc/NewPMDriver.cpp",
+        "tools/llc/llcdriver.cpp",
+    ],
+    hdrs = glob([
         "tools/llc/*.h",
     ]),
     copts = llvm_copts,
-    stamp = 0,
     deps = [
         ":AllTargetsAsmParsers",
         ":AllTargetsCodeGens",
@@ -5019,6 +5021,17 @@ cc_binary(
     ],
 )
 
+cc_binary(
+    name = "llc",
+    srcs = ["tools/llc/llc.cpp"],
+    copts = llvm_copts,
+    stamp = 0,
+    deps = [
+        ":Support",
+        ":llc-driver",
+    ],
+)
+
 cc_binary(
     name = "lli",
     srcs = glob([



More information about the llvm-commits mailing list