[llvm] [CodeGen][NPM] Support generic regalloc-npm option (PR #172485)

Teja Alaghari via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 16 06:47:41 PST 2025


https://github.com/TejaX-Alaghari created https://github.com/llvm/llvm-project/pull/172485

This PR is a port of [PR#135149](https://github.com/llvm/llvm-project/pull/135149) and provides the `--regalloc-npm` option as an override to register allocation passes added in the New PM codegen pipeline.

>From b7b67c32556417d86d31f573c9b7f336bc5bc730 Mon Sep 17 00:00:00 2001
From: vikhegde <vikram.hegde at amd.com>
Date: Tue, 16 Dec 2025 19:52:01 +0530
Subject: [PATCH 1/2] [CodeGen][NPM] Support generic --regalloc-npm option

This provides the `--regalloc-npm` option as an override to register
allocation passes added in the NewPM codegen pipeline. It accepts a
comma-separated list of passes using the normal `--passes` syntax.

Example: `llc --regalloc-npm='default,default,regallocfast<filter=vgpr>'`
will replace only the third regalloc pass with RAFast.

Key changes:
- Introduce `RA_PASS_WITH_PARAMS` macro to distinguish RA passes from
  other MachineFunction passes in MachinePassRegistry.def
- Add `addRegAllocPassFromOpt()` and `addRegAllocPassOrOpt()` helpers
  to CodeGenPassBuilder for consuming the option
- Replace `RegAllocType` enum usage with `StringRef RegAllocPipeline`
  field in CGPassBuilderOption
- Change parser signatures to accept `const PassBuilder &` for filter
  parsing
- Add `PassBuilder &` parameter to `CodeGenPassBuilder` constructor
  and `buildCodeGenPipeline` API
- Add X86 tile-register filter support (`tile-reg`)

The number of passes in `--regalloc-npm` should match what the target
pipeline adds. The special value "default" uses the pipeline's default.
Extra passes cause an error.

Co-authored-by: optimisan <76596238+optimisan at users.noreply.github.com>
---
 llvm/include/llvm/Passes/CodeGenPassBuilder.h | 86 ++++++++++++----
 .../llvm/Passes/MachinePassRegistry.def       | 41 +++++---
 llvm/include/llvm/Passes/PassBuilder.h        | 29 ++++--
 .../llvm/Passes/TargetPassRegistry.inc        |  2 +-
 .../include/llvm/Target/CGPassBuilderOption.h |  2 +-
 llvm/include/llvm/Target/TargetMachine.h      |  5 +-
 llvm/lib/Passes/PassBuilder.cpp               | 98 +++++++++++--------
 .../lib/Target/AMDGPU/AMDGPUTargetMachine.cpp | 31 +++---
 llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h  |  5 +-
 llvm/lib/Target/AMDGPU/R600TargetMachine.cpp  | 14 +--
 llvm/lib/Target/AMDGPU/R600TargetMachine.h    |  5 +-
 llvm/lib/Target/BPF/BPFTargetMachine.cpp      |  3 +-
 llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp | 34 +++++--
 llvm/lib/Target/X86/X86TargetMachine.cpp      | 15 ++-
 llvm/lib/Target/X86/X86TargetMachine.h        | 11 ++-
 .../test/tools/llc/new-pm/regalloc-amdgpu.mir |  5 +
 .../llc/new-pm/x86_64-regalloc-pipeline.mir   | 28 +++++-
 llvm/tools/llc/NewPMDriver.cpp                | 21 ++--
 18 files changed, 300 insertions(+), 135 deletions(-)

diff --git a/llvm/include/llvm/Passes/CodeGenPassBuilder.h b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
index 0e14f2e50ae04..8ac021cb369e7 100644
--- a/llvm/include/llvm/Passes/CodeGenPassBuilder.h
+++ b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
@@ -128,6 +128,8 @@
 #include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
 #include "llvm/Transforms/Utils/LowerInvoke.h"
 #include <cassert>
+#include <tuple>
+#include <type_traits>
 #include <utility>
 
 namespace llvm {
@@ -168,8 +170,9 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
 public:
   explicit CodeGenPassBuilder(TargetMachineT &TM,
                               const CGPassBuilderOption &Opts,
-                              PassInstrumentationCallbacks *PIC)
-      : TM(TM), Opt(Opts), PIC(PIC) {
+                              PassInstrumentationCallbacks *PIC,
+                              PassBuilder &PB)
+      : TM(TM), Opt(Opts), PIC(PIC), PB(PB) {
     // Target could set CGPassBuilderOption::MISchedPostRA to true to achieve
     //     substitutePass(&PostRASchedulerID, &PostMachineSchedulerID)
 
@@ -356,6 +359,8 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
   TargetMachineT &TM;
   CGPassBuilderOption Opt;
   PassInstrumentationCallbacks *PIC;
+  PassBuilder &PB;
+  mutable IntrusiveRefCntPtr<AsmPrinter> PrinterImpl;
 
   template <typename TMC> TMC &getTM() const { return static_cast<TMC &>(TM); }
   CodeGenOptLevel getOptLevel() const { return TM.getOptLevel(); }
@@ -563,6 +568,15 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
   /// addMachinePasses helper to create the target-selected or overriden
   /// regalloc pass.
   void addRegAllocPass(AddMachinePass &, bool Optimized) const;
+  /// Read the --regalloc-npm option to add the next pass in line.
+  /// Returns false if no pass is left in the option.
+  bool addRegAllocPassFromOpt(AddMachinePass &,
+                              StringRef MatchPassTo = StringRef{}) const;
+  /// Add the next pass in the cli option or the pass specified if no pass is
+  /// left in the option.
+  template <typename RegAllocPassBuilderT>
+  void addRegAllocPassOrOpt(AddMachinePass &,
+                            RegAllocPassBuilderT PassBuilder) const;
 
   /// Add core register alloator passes which do the actual register assignment
   /// and rewriting. \returns true if any passes were added.
@@ -667,6 +681,11 @@ Error CodeGenPassBuilder<Derived, TargetMachineT>::buildPipeline(
   if (PrintMIR)
     addPass(PrintMIRPass(Out), /*Force=*/true);
 
+  if (!Opt.RegAllocPipeline.empty())
+    return make_error<StringError>(
+        "extra passes in regalloc pipeline: " + Opt.RegAllocPipeline,
+        std::make_error_code(std::errc::invalid_argument));
+
   return verifyStartStop(*StartStopInfo);
 }
 
@@ -1176,6 +1195,48 @@ void CodeGenPassBuilder<Derived, TargetMachineT>::addTargetRegisterAllocator(
     addPass(RegAllocFastPass());
 }
 
+template <typename Derived, typename TargetMachineT>
+template <typename RegAllocPassBuilderT>
+void CodeGenPassBuilder<Derived, TargetMachineT>::addRegAllocPassOrOpt(
+    AddMachinePass &addPass, RegAllocPassBuilderT PassBuilder) const {
+  if (!addRegAllocPassFromOpt(addPass))
+    addPass(std::move(PassBuilder()));
+}
+
+template <typename Derived, typename TargetMachineT>
+bool CodeGenPassBuilder<Derived, TargetMachineT>::addRegAllocPassFromOpt(
+    AddMachinePass &addPass, StringRef MatchPassTo) const {
+  if (!Opt.RegAllocPipeline.empty()) {
+    StringRef PassOpt;
+    std::tie(PassOpt, Opt.RegAllocPipeline) = Opt.RegAllocPipeline.split(',');
+    // Reuse the registered parser to parse the pass name.
+#define RA_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)          \
+  if (PB.checkParametrizedPassName(PassOpt, NAME)) {                           \
+    auto Params = PB.parsePassParameters(PARSER, PassOpt, NAME,                \
+                                         const_cast<const PassBuilder &>(PB)); \
+    if (!Params) {                                                             \
+      auto Err = Params.takeError();                                           \
+      ExitOnError()(std::move(Err));                                           \
+    }                                                                          \
+    if (!MatchPassTo.empty()) {                                                \
+      if (MatchPassTo != CLASS)                                                \
+        report_fatal_error("expected " +                                       \
+                               PIC->getPassNameForClassName(MatchPassTo) +     \
+                               " in option --regalloc-npm",                    \
+                           false);                                             \
+    }                                                                          \
+    addPass(CREATE_PASS(Params.get()));                                        \
+    return true;                                                               \
+  }
+#include "llvm/Passes/MachinePassRegistry.def"
+    if (PassOpt != "default") {
+      report_fatal_error("unknown register allocator pass: " + PassOpt, false);
+    }
+  }
+  // If user did not give a specific pass, use the default provided.
+  return false;
+}
+
 /// Find and instantiate the register allocation pass requested by this target
 /// at the current optimization level.  Different register allocators are
 /// defined as separate passes because they may require different analysis.
@@ -1186,22 +1247,13 @@ template <typename Derived, typename TargetMachineT>
 void CodeGenPassBuilder<Derived, TargetMachineT>::addRegAllocPass(
     AddMachinePass &addPass, bool Optimized) const {
   // Use the specified -regalloc-npm={basic|greedy|fast|pbqp}
-  if (Opt.RegAlloc > RegAllocType::Default) {
-    switch (Opt.RegAlloc) {
-    case RegAllocType::Fast:
-      addPass(RegAllocFastPass());
-      break;
-    case RegAllocType::Greedy:
-      addPass(RAGreedyPass());
-      break;
-    default:
-      reportFatalUsageError("register allocator not supported yet");
-    }
-    return;
+  StringRef RegAllocPassName;
+  if (!Optimized)
+    RegAllocPassName = RegAllocFastPass::name();
+
+  if (!addRegAllocPassFromOpt(addPass, RegAllocPassName)) {
+    derived().addTargetRegisterAllocator(addPass, Optimized);
   }
-  // -regalloc=default or unspecified, so pick based on the optimization level
-  // or ask the target for the regalloc pass.
-  derived().addTargetRegisterAllocator(addPass, Optimized);
 }
 
 template <typename Derived, typename TargetMachineT>
diff --git a/llvm/include/llvm/Passes/MachinePassRegistry.def b/llvm/include/llvm/Passes/MachinePassRegistry.def
index 04a0da06fb6ec..94ce9cf25d6db 100644
--- a/llvm/include/llvm/Passes/MachinePassRegistry.def
+++ b/llvm/include/llvm/Passes/MachinePassRegistry.def
@@ -194,8 +194,8 @@ MACHINE_FUNCTION_PASS_WITH_PARAMS(
 MACHINE_FUNCTION_PASS_WITH_PARAMS(
     "branch-folder", "BranchFolderPass",
     [](bool EnableTailMerge) { return BranchFolderPass(EnableTailMerge); },
-    [](StringRef Params) {
-      return parseSinglePassOption(Params, "enable-tail-merge",
+    [](StringRef Params, const PassBuilder &) {
+      return PassBuilder::parseSinglePassOption(Params, "enable-tail-merge",
                                    "BranchFolderPass");
     },
     "enable-tail-merge")
@@ -205,8 +205,8 @@ MACHINE_FUNCTION_PASS_WITH_PARAMS(
     [](bool ShouldEmitDebugEntryValues) {
       return LiveDebugValuesPass(ShouldEmitDebugEntryValues);
     },
-    [](StringRef Params) {
-      return parseSinglePassOption(Params, "emit-debug-entry-values",
+    [](StringRef Params, const PassBuilder &) {
+      return PassBuilder::parseSinglePassOption(Params, "emit-debug-entry-values",
                                    "LiveDebugValuesPass");
     },
     "emit-debug-entry-values")
@@ -219,27 +219,36 @@ MACHINE_FUNCTION_PASS_WITH_PARAMS(
     parseMachineSinkingPassOptions, "enable-sink-fold")
 
 MACHINE_FUNCTION_PASS_WITH_PARAMS(
+    "virt-reg-rewriter", "VirtRegRewriterPass",
+    [](bool ClearVirtRegs) { return VirtRegRewriterPass(ClearVirtRegs); },
+    parseVirtRegRewriterPassOptions, "no-clear-vregs;clear-vregs")
+
+#ifndef RA_PASS_WITH_PARAMS
+// Define MachineFunction passes that are register allocators.
+// This is to differentiate them from other MachineFunction passes
+// to be used in the --regalloc-npm option.
+#define RA_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)          \
+  MACHINE_FUNCTION_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)
+#endif
+
+RA_PASS_WITH_PARAMS(
     "regallocfast", "RegAllocFastPass",
     [](RegAllocFastPass::Options Opts) { return RegAllocFastPass(Opts); },
-    [PB = this](StringRef Params) {
-      return parseRegAllocFastPassOptions(*PB, Params);
+    [](StringRef Params, const PassBuilder &PB) {
+      return parseRegAllocFastPassOptions(PB, Params);
     },
     "filter=reg-filter;no-clear-vregs")
 
 // 'all' is the default filter.
-MACHINE_FUNCTION_PASS_WITH_PARAMS(
+RA_PASS_WITH_PARAMS(
     "greedy", "RAGreedyPass",
     [](RAGreedyPass::Options Opts) { return RAGreedyPass(Opts); },
-    [PB = this](StringRef Params) {
-      return parseRegAllocGreedyFilterFunc(*PB, Params);
-    }, "reg-filter"
-)
-
-MACHINE_FUNCTION_PASS_WITH_PARAMS(
-    "virt-reg-rewriter", "VirtRegRewriterPass",
-    [](bool ClearVirtRegs) { return VirtRegRewriterPass(ClearVirtRegs); },
-    parseVirtRegRewriterPassOptions, "no-clear-vregs;clear-vregs")
+    [](StringRef Params, const PassBuilder &PB) {
+      return parseRegAllocGreedyFilterFunc(PB, Params);
+    },
+    "reg-filter")
 
+#undef RA_PASS_WITH_PARAMS
 #undef MACHINE_FUNCTION_PASS_WITH_PARAMS
 
 // After a pass is converted to new pass manager, its entry should be moved from
diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h
index 00d4874d5109b..2ad596c6c5739 100644
--- a/llvm/include/llvm/Passes/PassBuilder.h
+++ b/llvm/include/llvm/Passes/PassBuilder.h
@@ -18,6 +18,7 @@
 #include "llvm/Analysis/CGSCCPassManager.h"
 #include "llvm/CodeGen/MachinePassManager.h"
 #include "llvm/CodeGen/RegAllocCommon.h"
+#include "llvm/CodeGen/RegAllocGreedyPass.h"
 #include "llvm/IR/PassManager.h"
 #include "llvm/Passes/OptimizationLevel.h"
 #include "llvm/Support/Compiler.h"
@@ -409,7 +410,7 @@ class PassBuilder {
 
   /// Parse RegAllocFilterName to get RegAllocFilterFunc.
   LLVM_ABI std::optional<RegAllocFilterFunc>
-  parseRegAllocFilter(StringRef RegAllocFilterName);
+  parseRegAllocFilter(StringRef RegAllocFilterName) const;
 
   /// Print pass names.
   LLVM_ABI void printPassNames(raw_ostream &OS);
@@ -708,11 +709,13 @@ class PassBuilder {
   /// parameter list in a form of a custom parameters type, all wrapped into
   /// Expected<> template class.
   ///
-  template <typename ParametersParseCallableT>
+  template <typename ParametersParseCallableT, typename... ExtraArgs>
   static auto parsePassParameters(ParametersParseCallableT &&Parser,
-                                  StringRef Name, StringRef PassName)
-      -> decltype(Parser(StringRef{})) {
-    using ParametersT = typename decltype(Parser(StringRef{}))::value_type;
+                                  StringRef Name, StringRef PassName,
+                                  ExtraArgs &&...Args)
+      -> decltype(Parser(StringRef{}, std::forward<ExtraArgs>(Args)...)) {
+    using ParametersT = typename decltype(Parser(
+        StringRef{}, std::forward<ExtraArgs>(Args)...))::value_type;
 
     StringRef Params = Name;
     if (!Params.consume_front(PassName)) {
@@ -724,7 +727,8 @@ class PassBuilder {
       llvm_unreachable("invalid format for parametrized pass name");
     }
 
-    Expected<ParametersT> Result = Parser(Params);
+    Expected<ParametersT> Result =
+        Parser(Params, std::forward<ExtraArgs>(Args)...);
     assert((Result || Result.template errorIsA<StringError>()) &&
            "Pass parameter parser can only return StringErrors.");
     return Result;
@@ -1000,6 +1004,19 @@ class NoOpLoopAnalysis : public AnalysisInfoMixin<NoOpLoopAnalysis> {
 
 /// Common option used by multiple tools to print pipeline passes
 LLVM_ABI extern cl::opt<bool> PrintPipelinePasses;
+
+Expected<RAGreedyPass::Options>
+parseRegAllocGreedyFilterFunc(const PassBuilder &PB, StringRef Params);
+
+Expected<RegAllocFastPass::Options>
+parseRegAllocFastPassOptions(const PassBuilder &PB, StringRef Params);
+
+Expected<bool> parseMachineSinkingPassOptions(StringRef Params,
+                                              const PassBuilder &);
+Expected<bool> parseMachineBlockPlacementPassOptions(StringRef Params,
+                                                     const PassBuilder &);
+Expected<bool> parseVirtRegRewriterPassOptions(StringRef Params,
+                                               const PassBuilder &);
 }
 
 #endif
diff --git a/llvm/include/llvm/Passes/TargetPassRegistry.inc b/llvm/include/llvm/Passes/TargetPassRegistry.inc
index 068b27794191c..b50857eca31b6 100644
--- a/llvm/include/llvm/Passes/TargetPassRegistry.inc
+++ b/llvm/include/llvm/Passes/TargetPassRegistry.inc
@@ -83,7 +83,7 @@ if (PIC) {
 
 #define ADD_PASS_WITH_PARAMS(NAME, CREATE_PASS, PARSER)                        \
   if (PassBuilder::checkParametrizedPassName(Name, NAME)) {                    \
-    auto Params = PassBuilder::parsePassParameters(PARSER, Name, NAME);        \
+    auto Params = PassBuilder::parsePassParameters(PARSER, Name, NAME, PB);    \
     if (!Params) {                                                             \
       errs() << NAME ": " << toString(Params.takeError()) << '\n';             \
       return false;                                                            \
diff --git a/llvm/include/llvm/Target/CGPassBuilderOption.h b/llvm/include/llvm/Target/CGPassBuilderOption.h
index 54bee9de7a093..d2c72351c60d4 100644
--- a/llvm/include/llvm/Target/CGPassBuilderOption.h
+++ b/llvm/include/llvm/Target/CGPassBuilderOption.h
@@ -79,7 +79,7 @@ struct CGPassBuilderOption {
   bool RequiresCodeGenSCCOrder = false;
 
   RunOutliner EnableMachineOutliner = RunOutliner::TargetDefault;
-  RegAllocType RegAlloc = RegAllocType::Unset;
+  mutable StringRef RegAllocPipeline;
   std::optional<GlobalISelAbortMode> EnableGlobalISelAbort;
   std::string FSProfileFile;
   std::string FSRemappingFile;
diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h
index d0fd483a8ddaa..41afd28a20b74 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -487,8 +487,9 @@ class LLVM_ABI TargetMachine {
 
   virtual Error buildCodeGenPipeline(ModulePassManager &, raw_pwrite_stream &,
                                      raw_pwrite_stream *, CodeGenFileType,
-                                     const CGPassBuilderOption &,
-                                     PassInstrumentationCallbacks *) {
+                                     const CGPassBuilderOption &, MCContext &,
+                                     PassInstrumentationCallbacks *,
+                                     PassBuilder &) {
     return make_error<StringError>("buildCodeGenPipeline is not overridden",
                                    inconvertibleErrorCode());
   }
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index f5281ea69b512..d2c16d4085fcd 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -1545,39 +1545,6 @@ Expected<SmallVector<std::string, 0>> parseInternalizeGVs(StringRef Params) {
   return Expected<SmallVector<std::string, 0>>(std::move(PreservedGVs));
 }
 
-Expected<RegAllocFastPass::Options>
-parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) {
-  RegAllocFastPass::Options Opts;
-  while (!Params.empty()) {
-    StringRef ParamName;
-    std::tie(ParamName, Params) = Params.split(';');
-
-    if (ParamName.consume_front("filter=")) {
-      std::optional<RegAllocFilterFunc> Filter =
-          PB.parseRegAllocFilter(ParamName);
-      if (!Filter) {
-        return make_error<StringError>(
-            formatv("invalid regallocfast register filter '{}'", ParamName)
-                .str(),
-            inconvertibleErrorCode());
-      }
-      Opts.Filter = *Filter;
-      Opts.FilterName = ParamName;
-      continue;
-    }
-
-    if (ParamName == "no-clear-vregs") {
-      Opts.ClearVRegs = false;
-      continue;
-    }
-
-    return make_error<StringError>(
-        formatv("invalid regallocfast pass parameter '{}'", ParamName).str(),
-        inconvertibleErrorCode());
-  }
-  return Opts;
-}
-
 Expected<BoundsCheckingPass::Options>
 parseBoundsCheckingOptions(StringRef Params) {
   BoundsCheckingPass::Options Options;
@@ -1632,6 +1599,7 @@ parseBoundsCheckingOptions(StringRef Params) {
   }
   return Options;
 }
+} // namespace
 
 Expected<CodeGenOptLevel> parseExpandFpOptions(StringRef Param) {
   if (Param.empty())
@@ -1668,12 +1636,15 @@ parseRegAllocGreedyFilterFunc(PassBuilder &PB, StringRef Params) {
       inconvertibleErrorCode());
 }
 
-Expected<bool> parseMachineSinkingPassOptions(StringRef Params) {
+Expected<bool> llvm::parseMachineSinkingPassOptions(StringRef Params,
+                                              const PassBuilder &) {
   return PassBuilder::parseSinglePassOption(Params, "enable-sink-fold",
                                             "MachineSinkingPass");
 }
 
-Expected<bool> parseMachineBlockPlacementPassOptions(StringRef Params) {
+Expected<bool>
+llvm::parseMachineBlockPlacementPassOptions(StringRef Params,
+                                            const PassBuilder &) {
   bool AllowTailMerge = true;
   if (!Params.empty()) {
     AllowTailMerge = !Params.consume_front("no-");
@@ -1686,7 +1657,8 @@ Expected<bool> parseMachineBlockPlacementPassOptions(StringRef Params) {
   return AllowTailMerge;
 }
 
-Expected<bool> parseVirtRegRewriterPassOptions(StringRef Params) {
+Expected<bool> llvm::parseVirtRegRewriterPassOptions(StringRef Params,
+                                                     const PassBuilder &) {
   bool ClearVirtRegs = true;
   if (!Params.empty()) {
     ClearVirtRegs = !Params.consume_front("no-");
@@ -1698,6 +1670,53 @@ Expected<bool> parseVirtRegRewriterPassOptions(StringRef Params) {
   return ClearVirtRegs;
 }
 
+Expected<RegAllocFastPass::Options>
+llvm::parseRegAllocFastPassOptions(const PassBuilder &PB, StringRef Params) {
+  RegAllocFastPass::Options Opts;
+  while (!Params.empty()) {
+    StringRef ParamName;
+    std::tie(ParamName, Params) = Params.split(';');
+
+    if (ParamName.consume_front("filter=")) {
+      std::optional<RegAllocFilterFunc> Filter =
+          PB.parseRegAllocFilter(ParamName);
+      if (!Filter) {
+        return make_error<StringError>(
+            formatv("invalid regallocfast register filter '{0}' ", ParamName)
+                .str(),
+            inconvertibleErrorCode());
+      }
+      Opts.Filter = *Filter;
+      Opts.FilterName = ParamName;
+      continue;
+    }
+
+    if (ParamName == "no-clear-vregs") {
+      Opts.ClearVRegs = false;
+      continue;
+    }
+
+    return make_error<StringError>(
+        formatv("invalid regallocfast pass parameter '{0}' ", ParamName).str(),
+        inconvertibleErrorCode());
+  }
+  return Opts;
+}
+
+Expected<RAGreedyPass::Options>
+llvm::parseRegAllocGreedyFilterFunc(const PassBuilder &PB, StringRef Params) {
+  if (Params.empty() || Params == "all")
+    return RAGreedyPass::Options();
+
+  std::optional<RegAllocFilterFunc> Filter = PB.parseRegAllocFilter(Params);
+  if (Filter)
+    return RAGreedyPass::Options{*Filter, Params};
+
+  return make_error<StringError>(
+      formatv("invalid regallocgreedy register filter '{0}' ", Params).str(),
+      inconvertibleErrorCode());
+}
+
 struct FatLTOOptions {
   OptimizationLevel OptLevel;
   bool ThinLTO = false;
@@ -1733,8 +1752,6 @@ Expected<FatLTOOptions> parseFatLTOOptions(StringRef Params) {
   return Result;
 }
 
-} // namespace
-
 /// Tests whether registered callbacks will accept a given pass name.
 ///
 /// When parsing a pipeline text, the type of the outermost pipeline may be
@@ -2478,7 +2495,8 @@ Error PassBuilder::parseMachinePass(MachineFunctionPassManager &MFPM,
 #define MACHINE_FUNCTION_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER,    \
                                           PARAMS)                              \
   if (checkParametrizedPassName(Name, NAME)) {                                 \
-    auto Params = parsePassParameters(PARSER, Name, NAME);                     \
+    auto Params = parsePassParameters(PARSER, Name, NAME,                      \
+                                      const_cast<const PassBuilder &>(*this)); \
     if (!Params)                                                               \
       return Params.takeError();                                               \
     MFPM.addPass(CREATE_PASS(Params.get()));                                   \
@@ -2744,7 +2762,7 @@ Error PassBuilder::parseAAPipeline(AAManager &AA, StringRef PipelineText) {
 }
 
 std::optional<RegAllocFilterFunc>
-PassBuilder::parseRegAllocFilter(StringRef FilterName) {
+PassBuilder::parseRegAllocFilter(StringRef FilterName) const {
   if (FilterName == "all")
     return nullptr;
   for (auto &C : RegClassFilterParsingCallbacks)
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
index 8a831f7915882..279d66f4d969d 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
@@ -140,7 +140,8 @@ class AMDGPUCodeGenPassBuilder
 public:
   AMDGPUCodeGenPassBuilder(GCNTargetMachine &TM,
                            const CGPassBuilderOption &Opts,
-                           PassInstrumentationCallbacks *PIC);
+                           PassInstrumentationCallbacks *PIC,
+                           PassBuilder &PB);
 
   void addIRPasses(AddIRPass &) const;
   void addCodeGenPrepare(AddIRPass &) const;
@@ -817,7 +818,7 @@ void AMDGPUTargetMachine::registerDefaultAliasAnalyses(AAManager &AAM) {
 }
 
 static Expected<ScanOptions>
-parseAMDGPUAtomicOptimizerStrategy(StringRef Params) {
+parseAMDGPUAtomicOptimizerStrategy(StringRef Params, const PassBuilder &) {
   if (Params.empty())
     return ScanOptions::Iterative;
   Params.consume_front("strategy=");
@@ -831,8 +832,8 @@ parseAMDGPUAtomicOptimizerStrategy(StringRef Params) {
   return make_error<StringError>("invalid parameter", inconvertibleErrorCode());
 }
 
-Expected<AMDGPUAttributorOptions>
-parseAMDGPUAttributorPassOptions(StringRef Params) {
+static Expected<AMDGPUAttributorOptions>
+parseAMDGPUAttributorPassOptions(StringRef Params, const PassBuilder &PB) {
   AMDGPUAttributorOptions Result;
   while (!Params.empty()) {
     StringRef ParamName;
@@ -1159,10 +1160,10 @@ GCNTargetMachine::getTargetTransformInfo(const Function &F) const {
 
 Error GCNTargetMachine::buildCodeGenPipeline(
     ModulePassManager &MPM, raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut,
-    CodeGenFileType FileType, const CGPassBuilderOption &Opts,
-    PassInstrumentationCallbacks *PIC) {
-  AMDGPUCodeGenPassBuilder CGPB(*this, Opts, PIC);
-  return CGPB.buildPipeline(MPM, Out, DwoOut, FileType);
+    CodeGenFileType FileType, const CGPassBuilderOption &Opts, MCContext &Ctx,
+    PassInstrumentationCallbacks *PIC, PassBuilder &PB) {
+  AMDGPUCodeGenPassBuilder CGPB(*this, Opts, PIC, PB);
+  return CGPB.buildPipeline(MPM, Out, DwoOut, FileType, Ctx);
 }
 
 ScheduleDAGInstrs *
@@ -2089,8 +2090,8 @@ bool GCNTargetMachine::parseMachineFunctionInfo(
 
 AMDGPUCodeGenPassBuilder::AMDGPUCodeGenPassBuilder(
     GCNTargetMachine &TM, const CGPassBuilderOption &Opts,
-    PassInstrumentationCallbacks *PIC)
-    : CodeGenPassBuilder(TM, Opts, PIC) {
+    PassInstrumentationCallbacks *PIC, PassBuilder &PB)
+    : CodeGenPassBuilder(TM, Opts, PIC, PB) {
   Opt.MISchedPostRA = true;
   Opt.RequiresCodeGenSCCOrder = true;
   // Exceptions and StackMaps are not supported, so these passes will never do
@@ -2341,7 +2342,8 @@ Error AMDGPUCodeGenPassBuilder::addRegAssignmentOptimized(
 
   addPass(GCNPreRALongBranchRegPass());
 
-  addPass(RAGreedyPass({onlyAllocateSGPRs, "sgpr"}));
+  addRegAllocPassOrOpt(
+      addPass, []() { return RAGreedyPass({onlyAllocateSGPRs, "sgpr"}); });
 
   // Commit allocated register changes. This is mostly necessary because too
   // many things rely on the use lists of the physical registers, such as the
@@ -2361,14 +2363,15 @@ Error AMDGPUCodeGenPassBuilder::addRegAssignmentOptimized(
   addPass(SIPreAllocateWWMRegsPass());
 
   // For allocating other wwm register operands.
-  addPass(RAGreedyPass({onlyAllocateWWMRegs, "wwm"}));
+  addRegAllocPassOrOpt(
+      addPass, []() { return RAGreedyPass({onlyAllocateWWMRegs, "wwm"}); });
   addPass(SILowerWWMCopiesPass());
   addPass(VirtRegRewriterPass(false));
   addPass(AMDGPUReserveWWMRegsPass());
 
   // For allocating per-thread VGPRs.
-  addPass(RAGreedyPass({onlyAllocateVGPRs, "vgpr"}));
-
+  addRegAllocPassOrOpt(
+      addPass, []() { return RAGreedyPass({onlyAllocateVGPRs, "vgpr"}); });
 
   addPreRewrite(addPass);
   addPass(VirtRegRewriterPass(true));
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h
index 06a3047196b8a..34e7a189291ed 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h
@@ -100,8 +100,9 @@ class GCNTargetMachine final : public AMDGPUTargetMachine {
   Error buildCodeGenPipeline(ModulePassManager &MPM, raw_pwrite_stream &Out,
                              raw_pwrite_stream *DwoOut,
                              CodeGenFileType FileType,
-                             const CGPassBuilderOption &Opts,
-                             PassInstrumentationCallbacks *PIC) override;
+                             const CGPassBuilderOption &Opts, MCContext &Ctx,
+                             PassInstrumentationCallbacks *PIC,
+                             PassBuilder &) override;
 
   void registerMachineRegisterInfoCallback(MachineFunction &MF) const override;
 
diff --git a/llvm/lib/Target/AMDGPU/R600TargetMachine.cpp b/llvm/lib/Target/AMDGPU/R600TargetMachine.cpp
index c20487ebd8fc9..8ac8d3addb374 100644
--- a/llvm/lib/Target/AMDGPU/R600TargetMachine.cpp
+++ b/llvm/lib/Target/AMDGPU/R600TargetMachine.cpp
@@ -55,7 +55,7 @@ class R600CodeGenPassBuilder
     : public CodeGenPassBuilder<R600CodeGenPassBuilder, R600TargetMachine> {
 public:
   R600CodeGenPassBuilder(R600TargetMachine &TM, const CGPassBuilderOption &Opts,
-                         PassInstrumentationCallbacks *PIC);
+                         PassInstrumentationCallbacks *PIC,  PassBuilder &PB);
 
   void addPreISel(AddIRPass &addPass) const;
   void addAsmPrinter(AddMachinePass &, CreateMCStreamer) const;
@@ -164,10 +164,10 @@ TargetPassConfig *R600TargetMachine::createPassConfig(PassManagerBase &PM) {
 
 Error R600TargetMachine::buildCodeGenPipeline(
     ModulePassManager &MPM, raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut,
-    CodeGenFileType FileType, const CGPassBuilderOption &Opts,
-    PassInstrumentationCallbacks *PIC) {
-  R600CodeGenPassBuilder CGPB(*this, Opts, PIC);
-  return CGPB.buildPipeline(MPM, Out, DwoOut, FileType);
+    CodeGenFileType FileType, const CGPassBuilderOption &Opts, MCContext &Ctx,
+    PassInstrumentationCallbacks *PIC, PassBuilder &PB) {
+  R600CodeGenPassBuilder CGPB(*this, Opts, PIC, PB);
+  return CGPB.buildPipeline(MPM, Out, DwoOut, FileType, Ctx);
 }
 
 MachineFunctionInfo *R600TargetMachine::createMachineFunctionInfo(
@@ -183,8 +183,8 @@ MachineFunctionInfo *R600TargetMachine::createMachineFunctionInfo(
 
 R600CodeGenPassBuilder::R600CodeGenPassBuilder(
     R600TargetMachine &TM, const CGPassBuilderOption &Opts,
-    PassInstrumentationCallbacks *PIC)
-    : CodeGenPassBuilder(TM, Opts, PIC) {
+    PassInstrumentationCallbacks *PIC, PassBuilder &PB)
+    : CodeGenPassBuilder(TM, Opts, PIC, PB) {
   Opt.RequiresCodeGenSCCOrder = true;
 }
 
diff --git a/llvm/lib/Target/AMDGPU/R600TargetMachine.h b/llvm/lib/Target/AMDGPU/R600TargetMachine.h
index 7985ef136cead..b4ef4aaef4490 100644
--- a/llvm/lib/Target/AMDGPU/R600TargetMachine.h
+++ b/llvm/lib/Target/AMDGPU/R600TargetMachine.h
@@ -41,8 +41,9 @@ class R600TargetMachine final : public AMDGPUTargetMachine {
   Error buildCodeGenPipeline(ModulePassManager &MPM, raw_pwrite_stream &Out,
                              raw_pwrite_stream *DwoOut,
                              CodeGenFileType FileType,
-                             const CGPassBuilderOption &Opt,
-                             PassInstrumentationCallbacks *PIC) override;
+                             const CGPassBuilderOption &Opt, MCContext &Ctx,
+                             PassInstrumentationCallbacks *PIC,
+                             PassBuilder &) override;
 
   const TargetSubtargetInfo *getSubtargetImpl(const Function &) const override;
 
diff --git a/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp
index ad3df2c879fe7..0bcfdb5f53855 100644
--- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp
+++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp
@@ -114,7 +114,8 @@ TargetPassConfig *BPFTargetMachine::createPassConfig(PassManagerBase &PM) {
   return new BPFPassConfig(*this, PM);
 }
 
-static Expected<bool> parseBPFPreserveStaticOffsetOptions(StringRef Params) {
+static Expected<bool> parseBPFPreserveStaticOffsetOptions(StringRef Params,
+                                                          const PassBuilder &) {
   return PassBuilder::parseSinglePassOption(Params, "allow-partial",
                                             "BPFPreserveStaticOffsetPass");
 }
diff --git a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
index 2c0443da673a8..864cdc0b4547a 100644
--- a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
@@ -27,13 +27,27 @@ class X86CodeGenPassBuilder
 public:
   explicit X86CodeGenPassBuilder(X86TargetMachine &TM,
                                  const CGPassBuilderOption &Opts,
-                                 PassInstrumentationCallbacks *PIC)
-      : CodeGenPassBuilder(TM, Opts, PIC) {}
+                                 PassInstrumentationCallbacks *PIC,
+                                 PassBuilder &PB)
+      : CodeGenPassBuilder(TM, Opts, PIC, PB) {}
+  using Base = CodeGenPassBuilder<X86CodeGenPassBuilder, X86TargetMachine>;
   void addPreISel(AddIRPass &addPass) const;
   void addAsmPrinter(AddMachinePass &, CreateMCStreamer) const;
   Error addInstSelector(AddMachinePass &) const;
+  Error addRegAssignmentOptimized(AddMachinePass &addPass) const;
 };
 
+Error X86CodeGenPassBuilder::addRegAssignmentOptimized(
+    AddMachinePass &addPass) const {
+  if (EnableTileRAPass) {
+    addRegAllocPassOrOpt(addPass, []() {
+      return RAGreedyPass({onlyAllocateTileRegisters, "tile-reg"});
+    });
+    // TODO: addPass(X86TileConfigPass());
+  }
+  return Base::addRegAssignmentOptimized(addPass);
+}
+
 void X86CodeGenPassBuilder::addPreISel(AddIRPass &addPass) const {
   // TODO: Add passes pre instruction selection.
 }
@@ -54,12 +68,20 @@ Error X86CodeGenPassBuilder::addInstSelector(AddMachinePass &addPass) const {
 void X86TargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
 #define GET_PASS_REGISTRY "X86PassRegistry.def"
 #include "llvm/Passes/TargetPassRegistry.inc"
+
+PB.registerRegClassFilterParsingCallback(
+      [](StringRef FilterName) -> RegAllocFilterFunc {
+        if (FilterName == "tile-reg") {
+          return onlyAllocateTileRegisters;
+        }
+        return nullptr;
+      });
 }
 
 Error X86TargetMachine::buildCodeGenPipeline(
     ModulePassManager &MPM, raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut,
-    CodeGenFileType FileType, const CGPassBuilderOption &Opt,
-    PassInstrumentationCallbacks *PIC) {
-  auto CGPB = X86CodeGenPassBuilder(*this, Opt, PIC);
-  return CGPB.buildPipeline(MPM, Out, DwoOut, FileType);
+    CodeGenFileType FileType, const CGPassBuilderOption &Opt, MCContext &Ctx,
+    PassInstrumentationCallbacks *PIC, PassBuilder &PB) {
+  auto CGPB = X86CodeGenPassBuilder(*this, Opt, PIC, PB);
+  return CGPB.buildPipeline(MPM, Out, DwoOut, FileType, Ctx);
 }
diff --git a/llvm/lib/Target/X86/X86TargetMachine.cpp b/llvm/lib/Target/X86/X86TargetMachine.cpp
index 713df63479987..dab5d53402722 100644
--- a/llvm/lib/Target/X86/X86TargetMachine.cpp
+++ b/llvm/lib/Target/X86/X86TargetMachine.cpp
@@ -56,11 +56,10 @@ using namespace llvm;
 static cl::opt<bool> EnableMachineCombinerPass("x86-machine-combiner",
                                cl::desc("Enable the machine combiner pass"),
                                cl::init(true), cl::Hidden);
-
-static cl::opt<bool>
-    EnableTileRAPass("x86-tile-ra",
-                     cl::desc("Enable the tile register allocation pass"),
-                     cl::init(true), cl::Hidden);
+cl::opt<bool>
+    llvm::EnableTileRAPass("x86-tile-ra",
+                           cl::desc("Enable the tile register allocation pass"),
+                           cl::init(true), cl::Hidden);
 
 extern "C" LLVM_C_ABI void LLVMInitializeX86Target() {
   // Register the target.
@@ -635,9 +634,9 @@ std::unique_ptr<CSEConfigBase> X86PassConfig::getCSEConfig() const {
   return getStandardCSEConfigForOpt(TM->getOptLevel());
 }
 
-static bool onlyAllocateTileRegisters(const TargetRegisterInfo &TRI,
-                                      const MachineRegisterInfo &MRI,
-                                      const Register Reg) {
+bool llvm::onlyAllocateTileRegisters(const TargetRegisterInfo &TRI,
+                                     const MachineRegisterInfo &MRI,
+                                     const Register Reg) {
   const TargetRegisterClass *RC = MRI.getRegClass(Reg);
   return static_cast<const X86RegisterInfo &>(TRI).isTileRegisterClass(RC);
 }
diff --git a/llvm/lib/Target/X86/X86TargetMachine.h b/llvm/lib/Target/X86/X86TargetMachine.h
index ced0a9c71fdd8..47c75c1b4d48b 100644
--- a/llvm/lib/Target/X86/X86TargetMachine.h
+++ b/llvm/lib/Target/X86/X86TargetMachine.h
@@ -22,9 +22,15 @@
 
 namespace llvm {
 
+extern cl::opt<bool> EnableTileRAPass;
+
 class StringRef;
 class TargetTransformInfo;
 
+bool onlyAllocateTileRegisters(const TargetRegisterInfo &TRI,
+                               const MachineRegisterInfo &MRI,
+                               const Register Reg);
+
 class X86TargetMachine final : public CodeGenTargetMachineImpl {
   std::unique_ptr<TargetLoweringObjectFile> TLOF;
   mutable StringMap<std::unique_ptr<X86Subtarget>> SubtargetMap;
@@ -73,8 +79,9 @@ class X86TargetMachine final : public CodeGenTargetMachineImpl {
 
   Error buildCodeGenPipeline(ModulePassManager &, raw_pwrite_stream &,
                              raw_pwrite_stream *, CodeGenFileType,
-                             const CGPassBuilderOption &,
-                             PassInstrumentationCallbacks *) override;
+                             const CGPassBuilderOption &, MCContext &,
+                             PassInstrumentationCallbacks *,
+                             PassBuilder &) override;
 
   bool isJIT() const { return IsJIT; }
 
diff --git a/llvm/test/tools/llc/new-pm/regalloc-amdgpu.mir b/llvm/test/tools/llc/new-pm/regalloc-amdgpu.mir
index 07f2d350ffd9c..7c8b9a9e04dc1 100644
--- a/llvm/test/tools/llc/new-pm/regalloc-amdgpu.mir
+++ b/llvm/test/tools/llc/new-pm/regalloc-amdgpu.mir
@@ -2,11 +2,16 @@
 # RUN: llc -mtriple=amdgcn --passes='regallocfast<filter=sgpr>,regallocfast<filter=wwm>,regallocfast<filter=vgpr>' --print-pipeline-passes --filetype=null %s | FileCheck %s --check-prefix=PASS
 # RUN: not llc -mtriple=amdgcn --passes='regallocfast<filter=bad-filter>' --print-pipeline-passes --filetype=null %s 2>&1 | FileCheck %s --check-prefix=BAD-FILTER
 
+# RUN: llc -mtriple=amdgcn -enable-new-pm --regalloc-npm="regallocfast<filter=sgpr;no-clear-vregs>,greedy<wwm>" --print-pipeline-passes --filetype=null %s | FileCheck %s --check-prefix=RA-NPM
+
 # PASS: regallocfast<filter=sgpr>
 # PASS: regallocfast<filter=wwm>
 # PASS: regallocfast<filter=vgpr>
 # BAD-FILTER: invalid regallocfast register filter 'bad-filter'
 
+# RA-NPM: regallocfast<filter=sgpr;no-clear-vregs>
+# RA-NPM: greedy<wwm>
+# RA-NPM: greedy<vgpr>
 ---
 name: f
 ...
diff --git a/llvm/test/tools/llc/new-pm/x86_64-regalloc-pipeline.mir b/llvm/test/tools/llc/new-pm/x86_64-regalloc-pipeline.mir
index 7a50bcaf212c7..6de98c5f14f26 100644
--- a/llvm/test/tools/llc/new-pm/x86_64-regalloc-pipeline.mir
+++ b/llvm/test/tools/llc/new-pm/x86_64-regalloc-pipeline.mir
@@ -1,6 +1,28 @@
 # REQUIRES: x86-registered-target
-# RUN: llc -mtriple=x86_64-unknown-linux-gnu -enable-new-pm -O3 -regalloc-npm=fast -print-pipeline-passes %s -o - 2>&1 | FileCheck %s
-# RUN: llc -mtriple=x86_64-unknown-linux-gnu -enable-new-pm -O3 -regalloc-npm=greedy -print-pipeline-passes %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-GREEDY
+# Test default pipeline
+# RUN: llc -mtriple=x86_64-unknown-linux-gnu -enable-new-pm -O3 -print-pipeline-passes %s -o - 2>&1 | FileCheck %s
 
-# CHECK: regallocfast
+# Test the -regalloc-npm option
+# RUN: llc -mtriple=x86_64-unknown-linux-gnu -enable-new-pm -O3 -regalloc-npm=regallocfast -print-pipeline-passes %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-FAST
+
+# RUN: llc -mtriple=x86_64-unknown-linux-gnu -enable-new-pm -O3 -regalloc-npm='greedy<tile-reg>' -print-pipeline-passes %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-GREEDY-FILTER
+
+# This test attempts to bypass the tile register filter pass, inserts the default greedy<all> pass and then 
+# attempts to insert an extraneous pass.
+# RUN: not llc -mtriple=x86_64-unknown-linux-gnu -enable-new-pm -O3 -regalloc-npm='default,default,basic' 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
+
+# RUN: not llc -mtriple=x86_64-unknown-linux-gnu -enable-new-pm -O3 -regalloc-npm='machine-cp' -print-pipeline-passes %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID
+# RUN: not llc -mtriple=x86_64-unknown-linux-gnu -enable-new-pm -passes='machine-sink' -regalloc-npm='greedy' -print-pipeline-passes %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-BOTH-INVALID
+
+# RUN: not llc -mtriple=x86_64-unknown-linux-gnu -enable-new-pm -O0 -regalloc-npm='greedy' -print-pipeline-passes %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-ONLY-FAST
+
+# CHECK: greedy<tile-reg>
+# CHECK: greedy<all>
+
+# CHECK-FAST: regallocfast
 # CHECK-GREEDY: greedy<all>
+# CHECK-GREEDY-FILTER: greedy<tile-reg>
+# CHECK-ERROR: extra passes in regalloc pipeline: basic
+# CHECK-INVALID: unknown register allocator pass: machine-cp
+# CHECK-BOTH-INVALID: --passes and --regalloc-npm cannot be used together
+# CHECK-ONLY-FAST: expected regallocfast in option --regalloc-npm
diff --git a/llvm/tools/llc/NewPMDriver.cpp b/llvm/tools/llc/NewPMDriver.cpp
index 6d4989e278fc1..2caaf956e50c6 100644
--- a/llvm/tools/llc/NewPMDriver.cpp
+++ b/llvm/tools/llc/NewPMDriver.cpp
@@ -50,10 +50,11 @@
 
 using namespace llvm;
 
-static cl::opt<RegAllocType, false, RegAllocTypeParser>
-    RegAlloc("regalloc-npm",
-             cl::desc("Register allocator to use for new pass manager"),
-             cl::Hidden, cl::init(RegAllocType::Unset));
+static cl::opt<std::string> RegAllocPasses(
+    "regalloc-npm",
+    cl::desc("Register allocator pipeline for the new pass manager. Same as "
+             "--passes, but only regalloc passes can be used here."),
+    cl::Hidden);
 
 static cl::opt<bool>
     DebugPM("debug-pass-manager", cl::Hidden,
@@ -100,6 +101,11 @@ int llvm::compileModuleWithNewPM(
         << TargetPassConfig::getLimitedCodeGenPipelineReason() << ".\n";
     return 1;
   }
+  if (!PassPipeline.empty() && !RegAllocPasses.empty()) {
+    WithColor::error(errs(), Arg0)
+        << "--passes and --regalloc-npm cannot be used together.\n";
+    return 1;
+  }
 
   raw_pwrite_stream *OS = &Out->os();
 
@@ -114,7 +120,7 @@ int llvm::compileModuleWithNewPM(
   CGPassBuilderOption Opt = getCGPassBuilderOption();
   Opt.DisableVerify = VK != VerifierKind::InputOutput;
   Opt.DebugPM = DebugPM;
-  Opt.RegAlloc = RegAlloc;
+  Opt.RegAllocPipeline = RegAllocPasses;
 
   MachineModuleInfo MMI(Target.get());
 
@@ -173,8 +179,9 @@ int llvm::compileModuleWithNewPM(
     MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
 
   } else {
-    ExitOnErr(Target->buildCodeGenPipeline(
-        MPM, *OS, DwoOut ? &DwoOut->os() : nullptr, FileType, Opt, &PIC));
+    ExitOnErr(
+        Target->buildCodeGenPipeline(MPM, *OS, DwoOut ? &DwoOut->os() : nullptr,
+                                     FileType, Opt, MMI.getContext(), &PIC, PB));
   }
 
   // If user only wants to print the pipeline, print it before parsing the MIR.

>From 3f84dc4b87e4e8e3453a1bf71255efd2f3e8a165 Mon Sep 17 00:00:00 2001
From: Teja Alaghari <teja.alaghari at amd.com>
Date: Tue, 16 Dec 2025 19:54:10 +0530
Subject: [PATCH 2/2] [NFC] Cleanup and formatting fixes

- Add missing "PassBuilder.h" header in CodeGenPassBuilder.h
- Add MCContext& parameter to buildPipeline() for consistency with
  buildCodeGenPipeline() API
- Remove unused mutable PrinterImpl member
- Fix formatting
---
 llvm/include/llvm/Passes/CodeGenPassBuilder.h  | 8 ++++----
 llvm/lib/Passes/PassBuilder.cpp                | 2 +-
 llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp | 3 +--
 llvm/lib/Target/AMDGPU/R600TargetMachine.cpp   | 2 +-
 llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp  | 2 +-
 llvm/tools/llc/NewPMDriver.cpp                 | 6 +++---
 6 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/llvm/include/llvm/Passes/CodeGenPassBuilder.h b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
index 8ac021cb369e7..d3b9bdbd807e6 100644
--- a/llvm/include/llvm/Passes/CodeGenPassBuilder.h
+++ b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
@@ -126,6 +126,7 @@
 #include "llvm/Transforms/Scalar/ScalarizeMaskedMemIntrin.h"
 #include "llvm/Transforms/Utils/CanonicalizeFreezeInLoops.h"
 #include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
+#include "llvm/Passes/PassBuilder.h"
 #include "llvm/Transforms/Utils/LowerInvoke.h"
 #include <cassert>
 #include <tuple>
@@ -193,8 +194,8 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
   }
 
   Error buildPipeline(ModulePassManager &MPM, raw_pwrite_stream &Out,
-                      raw_pwrite_stream *DwoOut,
-                      CodeGenFileType FileType) const;
+                      raw_pwrite_stream *DwoOut, CodeGenFileType FileType,
+                      MCContext &Ctx) const;
 
   PassInstrumentationCallbacks *getPassInstrumentationCallbacks() const {
     return PIC;
@@ -360,7 +361,6 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
   CGPassBuilderOption Opt;
   PassInstrumentationCallbacks *PIC;
   PassBuilder &PB;
-  mutable IntrusiveRefCntPtr<AsmPrinter> PrinterImpl;
 
   template <typename TMC> TMC &getTM() const { return static_cast<TMC &>(TM); }
   CodeGenOptLevel getOptLevel() const { return TM.getOptLevel(); }
@@ -635,7 +635,7 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
 template <typename Derived, typename TargetMachineT>
 Error CodeGenPassBuilder<Derived, TargetMachineT>::buildPipeline(
     ModulePassManager &MPM, raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut,
-    CodeGenFileType FileType) const {
+    CodeGenFileType FileType, MCContext &Ctx) const {
   auto StartStopInfo = TargetPassConfig::getStartStopInfo(*PIC);
   if (!StartStopInfo)
     return StartStopInfo.takeError();
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index d2c16d4085fcd..74a9559261032 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -1637,7 +1637,7 @@ parseRegAllocGreedyFilterFunc(PassBuilder &PB, StringRef Params) {
 }
 
 Expected<bool> llvm::parseMachineSinkingPassOptions(StringRef Params,
-                                              const PassBuilder &) {
+                                                    const PassBuilder &) {
   return PassBuilder::parseSinglePassOption(Params, "enable-sink-fold",
                                             "MachineSinkingPass");
 }
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
index 279d66f4d969d..9bc3c1ab668ff 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
@@ -140,8 +140,7 @@ class AMDGPUCodeGenPassBuilder
 public:
   AMDGPUCodeGenPassBuilder(GCNTargetMachine &TM,
                            const CGPassBuilderOption &Opts,
-                           PassInstrumentationCallbacks *PIC,
-                           PassBuilder &PB);
+                           PassInstrumentationCallbacks *PIC, PassBuilder &PB);
 
   void addIRPasses(AddIRPass &) const;
   void addCodeGenPrepare(AddIRPass &) const;
diff --git a/llvm/lib/Target/AMDGPU/R600TargetMachine.cpp b/llvm/lib/Target/AMDGPU/R600TargetMachine.cpp
index 8ac8d3addb374..d401e2d3f213e 100644
--- a/llvm/lib/Target/AMDGPU/R600TargetMachine.cpp
+++ b/llvm/lib/Target/AMDGPU/R600TargetMachine.cpp
@@ -55,7 +55,7 @@ class R600CodeGenPassBuilder
     : public CodeGenPassBuilder<R600CodeGenPassBuilder, R600TargetMachine> {
 public:
   R600CodeGenPassBuilder(R600TargetMachine &TM, const CGPassBuilderOption &Opts,
-                         PassInstrumentationCallbacks *PIC,  PassBuilder &PB);
+                         PassInstrumentationCallbacks *PIC, PassBuilder &PB);
 
   void addPreISel(AddIRPass &addPass) const;
   void addAsmPrinter(AddMachinePass &, CreateMCStreamer) const;
diff --git a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
index 864cdc0b4547a..e3a4c54d4e534 100644
--- a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
@@ -69,7 +69,7 @@ void X86TargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
 #define GET_PASS_REGISTRY "X86PassRegistry.def"
 #include "llvm/Passes/TargetPassRegistry.inc"
 
-PB.registerRegClassFilterParsingCallback(
+  PB.registerRegClassFilterParsingCallback(
       [](StringRef FilterName) -> RegAllocFilterFunc {
         if (FilterName == "tile-reg") {
           return onlyAllocateTileRegisters;
diff --git a/llvm/tools/llc/NewPMDriver.cpp b/llvm/tools/llc/NewPMDriver.cpp
index 2caaf956e50c6..c81836ef7e357 100644
--- a/llvm/tools/llc/NewPMDriver.cpp
+++ b/llvm/tools/llc/NewPMDriver.cpp
@@ -179,9 +179,9 @@ int llvm::compileModuleWithNewPM(
     MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
 
   } else {
-    ExitOnErr(
-        Target->buildCodeGenPipeline(MPM, *OS, DwoOut ? &DwoOut->os() : nullptr,
-                                     FileType, Opt, MMI.getContext(), &PIC, PB));
+    ExitOnErr(Target->buildCodeGenPipeline(
+        MPM, *OS, DwoOut ? &DwoOut->os() : nullptr, FileType, Opt,
+        MMI.getContext(), &PIC, PB));
   }
 
   // If user only wants to print the pipeline, print it before parsing the MIR.



More information about the llvm-commits mailing list