[llvm] [RegAlloc] Avoid split past block-prologue interference (PR #209704)
Lukas Sommer via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 23 08:13:38 PDT 2026
https://github.com/sommerlukas updated https://github.com/llvm/llvm-project/pull/209704
>From 461bafb444c412b7c2912be68724c979507bfbad Mon Sep 17 00:00:00 2001
From: Lukas Sommer <lukas.sommer at amd.com>
Date: Tue, 14 Jul 2026 12:22:45 -0500
Subject: [PATCH 1/4] [RegAlloc] Avoid split past block-prologue interference
`leaveIntvAtTop` skips the target-specific block prologue when
determining the insertion point.
If the block prologue itself contains an instruction that interferes
with the interval, we must leave the interval before the block,
otherwise we will hit an assertion in `splitLiveThroughBlock`.
Signed-off-by: Lukas Sommer <lukas.sommer at amd.com>
---
llvm/lib/CodeGen/RegAllocGreedy.cpp | 9 +-
.../greedy-wwm-copy-prologue-assert.mir | 107 ++++++++++++++++++
2 files changed, 115 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
diff --git a/llvm/lib/CodeGen/RegAllocGreedy.cpp b/llvm/lib/CodeGen/RegAllocGreedy.cpp
index 6b8a9b8190f9a..799816191eca1 100644
--- a/llvm/lib/CodeGen/RegAllocGreedy.cpp
+++ b/llvm/lib/CodeGen/RegAllocGreedy.cpp
@@ -843,8 +843,15 @@ bool RAGreedy::addThroughConstraints(InterferenceCache::Cursor Intf,
SlotIndex::isEarlierInstr(LIS->getInstructionIndex(*FirstNonDebugInstr),
SA->getFirstSplitPoint(Number)))
return false;
+
// Interference for the live-in value.
- if (Intf.first() <= Indexes->getMBBStartIdx(Number))
+ Register Reg = SA->getParent().reg();
+ auto InsertPt = MBB->SkipPHIsLabelsAndDebug(MBB->begin(), Reg);
+ SlotIndex InsertIdx = InsertPt == MBB->end()
+ ? Indexes->getMBBEndIdx(Number)
+ : LIS->getInstructionIndex(*InsertPt);
+ if (Intf.first() <= Indexes->getMBBStartIdx(Number) ||
+ SlotIndex::isEarlierInstr(Intf.first(), InsertIdx))
BCS[B].Entry = SpillPlacement::MustSpill;
else
BCS[B].Entry = SpillPlacement::PrefSpill;
diff --git a/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir b/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
new file mode 100644
index 0000000000000..0c59d92012e35
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
@@ -0,0 +1,107 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -run-pass=greedy -o - %s | FileCheck %s
+
+# Check that splitting doesn't attempt to split after the prologue, if the first
+# interference is in the prologue. The hot loop in bb.1 keeps %0 in $vgpr0.
+# On the cold exit, the pre-existing WWM_COPY in bb.2 is a block prologue and
+# also occupies $vgpr0. Therefore, we can't split in bb.2. In this case,
+# spilling is chosen instead.
+# This is a regression test for the SplitKit interference assertion in
+# 'leaveIntvAtTop'.
+#
+--- |
+ define amdgpu_kernel void @wwm_copy_prologue_assert() #0 {
+ ret void
+ }
+
+ attributes #0 = { "amdgpu-num-vgpr"="2" }
+...
+---
+name: wwm_copy_prologue_assert
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: vgpr_32, flags: [ WWM_REG ] }
+ - { id: 1, class: vgpr_32, flags: [ WWM_REG ] }
+machineFunctionInfo:
+ isEntryFunction: true
+ scratchRSrcReg: '$sgpr0_sgpr1_sgpr2_sgpr3'
+ stackPtrOffsetReg: '$sgpr32'
+ sgprForEXECCopy: '$sgpr100_sgpr101'
+body: |
+ ; CHECK-LABEL: name: wwm_copy_prologue_assert
+ ; CHECK: bb.0:
+ ; CHECK-NEXT: successors: %bb.1(0x80000000)
+ ; CHECK-NEXT: liveins: $vgpr1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[V_ADD_U32_e32_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e32 $vgpr1, $vgpr1, implicit $exec
+ ; CHECK-NEXT: S_NOP 0, implicit [[V_ADD_U32_e32_]], implicit $vgpr1
+ ; CHECK-NEXT: S_BRANCH %bb.1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1:
+ ; CHECK-NEXT: successors: %bb.1(0x7fffffff), %bb.2(0x00000001)
+ ; CHECK-NEXT: liveins: $vgpr1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: S_NOP 0, implicit [[V_ADD_U32_e32_]], implicit $vgpr1
+ ; CHECK-NEXT: S_CBRANCH_VCCNZ %bb.1, implicit undef $vcc
+ ; CHECK-NEXT: S_BRANCH %bb.2
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.2:
+ ; CHECK-NEXT: successors: %bb.3(0x80000000)
+ ; CHECK-NEXT: liveins: $vgpr1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: SI_SPILL_WWM_V32_SAVE [[V_ADD_U32_e32_]], %stack.0, $sgpr32, 0, implicit $exec :: (store (s32) into %stack.0, addrspace 5)
+ ; CHECK-NEXT: [[WWM_COPY:%[0-9]+]]:vgpr_32 = lr-split WWM_COPY $vgpr1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.3:
+ ; CHECK-NEXT: successors: %bb.4(0x80000000)
+ ; CHECK-NEXT: liveins: $vgpr1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.4:
+ ; CHECK-NEXT: successors: %bb.5(0x80000000)
+ ; CHECK-NEXT: liveins: $vgpr1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: S_NOP 0, implicit [[WWM_COPY]], implicit $vgpr1
+ ; CHECK-NEXT: [[SI_SPILL_WWM_V32_RESTORE:%[0-9]+]]:vgpr_32 = SI_SPILL_WWM_V32_RESTORE %stack.0, $sgpr32, 0, implicit $exec :: (load (s32) from %stack.0, addrspace 5)
+ ; CHECK-NEXT: S_NOP 0, implicit [[SI_SPILL_WWM_V32_RESTORE]], implicit $vgpr1
+ ; CHECK-NEXT: S_BRANCH %bb.5
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.5:
+ ; CHECK-NEXT: liveins: $vgpr1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: S_NOP 0, implicit [[SI_SPILL_WWM_V32_RESTORE]], implicit $vgpr1
+ ; CHECK-NEXT: S_ENDPGM 0
+ bb.0:
+ successors: %bb.1
+ liveins: $vgpr1
+ %0:vgpr_32 = V_ADD_U32_e32 $vgpr1, $vgpr1, implicit $exec
+ S_NOP 0, implicit %0, implicit $vgpr1
+ S_BRANCH %bb.1
+
+ bb.1:
+ successors: %bb.1(0x7fffffff), %bb.2(0x00000001)
+ liveins: $vgpr1
+ S_NOP 0, implicit %0, implicit $vgpr1
+ S_CBRANCH_VCCNZ %bb.1, implicit undef $vcc
+ S_BRANCH %bb.2
+
+ bb.2:
+ successors: %bb.3
+ liveins: $vgpr1
+ %1:vgpr_32 = lr-split WWM_COPY $vgpr1
+
+ bb.3:
+ successors: %bb.4
+ liveins: $vgpr1
+
+ bb.4:
+ successors: %bb.5
+ liveins: $vgpr1
+ S_NOP 0, implicit killed %1, implicit $vgpr1
+ S_NOP 0, implicit %0, implicit $vgpr1
+ S_BRANCH %bb.5
+
+ bb.5:
+ liveins: $vgpr1
+ S_NOP 0, implicit %0, implicit $vgpr1
+ S_ENDPGM 0
+...
>From 56448e81c4369aa8bf7cb8328a89d619b7d8300f Mon Sep 17 00:00:00 2001
From: Lukas Sommer <lukas.sommer at amd.com>
Date: Wed, 15 Jul 2026 09:15:25 -0500
Subject: [PATCH 2/4] Address PR feedback on test
Signed-off-by: Lukas Sommer <lukas.sommer at amd.com>
---
.../CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir b/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
index 0c59d92012e35..94795f11f9039 100644
--- a/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
+++ b/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
@@ -1,20 +1,18 @@
-# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
-# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -run-pass=greedy -o - %s | FileCheck %s
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=amdgpu9.00-amd-amdhsa -stress-regalloc=2 -passes='greedy<wwm>' -o - %s | FileCheck %s
# Check that splitting doesn't attempt to split after the prologue, if the first
# interference is in the prologue. The hot loop in bb.1 keeps %0 in $vgpr0.
# On the cold exit, the pre-existing WWM_COPY in bb.2 is a block prologue and
# also occupies $vgpr0. Therefore, we can't split in bb.2. In this case,
# spilling is chosen instead.
-# This is a regression test for the SplitKit interference assertion in
+# This is a regression test for the SplitKit interference assertion in
# 'leaveIntvAtTop'.
#
--- |
- define amdgpu_kernel void @wwm_copy_prologue_assert() #0 {
+ define amdgpu_kernel void @wwm_copy_prologue_assert() {
ret void
}
-
- attributes #0 = { "amdgpu-num-vgpr"="2" }
...
---
name: wwm_copy_prologue_assert
>From 74eca5433ddce0d2142f31eb88438e11581840c5 Mon Sep 17 00:00:00 2001
From: Lukas Sommer <lukas.sommer at amd.com>
Date: Wed, 15 Jul 2026 11:53:04 -0500
Subject: [PATCH 3/4] Add legacy PM run line to test
Signed-off-by: Lukas Sommer <lukas.sommer at amd.com>
---
llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir b/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
index 94795f11f9039..d704b3c27e4c6 100644
--- a/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
+++ b/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
@@ -1,4 +1,5 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=amdgpu9.00-amd-amdhsa -stress-regalloc=2 --start-before=greedy,1 --stop-after=greedy,1 -o - %s | FileCheck %s
# RUN: llc -mtriple=amdgpu9.00-amd-amdhsa -stress-regalloc=2 -passes='greedy<wwm>' -o - %s | FileCheck %s
# Check that splitting doesn't attempt to split after the prologue, if the first
>From 6bdce9d3e5800351c5b0351fb20efbd19c2fff45 Mon Sep 17 00:00:00 2001
From: Lukas Sommer <lukas.sommer at amd.com>
Date: Thu, 16 Jul 2026 03:13:56 -0500
Subject: [PATCH 4/4] Revert "Add legacy PM run line to test"
This reverts commit a26c79c9f9bba9bb96fd51bb3f283879658ebca5.
---
llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir b/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
index d704b3c27e4c6..94795f11f9039 100644
--- a/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
+++ b/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
@@ -1,5 +1,4 @@
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
-# RUN: llc -mtriple=amdgpu9.00-amd-amdhsa -stress-regalloc=2 --start-before=greedy,1 --stop-after=greedy,1 -o - %s | FileCheck %s
# RUN: llc -mtriple=amdgpu9.00-amd-amdhsa -stress-regalloc=2 -passes='greedy<wwm>' -o - %s | FileCheck %s
# Check that splitting doesn't attempt to split after the prologue, if the first
More information about the llvm-commits
mailing list