[llvm] [NewPM][CodeGen][llc] Add NPM support (PR #70922)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 18 03:14:15 PST 2024


https://github.com/paperchalice updated https://github.com/llvm/llvm-project/pull/70922

>From efe5b8a7fc2c9f872ca7505cc220314abe49b633 Mon Sep 17 00:00:00 2001
From: Yuanfang Chen <455423+yuanfang-chen at users.noreply.github.com>
Date: Wed, 1 Nov 2023 10:48:45 +0800
Subject: [PATCH] [NewPM][CodeGen] Add NPM support to llc

---
 llvm/include/llvm/Passes/PassBuilder.h |   2 +
 llvm/lib/Passes/PassBuilder.cpp        |  23 +++
 llvm/tools/llc/CMakeLists.txt          |   3 +
 llvm/tools/llc/NewPMDriver.cpp         | 245 +++++++++++++++++++++++++
 llvm/tools/llc/NewPMDriver.h           |  47 +++++
 llvm/tools/llc/llc.cpp                 |  48 ++---
 6 files changed, 336 insertions(+), 32 deletions(-)
 create mode 100644 llvm/tools/llc/NewPMDriver.cpp
 create mode 100644 llvm/tools/llc/NewPMDriver.h

diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h
index 33cf8af87381fb..d69b9f58a03b98 100644
--- a/llvm/include/llvm/Passes/PassBuilder.h
+++ b/llvm/include/llvm/Passes/PassBuilder.h
@@ -628,6 +628,8 @@ class PassBuilder {
   void invokePipelineEarlySimplificationEPCallbacks(ModulePassManager &MPM,
                                                     OptimizationLevel Level);
 
+  bool isMachineFunctionPassName(StringRef Name) const;
+
 private:
   // O1 pass pipeline
   FunctionPassManager
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 8d3f69be503831..2ba393cf348589 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -1281,6 +1281,29 @@ static bool isLoopPassName(StringRef Name, CallbacksT &Callbacks,
   return callbacksAcceptPassName<LoopPassManager>(Name, Callbacks);
 }
 
+template <typename CallbacksT>
+static bool isMachineFunctionPassName(StringRef Name, CallbacksT &Callbacks) {
+#define MACHINE_FUNCTION_PASS(NAME, PASS_NAME, CONSTRUCTOR)                    \
+  if (Name == NAME)                                                            \
+    return true;
+#define MACHINE_MODULE_PASS(NAME, PASS_NAME, CONSTRUCTOR)                      \
+  if (Name == NAME)                                                            \
+    return true;
+#include "llvm/CodeGen/MachinePassRegistry.def"
+
+  if (!Callbacks.empty()) {
+    MachineFunctionPassManager DummyPM;
+    for (auto &CB : Callbacks)
+      if (CB(Name, DummyPM))
+        return true;
+  }
+  return false;
+}
+
+bool PassBuilder::isMachineFunctionPassName(StringRef Name) const {
+  return ::isMachineFunctionPassName(Name, MachinePipelineParsingCallbacks);
+}
+
 std::optional<std::vector<PassBuilder::PipelineElement>>
 PassBuilder::parsePipelineText(StringRef Text) {
   std::vector<PipelineElement> ResultPipeline;
diff --git a/llvm/tools/llc/CMakeLists.txt b/llvm/tools/llc/CMakeLists.txt
index 257d5b519f0406..01825c6e4c64c7 100644
--- a/llvm/tools/llc/CMakeLists.txt
+++ b/llvm/tools/llc/CMakeLists.txt
@@ -8,9 +8,11 @@ set(LLVM_LINK_COMPONENTS
   CodeGen
   CodeGenTypes
   Core
+  IRPrinter
   IRReader
   MC
   MIRParser
+  Passes
   Remarks
   ScalarOpts
   SelectionDAG
@@ -23,6 +25,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_llvm_tool(llc
   llc.cpp
+  NewPMDriver.cpp
 
   DEPENDS
   intrinsics_gen
diff --git a/llvm/tools/llc/NewPMDriver.cpp b/llvm/tools/llc/NewPMDriver.cpp
new file mode 100644
index 00000000000000..017075c72e3810
--- /dev/null
+++ b/llvm/tools/llc/NewPMDriver.cpp
@@ -0,0 +1,245 @@
+//===- NewPMDriver.cpp - Driver for llc using 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 llc.cpp but
+/// that includes the new pass manager headers.
+///
+//===----------------------------------------------------------------------===//
+
+#include "NewPMDriver.h"
+#include "llvm/Analysis/CGSCCPassManager.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/CodeGen/CodeGenPassBuilder.h"
+#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/CodeGen/MIRParser/MIRParser.h"
+#include "llvm/CodeGen/MIRPrinter.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachinePassManager.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.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/IRReader/IRReader.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Passes/StandardInstrumentations.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Target/CGPassBuilderOption.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/Transforms/Scalar/LoopPassManager.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+namespace llvm {
+extern cl::opt<bool> PrintPipelinePasses;
+} // namespace llvm
+
+using namespace llvm;
+
+static cl::opt<RegAllocType> RegAlloc(
+    "regalloc-npm", cl::desc("Register allocator to use for new pass manager"),
+    cl::Hidden, cl::ValueOptional, cl::init(RegAllocType::Default),
+    cl::values(
+        clEnumValN(RegAllocType::Default, "default",
+                   "pick register allocator based on -O option"),
+        clEnumValN(RegAllocType::Basic, "basic", "basic register allocator"),
+        clEnumValN(RegAllocType::Fast, "fast", "fast register allocator"),
+        clEnumValN(RegAllocType::Greedy, "greedy", "greedy register allocator"),
+        clEnumValN(RegAllocType::PBQP, "pbqp", "PBQP register allocator")));
+
+static cl::opt<bool>
+    DebugPM("debug-pass-manager", cl::Hidden,
+            cl::desc("Print pass management debugging information"));
+
+bool LLCDiagnosticHandler::handleDiagnostics(const DiagnosticInfo &DI) {
+  DiagnosticHandler::handleDiagnostics(DI);
+  if (DI.getKind() == llvm::DK_SrcMgr) {
+    const auto &DISM = cast<DiagnosticInfoSrcMgr>(DI);
+    const SMDiagnostic &SMD = DISM.getSMDiag();
+
+    SMD.print(nullptr, errs());
+
+    // For testing purposes, we print the LocCookie here.
+    if (DISM.isInlineAsmDiag() && DISM.getLocCookie())
+      WithColor::note() << "!srcloc = " << DISM.getLocCookie() << "\n";
+
+    return true;
+  }
+
+  if (auto *Remark = dyn_cast<DiagnosticInfoOptimizationBase>(&DI))
+    if (!Remark->isEnabled())
+      return true;
+
+  DiagnosticPrinterRawOStream DP(errs());
+  errs() << LLVMContext::getDiagnosticMessagePrefix(DI.getSeverity()) << ": ";
+  DI.print(DP);
+  errs() << "\n";
+  return true;
+}
+
+static llvm::ExitOnError ExitOnErr;
+
+static void RunPasses(bool BOS, ToolOutputFile *Out, Module *M,
+                      LLVMContext &Context, SmallString<0> &Buffer,
+                      ModulePassManager *MPM, ModuleAnalysisManager *MAM,
+                      MachineFunctionPassManager &MFPM,
+                      MachineFunctionAnalysisManager &MFAM) {
+  assert(M && "invalid input module!");
+
+  // Before executing passes, print the final values of the LLVM options.
+  cl::PrintOptionValues();
+
+  if (MPM) {
+    assert(MAM && "expect a ModuleAnalysisManager!");
+    MPM->run(*M, *MAM);
+  }
+
+  ExitOnErr(MFPM.run(*M, MFAM));
+
+  if (Context.getDiagHandlerPtr()->HasErrors)
+    exit(1);
+
+  if (BOS)
+    Out->os() << Buffer;
+}
+
+int llvm::compileModuleWithNewPM(
+    StringRef Arg0, std::unique_ptr<Module> M, std::unique_ptr<MIRParser> MIR,
+    std::unique_ptr<TargetMachine> Target, std::unique_ptr<ToolOutputFile> Out,
+    std::unique_ptr<ToolOutputFile> DwoOut, LLVMContext &Context,
+    const TargetLibraryInfoImpl &TLII, bool NoVerify,
+    const std::vector<std::string> &RunPassNames, CodeGenFileType FileType) {
+
+  if (!RunPassNames.empty() && TargetPassConfig::hasLimitedCodeGenPipeline()) {
+    WithColor::warning(errs(), Arg0)
+        << "run-pass cannot be used with "
+        << TargetPassConfig::getLimitedCodeGenPipelineReason(" and ") << ".\n";
+    return 1;
+  }
+
+  LLVMTargetMachine &LLVMTM = static_cast<LLVMTargetMachine &>(*Target);
+
+  {
+    raw_pwrite_stream *OS = &Out->os();
+
+    // Manually do the buffering rather than using buffer_ostream,
+    // so we can memcmp the contents in CompileTwice mode in future.
+    SmallString<0> Buffer;
+    std::unique_ptr<raw_svector_ostream> BOS;
+    if ((codegen::getFileType() != CodeGenFileType::AssemblyFile &&
+         !Out->os().supportsSeeking())) {
+      BOS = std::make_unique<raw_svector_ostream>(Buffer);
+      OS = BOS.get();
+    }
+
+    // Fetch options from TargetPassConfig
+    CGPassBuilderOption Opt = getCGPassBuilderOption();
+    Opt.DisableVerify = NoVerify;
+    Opt.DebugPM = DebugPM;
+    Opt.RegAlloc = RegAlloc;
+
+    PassInstrumentationCallbacks PIC;
+    StandardInstrumentations SI(Context, Opt.DebugPM);
+    SI.registerCallbacks(PIC);
+    registerCodeGenCallback(PIC, LLVMTM);
+
+    LoopAnalysisManager LAM;
+    FunctionAnalysisManager FAM;
+    CGSCCAnalysisManager CGAM;
+    ModuleAnalysisManager MAM;
+    PassBuilder PB(Target.get(), PipelineTuningOptions(), std::nullopt, &PIC);
+    PB.registerModuleAnalyses(MAM);
+    PB.registerCGSCCAnalyses(CGAM);
+    PB.registerFunctionAnalyses(FAM);
+    PB.registerLoopAnalyses(LAM);
+    PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
+
+    FAM.registerPass([&] { return TargetLibraryAnalysis(TLII); });
+    MAM.registerPass([&] { return MachineModuleAnalysis(&LLVMTM); });
+
+    MachineFunctionAnalysisManager MFAM(FAM, MAM);
+
+    if (!RunPassNames.empty()) {
+      // Construct a custom pass pipeline that starts after instruction
+      // selection.
+
+      if (!MIR) {
+        WithColor::warning(errs(), Arg0) << "run-pass is for .mir file only.\n";
+        return 1;
+      }
+
+      MachineFunctionPassManager MFPM;
+      ExitOnErr(PB.parsePassPipeline(MFPM, llvm::join(RunPassNames, ",")));
+      MFPM.addPass(PrintMIRPass(*OS));
+      MFPM.addPass(FreeMachineFunctionPass());
+
+      auto &MMI = MFAM.getResult<MachineModuleAnalysis>(*M);
+      if (MIR->parseMachineFunctions(*M, MMI))
+        return 1;
+
+      RunPasses(BOS.get(), Out.get(), M.get(), Context, Buffer, nullptr,
+                nullptr, MFPM, MFAM);
+    } else {
+      ModulePassManager MPM;
+      MachineFunctionPassManager MFPM;
+
+      ExitOnErr(LLVMTM.buildCodeGenPipeline(MPM, MFPM, MFAM, *OS,
+                                            DwoOut ? &DwoOut->os() : nullptr,
+                                            FileType, Opt, &PIC));
+
+      auto StartStopInfo = TargetPassConfig::getStartStopInfo(PIC);
+      assert(StartStopInfo && "Expect StartStopInfo!");
+      // Add IR or MIR printing pass according the pass type.
+
+      if (auto StopPassName = StartStopInfo->StopPass; !StopPassName.empty()) {
+        if (PB.isMachineFunctionPassName(StopPassName))
+          MFPM.addPass(PrintMIRPass(*OS));
+        else
+          MPM.addPass(PrintModulePass(*OS));
+      }
+
+      if (PrintPipelinePasses) {
+        std::string IRPipeline;
+        raw_string_ostream IRSOS(IRPipeline);
+        MPM.printPipeline(IRSOS, [&PIC](StringRef ClassName) {
+          auto PassName = PIC.getPassNameForClassName(ClassName);
+          return PassName.empty() ? ClassName : PassName;
+        });
+        outs() << "IR pipeline: " << IRPipeline << '\n';
+
+        std::string MIRPipeline;
+        raw_string_ostream MIRSOS(MIRPipeline);
+        MFPM.printPipeline(IRSOS, [&PIC](StringRef ClassName) {
+          auto PassName = PIC.getPassNameForClassName(ClassName);
+          return PassName.empty() ? ClassName : PassName;
+        });
+        outs() << "MIR pipeline: " << IRPipeline << '\n';
+      }
+
+      RunPasses(BOS.get(), Out.get(), M.get(), Context, Buffer, &MPM, &MAM,
+                MFPM, MFAM);
+    }
+  }
+
+  // Declare success.
+  Out->keep();
+  if (DwoOut)
+    DwoOut->keep();
+
+  return 0;
+}
diff --git a/llvm/tools/llc/NewPMDriver.h b/llvm/tools/llc/NewPMDriver.h
new file mode 100644
index 00000000000000..e6186d9817f972
--- /dev/null
+++ b/llvm/tools/llc/NewPMDriver.h
@@ -0,0 +1,47 @@
+//===- NewPMDriver.h - Function to drive llc with the new PM ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// A single function which is called to drive the llc behavior for the new
+/// PassManager.
+///
+/// This is only in a separate TU with a header to avoid including all of the
+/// old pass manager headers and the new pass manager headers into the same
+/// file. Eventually all of the routines here will get folded back into
+/// llc.cpp.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_LLC_NEWPMDRIVER_H
+#define LLVM_TOOLS_LLC_NEWPMDRIVER_H
+
+#include "llvm/IR/DiagnosticHandler.h"
+#include "llvm/Support/CodeGen.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+class Module;
+class TargetLibraryInfoImpl;
+class TargetMachine;
+class ToolOutputFile;
+class LLVMContext;
+class MIRParser;
+
+struct LLCDiagnosticHandler : public DiagnosticHandler {
+  bool handleDiagnostics(const DiagnosticInfo &DI) override;
+};
+
+int compileModuleWithNewPM(
+    StringRef Arg0, std::unique_ptr<Module> M, std::unique_ptr<MIRParser> MIR,
+    std::unique_ptr<TargetMachine> Target, std::unique_ptr<ToolOutputFile> Out,
+    std::unique_ptr<ToolOutputFile> DwoOut, LLVMContext &Context,
+    const TargetLibraryInfoImpl &TLII, bool NoVerify,
+    const std::vector<std::string> &RunPassNames, CodeGenFileType FileType);
+} // namespace llvm
+
+#endif
diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp
index 4a1957588a2243..ee78d128ba5cc6 100644
--- a/llvm/tools/llc/llc.cpp
+++ b/llvm/tools/llc/llc.cpp
@@ -12,6 +12,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "NewPMDriver.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
@@ -186,6 +187,8 @@ static cl::opt<std::string> RemarksFormat(
     cl::desc("The format used for serializing remarks (default: YAML)"),
     cl::value_desc("format"), cl::init("yaml"));
 
+static cl::opt<bool> EnableNewPassManager(
+    "enable-new-pm", cl::desc("Enable the new pass manager"), cl::init(false));
 static cl::opt<bool> TryUseNewDbgInfoFormat(
     "try-experimental-debuginfo-iterators",
     cl::desc("Enable debuginfo iterator positions, if they're built in"),
@@ -306,34 +309,6 @@ static std::unique_ptr<ToolOutputFile> GetOutputStream(const char *TargetName,
   return FDOut;
 }
 
-struct LLCDiagnosticHandler : public DiagnosticHandler {
-  bool handleDiagnostics(const DiagnosticInfo &DI) override {
-    DiagnosticHandler::handleDiagnostics(DI);
-    if (DI.getKind() == llvm::DK_SrcMgr) {
-      const auto &DISM = cast<DiagnosticInfoSrcMgr>(DI);
-      const SMDiagnostic &SMD = DISM.getSMDiag();
-
-      SMD.print(nullptr, errs());
-
-      // For testing purposes, we print the LocCookie here.
-      if (DISM.isInlineAsmDiag() && DISM.getLocCookie())
-        WithColor::note() << "!srcloc = " << DISM.getLocCookie() << "\n";
-
-      return true;
-    }
-
-    if (auto *Remark = dyn_cast<DiagnosticInfoOptimizationBase>(&DI))
-      if (!Remark->isEnabled())
-        return true;
-
-    DiagnosticPrinterRawOStream DP(errs());
-    errs() << LLVMContext::getDiagnosticMessagePrefix(DI.getSeverity()) << ": ";
-    DI.print(DP);
-    errs() << "\n";
-    return true;
-  }
-};
-
 // main - Entry point for the llc compiler.
 //
 int main(int argc, char **argv) {
@@ -642,16 +617,12 @@ static int compileModule(char **argv, LLVMContext &Context) {
       reportError(EC.message(), SplitDwarfOutputFile);
   }
 
-  // Build up all of the passes that we want to do to the module.
-  legacy::PassManager PM;
-
   // Add an appropriate TargetLibraryInfo pass for the module's triple.
   TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple()));
 
   // The -disable-simplify-libcalls flag actually disables all builtin optzns.
   if (DisableSimplifyLibCalls)
     TLII.disableAllFunctions();
-  PM.add(new TargetLibraryInfoWrapperPass(TLII));
 
   // Verify module immediately to catch problems before doInitialization() is
   // called on any passes.
@@ -667,6 +638,19 @@ static int compileModule(char **argv, LLVMContext &Context) {
     WithColor::warning(errs(), argv[0])
         << ": warning: ignoring -mc-relax-all because filetype != obj";
 
+  bool RunPassNone =
+      !getRunPassNames().empty() && getRunPassNames().at(0) == "none";
+  if (EnableNewPassManager && !RunPassNone) {
+    return compileModuleWithNewPM(argv[0], std::move(M), std::move(MIR),
+                                  std::move(Target), std::move(Out),
+                                  std::move(DwoOut), Context, TLII, NoVerify,
+                                  getRunPassNames(), codegen::getFileType());
+  }
+
+  // Build up all of the passes that we want to do to the module.
+  legacy::PassManager PM;
+  PM.add(new TargetLibraryInfoWrapperPass(TLII));
+
   {
     raw_pwrite_stream *OS = &Out->os();
 



More information about the llvm-commits mailing list