[llvm] [AMDGPU] Fix crash in SIWholeQuadMode with debug instructions. (PR #178282)
Daniil Fukalov via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 27 11:56:48 PST 2026
https://github.com/dfukalov updated https://github.com/llvm/llvm-project/pull/178282
>From 5ac945f13e1b7c9ae93c612416133ef500189f89 Mon Sep 17 00:00:00 2001
From: Daniil Fukalov <dfukalov at gmail.com>
Date: Tue, 27 Jan 2026 20:19:57 +0100
Subject: [PATCH 1/2] [AMDGPU] Fix crash in SIWholeQuadMode with debug
instructions.
The prepareInsertion function was crashing when debug instructions
appeared at positions being queried for slot indices. Debug instructions
don't have entries in the slot index map, so getInstructionIndex would
fail with an assertion.
Fixes SWDEV-480902.
---
llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp | 18 ++-
llvm/test/CodeGen/AMDGPU/wqm-debug-instr.mir | 122 +++++++++++++++++++
2 files changed, 134 insertions(+), 6 deletions(-)
create mode 100644 llvm/test/CodeGen/AMDGPU/wqm-debug-instr.mir
diff --git a/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp b/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp
index 0452dea982d48..c8cb938d088d1 100644
--- a/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp
+++ b/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp
@@ -1104,10 +1104,16 @@ MachineBasicBlock::iterator SIWholeQuadMode::prepareInsertion(
LiveRange &LR =
LIS->getRegUnit(*TRI->regunits(MCRegister::from(AMDGPU::SCC)).begin());
auto MBBE = MBB.end();
- SlotIndex FirstIdx = First != MBBE ? LIS->getInstructionIndex(*First)
- : LIS->getMBBEndIdx(&MBB);
- SlotIndex LastIdx =
- Last != MBBE ? LIS->getInstructionIndex(*Last) : LIS->getMBBEndIdx(&MBB);
+ // Skip debug instructions when getting slot indices, as they don't have
+ // entries in the slot index map.
+ auto FirstNonDbg = skipDebugInstructionsForward(First, MBBE);
+ auto LastNonDbg = skipDebugInstructionsForward(Last, MBBE);
+ SlotIndex FirstIdx = FirstNonDbg != MBBE
+ ? LIS->getInstructionIndex(*FirstNonDbg)
+ : LIS->getMBBEndIdx(&MBB);
+ SlotIndex LastIdx = LastNonDbg != MBBE
+ ? LIS->getInstructionIndex(*LastNonDbg)
+ : LIS->getMBBEndIdx(&MBB);
SlotIndex Idx = PreferLast ? LastIdx : FirstIdx;
const LiveRange::Segment *S;
@@ -1124,8 +1130,8 @@ MachineBasicBlock::iterator SIWholeQuadMode::prepareInsertion(
} else {
MachineInstr *EndMI = LIS->getInstructionFromIndex(S->end.getBaseIndex());
assert(EndMI && "Segment does not end on valid instruction");
- auto NextI = std::next(EndMI->getIterator());
- if (NextI == MBB.end())
+ auto NextI = next_nodbg(EndMI->getIterator(), MBB.instr_end());
+ if (NextI == MBB.instr_end())
break;
SlotIndex Next = LIS->getInstructionIndex(*NextI);
if (Next > LastIdx)
diff --git a/llvm/test/CodeGen/AMDGPU/wqm-debug-instr.mir b/llvm/test/CodeGen/AMDGPU/wqm-debug-instr.mir
new file mode 100644
index 0000000000000..1cb46886cf055
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/wqm-debug-instr.mir
@@ -0,0 +1,122 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=amdgcn -verify-machineinstrs -run-pass si-wqm -o - %s | FileCheck %s
+
+# Test that si-wqm correctly handles debug instructions when computing
+# insertion points for SCC save/restore. Debug instructions don't have
+# slot indices, so they must be skipped when querying LiveIntervals.
+
+---
+# Test case 1: Debug instruction at the First position (start of region
+# requiring mode change). The pass must skip debug instructions when
+# getting slot indices to avoid assertion failure in SlotIndexes.
+name: test_debug_instr_at_first
+tracksRegLiveness: true
+body: |
+ ; CHECK-LABEL: name: test_debug_instr_at_first
+ ; CHECK: bb.0:
+ ; CHECK-NEXT: successors: %bb.1(0x80000000)
+ ; CHECK-NEXT: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ENTER_STRICT_WWM:%[0-9]+]]:sreg_64 = ENTER_STRICT_WWM -1, implicit-def $exec, implicit-def $scc, implicit $exec
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0
+ ; CHECK-NEXT: $exec = EXIT_STRICT_WWM [[ENTER_STRICT_WWM]]
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:sgpr_32 = COPY $sgpr2
+ ; CHECK-NEXT: [[COPY2:%[0-9]+]]:sgpr_32 = COPY $sgpr1
+ ; CHECK-NEXT: [[COPY3:%[0-9]+]]:sgpr_32 = COPY $sgpr0
+ ; CHECK-NEXT: [[DEF:%[0-9]+]]:sgpr_128 = IMPLICIT_DEF
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1:
+ ; CHECK-NEXT: S_CMP_LT_I32 0, [[COPY3]], implicit-def $scc
+ ; CHECK-NEXT: [[S_CSELECT_B32_:%[0-9]+]]:sgpr_32 = S_CSELECT_B32 [[COPY1]], [[COPY2]], implicit $scc
+ ; CHECK-NEXT: DBG_VALUE $noreg, $noreg
+ ; CHECK-NEXT: [[BUFFER_LOAD_DWORD_OFFEN:%[0-9]+]]:vgpr_32 = BUFFER_LOAD_DWORD_OFFEN [[COPY]], [[DEF]], 0, 0, 0, 0, implicit $exec
+ ; CHECK-NEXT: [[ENTER_STRICT_WWM1:%[0-9]+]]:sreg_64 = ENTER_STRICT_WWM -1, implicit-def $exec, implicit-def $scc, implicit $exec
+ ; CHECK-NEXT: [[V_ADD_CO_U32_e32_:%[0-9]+]]:vgpr_32 = V_ADD_CO_U32_e32 [[COPY]], [[COPY]], implicit-def $vcc, implicit $exec
+ ; CHECK-NEXT: [[V_ADD_CO_U32_e32_1:%[0-9]+]]:vgpr_32 = V_ADD_CO_U32_e32 [[S_CSELECT_B32_]], [[V_ADD_CO_U32_e32_]], implicit-def $vcc, implicit $exec
+ ; CHECK-NEXT: $exec = EXIT_STRICT_WWM [[ENTER_STRICT_WWM1]]
+ ; CHECK-NEXT: early-clobber $vgpr0 = V_MOV_B32_e32 [[V_ADD_CO_U32_e32_1]], implicit $exec
+ ; CHECK-NEXT: $vgpr1 = COPY [[BUFFER_LOAD_DWORD_OFFEN]]
+ ; CHECK-NEXT: SI_RETURN_TO_EPILOG $vgpr0, $vgpr1
+ bb.0:
+ liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0
+
+ %3:vgpr_32 = COPY $vgpr0
+ %2:sgpr_32 = COPY $sgpr2
+ %1:sgpr_32 = COPY $sgpr1
+ %0:sgpr_32 = COPY $sgpr0
+ %13:sgpr_128 = IMPLICIT_DEF
+
+ bb.1:
+ S_CMP_LT_I32 0, %0:sgpr_32, implicit-def $scc
+ %5:sgpr_32 = S_CSELECT_B32 %2:sgpr_32, %1:sgpr_32, implicit $scc
+ ; Debug instruction - First may point here when analyzing region
+ DBG_VALUE $noreg, $noreg
+ %10:vgpr_32 = BUFFER_LOAD_DWORD_OFFEN %3:vgpr_32, %13:sgpr_128, 0, 0, 0, 0, implicit $exec
+ %12:vgpr_32 = V_ADD_CO_U32_e32 %3:vgpr_32, %3:vgpr_32, implicit-def $vcc, implicit $exec
+ %11:vgpr_32 = V_ADD_CO_U32_e32 %5:sgpr_32, %12:vgpr_32, implicit-def $vcc, implicit $exec
+ $vgpr0 = STRICT_WWM %11:vgpr_32, implicit $exec
+ $vgpr1 = COPY %10:vgpr_32
+ SI_RETURN_TO_EPILOG $vgpr0, $vgpr1
+
+...
+---
+# Test case 2: Multiple debug instructions after SCC use (S_CSELECT).
+# When iterating through SCC live range segments, NextI (instruction after
+# segment end) may be a debug instruction followed by more debug instructions.
+# The pass must skip all debug instructions to find a valid slot index.
+name: test_multiple_debug_after_scc_use
+tracksRegLiveness: true
+body: |
+ ; CHECK-LABEL: name: test_multiple_debug_after_scc_use
+ ; CHECK: bb.0:
+ ; CHECK-NEXT: successors: %bb.1(0x80000000)
+ ; CHECK-NEXT: liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[ENTER_STRICT_WWM:%[0-9]+]]:sreg_64 = ENTER_STRICT_WWM -1, implicit-def $exec, implicit-def $scc, implicit $exec
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr0
+ ; CHECK-NEXT: $exec = EXIT_STRICT_WWM [[ENTER_STRICT_WWM]]
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:sgpr_32 = COPY $sgpr2
+ ; CHECK-NEXT: [[COPY2:%[0-9]+]]:sgpr_32 = COPY $sgpr1
+ ; CHECK-NEXT: [[COPY3:%[0-9]+]]:sgpr_32 = COPY $sgpr0
+ ; CHECK-NEXT: [[DEF:%[0-9]+]]:sgpr_128 = IMPLICIT_DEF
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1:
+ ; CHECK-NEXT: S_CMP_LT_I32 0, [[COPY3]], implicit-def $scc
+ ; CHECK-NEXT: [[BUFFER_LOAD_DWORD_OFFEN:%[0-9]+]]:vgpr_32 = BUFFER_LOAD_DWORD_OFFEN [[COPY]], [[DEF]], 0, 0, 0, 0, implicit $exec
+ ; CHECK-NEXT: [[COPY4:%[0-9]+]]:sreg_32_xm0 = COPY $scc
+ ; CHECK-NEXT: [[ENTER_STRICT_WWM1:%[0-9]+]]:sreg_64 = ENTER_STRICT_WWM -1, implicit-def $exec, implicit-def $scc, implicit $exec
+ ; CHECK-NEXT: $scc = COPY [[COPY4]]
+ ; CHECK-NEXT: [[V_ADD_CO_U32_e32_:%[0-9]+]]:vgpr_32 = V_ADD_CO_U32_e32 [[COPY]], [[COPY]], implicit-def $vcc, implicit $exec
+ ; CHECK-NEXT: [[S_CSELECT_B32_:%[0-9]+]]:sgpr_32 = S_CSELECT_B32 [[COPY1]], [[COPY2]], implicit $scc
+ ; CHECK-NEXT: DBG_VALUE $noreg, $noreg
+ ; CHECK-NEXT: DBG_VALUE $noreg, $noreg
+ ; CHECK-NEXT: DBG_VALUE $noreg, $noreg
+ ; CHECK-NEXT: [[V_ADD_CO_U32_e32_1:%[0-9]+]]:vgpr_32 = V_ADD_CO_U32_e32 [[S_CSELECT_B32_]], [[V_ADD_CO_U32_e32_]], implicit-def $vcc, implicit $exec
+ ; CHECK-NEXT: $exec = EXIT_STRICT_WWM [[ENTER_STRICT_WWM1]]
+ ; CHECK-NEXT: early-clobber $vgpr0 = V_MOV_B32_e32 [[V_ADD_CO_U32_e32_1]], implicit $exec
+ ; CHECK-NEXT: $vgpr1 = COPY [[BUFFER_LOAD_DWORD_OFFEN]]
+ ; CHECK-NEXT: SI_RETURN_TO_EPILOG $vgpr0, $vgpr1
+ bb.0:
+ liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr0
+
+ %3:vgpr_32 = COPY $vgpr0
+ %2:sgpr_32 = COPY $sgpr2
+ %1:sgpr_32 = COPY $sgpr1
+ %0:sgpr_32 = COPY $sgpr0
+ %13:sgpr_128 = IMPLICIT_DEF
+
+ bb.1:
+ S_CMP_LT_I32 0, %0:sgpr_32, implicit-def $scc
+ %10:vgpr_32 = BUFFER_LOAD_DWORD_OFFEN %3:vgpr_32, %13:sgpr_128, 0, 0, 0, 0, implicit $exec
+ %12:vgpr_32 = V_ADD_CO_U32_e32 %3:vgpr_32, %3:vgpr_32, implicit-def $vcc, implicit $exec
+ %5:sgpr_32 = S_CSELECT_B32 %2:sgpr_32, %1:sgpr_32, implicit $scc
+ ; Multiple debug instructions after SCC use
+ DBG_VALUE $noreg, $noreg
+ DBG_VALUE $noreg, $noreg
+ DBG_VALUE $noreg, $noreg
+ %11:vgpr_32 = V_ADD_CO_U32_e32 %5:sgpr_32, %12:vgpr_32, implicit-def $vcc, implicit $exec
+ $vgpr0 = STRICT_WWM %11:vgpr_32, implicit $exec
+ $vgpr1 = COPY %10:vgpr_32
+ SI_RETURN_TO_EPILOG $vgpr0, $vgpr1
+
+...
>From 319b08918767f53a3206ccf44abfafdb4c76c6ae Mon Sep 17 00:00:00 2001
From: Daniil Fukalov <dfukalov at gmail.com>
Date: Tue, 27 Jan 2026 20:56:13 +0100
Subject: [PATCH 2/2] Formatting fixed.
---
llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp b/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp
index c8cb938d088d1..5fd0c1e1064cb 100644
--- a/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp
+++ b/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp
@@ -1111,9 +1111,8 @@ MachineBasicBlock::iterator SIWholeQuadMode::prepareInsertion(
SlotIndex FirstIdx = FirstNonDbg != MBBE
? LIS->getInstructionIndex(*FirstNonDbg)
: LIS->getMBBEndIdx(&MBB);
- SlotIndex LastIdx = LastNonDbg != MBBE
- ? LIS->getInstructionIndex(*LastNonDbg)
- : LIS->getMBBEndIdx(&MBB);
+ SlotIndex LastIdx = LastNonDbg != MBBE ? LIS->getInstructionIndex(*LastNonDbg)
+ : LIS->getMBBEndIdx(&MBB);
SlotIndex Idx = PreferLast ? LastIdx : FirstIdx;
const LiveRange::Segment *S;
More information about the llvm-commits
mailing list