Skip to content

[CodeGen][NPM] Support generic regalloc-npm option #135149

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

optimisan
Copy link
Contributor

@optimisan optimisan commented Apr 10, 2025

This provides the option --regalloc-npm as an override to register allocation passes added. It accepts a list of passes, reusing the normal --passes syntax, as opposed to [Support AMDGPU regalloc options -sgpr-regalloc etc #129035]

Example: llc --regalloc-npm='default,default,regallocfast<filter=vgpr>' -O3 -mtriple=amdgcn
will only replace the vgpr greedy (which is default) with RAFast.

Note that the number of passes in this options should match the number of RA passes the pipeline adds by default. The special pass value "default" is to add the pipeline's default RAPass choice. Only register allocator passes can be added here (introduced new macro RA_PASS_WITH_PARAMS for this)

If the option contains less passes, the rest will be decided according to the opt level. It is an error to provide more passes than what the pipeline adds itself.

This patch also adds X86's tile-register filter support with the filter name tile-reg.

We don't really need the addTargetRegisterAllocator override: it is not used currently, but with a new TargetPassBuilder design we'll have something else anyway.

Copy link
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link

github-actions bot commented Apr 10, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@optimisan optimisan force-pushed the users/optimisan/generic-regalloc-option branch 3 times, most recently from ce260c8 to 89711d5 Compare April 10, 2025 10:12
@optimisan optimisan marked this pull request as ready for review April 10, 2025 10:19
@llvmbot
Copy link
Member

llvmbot commented Apr 10, 2025

@llvm/pr-subscribers-backend-x86

@llvm/pr-subscribers-backend-amdgpu

Author: Akshat Oke (optimisan)

Changes

This provides the option --regalloc-npm as an override to register allocation passes added. It accepts a list of passes, reusing the normal --passes syntax, as opposed to [Support AMDGPU regalloc options -sgpr-regalloc etc #129035]

Example: llc --regalloc-npm='default,default,regallocfast&lt;filter=vgpr&gt;' -O3 -mtriple=amdgcn
will only replace the vgpr greedy (which is default) with RAFast.

Note that the number of passes in this options should match the number of RA passes the pipeline adds by default. The special pass value "default" is to add the pipeline's default RAPass choice.

If the option contains less passes, the rest will be decided according to the opt level. It is an error to provide more passes than what the pipeline adds itself.

This patch also adds X86's tile-register filter support with the filter name tile-regs.


Patch is 37.59 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/135149.diff

18 Files Affected:

  • (modified) llvm/include/llvm/Passes/CodeGenPassBuilder.h (+67-17)
  • (modified) llvm/include/llvm/Passes/MachinePassRegistry.def (+8-8)
  • (modified) llvm/include/llvm/Passes/PassBuilder.h (+20-6)
  • (modified) llvm/include/llvm/Passes/TargetPassRegistry.inc (+1-1)
  • (modified) llvm/include/llvm/Target/CGPassBuilderOption.h (+1-1)
  • (modified) llvm/include/llvm/Target/TargetMachine.h (+2-1)
  • (modified) llvm/lib/Passes/PassBuilder.cpp (+54-51)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp (+45-7)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h (+4-2)
  • (modified) llvm/lib/Target/AMDGPU/R600TargetMachine.cpp (+4-4)
  • (modified) llvm/lib/Target/AMDGPU/R600TargetMachine.h (+3-2)
  • (modified) llvm/lib/Target/BPF/BPFTargetMachine.cpp (+2-1)
  • (modified) llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp (+25-4)
  • (modified) llvm/lib/Target/X86/X86TargetMachine.cpp (+7-8)
  • (modified) llvm/lib/Target/X86/X86TargetMachine.h (+8-1)
  • (modified) llvm/test/tools/llc/new-pm/regalloc-amdgpu.mir (+5)
  • (modified) llvm/test/tools/llc/new-pm/x86_64-regalloc-pipeline.mir (+16-2)
  • (modified) llvm/tools/llc/NewPMDriver.cpp (+4-4)
diff --git a/llvm/include/llvm/Passes/CodeGenPassBuilder.h b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
index 25ca982916ff8..8af5d9e51eddc 100644
--- a/llvm/include/llvm/Passes/CodeGenPassBuilder.h
+++ b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
@@ -96,6 +96,7 @@
 #include "llvm/IRPrinter/IRPrintingPasses.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Passes/PassBuilder.h"
 #include "llvm/Support/CodeGen.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Error.h"
@@ -113,6 +114,7 @@
 #include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
 #include "llvm/Transforms/Utils/LowerInvoke.h"
 #include <cassert>
+#include <tuple>
 #include <type_traits>
 #include <utility>
 
@@ -154,8 +156,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)
 
@@ -291,6 +294,7 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
   TargetMachineT &TM;
   CGPassBuilderOption Opt;
   PassInstrumentationCallbacks *PIC;
+  PassBuilder &PB;
 
   template <typename TMC> TMC &getTM() const { return static_cast<TMC &>(TM); }
   CodeGenOptLevel getOptLevel() const { return TM.getOptLevel(); }
@@ -498,6 +502,13 @@ 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.
+  bool addRegAllocPassFromOpt(AddMachinePass &,
+                              StringRef MatchPassTo = StringRef{}) const;
+  /// Add the next pass in the cli option, or return false if there is no pass
+  /// left in the option.
+  template <typename RegAllocPassT>
+  void addRegAllocPassOrOpt(AddMachinePass &, RegAllocPassT Pass) const;
 
   /// Add core register alloator passes which do the actual register assignment
   /// and rewriting. \returns true if any passes were added.
@@ -594,6 +605,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);
 }
 
@@ -1088,6 +1104,49 @@ void CodeGenPassBuilder<Derived, TargetMachineT>::addTargetRegisterAllocator(
     addPass(RegAllocFastPass());
 }
 
+template <typename Derived, typename TargetMachineT>
+template <typename RegAllocPassT>
+void CodeGenPassBuilder<Derived, TargetMachineT>::addRegAllocPassOrOpt(
+    AddMachinePass &addPass, RegAllocPassT Pass) const {
+  if (!addRegAllocPassFromOpt(addPass))
+    addPass(std::move(Pass));
+}
+
+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 MACHINE_FUNCTION_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.
@@ -1098,22 +1157,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:
-      report_fatal_error("register allocator not supported yet", false);
-    }
-    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 3e9e788662900..e5d3cdfb935a6 100644
--- a/llvm/include/llvm/Passes/MachinePassRegistry.def
+++ b/llvm/include/llvm/Passes/MachinePassRegistry.def
@@ -209,8 +209,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")
@@ -220,8 +220,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")
@@ -236,8 +236,8 @@ MACHINE_FUNCTION_PASS_WITH_PARAMS(
 MACHINE_FUNCTION_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")
 
@@ -245,8 +245,8 @@ MACHINE_FUNCTION_PASS_WITH_PARAMS(
 MACHINE_FUNCTION_PASS_WITH_PARAMS(
     "greedy", "RAGreedyPass",
     [](RAGreedyPass::Options Opts) { return RAGreedyPass(Opts); },
-    [PB = this](StringRef Params) {
-      return parseRegAllocGreedyFilterFunc(*PB, Params);
+    [](StringRef Params, const PassBuilder &PB) {
+      return parseRegAllocGreedyFilterFunc(PB, Params);
     }, "reg-filter"
 )
 #undef MACHINE_FUNCTION_PASS_WITH_PARAMS
diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h
index 51ccaa53447d7..ac494aef9aab8 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/Error.h"
@@ -397,7 +398,7 @@ class PassBuilder {
 
   /// Parse RegAllocFilterName to get RegAllocFilterFunc.
   std::optional<RegAllocFilterFunc>
-  parseRegAllocFilter(StringRef RegAllocFilterName);
+  parseRegAllocFilter(StringRef RegAllocFilterName) const;
 
   /// Print pass names.
   void printPassNames(raw_ostream &OS);
@@ -688,11 +689,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)) {
@@ -704,7 +707,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;
@@ -980,6 +984,16 @@ class NoOpLoopAnalysis : public AnalysisInfoMixin<NoOpLoopAnalysis> {
 /// Common option used by multiple tools to print pipeline passes
 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 &);
 }
 
 #endif
diff --git a/llvm/include/llvm/Passes/TargetPassRegistry.inc b/llvm/include/llvm/Passes/TargetPassRegistry.inc
index 521913cb25a4a..da9fa7242ab80 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 51f25c1360b87..96829fbd5f445 100644
--- a/llvm/include/llvm/Target/CGPassBuilderOption.h
+++ b/llvm/include/llvm/Target/CGPassBuilderOption.h
@@ -70,7 +70,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 27eeb415ed644..420078ffa4f46 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -469,7 +469,8 @@ class TargetMachine {
   virtual Error buildCodeGenPipeline(ModulePassManager &, raw_pwrite_stream &,
                                      raw_pwrite_stream *, CodeGenFileType,
                                      const CGPassBuilderOption &,
-                                     PassInstrumentationCallbacks *) {
+                                     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 5cda1517e127d..8aa9fee37f87d 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -1385,39 +1385,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 '{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<BoundsCheckingPass::Options>
 parseBoundsCheckingOptions(StringRef Params) {
   BoundsCheckingPass::Options Options;
@@ -1466,26 +1433,17 @@ parseBoundsCheckingOptions(StringRef Params) {
   return Options;
 }
 
-Expected<RAGreedyPass::Options>
-parseRegAllocGreedyFilterFunc(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());
-}
+} // namespace
 
-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-");
@@ -1498,8 +1456,52 @@ Expected<bool> parseMachineBlockPlacementPassOptions(StringRef Params) {
   return AllowTailMerge;
 }
 
-} // namespace
+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());
+}
 /// Tests whether a pass name starts with a valid prefix for a default pipeline
 /// alias.
 static bool startsWithDefaultPipelineAliasPrefix(StringRef Name) {
@@ -2218,7 +2220,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()));                                   \
@@ -2484,7 +2487,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 c2bcd53644371..b904751a95c96 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
@@ -767,7 +767,7 @@ void AMDGPUTargetMachine::registerDefaultAliasAnalyses(AAManager &AAM) {
 }
 
 static Expected<ScanOptions>
-parseAMDGPUAtomic...
[truncated]

@arsenm
Copy link
Contributor

arsenm commented Apr 10, 2025

--regalloc-npm='default,default,regallocfast<filter=vgpr>'

I think having a generalized pass builder syntax for this is overly expressive and it's not obvious to me how it interacts with a proper list of passes. Can you run other passes in here? What happens if you also have a separate passes argument?

@optimisan
Copy link
Contributor Author

--regalloc-npm='default,default,regallocfast<filter=vgpr>'

I think having a generalized pass builder syntax for this is overly expressive and it's not obvious to me how it interacts with a proper list of passes. Can you run other passes in here? What happens if you also have a separate passes argument?

Right now other passes can be run here (will need to add a way to mark a pass as a regalloc pass)
If -passes is used, this argument will be ignored.
Objective was to share the same logic instead of adding target-specific options like AMDGPU has.

@arsenm
Copy link
Contributor

arsenm commented Apr 13, 2025

Right now other passes can be run here (will need to add a way to mark a pass as a regalloc pass) If -passes is used, this argument will be ignored.

Ignore is bad. If we're going to have this embedded flag, it needs to be a hard error that you can't mix the flags.

@optimisan optimisan force-pushed the users/optimisan/generic-regalloc-option branch from 89711d5 to adabf4e Compare April 22, 2025 05:54
@optimisan
Copy link
Contributor Author

Right now other passes can be run here (will need to add a way to mark a pass as a regalloc pass) If -passes is used, this argument will be ignored.

Ignore is bad. If we're going to have this embedded flag, it needs to be a hard error that you can't mix the flags.

Updated so that --passes and --regalloc-npm cannot be both specified and only regalloc passes can be added in the --regalloc-npm option.

@optimisan optimisan force-pushed the users/optimisan/generic-regalloc-option branch from 72d3867 to a502108 Compare April 23, 2025 08:38
addRegAllocPassOrOpt(
addPass, []() { return RAGreedyPass({onlyAllocateVGPRs, "vgpr"}); });

// TODO: addPreRewrite();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enable this.

@optimisan optimisan force-pushed the users/optimisan/generic-regalloc-option branch from a502108 to 3ead04f Compare May 2, 2025 09:49
@optimisan optimisan force-pushed the users/optimisan/generic-regalloc-option branch from d99ec3a to cadd6e0 Compare May 2, 2025 10:08
Copy link
Collaborator

@cdevadas cdevadas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Comment on lines +6 to +15
# 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need all the -O3s

# 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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this comprehensively test every permitted pass? I'm not sure how I would precisely define "regalloc" passes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants