[llvm] [RegAlloc] Avoid split past block-prologue interference (PR #209704)

Lukas Sommer via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 30 21:53:29 PDT 2026


https://github.com/sommerlukas updated https://github.com/llvm/llvm-project/pull/209704

>From c2dc3e8f26c2eee726013904756ee1a16467fd3a 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 56e659a7d7762..ef23468b1e752 100644
--- a/llvm/lib/CodeGen/RegAllocGreedy.cpp
+++ b/llvm/lib/CodeGen/RegAllocGreedy.cpp
@@ -839,8 +839,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 31eba88a0dd5237ba058603fa2f666821132f21c 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 74d91272f07dafce5bf2e5f6d4ea8a3a3bd4446b 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 17cc7307cb3d098e9fde3aaa4beed334e314ad63 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