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

Lukas Sommer via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 16 02:34:00 PDT 2026


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

>From 0049f8583905f3dddf71bc7ce78b71d3b5ded9ba 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 63d8c6ef48c723fce84db499b6f8cc950e675ff2 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 cbfba06bce9177496726de07057c66cf92f76372 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 532a9e5238b08f36b35b6d4a5b19739c754748d6 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