[llvm] 9d10180 - [RegAlloc] Avoid split past block-prologue interference (#209704)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 31 00:58:03 PDT 2026
Author: Lukas Sommer
Date: 2026-07-31T09:57:58+02:00
New Revision: 9d1018038c01d12801ccca9da5e6b5589989750a
URL: https://github.com/llvm/llvm-project/commit/9d1018038c01d12801ccca9da5e6b5589989750a
DIFF: https://github.com/llvm/llvm-project/commit/9d1018038c01d12801ccca9da5e6b5589989750a.diff
LOG: [RegAlloc] Avoid split past block-prologue interference (#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`.
---------
Signed-off-by: Lukas Sommer <lukas.sommer at amd.com>
Added:
llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
Modified:
llvm/lib/CodeGen/RegAllocGreedy.cpp
Removed:
################################################################################
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..94795f11f9039
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/greedy-wwm-copy-prologue-assert.mir
@@ -0,0 +1,105 @@
+# 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
+# 'leaveIntvAtTop'.
+#
+--- |
+ define amdgpu_kernel void @wwm_copy_prologue_assert() {
+ ret void
+ }
+...
+---
+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