[llvm] [AMDGPU] Add per-class register stress options (PR #210907)
Romanov Vlad via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 21 02:23:57 PDT 2026
https://github.com/romanovvlad updated https://github.com/llvm/llvm-project/pull/210907
>From c021659c5202dc97dd80c81c3039732c53bed087 Mon Sep 17 00:00:00 2001
From: Vlad <Vladislav.Romanov at amd.com>
Date: Mon, 13 Jul 2026 10:04:27 -0500
Subject: [PATCH 1/3] [AMDGPU] Add per-class register stress options
Add options -amdgpu-stress-vgpr=N, -amdgpu-stress-agpr=N, and
-amdgpu-stress-sgpr=N to limit each register class independently by
reserving registers beyond N.
---
llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp | 20 ++++++
.../stress-regalloc-limits-regalloc.mir | 60 +++++++++++++++++
.../AMDGPU/stress-regalloc-limits-sched.mir | 64 +++++++++++++++++++
3 files changed, 144 insertions(+)
create mode 100644 llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-regalloc.mir
create mode 100644 llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-sched.mir
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
index 358aa054b3a3f..6f5c233e74598 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
@@ -40,6 +40,18 @@ static cl::opt<bool> EnableSpillCFISavedRegs(
cl::desc("Enable spilling the registers required for CFI emission"),
cl::ReallyHidden, cl::init(false), cl::ZeroOrMore);
+static cl::opt<unsigned>
+ StressVGPRLimit("amdgpu-stress-vgpr", cl::Hidden, cl::init(0),
+ cl::desc("Limit VGPRs to N registers by reserving the rest"));
+
+static cl::opt<unsigned>
+ StressAGPRLimit("amdgpu-stress-agpr", cl::Hidden, cl::init(0),
+ cl::desc("Limit AGPRs to N registers by reserving the rest"));
+
+static cl::opt<unsigned>
+ StressSGPRLimit("amdgpu-stress-sgpr", cl::Hidden, cl::init(0),
+ cl::desc("Limit SGPRs to N registers by reserving the rest"));
+
std::array<std::vector<int16_t>, 32> SIRegisterInfo::RegSplitParts;
std::array<std::array<uint16_t, 32>, 9> SIRegisterInfo::SubRegFromChannelTable;
@@ -644,6 +656,8 @@ BitVector SIRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
// Reserve SGPRs.
//
unsigned MaxNumSGPRs = ST.getMaxNumSGPRs(MF);
+ if (StressSGPRLimit.getNumOccurrences() && StressSGPRLimit < MaxNumSGPRs)
+ MaxNumSGPRs = StressSGPRLimit;
unsigned TotalNumSGPRs = AMDGPU::SGPR_32RegClass.getNumRegs();
for (const TargetRegisterClass &RC : regclasses()) {
if (RC.isBaseClass() && isSGPRClass(&RC)) {
@@ -701,6 +715,12 @@ BitVector SIRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
//
auto [MaxNumVGPRs, MaxNumAGPRs] = ST.getMaxNumVectorRegs(MF.getFunction());
+ // Stress test: override VGPR/AGPR limits.
+ if (StressVGPRLimit.getNumOccurrences() && StressVGPRLimit < MaxNumVGPRs)
+ MaxNumVGPRs = StressVGPRLimit;
+ if (StressAGPRLimit.getNumOccurrences() && StressAGPRLimit < MaxNumAGPRs)
+ MaxNumAGPRs = StressAGPRLimit;
+
for (const TargetRegisterClass &RC : regclasses()) {
if (RC.isBaseClass() && isVGPRClass(&RC)) {
unsigned NumRegs = divideCeil(getRegSizeInBits(RC), 32);
diff --git a/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-regalloc.mir b/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-regalloc.mir
new file mode 100644
index 0000000000000..d035b02a5754c
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-regalloc.mir
@@ -0,0 +1,60 @@
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx950 %s -o - | FileCheck -check-prefix=DEFAULT %s
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx950 -amdgpu-stress-vgpr=2 %s -o - | FileCheck -check-prefix=VGPR2 %s
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx950 -amdgpu-stress-vgpr=4 -amdgpu-stress-agpr=0 %s -o - | FileCheck -check-prefix=VGPR4-AGPR0 %s
+
+# Test that -amdgpu-stress-vgpr and -amdgpu-stress-agpr limit register
+# availability during register allocation.
+#
+# No limits - all values stay in VGPRs, no spills.
+# With -amdgpu-stress-vgpr=2 - overflow to AGPRs.
+# With -amdgpu-stress-vgpr=4 -amdgpu-stress-agpr=0 - forced to spill to scratch.
+
+--- |
+ define amdgpu_kernel void @stress_regalloc(ptr addrspace(1) %p) #0 { ret void }
+ attributes #0 = { "amdgpu-waves-per-eu"="1,1" "amdgpu-flat-work-group-size"="64,64" }
+...
+
+---
+# DEFAULT-LABEL: stress_regalloc:
+# DEFAULT: global_load_dword v
+# DEFAULT-NOT: global_load_dword a
+# DEFAULT-NOT: scratch_store
+# DEFAULT: s_endpgm
+
+# VGPR2-LABEL: stress_regalloc:
+# VGPR2: global_load_dword a
+# VGPR2: s_endpgm
+
+# VGPR4-AGPR0-LABEL: stress_regalloc:
+# VGPR4-AGPR0-NOT: global_load_dword a
+# VGPR4-AGPR0: scratch_store
+# VGPR4-AGPR0: s_endpgm
+
+name: stress_regalloc
+tracksRegLiveness: true
+machineFunctionInfo:
+ isEntryFunction: true
+body: |
+ bb.0:
+ liveins: $sgpr4_sgpr5
+
+ %0:sgpr_64 = COPY $sgpr4_sgpr5
+ %1:sreg_64_xexec = S_LOAD_DWORDX2_IMM %0, 0, 0 :: (load (s64), addrspace 4)
+ %addr:vreg_64_align2 = COPY %1
+
+ %v0:vgpr_32 = GLOBAL_LOAD_DWORD %addr, 0, 0, implicit $exec :: (volatile load (s32), addrspace 1)
+ %v1:vgpr_32 = GLOBAL_LOAD_DWORD %addr, 4, 0, implicit $exec :: (volatile load (s32), addrspace 1)
+ %v2:vgpr_32 = GLOBAL_LOAD_DWORD %addr, 8, 0, implicit $exec :: (volatile load (s32), addrspace 1)
+ %v3:vgpr_32 = GLOBAL_LOAD_DWORD %addr, 12, 0, implicit $exec :: (volatile load (s32), addrspace 1)
+ %v4:vgpr_32 = GLOBAL_LOAD_DWORD %addr, 16, 0, implicit $exec :: (volatile load (s32), addrspace 1)
+ %v5:vgpr_32 = GLOBAL_LOAD_DWORD %addr, 20, 0, implicit $exec :: (volatile load (s32), addrspace 1)
+
+ GLOBAL_STORE_DWORD %addr, %v0, 40, 0, implicit $exec :: (volatile store (s32), addrspace 1)
+ GLOBAL_STORE_DWORD %addr, %v1, 44, 0, implicit $exec :: (volatile store (s32), addrspace 1)
+ GLOBAL_STORE_DWORD %addr, %v2, 48, 0, implicit $exec :: (volatile store (s32), addrspace 1)
+ GLOBAL_STORE_DWORD %addr, %v3, 52, 0, implicit $exec :: (volatile store (s32), addrspace 1)
+ GLOBAL_STORE_DWORD %addr, %v4, 56, 0, implicit $exec :: (volatile store (s32), addrspace 1)
+ GLOBAL_STORE_DWORD %addr, %v5, 60, 0, implicit $exec :: (volatile store (s32), addrspace 1)
+
+ S_ENDPGM 0
+...
diff --git a/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-sched.mir b/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-sched.mir
new file mode 100644
index 0000000000000..8708d26396dc9
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-sched.mir
@@ -0,0 +1,64 @@
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx950 -run-pass=machine-scheduler %s -o - | FileCheck -check-prefix=DEFAULT %s
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx950 -run-pass=machine-scheduler -amdgpu-stress-vgpr=3 %s -o - | FileCheck -check-prefix=STRESS %s
+
+# Test that -amdgpu-stress-vgpr affects scheduler pressure tracking.
+# Without stress, the scheduler keeps all producers before consumers.
+# With stress, the scheduler interleaves producers and consumers to
+# reduce register pressure.
+
+--- |
+ define amdgpu_kernel void @sched_pressure() #0 { ret void }
+ attributes #0 = { "amdgpu-waves-per-eu"="1,1" "amdgpu-flat-work-group-size"="64,64" }
+...
+
+---
+# DEFAULT-LABEL: name: sched_pressure
+# DEFAULT: %v0:vgpr_32 = V_ADD_U32_e32
+# DEFAULT-NEXT: %v1:vgpr_32 = V_MUL_LO_U32_e64
+# DEFAULT-NEXT: %v2:vgpr_32 = V_SUB_U32_e32
+# DEFAULT-NEXT: %v3:vgpr_32 = V_XOR_B32_e32
+# DEFAULT-NEXT: %v4:vgpr_32 = V_OR_B32_e32
+# DEFAULT-NEXT: %v5:vgpr_32 = V_AND_B32_e32
+# DEFAULT-NEXT: %r0:vgpr_32 = V_ADD_U32_e32 %v0, %v1
+# DEFAULT-NEXT: %r1:vgpr_32 = V_ADD_U32_e32 %v2, %v3
+# DEFAULT-NEXT: %r2:vgpr_32 = V_ADD_U32_e32 %v4, %v5
+
+# STRESS-LABEL: name: sched_pressure
+# STRESS: %v0:vgpr_32 = V_ADD_U32_e32
+# STRESS-NEXT: %v1:vgpr_32 = V_MUL_LO_U32_e64
+# STRESS-NEXT: %r0:vgpr_32 = V_ADD_U32_e32 %v0, %v1
+# STRESS-NEXT: %v2:vgpr_32 = V_SUB_U32_e32
+# STRESS-NEXT: %v3:vgpr_32 = V_XOR_B32_e32
+# STRESS-NEXT: %r1:vgpr_32 = V_ADD_U32_e32 %v2, %v3
+# STRESS-NEXT: %v4:vgpr_32 = V_OR_B32_e32
+# STRESS-NEXT: %v5:vgpr_32 = V_AND_B32_e32
+# STRESS-NEXT: %r2:vgpr_32 = V_ADD_U32_e32 %v4, %v5
+
+name: sched_pressure
+tracksRegLiveness: true
+machineFunctionInfo:
+ isEntryFunction: true
+body: |
+ bb.0:
+ liveins: $vgpr0, $vgpr1
+
+ %a:vgpr_32 = COPY $vgpr0
+ %b:vgpr_32 = COPY $vgpr1
+
+ %v0:vgpr_32 = V_ADD_U32_e32 %a, %b, implicit $exec
+ %v1:vgpr_32 = V_MUL_LO_U32_e64 %a, %b, implicit $exec
+ %v2:vgpr_32 = V_SUB_U32_e32 %a, %b, implicit $exec
+ %v3:vgpr_32 = V_XOR_B32_e32 %a, %b, implicit $exec
+ %v4:vgpr_32 = V_OR_B32_e32 %a, %b, implicit $exec
+ %v5:vgpr_32 = V_AND_B32_e32 %a, %b, implicit $exec
+
+ %r0:vgpr_32 = V_ADD_U32_e32 %v0, %v1, implicit $exec
+ %r1:vgpr_32 = V_ADD_U32_e32 %v2, %v3, implicit $exec
+ %r2:vgpr_32 = V_ADD_U32_e32 %v4, %v5, implicit $exec
+ %r3:vgpr_32 = V_ADD_U32_e32 %r0, %r1, implicit $exec
+ %r4:vgpr_32 = V_ADD_U32_e32 %r3, %r2, implicit $exec
+
+ DS_WRITE_B32_gfx9 %a, %r4, 0, 0, implicit $exec :: (store (s32), addrspace 3)
+
+ S_ENDPGM 0
+...
>From 7d248fa255390abc3b91671815834202b4c61f4f Mon Sep 17 00:00:00 2001
From: Vlad <Vladislav.Romanov at amd.com>
Date: Tue, 21 Jul 2026 03:30:37 -0500
Subject: [PATCH 2/3] format
---
llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
index 6f5c233e74598..14f5c397e7585 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
@@ -40,17 +40,17 @@ static cl::opt<bool> EnableSpillCFISavedRegs(
cl::desc("Enable spilling the registers required for CFI emission"),
cl::ReallyHidden, cl::init(false), cl::ZeroOrMore);
-static cl::opt<unsigned>
- StressVGPRLimit("amdgpu-stress-vgpr", cl::Hidden, cl::init(0),
- cl::desc("Limit VGPRs to N registers by reserving the rest"));
+static cl::opt<unsigned> StressVGPRLimit(
+ "amdgpu-stress-vgpr", cl::Hidden, cl::init(0),
+ cl::desc("Limit VGPRs to N registers by reserving the rest"));
-static cl::opt<unsigned>
- StressAGPRLimit("amdgpu-stress-agpr", cl::Hidden, cl::init(0),
- cl::desc("Limit AGPRs to N registers by reserving the rest"));
+static cl::opt<unsigned> StressAGPRLimit(
+ "amdgpu-stress-agpr", cl::Hidden, cl::init(0),
+ cl::desc("Limit AGPRs to N registers by reserving the rest"));
-static cl::opt<unsigned>
- StressSGPRLimit("amdgpu-stress-sgpr", cl::Hidden, cl::init(0),
- cl::desc("Limit SGPRs to N registers by reserving the rest"));
+static cl::opt<unsigned> StressSGPRLimit(
+ "amdgpu-stress-sgpr", cl::Hidden, cl::init(0),
+ cl::desc("Limit SGPRs to N registers by reserving the rest"));
std::array<std::vector<int16_t>, 32> SIRegisterInfo::RegSplitParts;
std::array<std::array<uint16_t, 32>, 9> SIRegisterInfo::SubRegFromChannelTable;
>From ad1df44265d285396f67664a5a203c429a2a85fa Mon Sep 17 00:00:00 2001
From: Vlad <Vladislav.Romanov at amd.com>
Date: Tue, 21 Jul 2026 04:23:43 -0500
Subject: [PATCH 3/3] update triple
---
.../test/CodeGen/AMDGPU/stress-regalloc-limits-regalloc.mir | 6 +++---
llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-sched.mir | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-regalloc.mir b/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-regalloc.mir
index d035b02a5754c..2595d1e80b39d 100644
--- a/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-regalloc.mir
+++ b/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-regalloc.mir
@@ -1,6 +1,6 @@
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx950 %s -o - | FileCheck -check-prefix=DEFAULT %s
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx950 -amdgpu-stress-vgpr=2 %s -o - | FileCheck -check-prefix=VGPR2 %s
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx950 -amdgpu-stress-vgpr=4 -amdgpu-stress-agpr=0 %s -o - | FileCheck -check-prefix=VGPR4-AGPR0 %s
+# RUN: llc -mtriple=amdgpu9.50-amd-amdhsa %s -o - | FileCheck -check-prefix=DEFAULT %s
+# RUN: llc -mtriple=amdgpu9.50-amd-amdhsa -amdgpu-stress-vgpr=2 %s -o - | FileCheck -check-prefix=VGPR2 %s
+# RUN: llc -mtriple=amdgpu9.50-amd-amdhsa -amdgpu-stress-vgpr=4 -amdgpu-stress-agpr=0 %s -o - | FileCheck -check-prefix=VGPR4-AGPR0 %s
# Test that -amdgpu-stress-vgpr and -amdgpu-stress-agpr limit register
# availability during register allocation.
diff --git a/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-sched.mir b/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-sched.mir
index 8708d26396dc9..0702d938ef337 100644
--- a/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-sched.mir
+++ b/llvm/test/CodeGen/AMDGPU/stress-regalloc-limits-sched.mir
@@ -1,5 +1,5 @@
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx950 -run-pass=machine-scheduler %s -o - | FileCheck -check-prefix=DEFAULT %s
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx950 -run-pass=machine-scheduler -amdgpu-stress-vgpr=3 %s -o - | FileCheck -check-prefix=STRESS %s
+# RUN: llc -mtriple=amdgpu9.50-amd-amdhsa -run-pass=machine-scheduler %s -o - | FileCheck -check-prefix=DEFAULT %s
+# RUN: llc -mtriple=amdgpu9.50-amd-amdhsa -run-pass=machine-scheduler -amdgpu-stress-vgpr=3 %s -o - | FileCheck -check-prefix=STRESS %s
# Test that -amdgpu-stress-vgpr affects scheduler pressure tracking.
# Without stress, the scheduler keeps all producers before consumers.
More information about the llvm-commits
mailing list