[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