[llvm] [AMDGPU][CodeGen] Incrementally update reserved regs for SIPreAllocateWWMRegs pass in RegisterClassInfo (PR #212201)

Nikhil Kotikalapudi via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 21 11:24:31 PDT 2026


https://github.com/nkotikal updated https://github.com/llvm/llvm-project/pull/212201

>From a4caf3d1597943f39f008609b9f8ae5214c55d08 Mon Sep 17 00:00:00 2001
From: Nikhil Kotikalapudi <Nikhil.Kotikalapudi at amd.com>
Date: Mon, 27 Jul 2026 02:29:54 -0500
Subject: [PATCH 01/14] added updateReservedRegs method to rci cpp file to
 update reservation bitvector without invalidating full object

---
 llvm/include/llvm/CodeGen/RegisterClassInfo.h | 10 +++
 llvm/lib/CodeGen/RegisterClassInfo.cpp        | 74 ++++++++++++++++++-
 2 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/CodeGen/RegisterClassInfo.h b/llvm/include/llvm/CodeGen/RegisterClassInfo.h
index 256277832db24..995cb6b28e2c2 100644
--- a/llvm/include/llvm/CodeGen/RegisterClassInfo.h
+++ b/llvm/include/llvm/CodeGen/RegisterClassInfo.h
@@ -98,6 +98,16 @@ class RegisterClassInfo {
   LLVM_ABI void runOnMachineFunction(const MachineFunction &MF,
                                      bool Rev = false);
 
+  /// allows modification of current reserved register vector
+  /// without invalidating RCI and triggering recomputation.
+  /// prereqs for use:
+  ///     RCI already initialized,
+  ///     the caller updated MRI's reserved vector (only adding reservations)
+  ///     note: target information, callee-saved regs, cost, and alloc order
+  ///     must not change.
+  ///     input: MRI's current frozen vector
+  LLVM_ABI void updateReservedRegs(const BitVector &ReservedInput);
+
   LLVM_ABI bool invalidate(MachineFunction &, const PreservedAnalyses &PA,
                            MachineFunctionAnalysisManager::Invalidator &) {
     auto PAC = PA.getChecker<MachineRegisterClassAnalysis>();
diff --git a/llvm/lib/CodeGen/RegisterClassInfo.cpp b/llvm/lib/CodeGen/RegisterClassInfo.cpp
index f4b9e8d9b1704..b575e39600834 100644
--- a/llvm/lib/CodeGen/RegisterClassInfo.cpp
+++ b/llvm/lib/CodeGen/RegisterClassInfo.cpp
@@ -123,6 +123,78 @@ void RegisterClassInfo::runOnMachineFunction(const MachineFunction &mf,
   }
 }
 
+void RegisterClassInfo::updateReservedRegs(const BitVector &ReservedInput) {
+  assert(MF && TRI && RegClass &&
+         "RegisterClassInfo must be initialized before updating reserved regs");
+  assert(ReservedInput.size() == Reserved.size() &&
+         "Reserved register bit vectors must have the same size");
+  assert(Reserved.subsetOf(ReservedInput) &&
+         "updateReservedRegs cannot remove reserved registers");
+  if (ReservedInput == Reserved)
+    return;
+
+  // subtracts reserved set from input set to get newly reserved regs
+  BitVector NewReservations = ReservedInput;
+  NewReservations.reset(Reserved);
+
+  Reserved = ReservedInput;
+
+  // Pressure limits depend on the number of allocatable registers.
+  std::fill_n(PSetLimits.get(), TRI->getNumRegPressureSets(), 0);
+
+  // NumRegs may hide entries beyond the stress limit, so those orders cannot
+  // safely be compacted using only their visible prefix.
+  if (StressRA) {
+    ++Tag;
+    return;
+  }
+
+  for (const TargetRegisterClass &RC : TRI->regclasses()) {
+    RCInfo &Info = RegClass[RC.getID()];
+    Info.ProperSubClass = false;
+
+    // Stale entries will be computed lazily with the new Reserved vector.
+    if (Info.Tag != Tag)
+      continue;
+
+    unsigned NewNumRegs = 0;
+    uint8_t MinCost = uint8_t(~0u);
+    uint8_t LastCost = uint8_t(~0u);
+    unsigned LastCostChange = 0;
+
+    for (unsigned I = 0; I != Info.NumRegs; ++I) {
+      MCPhysReg PhysReg = Info.Order[I];
+      if (NewReservations.test(PhysReg))
+        continue;
+
+      uint8_t Cost = RegCosts[PhysReg];
+      MinCost = std::min(MinCost, Cost);
+      if (Cost != LastCost)
+        LastCostChange = NewNumRegs;
+
+      Info.Order[NewNumRegs++] = PhysReg;
+      LastCost = Cost;
+    }
+
+    Info.NumRegs = NewNumRegs;
+    Info.MinCost = MinCost;
+    Info.LastCostChange = LastCostChange;
+  }
+
+  // ProperSubClass depends on both this class and its superclass counts, so
+  // calculate it only after all valid orders have been compacted.
+  for (const TargetRegisterClass &RC : TRI->regclasses()) {
+    RCInfo &Info = RegClass[RC.getID()];
+    if (Info.Tag != Tag)
+      continue;
+
+    if (const TargetRegisterClass *Super =
+            TRI->getLargestLegalSuperClass(&RC, *MF))
+      if (Super != &RC && getNumAllocatableRegs(Super) > Info.NumRegs)
+        Info.ProperSubClass = true;
+  }
+}
+
 /// compute - Compute the preferred allocation order for RC with reserved
 /// registers filtered out. Volatile registers come first followed by CSR
 /// aliases ordered according to the CSR order specified by the target.
@@ -181,6 +253,7 @@ void RegisterClassInfo::compute(const TargetRegisterClass *RC) const {
     RCI.NumRegs = StressRA;
 
   // Check if RC is a proper sub-class.
+  RCI.ProperSubClass = false;
   if (const TargetRegisterClass *Super =
           TRI->getLargestLegalSuperClass(RC, *MF))
     if (Super != RC && getNumAllocatableRegs(Super) > RCI.NumRegs)
@@ -206,7 +279,6 @@ void RegisterClassInfo::compute(const TargetRegisterClass *RC) const {
 unsigned RegisterClassInfo::computePSetLimit(unsigned Idx) const {
   const TargetRegisterClass *RC = TRI->getLargestRegClassForRegPressureSet(Idx);
   assert(RC && "Failed to find register class");
-  compute(RC);
   unsigned NAllocatableRegs = getNumAllocatableRegs(RC);
   unsigned RegPressureSetLimit = TRI->getRegPressureSetLimit(*MF, Idx);
   // If all the regs are reserved, return raw RegPressureSetLimit.

>From 2cdf9866bb2bb2c1d19ee87efa6a35ae2dbf9694 Mon Sep 17 00:00:00 2001
From: Nikhil Kotikalapudi <Nikhil.Kotikalapudi at amd.com>
Date: Mon, 27 Jul 2026 03:26:51 -0500
Subject: [PATCH 02/14] used new function in SIPreAllocateWWMRegs, test
 validation

---
 llvm/include/llvm/CodeGen/RegisterClassInfo.h |  4 +--
 llvm/lib/CodeGen/RegisterClassInfo.cpp        | 14 ++++----
 .../Target/AMDGPU/SIPreAllocateWWMRegs.cpp    | 29 ++++++-----------
 ...i-pre-allocate-wwm-regs-invalidate-rci.mir | 32 -------------------
 .../si-pre-allocate-wwm-regs-preserve-rci.mir | 27 ++++++++++++++++
 5 files changed, 46 insertions(+), 60 deletions(-)
 delete mode 100644 llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-invalidate-rci.mir
 create mode 100644 llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir

diff --git a/llvm/include/llvm/CodeGen/RegisterClassInfo.h b/llvm/include/llvm/CodeGen/RegisterClassInfo.h
index 995cb6b28e2c2..53e7faba12555 100644
--- a/llvm/include/llvm/CodeGen/RegisterClassInfo.h
+++ b/llvm/include/llvm/CodeGen/RegisterClassInfo.h
@@ -99,10 +99,10 @@ class RegisterClassInfo {
                                      bool Rev = false);
 
   /// allows modification of current reserved register vector
-  /// without invalidating RCI and triggering recomputation.
+  /// without invalidating RCI and triggering recomputation when possible
   /// prereqs for use:
   ///     RCI already initialized,
-  ///     the caller updated MRI's reserved vector (only adding reservations)
+  ///     the caller updated MRI's reserved vector
   ///     note: target information, callee-saved regs, cost, and alloc order
   ///     must not change.
   ///     input: MRI's current frozen vector
diff --git a/llvm/lib/CodeGen/RegisterClassInfo.cpp b/llvm/lib/CodeGen/RegisterClassInfo.cpp
index b575e39600834..fcb2f6f8d65e7 100644
--- a/llvm/lib/CodeGen/RegisterClassInfo.cpp
+++ b/llvm/lib/CodeGen/RegisterClassInfo.cpp
@@ -128,11 +128,12 @@ void RegisterClassInfo::updateReservedRegs(const BitVector &ReservedInput) {
          "RegisterClassInfo must be initialized before updating reserved regs");
   assert(ReservedInput.size() == Reserved.size() &&
          "Reserved register bit vectors must have the same size");
-  assert(Reserved.subsetOf(ReservedInput) &&
-         "updateReservedRegs cannot remove reserved registers");
   if (ReservedInput == Reserved)
     return;
 
+  // Cached orders cannot regain unreserved registers; recompute them lazily.
+  bool OnlyNewReservations = Reserved.subsetOf(ReservedInput);
+
   // subtracts reserved set from input set to get newly reserved regs
   BitVector NewReservations = ReservedInput;
   NewReservations.reset(Reserved);
@@ -144,19 +145,21 @@ void RegisterClassInfo::updateReservedRegs(const BitVector &ReservedInput) {
 
   // NumRegs may hide entries beyond the stress limit, so those orders cannot
   // safely be compacted using only their visible prefix.
-  if (StressRA) {
+  if (!OnlyNewReservations || StressRA) {
     ++Tag;
     return;
   }
 
   for (const TargetRegisterClass &RC : TRI->regclasses()) {
     RCInfo &Info = RegClass[RC.getID()];
-    Info.ProperSubClass = false;
 
-    // Stale entries will be computed lazily with the new Reserved vector.
+    // skip if class info is out of date
     if (Info.Tag != Tag)
       continue;
 
+    // Recomputed below, once every order has been narrowed.
+    Info.ProperSubClass = false;
+
     unsigned NewNumRegs = 0;
     uint8_t MinCost = uint8_t(~0u);
     uint8_t LastCost = uint8_t(~0u);
@@ -253,7 +256,6 @@ void RegisterClassInfo::compute(const TargetRegisterClass *RC) const {
     RCI.NumRegs = StressRA;
 
   // Check if RC is a proper sub-class.
-  RCI.ProperSubClass = false;
   if (const TargetRegisterClass *Super =
           TRI->getLargestLegalSuperClass(RC, *MF))
     if (Super != RC && getNumAllocatableRegs(Super) > RCI.NumRegs)
diff --git a/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp b/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp
index bf484cef98da4..c7ed1b0d02e6b 100644
--- a/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp
+++ b/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp
@@ -17,13 +17,11 @@
 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
 #include "SIMachineFunctionInfo.h"
 #include "llvm/ADT/PostOrderIterator.h"
-#include "llvm/CodeGen/LiveDebugVariables.h"
 #include "llvm/CodeGen/LiveIntervals.h"
 #include "llvm/CodeGen/LiveRegMatrix.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/RegisterClassInfo.h"
-#include "llvm/CodeGen/SlotIndexes.h"
 #include "llvm/CodeGen/VirtRegMap.h"
 #include "llvm/InitializePasses.h"
 
@@ -45,7 +43,7 @@ class SIPreAllocateWWMRegs {
   LiveIntervals *LIS;
   LiveRegMatrix *Matrix;
   VirtRegMap *VRM;
-  const RegisterClassInfo &RegClassInfo;
+  RegisterClassInfo &RegClassInfo;
 
   std::vector<unsigned> RegsToRewrite;
 #ifndef NDEBUG
@@ -56,7 +54,7 @@ class SIPreAllocateWWMRegs {
 
 public:
   SIPreAllocateWWMRegs(LiveIntervals *LIS, LiveRegMatrix *Matrix,
-                       VirtRegMap *VRM, const RegisterClassInfo &RCI)
+                       VirtRegMap *VRM, RegisterClassInfo &RCI)
       : LIS(LIS), Matrix(Matrix), VRM(VRM), RegClassInfo(RCI) {}
   bool run(MachineFunction &MF);
 };
@@ -73,14 +71,8 @@ class SIPreAllocateWWMRegsLegacy : public MachineFunctionPass {
     AU.addRequired<LiveIntervalsWrapperPass>();
     AU.addRequired<VirtRegMapWrapperLegacy>();
     AU.addRequired<LiveRegMatrixWrapperLegacy>();
-    // TODO: Update RCI with the additional reserved registers the pass sets.
     AU.addRequired<MachineRegisterClassInfoWrapperPass>();
-    AU.setPreservesCFG();
-    AU.addPreserved<LiveIntervalsWrapperPass>();
-    AU.addPreserved<SlotIndexesWrapperPass>();
-    AU.addPreserved<VirtRegMapWrapperLegacy>();
-    AU.addPreserved<LiveRegMatrixWrapperLegacy>();
-    AU.addPreserved<LiveDebugVariablesWrapperLegacy>();
+    AU.setPreservesAll();
     MachineFunctionPass::getAnalysisUsage(AU);
   }
 };
@@ -175,8 +167,10 @@ void SIPreAllocateWWMRegs::rewriteRegs(MachineFunction &MF) {
 
   RegsToRewrite.clear();
 
-  // Update the set of reserved registers to include WWM ones.
+  // Update the set of reserved registers to include WWM ones 
+  // without unnecessarily invalidating RegClassInfo
   MRI->freezeReservedRegs();
+  RegClassInfo.updateReservedRegs(MRI->getReservedRegs());
 }
 
 #ifndef NDEBUG
@@ -208,7 +202,7 @@ bool SIPreAllocateWWMRegsLegacy::runOnMachineFunction(MachineFunction &MF) {
   auto *LIS = &getAnalysis<LiveIntervalsWrapperPass>().getLIS();
   auto *Matrix = &getAnalysis<LiveRegMatrixWrapperLegacy>().getLRM();
   auto *VRM = &getAnalysis<VirtRegMapWrapperLegacy>().getVRM();
-  const auto &RCI = getAnalysis<MachineRegisterClassInfoWrapperPass>().getRCI();
+  auto &RCI = getAnalysis<MachineRegisterClassInfoWrapperPass>().getRCI();
   return SIPreAllocateWWMRegs(LIS, Matrix, VRM, RCI).run(MF);
 }
 
@@ -280,12 +274,7 @@ SIPreAllocateWWMRegsPass::run(MachineFunction &MF,
   auto *LIS = &MFAM.getResult<LiveIntervalsAnalysis>(MF);
   auto *Matrix = &MFAM.getResult<LiveRegMatrixAnalysis>(MF);
   auto *VRM = &MFAM.getResult<VirtRegMapAnalysis>(MF);
-  const auto &RCI = MFAM.getResult<MachineRegisterClassAnalysis>(MF);
+  auto &RCI = MFAM.getResult<MachineRegisterClassAnalysis>(MF);
   SIPreAllocateWWMRegs(LIS, Matrix, VRM, RCI).run(MF);
-  // The pass reserves WWM registers, invalidating RegisterClassInfo's
-  // allocation order, so it cannot be preserved (see the legacy
-  // getAnalysisUsage above).
-  PreservedAnalyses PA = PreservedAnalyses::all();
-  PA.abandon<MachineRegisterClassAnalysis>();
-  return PA;
+  return PreservedAnalyses::all();
 }
diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-invalidate-rci.mir b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-invalidate-rci.mir
deleted file mode 100644
index 6571294bac741..0000000000000
--- a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-invalidate-rci.mir
+++ /dev/null
@@ -1,32 +0,0 @@
-# RUN: llc -mtriple=amdgpu7.00-amd-amdhsa -passes="require<machine-register-class-info>,si-pre-allocate-wwm-regs,require<machine-register-class-info>" -debug-pass-manager -filetype=null %s 2>&1 | FileCheck %s
-
-# INFO: Test that MachineRegisterClassInfo is not preserved in WWM preallocation
-
-# CHECK: Running analysis: MachineRegisterClassAnalysis on test_wwm_reserved
-# CHECK: Running pass: SIPreAllocateWWMRegsPass on test_wwm_reserved
-# CHECK: Invalidating analysis: MachineRegisterClassAnalysis on test_wwm_reserved
-# CHECK: Running analysis: MachineRegisterClassAnalysis on test_wwm_reserved
-
----
-name: test_wwm_reserved
-tracksRegLiveness: true
-frameInfo:
-  maxAlignment: 4
-stack:
-  - { id: 0, type: spill-slot, size: 4, alignment: 4, stack-id: sgpr-spill }
-machineFunctionInfo:
-  isEntryFunction: false
-  scratchRSrcReg: '$sgpr0_sgpr1_sgpr2_sgpr3'
-  stackPtrOffsetReg: '$sgpr32'
-  frameOffsetReg: '$sgpr33'
-  hasSpilledSGPRs: true
-body: |
-  bb.0:
-    liveins: $sgpr4, $vgpr2_vgpr3
-    SI_SPILL_S32_SAVE killed $sgpr4, %stack.0, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
-    S_NOP 0
-    renamable $sgpr4 = SI_SPILL_S32_RESTORE %stack.0, implicit $exec, implicit $sgpr0_sgpr1_sgpr2_sgpr3, implicit $sgpr32
-    %0:vgpr_32 = V_MOV_B32_e32 20, implicit $exec
-    GLOBAL_STORE_DWORD $vgpr2_vgpr3, %0:vgpr_32, 0, 0, implicit $exec
-    SI_RETURN
-...
diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
new file mode 100644
index 0000000000000..9b2793795e35c
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
@@ -0,0 +1,27 @@
+# RUN: llc -mtriple=amdgpu9.0a -passes="require<machine-register-class-info>,si-pre-allocate-wwm-regs,require<machine-register-class-info>" -debug-pass-manager -filetype=null %s 2>&1 | FileCheck %s
+# RUN: llc -mtriple=amdgpu9.0a -passes=si-pre-allocate-wwm-regs -o - %s | FileCheck %s --check-prefix=MIR
+
+# INFO: Test that WWM preallocation updates MachineRegisterClassInfo in place
+# instead of invalidating it, so the analysis is not recomputed afterwards.
+
+# CHECK: Running analysis: MachineRegisterClassAnalysis on test_wwm_reserved
+# CHECK: Running pass: SIPreAllocateWWMRegsPass on test_wwm_reserved
+# CHECK-NOT: Invalidating analysis: MachineRegisterClassAnalysis on test_wwm_reserved
+# CHECK-NOT: Running analysis: MachineRegisterClassAnalysis on test_wwm_reserved
+
+# MIR: wwmReservedRegs:
+# MIR-NEXT: - '$vgpr0'
+
+---
+name: test_wwm_reserved
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $sgpr1
+    %0:vgpr_32 = IMPLICIT_DEF
+    renamable $sgpr4_sgpr5 = ENTER_STRICT_WWM -1, implicit-def $exec, implicit-def $scc, implicit $exec
+    %1:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+    %2:vgpr_32 = V_MOV_B32_dpp %1, %0, 323, 12, 15, 0, implicit $exec
+    $exec = EXIT_STRICT_WWM killed renamable $sgpr4_sgpr5
+    %3:vgpr_32 = COPY %0
+...

>From 5d78fe86233a25883ee105e70f89055928b71e17 Mon Sep 17 00:00:00 2001
From: Nikhil Kotikalapudi <Nikhil.Kotikalapudi at amd.com>
Date: Mon, 27 Jul 2026 03:57:51 -0500
Subject: [PATCH 03/14] format fix

---
 llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp               | 2 +-
 .../CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir  | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp b/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp
index c7ed1b0d02e6b..f8bb13172d724 100644
--- a/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp
+++ b/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp
@@ -167,7 +167,7 @@ void SIPreAllocateWWMRegs::rewriteRegs(MachineFunction &MF) {
 
   RegsToRewrite.clear();
 
-  // Update the set of reserved registers to include WWM ones 
+  // Update the set of reserved registers to include WWM ones
   // without unnecessarily invalidating RegClassInfo
   MRI->freezeReservedRegs();
   RegClassInfo.updateReservedRegs(MRI->getReservedRegs());
diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
index 9b2793795e35c..703fe595b3cad 100644
--- a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
@@ -1,5 +1,5 @@
-# RUN: llc -mtriple=amdgpu9.0a -passes="require<machine-register-class-info>,si-pre-allocate-wwm-regs,require<machine-register-class-info>" -debug-pass-manager -filetype=null %s 2>&1 | FileCheck %s
-# RUN: llc -mtriple=amdgpu9.0a -passes=si-pre-allocate-wwm-regs -o - %s | FileCheck %s --check-prefix=MIR
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -passes="require<machine-register-class-info>,si-pre-allocate-wwm-regs,require<machine-register-class-info>" -debug-pass-manager -filetype=null %s 2>&1 | FileCheck %s
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -passes=si-pre-allocate-wwm-regs -o - %s | FileCheck %s --check-prefix=MIR
 
 # INFO: Test that WWM preallocation updates MachineRegisterClassInfo in place
 # instead of invalidating it, so the analysis is not recomputed afterwards.

>From de9ab11538b0152db507cb5a9f0fa7db9071edf4 Mon Sep 17 00:00:00 2001
From: Nikhil Kotikalapudi <Nikhil.Kotikalapudi at amd.com>
Date: Mon, 27 Jul 2026 09:52:24 -0500
Subject: [PATCH 04/14] comments fix

---
 llvm/include/llvm/CodeGen/RegisterClassInfo.h   | 15 +++++++--------
 llvm/lib/CodeGen/RegisterClassInfo.cpp          |  4 ++--
 llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp |  2 +-
 3 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/RegisterClassInfo.h b/llvm/include/llvm/CodeGen/RegisterClassInfo.h
index 53e7faba12555..cd5c62add4a67 100644
--- a/llvm/include/llvm/CodeGen/RegisterClassInfo.h
+++ b/llvm/include/llvm/CodeGen/RegisterClassInfo.h
@@ -98,14 +98,13 @@ class RegisterClassInfo {
   LLVM_ABI void runOnMachineFunction(const MachineFunction &MF,
                                      bool Rev = false);
 
-  /// allows modification of current reserved register vector
-  /// without invalidating RCI and triggering recomputation when possible
-  /// prereqs for use:
-  ///     RCI already initialized,
-  ///     the caller updated MRI's reserved vector
-  ///     note: target information, callee-saved regs, cost, and alloc order
-  ///     must not change.
-  ///     input: MRI's current frozen vector
+  /// Update cached register class information using \p ReservedInput, MRI's
+  /// current frozen reserved-register set. Cached orders are compacted when
+  /// only registers are added and `-stress-regalloc` is disabled; otherwise,
+  /// they are invalidated and recomputed on demand.
+  ///
+  /// RegisterClassInfo must be initialized. Target information, callee-saved
+  /// registers, register costs, and allocation orders must remain unchanged.
   LLVM_ABI void updateReservedRegs(const BitVector &ReservedInput);
 
   LLVM_ABI bool invalidate(MachineFunction &, const PreservedAnalyses &PA,
diff --git a/llvm/lib/CodeGen/RegisterClassInfo.cpp b/llvm/lib/CodeGen/RegisterClassInfo.cpp
index fcb2f6f8d65e7..2b39ba13d4ccb 100644
--- a/llvm/lib/CodeGen/RegisterClassInfo.cpp
+++ b/llvm/lib/CodeGen/RegisterClassInfo.cpp
@@ -134,7 +134,7 @@ void RegisterClassInfo::updateReservedRegs(const BitVector &ReservedInput) {
   // Cached orders cannot regain unreserved registers; recompute them lazily.
   bool OnlyNewReservations = Reserved.subsetOf(ReservedInput);
 
-  // subtracts reserved set from input set to get newly reserved regs
+  // Subtract the old set to find newly reserved registers.
   BitVector NewReservations = ReservedInput;
   NewReservations.reset(Reserved);
 
@@ -153,7 +153,7 @@ void RegisterClassInfo::updateReservedRegs(const BitVector &ReservedInput) {
   for (const TargetRegisterClass &RC : TRI->regclasses()) {
     RCInfo &Info = RegClass[RC.getID()];
 
-    // skip if class info is out of date
+    // Skip stale class information.
     if (Info.Tag != Tag)
       continue;
 
diff --git a/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp b/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp
index f8bb13172d724..4c47728851591 100644
--- a/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp
+++ b/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp
@@ -168,7 +168,7 @@ void SIPreAllocateWWMRegs::rewriteRegs(MachineFunction &MF) {
   RegsToRewrite.clear();
 
   // Update the set of reserved registers to include WWM ones
-  // without unnecessarily invalidating RegClassInfo
+  // without unnecessarily invalidating RegClassInfo.
   MRI->freezeReservedRegs();
   RegClassInfo.updateReservedRegs(MRI->getReservedRegs());
 }

>From 47afed3814d4a62168daab861b08bc0578cfd75b Mon Sep 17 00:00:00 2001
From: Nikhil Kotikalapudi <Nikhil.Kotikalapudi at amd.com>
Date: Sun, 2 Aug 2026 16:39:28 -0500
Subject: [PATCH 05/14] replaced check-not with exhaustive order check

---
 .../si-pre-allocate-wwm-regs-preserve-rci.mir | 30 ++++++++++++++-----
 1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
index 703fe595b3cad..ff07f41b18373 100644
--- a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
@@ -1,13 +1,29 @@
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -passes="require<machine-register-class-info>,si-pre-allocate-wwm-regs,require<machine-register-class-info>" -debug-pass-manager -filetype=null %s 2>&1 | FileCheck %s
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -passes="require<machine-register-class-info>,si-pre-allocate-wwm-regs,require<machine-register-class-info>" -debug-pass-manager -o /dev/null %s 2>&1 | FileCheck %s
 # RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -passes=si-pre-allocate-wwm-regs -o - %s | FileCheck %s --check-prefix=MIR
 
-# INFO: Test that WWM preallocation updates MachineRegisterClassInfo in place
-# instead of invalidating it, so the analysis is not recomputed afterwards.
+# Test that WWM preallocation updates MachineRegisterClassInfo in place instead
+# of invalidating it. The pass manager log is matched in full, so the second
+# require<machine-register-class-info> is shown to run without recomputing
+# MachineRegisterClassAnalysis.
 
-# CHECK: Running analysis: MachineRegisterClassAnalysis on test_wwm_reserved
-# CHECK: Running pass: SIPreAllocateWWMRegsPass on test_wwm_reserved
-# CHECK-NOT: Invalidating analysis: MachineRegisterClassAnalysis on test_wwm_reserved
-# CHECK-NOT: Running analysis: MachineRegisterClassAnalysis on test_wwm_reserved
+# CHECK:      Running analysis: MachineModuleAnalysis on [module]
+# CHECK-NEXT: Running analysis: InnerAnalysisManagerProxy<llvm::AnalysisManager<llvm::Function>, llvm::Module> on [module]
+# CHECK-NEXT: Running analysis: MachineFunctionAnalysis on test_wwm_reserved
+# CHECK-NEXT: Running analysis: OuterAnalysisManagerProxy<llvm::AnalysisManager<llvm::Module>, llvm::Function> on test_wwm_reserved
+# CHECK-NEXT: Running analysis: InnerAnalysisManagerProxy<llvm::AnalysisManager<llvm::MachineFunction>, llvm::Function> on test_wwm_reserved
+# CHECK-NEXT: Running pass: RequireAnalysisPass<llvm::MachineRegisterClassAnalysis, llvm::MachineFunction> on test_wwm_reserved
+# CHECK-NEXT: Running analysis: MachineRegisterClassAnalysis on test_wwm_reserved
+# CHECK-NEXT: Running pass: SIPreAllocateWWMRegsPass on test_wwm_reserved
+# CHECK-NEXT: Running analysis: LiveIntervalsAnalysis on test_wwm_reserved
+# CHECK-NEXT: Running analysis: MachineDominatorTreeAnalysis on test_wwm_reserved
+# CHECK-NEXT: Running analysis: SlotIndexesAnalysis on test_wwm_reserved
+# CHECK-NEXT: Running analysis: LiveRegMatrixAnalysis on test_wwm_reserved
+# CHECK-NEXT: Running analysis: VirtRegMapAnalysis on test_wwm_reserved
+# CHECK-NEXT: Running pass: RequireAnalysisPass<llvm::MachineRegisterClassAnalysis, llvm::MachineFunction> on test_wwm_reserved
+# CHECK-NEXT: Running pass: PrintMIRPreparePass on [module]
+# CHECK-NEXT: Running pass: MachineVerifierPass on test_wwm_reserved
+# CHECK-NEXT: Running pass: PrintMIRPass on test_wwm_reserved
+# CHECK-NEXT: Running analysis: FunctionAnalysisManagerMachineFunctionProxy on test_wwm_reserved
 
 # MIR: wwmReservedRegs:
 # MIR-NEXT: - '$vgpr0'

>From a72eae27fca81b03f152b3d1d16de7a438a7df00 Mon Sep 17 00:00:00 2001
From: Nikhil Kotikalapudi <Nikhil.Kotikalapudi at amd.com>
Date: Sun, 2 Aug 2026 19:47:35 -0500
Subject: [PATCH 06/14] reduced window for pass manager log check, alias
 testing

---
 .../si-pre-allocate-wwm-regs-preserve-rci.mir | 57 +++++++++++--------
 1 file changed, 34 insertions(+), 23 deletions(-)

diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
index ff07f41b18373..ba4590792c0e0 100644
--- a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
@@ -1,33 +1,42 @@
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -passes="require<machine-register-class-info>,si-pre-allocate-wwm-regs,require<machine-register-class-info>" -debug-pass-manager -o /dev/null %s 2>&1 | FileCheck %s
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a -passes=si-pre-allocate-wwm-regs -o - %s | FileCheck %s --check-prefix=MIR
-
-# Test that WWM preallocation updates MachineRegisterClassInfo in place instead
-# of invalidating it. The pass manager log is matched in full, so the second
-# require<machine-register-class-info> is shown to run without recomputing
-# MachineRegisterClassAnalysis.
-
-# CHECK:      Running analysis: MachineModuleAnalysis on [module]
-# CHECK-NEXT: Running analysis: InnerAnalysisManagerProxy<llvm::AnalysisManager<llvm::Function>, llvm::Module> on [module]
-# CHECK-NEXT: Running analysis: MachineFunctionAnalysis on test_wwm_reserved
-# CHECK-NEXT: Running analysis: OuterAnalysisManagerProxy<llvm::AnalysisManager<llvm::Module>, llvm::Function> on test_wwm_reserved
-# CHECK-NEXT: Running analysis: InnerAnalysisManagerProxy<llvm::AnalysisManager<llvm::MachineFunction>, llvm::Function> on test_wwm_reserved
-# CHECK-NEXT: Running pass: RequireAnalysisPass<llvm::MachineRegisterClassAnalysis, llvm::MachineFunction> on test_wwm_reserved
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a \
+# RUN:   -passes="require<machine-register-class-info>,si-pre-allocate-wwm-regs,require<machine-register-class-info>" \
+# RUN:   -debug-pass-manager -o /dev/null %s 2>&1 | FileCheck %s
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a \
+# RUN:   -passes=si-pre-allocate-wwm-regs -o - %s | FileCheck %s --check-prefix=MIR
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a \
+# RUN:   -passes="si-pre-allocate-wwm-regs,greedy<vgpr>,virt-reg-rewriter" \
+# RUN:   -o - %s | FileCheck %s --check-prefix=ALIAS
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a \
+# RUN:   -passes="greedy<vgpr>,virt-reg-rewriter" \
+# RUN:   -o - %s | FileCheck %s --check-prefix=NO-WWM
+
+# Verify that SIPreAllocateWWMRegsPass updates the
+# MachineRegisterClassAnalysis result in place. The second require must reuse
+# the result computed by the first.
+
+# CHECK:      Running pass: RequireAnalysisPass<llvm::MachineRegisterClassAnalysis, llvm::MachineFunction> on test_wwm_reserved
 # CHECK-NEXT: Running analysis: MachineRegisterClassAnalysis on test_wwm_reserved
 # CHECK-NEXT: Running pass: SIPreAllocateWWMRegsPass on test_wwm_reserved
-# CHECK-NEXT: Running analysis: LiveIntervalsAnalysis on test_wwm_reserved
-# CHECK-NEXT: Running analysis: MachineDominatorTreeAnalysis on test_wwm_reserved
-# CHECK-NEXT: Running analysis: SlotIndexesAnalysis on test_wwm_reserved
-# CHECK-NEXT: Running analysis: LiveRegMatrixAnalysis on test_wwm_reserved
-# CHECK-NEXT: Running analysis: VirtRegMapAnalysis on test_wwm_reserved
-# CHECK-NEXT: Running pass: RequireAnalysisPass<llvm::MachineRegisterClassAnalysis, llvm::MachineFunction> on test_wwm_reserved
+# CHECK:      Running pass: RequireAnalysisPass<llvm::MachineRegisterClassAnalysis, llvm::MachineFunction> on test_wwm_reserved
 # CHECK-NEXT: Running pass: PrintMIRPreparePass on [module]
-# CHECK-NEXT: Running pass: MachineVerifierPass on test_wwm_reserved
-# CHECK-NEXT: Running pass: PrintMIRPass on test_wwm_reserved
-# CHECK-NEXT: Running analysis: FunctionAnalysisManagerMachineFunctionProxy on test_wwm_reserved
 
 # MIR: wwmReservedRegs:
 # MIR-NEXT: - '$vgpr0'
 
+# Verify that reserving $vgpr0 for WWM also reserves the aliasing tuple
+# $vgpr0_vgpr1. The allocator must assign %4 to the next available tuple.
+
+# ALIAS:      $vgpr0 = V_MOV_B32_e32 0, implicit $exec
+# ALIAS:      $exec = EXIT_STRICT_WWM killed renamable $sgpr4_sgpr5
+# ALIAS-NEXT: renamable $vgpr1_vgpr2 = IMPLICIT_DEF
+# ALIAS-NEXT: S_NOP 0, implicit killed renamable $vgpr1_vgpr2
+
+# Without WWM preallocation, the allocator must assign %4 to the first tuple.
+
+# NO-WWM:      $exec = EXIT_STRICT_WWM killed renamable $sgpr4_sgpr5
+# NO-WWM-NEXT: renamable $vgpr0_vgpr1 = IMPLICIT_DEF
+# NO-WWM-NEXT: S_NOP 0, implicit killed renamable $vgpr0_vgpr1
+
 ---
 name: test_wwm_reserved
 tracksRegLiveness: true
@@ -40,4 +49,6 @@ body: |
     %2:vgpr_32 = V_MOV_B32_dpp %1, %0, 323, 12, 15, 0, implicit $exec
     $exec = EXIT_STRICT_WWM killed renamable $sgpr4_sgpr5
     %3:vgpr_32 = COPY %0
+    %4:vreg_64 = IMPLICIT_DEF
+    S_NOP 0, implicit %4
 ...

>From 139ddb0f9db892153b7ce1be7717e3a6db490488 Mon Sep 17 00:00:00 2001
From: Nikhil Kotikalapudi <Nikhil.Kotikalapudi at amd.com>
Date: Sun, 2 Aug 2026 20:47:10 -0500
Subject: [PATCH 07/14] ci fix

---
 .../CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir  | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
index ba4590792c0e0..d2ed17fc38294 100644
--- a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
@@ -14,10 +14,10 @@
 # MachineRegisterClassAnalysis result in place. The second require must reuse
 # the result computed by the first.
 
-# CHECK:      Running pass: RequireAnalysisPass<llvm::MachineRegisterClassAnalysis, llvm::MachineFunction> on test_wwm_reserved
+# CHECK:      Running pass: RequireAnalysisPass<llvm::MachineRegisterClassAnalysis, llvm::MachineFunction{{.*}}> on test_wwm_reserved
 # CHECK-NEXT: Running analysis: MachineRegisterClassAnalysis on test_wwm_reserved
 # CHECK-NEXT: Running pass: SIPreAllocateWWMRegsPass on test_wwm_reserved
-# CHECK:      Running pass: RequireAnalysisPass<llvm::MachineRegisterClassAnalysis, llvm::MachineFunction> on test_wwm_reserved
+# CHECK:      Running pass: RequireAnalysisPass<llvm::MachineRegisterClassAnalysis, llvm::MachineFunction{{.*}}> on test_wwm_reserved
 # CHECK-NEXT: Running pass: PrintMIRPreparePass on [module]
 
 # MIR: wwmReservedRegs:

>From 69d92d007cd5c066c5cda956ab1a28bff0d0aa3f Mon Sep 17 00:00:00 2001
From: Nikhil Kotikalapudi <Nikhil.Kotikalapudi at amd.com>
Date: Mon, 3 Aug 2026 07:56:56 -0500
Subject: [PATCH 08/14] comment fix

---
 .../AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir   | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
index d2ed17fc38294..c112efdfc44c4 100644
--- a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
@@ -1,12 +1,12 @@
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a \
+# RUN: llc -mtriple=amdgpu9.0a-amd-amdhsa \
 # RUN:   -passes="require<machine-register-class-info>,si-pre-allocate-wwm-regs,require<machine-register-class-info>" \
-# RUN:   -debug-pass-manager -o /dev/null %s 2>&1 | FileCheck %s
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a \
+# RUN:   -debug-pass-manager -filetype=null %s 2>&1 | FileCheck %s
+# RUN: llc -mtriple=amdgpu9.0a-amd-amdhsa \
 # RUN:   -passes=si-pre-allocate-wwm-regs -o - %s | FileCheck %s --check-prefix=MIR
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a \
+# RUN: llc -mtriple=amdgpu9.0a-amd-amdhsa \
 # RUN:   -passes="si-pre-allocate-wwm-regs,greedy<vgpr>,virt-reg-rewriter" \
 # RUN:   -o - %s | FileCheck %s --check-prefix=ALIAS
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a \
+# RUN: llc -mtriple=amdgpu9.0a-amd-amdhsa \
 # RUN:   -passes="greedy<vgpr>,virt-reg-rewriter" \
 # RUN:   -o - %s | FileCheck %s --check-prefix=NO-WWM
 

>From 6ee2d840fa721302dc0534b73a90ee08ba69efa9 Mon Sep 17 00:00:00 2001
From: Nikhil Kotikalapudi <Nikhil.Kotikalapudi at amd.com>
Date: Thu, 6 Aug 2026 11:13:35 -0500
Subject: [PATCH 09/14] removed second loop for ProperSubClass eval

---
 llvm/lib/CodeGen/RegisterClassInfo.cpp | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/llvm/lib/CodeGen/RegisterClassInfo.cpp b/llvm/lib/CodeGen/RegisterClassInfo.cpp
index 2b39ba13d4ccb..566f574e3c7d1 100644
--- a/llvm/lib/CodeGen/RegisterClassInfo.cpp
+++ b/llvm/lib/CodeGen/RegisterClassInfo.cpp
@@ -157,9 +157,6 @@ void RegisterClassInfo::updateReservedRegs(const BitVector &ReservedInput) {
     if (Info.Tag != Tag)
       continue;
 
-    // Recomputed below, once every order has been narrowed.
-    Info.ProperSubClass = false;
-
     unsigned NewNumRegs = 0;
     uint8_t MinCost = uint8_t(~0u);
     uint8_t LastCost = uint8_t(~0u);
@@ -182,15 +179,8 @@ void RegisterClassInfo::updateReservedRegs(const BitVector &ReservedInput) {
     Info.NumRegs = NewNumRegs;
     Info.MinCost = MinCost;
     Info.LastCostChange = LastCostChange;
-  }
-
-  // ProperSubClass depends on both this class and its superclass counts, so
-  // calculate it only after all valid orders have been compacted.
-  for (const TargetRegisterClass &RC : TRI->regclasses()) {
-    RCInfo &Info = RegClass[RC.getID()];
-    if (Info.Tag != Tag)
-      continue;
 
+    Info.ProperSubClass = false;
     if (const TargetRegisterClass *Super =
             TRI->getLargestLegalSuperClass(&RC, *MF))
       if (Super != &RC && getNumAllocatableRegs(Super) > Info.NumRegs)

>From 0c9e7be2f9f485c8f48032a49ca526b05968a011 Mon Sep 17 00:00:00 2001
From: Nikhil Kotikalapudi <Nikhil.Kotikalapudi at amd.com>
Date: Thu, 6 Aug 2026 15:11:42 -0500
Subject: [PATCH 10/14] new cpp test to verify updated regs RCI equals new RCI

---
 .../si-pre-allocate-wwm-regs-preserve-rci.mir |  20 ---
 llvm/unittests/CodeGen/CMakeLists.txt         |   1 +
 .../CodeGen/RegisterClassInfoTest.cpp         | 128 ++++++++++++++++++
 3 files changed, 129 insertions(+), 20 deletions(-)
 create mode 100644 llvm/unittests/CodeGen/RegisterClassInfoTest.cpp

diff --git a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
index c112efdfc44c4..4c990d3ec68ad 100644
--- a/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
+++ b/llvm/test/CodeGen/AMDGPU/si-pre-allocate-wwm-regs-preserve-rci.mir
@@ -3,12 +3,6 @@
 # RUN:   -debug-pass-manager -filetype=null %s 2>&1 | FileCheck %s
 # RUN: llc -mtriple=amdgpu9.0a-amd-amdhsa \
 # RUN:   -passes=si-pre-allocate-wwm-regs -o - %s | FileCheck %s --check-prefix=MIR
-# RUN: llc -mtriple=amdgpu9.0a-amd-amdhsa \
-# RUN:   -passes="si-pre-allocate-wwm-regs,greedy<vgpr>,virt-reg-rewriter" \
-# RUN:   -o - %s | FileCheck %s --check-prefix=ALIAS
-# RUN: llc -mtriple=amdgpu9.0a-amd-amdhsa \
-# RUN:   -passes="greedy<vgpr>,virt-reg-rewriter" \
-# RUN:   -o - %s | FileCheck %s --check-prefix=NO-WWM
 
 # Verify that SIPreAllocateWWMRegsPass updates the
 # MachineRegisterClassAnalysis result in place. The second require must reuse
@@ -23,20 +17,6 @@
 # MIR: wwmReservedRegs:
 # MIR-NEXT: - '$vgpr0'
 
-# Verify that reserving $vgpr0 for WWM also reserves the aliasing tuple
-# $vgpr0_vgpr1. The allocator must assign %4 to the next available tuple.
-
-# ALIAS:      $vgpr0 = V_MOV_B32_e32 0, implicit $exec
-# ALIAS:      $exec = EXIT_STRICT_WWM killed renamable $sgpr4_sgpr5
-# ALIAS-NEXT: renamable $vgpr1_vgpr2 = IMPLICIT_DEF
-# ALIAS-NEXT: S_NOP 0, implicit killed renamable $vgpr1_vgpr2
-
-# Without WWM preallocation, the allocator must assign %4 to the first tuple.
-
-# NO-WWM:      $exec = EXIT_STRICT_WWM killed renamable $sgpr4_sgpr5
-# NO-WWM-NEXT: renamable $vgpr0_vgpr1 = IMPLICIT_DEF
-# NO-WWM-NEXT: S_NOP 0, implicit killed renamable $vgpr0_vgpr1
-
 ---
 name: test_wwm_reserved
 tracksRegLiveness: true
diff --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt
index 709017380fa4e..6fda711bb759d 100644
--- a/llvm/unittests/CodeGen/CMakeLists.txt
+++ b/llvm/unittests/CodeGen/CMakeLists.txt
@@ -40,6 +40,7 @@ add_llvm_unittest(CodeGenTests
   MIR2VecTest.cpp
   RegAllocBasicTest.cpp
   RegAllocScoreTest.cpp
+  RegisterClassInfoTest.cpp
   RegisterTest.cpp
   PassManagerTest.cpp
   RematerializerTest.cpp
diff --git a/llvm/unittests/CodeGen/RegisterClassInfoTest.cpp b/llvm/unittests/CodeGen/RegisterClassInfoTest.cpp
new file mode 100644
index 0000000000000..31ddc44f15f9e
--- /dev/null
+++ b/llvm/unittests/CodeGen/RegisterClassInfoTest.cpp
@@ -0,0 +1,128 @@
+//===- RegisterClassInfoTest.cpp - RegisterClassInfo tests ----------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/RegisterClassInfo.h"
+#include "CodeGenTestBase.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
+#include "llvm/Config/Targets.h"
+#include "llvm/MC/MCRegister.h"
+#include "llvm/Support/TargetSelect.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+class RegisterClassInfoTest : public CodeGenTestBase {
+public:
+  static void SetUpTestCase() {
+#if LLVM_HAS_AMDGPU_TARGET
+    LLVMInitializeAMDGPUTargetInfo();
+    LLVMInitializeAMDGPUTarget();
+    LLVMInitializeAMDGPUTargetMC();
+#else
+    GTEST_SKIP();
+#endif
+  }
+
+  void SetUp() override { setUpImpl("amdgcn-amd-amdhsa", "gfx900", /*FS=*/""); }
+};
+
+static void materializeAll(RegisterClassInfo &RCI,
+                           const TargetRegisterInfo &TRI) {
+  for (const TargetRegisterClass &RC : TRI.regclasses()) {
+    (void)RCI.getOrder(&RC);
+    (void)RCI.getNumAllocatableRegs(&RC);
+    (void)RCI.isProperSubClass(&RC);
+    (void)RCI.getMinCost(&RC);
+    (void)RCI.getLastCostChange(&RC);
+  }
+
+  for (unsigned I = 0; I != TRI.getNumRegPressureSets(); ++I)
+    (void)RCI.getRegPressureSetLimit(I);
+}
+
+static void expectEqual(RegisterClassInfo &Incremental,
+                        RegisterClassInfo &Recomputed,
+                        const TargetRegisterInfo &TRI) {
+  for (const TargetRegisterClass &RC : TRI.regclasses()) {
+    SCOPED_TRACE(TRI.getRegClassName(&RC));
+    EXPECT_EQ(Incremental.getOrder(&RC), Recomputed.getOrder(&RC));
+    EXPECT_EQ(Incremental.getNumAllocatableRegs(&RC),
+              Recomputed.getNumAllocatableRegs(&RC));
+    EXPECT_EQ(Incremental.isProperSubClass(&RC),
+              Recomputed.isProperSubClass(&RC));
+    EXPECT_EQ(Incremental.getMinCost(&RC), Recomputed.getMinCost(&RC));
+    EXPECT_EQ(Incremental.getLastCostChange(&RC),
+              Recomputed.getLastCostChange(&RC));
+  }
+
+  for (unsigned I = 0; I != TRI.getNumRegPressureSets(); ++I) {
+    SCOPED_TRACE(I);
+    EXPECT_EQ(Incremental.getRegPressureSetLimit(I),
+              Recomputed.getRegPressureSetLimit(I));
+  }
+}
+
+static MCRegister findRegisterByName(const TargetRegisterInfo &TRI,
+                                     StringRef Name) {
+  for (unsigned I = MCRegister::FirstPhysicalReg; I != TRI.getNumRegs(); ++I) {
+    MCRegister Reg = MCRegister::from(I);
+    if (Name == TRI.getName(Reg))
+      return Reg;
+  }
+  return MCRegister();
+}
+
+TEST_F(RegisterClassInfoTest, IncrementalUpdateMatchesRecompute) {
+  ASSERT_TRUE(parseMIR(R"MIR(
+---
+name: func
+tracksRegLiveness: true
+machineFunctionInfo:
+  isEntryFunction: true
+body:             |
+  bb.0:
+    S_ENDPGM 0
+...
+)MIR"));
+
+  MachineFunction &MF = getMF("func");
+  MachineRegisterInfo &MRI = MF.getRegInfo();
+  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
+  MRI.freezeReservedRegs();
+
+  RegisterClassInfo Incremental;
+  Incremental.runOnMachineFunction(MF);
+  // Populate every cache entry so the update exercises incremental compaction
+  // for every register class instead of lazy recomputation.
+  materializeAll(Incremental, TRI);
+
+  MCRegister VGPR0 = findRegisterByName(TRI, "VGPR0");
+  ASSERT_TRUE(VGPR0.isValid());
+  ASSERT_FALSE(MRI.isReserved(VGPR0));
+  ASSERT_TRUE(
+      llvm::any_of(TRI.regclasses(), [&](const TargetRegisterClass &RC) {
+        return llvm::is_contained(Incremental.getOrder(&RC),
+                                  static_cast<MCPhysReg>(VGPR0.id()));
+      }));
+
+  MRI.reserveReg(VGPR0, &TRI);
+  Incremental.updateReservedRegs(MRI.getReservedRegs());
+
+  // Construct an independent baseline from the updated reserved-register set.
+  RegisterClassInfo Recomputed;
+  Recomputed.runOnMachineFunction(MF);
+
+  expectEqual(Incremental, Recomputed, TRI);
+}
+
+} // namespace

>From 07a68ae12987c832b5bd862151564c045fda7f91 Mon Sep 17 00:00:00 2001
From: Nikhil Kotikalapudi <nak00001 at outlook.com>
Date: Fri, 21 Aug 2026 11:03:09 -0400
Subject: [PATCH 11/14] Update llvm/include/llvm/CodeGen/RegisterClassInfo.h

Co-authored-by: Matt Arsenault <arsenm2 at gmail.com>
---
 llvm/include/llvm/CodeGen/RegisterClassInfo.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/CodeGen/RegisterClassInfo.h b/llvm/include/llvm/CodeGen/RegisterClassInfo.h
index cd5c62add4a67..05c886e2f3d12 100644
--- a/llvm/include/llvm/CodeGen/RegisterClassInfo.h
+++ b/llvm/include/llvm/CodeGen/RegisterClassInfo.h
@@ -99,7 +99,7 @@ class RegisterClassInfo {
                                      bool Rev = false);
 
   /// Update cached register class information using \p ReservedInput, MRI's
-  /// current frozen reserved-register set. Cached orders are compacted when
+  /// current reserved-register set. Cached orders are compacted when
   /// only registers are added and `-stress-regalloc` is disabled; otherwise,
   /// they are invalidated and recomputed on demand.
   ///

>From 8e644468d021de515c98135009358ee50bb75a7e Mon Sep 17 00:00:00 2001
From: Nikhil Kotikalapudi <nak00001 at outlook.com>
Date: Fri, 21 Aug 2026 11:07:47 -0400
Subject: [PATCH 12/14] Update llvm/unittests/CodeGen/RegisterClassInfoTest.cpp

Co-authored-by: Matt Arsenault <arsenm2 at gmail.com>
---
 llvm/unittests/CodeGen/RegisterClassInfoTest.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/unittests/CodeGen/RegisterClassInfoTest.cpp b/llvm/unittests/CodeGen/RegisterClassInfoTest.cpp
index 31ddc44f15f9e..b2dda5f90c96c 100644
--- a/llvm/unittests/CodeGen/RegisterClassInfoTest.cpp
+++ b/llvm/unittests/CodeGen/RegisterClassInfoTest.cpp
@@ -33,7 +33,7 @@ class RegisterClassInfoTest : public CodeGenTestBase {
 #endif
   }
 
-  void SetUp() override { setUpImpl("amdgcn-amd-amdhsa", "gfx900", /*FS=*/""); }
+  void SetUp() override { setUpImpl("amdgpu9.00-amd-amdhsa", "", /*FS=*/""); }
 };
 
 static void materializeAll(RegisterClassInfo &RCI,

>From 7717927ab8d482e772a94eaca1402b807bd3a9f0 Mon Sep 17 00:00:00 2001
From: nkotikal <nak00001 at outlook.com>
Date: Fri, 21 Aug 2026 11:38:32 -0400
Subject: [PATCH 13/14] addressed rcitest comments

---
 .../CodeGen/RegisterClassInfoTest.cpp         | 30 +++++++++----------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/llvm/unittests/CodeGen/RegisterClassInfoTest.cpp b/llvm/unittests/CodeGen/RegisterClassInfoTest.cpp
index b2dda5f90c96c..04abdea60201a 100644
--- a/llvm/unittests/CodeGen/RegisterClassInfoTest.cpp
+++ b/llvm/unittests/CodeGen/RegisterClassInfoTest.cpp
@@ -8,12 +8,13 @@
 
 #include "llvm/CodeGen/RegisterClassInfo.h"
 #include "CodeGenTestBase.h"
+#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 #include "llvm/Config/Targets.h"
-#include "llvm/MC/MCRegister.h"
+#include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/Support/TargetSelect.h"
 #include "gtest/gtest.h"
 
@@ -23,6 +24,7 @@ namespace {
 
 class RegisterClassInfoTest : public CodeGenTestBase {
 public:
+  /// Register the AMDGPU target components needed by this test suite.
   static void SetUpTestCase() {
 #if LLVM_HAS_AMDGPU_TARGET
     LLVMInitializeAMDGPUTargetInfo();
@@ -33,9 +35,13 @@ class RegisterClassInfoTest : public CodeGenTestBase {
 #endif
   }
 
+  /// Use a GCN triple so VGPR registers are available to the test.
   void SetUp() override { setUpImpl("amdgpu9.00-amd-amdhsa", "", /*FS=*/""); }
 };
 
+/// Force every RegisterClassInfo cache entry to be populated so
+/// updateReservedRegs exercises incremental compaction instead of lazy
+/// recomputation on the next query.
 static void materializeAll(RegisterClassInfo &RCI,
                            const TargetRegisterInfo &TRI) {
   for (const TargetRegisterClass &RC : TRI.regclasses()) {
@@ -50,6 +56,7 @@ static void materializeAll(RegisterClassInfo &RCI,
     (void)RCI.getRegPressureSetLimit(I);
 }
 
+/// Compare every cached RegisterClassInfo field against a freshly built object.
 static void expectEqual(RegisterClassInfo &Incremental,
                         RegisterClassInfo &Recomputed,
                         const TargetRegisterInfo &TRI) {
@@ -72,16 +79,8 @@ static void expectEqual(RegisterClassInfo &Incremental,
   }
 }
 
-static MCRegister findRegisterByName(const TargetRegisterInfo &TRI,
-                                     StringRef Name) {
-  for (unsigned I = MCRegister::FirstPhysicalReg; I != TRI.getNumRegs(); ++I) {
-    MCRegister Reg = MCRegister::from(I);
-    if (Name == TRI.getName(Reg))
-      return Reg;
-  }
-  return MCRegister();
-}
-
+/// Verify that updateReservedRegs matches rebuilding RegisterClassInfo from
+/// scratch.
 TEST_F(RegisterClassInfoTest, IncrementalUpdateMatchesRecompute) {
   ASSERT_TRUE(parseMIR(R"MIR(
 ---
@@ -102,12 +101,9 @@ body:             |
 
   RegisterClassInfo Incremental;
   Incremental.runOnMachineFunction(MF);
-  // Populate every cache entry so the update exercises incremental compaction
-  // for every register class instead of lazy recomputation.
   materializeAll(Incremental, TRI);
 
-  MCRegister VGPR0 = findRegisterByName(TRI, "VGPR0");
-  ASSERT_TRUE(VGPR0.isValid());
+  MCRegister VGPR0 = AMDGPU::VGPR0;
   ASSERT_FALSE(MRI.isReserved(VGPR0));
   ASSERT_TRUE(
       llvm::any_of(TRI.regclasses(), [&](const TargetRegisterClass &RC) {
@@ -116,6 +112,10 @@ body:             |
       }));
 
   MRI.reserveReg(VGPR0, &TRI);
+  for (MCRegAliasIterator Alias(VGPR0, &TRI, /*IncludeSubRegs=*/true);
+       Alias.isValid(); ++Alias)
+    EXPECT_TRUE(MRI.isReserved(*Alias)) << TRI.getName(*Alias);
+
   Incremental.updateReservedRegs(MRI.getReservedRegs());
 
   // Construct an independent baseline from the updated reserved-register set.

>From 36b7bf282a67aaadbb591dc5d5792029e06726b6 Mon Sep 17 00:00:00 2001
From: nkotikal <nak00001 at outlook.com>
Date: Fri, 21 Aug 2026 14:24:14 -0400
Subject: [PATCH 14/14] fixed ci failures by moving the cpp test to amdgpu unit
 tests

---
 llvm/unittests/CodeGen/CMakeLists.txt         |  1 -
 llvm/unittests/Target/AMDGPU/CMakeLists.txt   |  1 +
 .../AMDGPU/RCIUpdateReservedRegsTest.cpp}     | 19 +++----------------
 3 files changed, 4 insertions(+), 17 deletions(-)
 rename llvm/unittests/{CodeGen/RegisterClassInfoTest.cpp => Target/AMDGPU/RCIUpdateReservedRegsTest.cpp} (90%)

diff --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt
index 4163d115d5c0b..6302dc2771775 100644
--- a/llvm/unittests/CodeGen/CMakeLists.txt
+++ b/llvm/unittests/CodeGen/CMakeLists.txt
@@ -41,7 +41,6 @@ add_llvm_unittest(CodeGenTests
   MIR2VecTest.cpp
   RegAllocBasicTest.cpp
   RegAllocScoreTest.cpp
-  RegisterClassInfoTest.cpp
   RegisterTest.cpp
   PassManagerTest.cpp
   RematerializerTest.cpp
diff --git a/llvm/unittests/Target/AMDGPU/CMakeLists.txt b/llvm/unittests/Target/AMDGPU/CMakeLists.txt
index 39cced662567d..70a9954246a3e 100644
--- a/llvm/unittests/Target/AMDGPU/CMakeLists.txt
+++ b/llvm/unittests/Target/AMDGPU/CMakeLists.txt
@@ -32,5 +32,6 @@ add_llvm_target_unittest(AMDGPUTests
   InstSizes.cpp
   LiveRegUnits.cpp
   PALMetadata.cpp
+  RegisterClassInfoTest.cpp
   UniformityAnalysisTest.cpp
   )
diff --git a/llvm/unittests/CodeGen/RegisterClassInfoTest.cpp b/llvm/unittests/Target/AMDGPU/RCIUpdateReservedRegsTest.cpp
similarity index 90%
rename from llvm/unittests/CodeGen/RegisterClassInfoTest.cpp
rename to llvm/unittests/Target/AMDGPU/RCIUpdateReservedRegsTest.cpp
index 04abdea60201a..888f28c14ec2d 100644
--- a/llvm/unittests/CodeGen/RegisterClassInfoTest.cpp
+++ b/llvm/unittests/Target/AMDGPU/RCIUpdateReservedRegsTest.cpp
@@ -6,35 +6,22 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/CodeGen/RegisterClassInfo.h"
-#include "CodeGenTestBase.h"
+#include "AMDGPUUnitTests.h"
 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/RegisterClassInfo.h"
 #include "llvm/CodeGen/TargetRegisterInfo.h"
-#include "llvm/Config/Targets.h"
 #include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/Support/TargetSelect.h"
 #include "gtest/gtest.h"
 
 using namespace llvm;
 
 namespace {
 
-class RegisterClassInfoTest : public CodeGenTestBase {
+class RegisterClassInfoTest : public AMDGPUCodeGenTestBase {
 public:
-  /// Register the AMDGPU target components needed by this test suite.
-  static void SetUpTestCase() {
-#if LLVM_HAS_AMDGPU_TARGET
-    LLVMInitializeAMDGPUTargetInfo();
-    LLVMInitializeAMDGPUTarget();
-    LLVMInitializeAMDGPUTargetMC();
-#else
-    GTEST_SKIP();
-#endif
-  }
-
   /// Use a GCN triple so VGPR registers are available to the test.
   void SetUp() override { setUpImpl("amdgpu9.00-amd-amdhsa", "", /*FS=*/""); }
 };



More information about the llvm-commits mailing list