[llvm-branch-commits] [llvm] [MachinePipeliner] Add PipelinerLoopInfo hooks to reuse the reg-pressure detector (PR #212538)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Aug 11 13:56:18 PDT 2026


https://github.com/hjagasiaAMD updated https://github.com/llvm/llvm-project/pull/212538

>From 86daba1dd2b5036f63fcb45f586395fb52b457c4 Mon Sep 17 00:00:00 2001
From: Harsha Jagasia <harsha.jagasia at amd.com>
Date: Tue, 11 Aug 2026 15:26:46 -0500
Subject: [PATCH] [MachinePipeliner] Let targets reuse the reg-pressure
 detector

The generic MachinePipeliner register-pressure detector (added in #74807)
was only reachable via the global -pipeliner-register-pressure flag, which
cannot be enabled per-target, and it judges pressure against generic
per-pressure-set limits. Extend the pipeliner policy so a target can reuse
that detector on its own terms:

- MachinePipelinerPolicy::ShouldLimitRegPressure, which a target sets in
  TargetSubtargetInfo::overridePipelinerPolicy, opts the loop into the
  detector without the global flag.
- TargetSubtargetInfo::isPipelinerScheduleRegPressureTooHigh(MaxSetPressure)
  lets the target replace the detector's generic per-pressure-set limit
  check with its own verdict, or return nullopt to keep that check. It is a
  hook rather than a policy field because the verdict depends on the
  candidate schedule.

Both default to preserving current behavior, so targets that do not
override them are unaffected.

Exercised by the AMDGPU adoption in the following commit.
---
 llvm/include/llvm/CodeGen/MachinePipeliner.h  |  4 +++
 .../llvm/CodeGen/TargetSubtargetInfo.h        |  9 +++++++
 llvm/lib/CodeGen/MachinePipeliner.cpp         | 27 ++++++++++++++-----
 3 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/MachinePipeliner.h b/llvm/include/llvm/CodeGen/MachinePipeliner.h
index 41ab7c6891bb1..9a22bd04accae 100644
--- a/llvm/include/llvm/CodeGen/MachinePipeliner.h
+++ b/llvm/include/llvm/CodeGen/MachinePipeliner.h
@@ -69,6 +69,10 @@ struct MachinePipelinerPolicy {
   /// Don't pipeline loops whose minimum initiation interval exceeds this.
   /// Overridden by -pipeliner-max-mii when that is passed.
   int MaxMII = 27;
+
+  /// Limit the register pressure of the scheduled loop, retrying at a higher
+  /// II when a schedule needs too many registers.
+  bool ShouldLimitRegPressure = false;
 };
 
 /// The main class in the implementation of the target independent
diff --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
index 616ed755de2be..04df3a3c07c1f 100644
--- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h
@@ -280,6 +280,15 @@ class LLVM_ABI TargetSubtargetInfo : public MCSubtargetInfo {
   /// Override generic software pipelining policy.
   virtual void overridePipelinerPolicy(MachinePipelinerPolicy &Policy) const {}
 
+  /// Given the per-pressure-set maxima \p MaxSetPressure of a candidate
+  /// pipeliner schedule for \p MF, return whether it uses too many registers,
+  /// or nullopt to defer to the pipeliner's generic per-set limit check. A
+  /// non-nullopt verdict takes precedence over that check (and its margin).
+  virtual std::optional<bool> isPipelinerScheduleRegPressureTooHigh(
+      const MachineFunction &MF, ArrayRef<unsigned> MaxSetPressure) const {
+    return std::nullopt;
+  }
+
   // Perform target-specific adjustments to the latency of a schedule
   // dependency.
   // If a pair of operands is associated with the schedule dependency, DefOpIdx
diff --git a/llvm/lib/CodeGen/MachinePipeliner.cpp b/llvm/lib/CodeGen/MachinePipeliner.cpp
index d24e2425c8e14..02ce5ca7ba5ee 100644
--- a/llvm/lib/CodeGen/MachinePipeliner.cpp
+++ b/llvm/lib/CodeGen/MachinePipeliner.cpp
@@ -1577,6 +1577,7 @@ struct FuncUnitSorter {
 /// Calculate the maximum register pressure of the scheduled instructions stream
 class HighRegisterPressureDetector {
   MachineBasicBlock *OrigMBB;
+  const MachineFunction &MF;
   const MachineRegisterInfo &MRI;
   const TargetRegisterInfo *TRI;
 
@@ -1876,7 +1877,7 @@ class HighRegisterPressureDetector {
 public:
   HighRegisterPressureDetector(MachineBasicBlock *OrigMBB,
                                const MachineFunction &MF)
-      : OrigMBB(OrigMBB), MRI(MF.getRegInfo()),
+      : OrigMBB(OrigMBB), MF(MF), MRI(MF.getRegInfo()),
         TRI(MF.getSubtarget().getRegisterInfo()),
         PSetNum(TRI->getNumRegPressureSets()), InitSetPressure(PSetNum, 0),
         PressureSetLimit(PSetNum, 0) {}
@@ -1895,7 +1896,8 @@ class HighRegisterPressureDetector {
   }
 
   // Calculate the maximum register pressures of the loop and check if they
-  // exceed the limit
+  // exceed the limit, or defer to the target's verdict via
+  // TargetSubtargetInfo::isPipelinerScheduleRegPressureTooHigh.
   bool detect(const SwingSchedulerDAG *SSD, SMSchedule &Schedule,
               const unsigned MaxStage) const {
     assert(0 <= RegPressureMargin && RegPressureMargin <= 100 &&
@@ -1915,6 +1917,17 @@ class HighRegisterPressureDetector {
       dbgs() << '\n';
     });
 
+    const TargetSubtargetInfo &ST = MF.getSubtarget();
+    if (std::optional<bool> TooHigh =
+            ST.isPipelinerScheduleRegPressureTooHigh(MF, MaxSetPressure)) {
+      LLVM_DEBUG(dbgs() << (*TooHigh ? "Rejected the schedule because of too "
+                                       "high register pressure (per target "
+                                       "verdict)\n"
+                                     : "Accepted the schedule (per target "
+                                       "verdict)\n"));
+      return *TooHigh;
+    }
+
     for (unsigned PSet = 0; PSet < PSetNum; PSet++) {
       unsigned Limit = PressureSetLimit[PSet];
       unsigned Margin = Limit * RegPressureMargin / 100;
@@ -2789,6 +2802,8 @@ void SwingSchedulerDAG::initPolicy() {
   // After subtarget overrides, apply command line options.
   if (SwpMaxMii.getNumOccurrences())
     Policy.MaxMII = SwpMaxMii;
+  if (LimitRegPressure.getNumOccurrences())
+    Policy.ShouldLimitRegPressure = LimitRegPressure;
 }
 
 /// Process the nodes in the computed order and create the pipelined schedule
@@ -2802,7 +2817,7 @@ bool SwingSchedulerDAG::schedulePipeline(SMSchedule &Schedule) {
 
   bool scheduleFound = false;
   std::unique_ptr<HighRegisterPressureDetector> HRPDetector;
-  if (LimitRegPressure) {
+  if (Policy.ShouldLimitRegPressure) {
     HRPDetector =
         std::make_unique<HighRegisterPressureDetector>(Loop.getHeader(), MF);
     HRPDetector->init(RegClassInfo);
@@ -2886,9 +2901,9 @@ bool SwingSchedulerDAG::schedulePipeline(SMSchedule &Schedule) {
     if (scheduleFound)
       scheduleFound = Schedule.isValidSchedule(this);
 
-    // If a schedule was found and the option is enabled, check if the schedule
-    // might generate additional register spills/fills.
-    if (scheduleFound && LimitRegPressure)
+    // If a schedule was found and the detector is enabled, check if the
+    // schedule might generate additional register spills/fills.
+    if (scheduleFound && HRPDetector)
       scheduleFound =
           !HRPDetector->detect(this, Schedule, Schedule.getMaxStageCount());
   }



More information about the llvm-branch-commits mailing list