[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
Sun Aug 2 17:47:49 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 1/6] 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 2/6] 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 3/6] 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 4/6] 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 5/6] 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 6/6] 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
...
More information about the llvm-commits
mailing list