[llvm] [RegAlloc] Avoid split past block-prologue interference (PR #209704)
Lukas Sommer via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 15 02:15:16 PDT 2026
https://github.com/sommerlukas created https://github.com/llvm/llvm-project/pull/209704
`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`.
>From eb8d5e72445ba693d9b50cc68b8424458ac87cec 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] [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
+...
More information about the llvm-commits
mailing list