[llvm] f7cc8c8 - AMDGPU: Maintain LiveIntervals when removing blocks in SILowerControlFlow (#223642)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 16 00:51:56 PDT 2026
Author: Matt Arsenault
Date: 2026-09-16T09:51:51+02:00
New Revision: f7cc8c8407551aabcd013555bafaafd62f0494fa
URL: https://github.com/llvm/llvm-project/commit/f7cc8c8407551aabcd013555bafaafd62f0494fa
DIFF: https://github.com/llvm/llvm-project/commit/f7cc8c8407551aabcd013555bafaafd62f0494fa.diff
LOG: AMDGPU: Maintain LiveIntervals when removing blocks in SILowerControlFlow (#223642)
removeMBBifRedundant removed a redundant block's instructions from the
LiveIntervals maps but not the block itself, leaving a stale idx2MBBMap
entry that crashed getMBBFromIndex in the verifier.
Add SlotIndexes::removeMBBFromMaps to drop the erased block's slot
range, and recompute the intervals that spanned it.
Co-authored-by: Claude claude-opus-4.8 <noreply at anthropic.com>
Added:
llvm/test/CodeGen/AMDGPU/si-lower-control-flow-remove-redundant-block-liveintervals.mir
Modified:
llvm/include/llvm/CodeGen/SlotIndexes.h
llvm/lib/CodeGen/SlotIndexes.cpp
llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/CodeGen/SlotIndexes.h b/llvm/include/llvm/CodeGen/SlotIndexes.h
index eb9906e597f34..5204ef0dd87cb 100644
--- a/llvm/include/llvm/CodeGen/SlotIndexes.h
+++ b/llvm/include/llvm/CodeGen/SlotIndexes.h
@@ -629,6 +629,11 @@ class raw_ostream;
llvm::sort(idx2MBBMap, less_first());
}
+ /// Inverse of insertMBBInMaps: merge \p MBB's slot range into its layout
+ /// predecessor and drop it from the maps. Call before erasing \p MBB and
+ /// after its instructions have been removed from the maps.
+ LLVM_ABI void removeMBBFromMaps(MachineBasicBlock &MBB);
+
/// Renumber all indexes using the default instruction distance.
LLVM_ABI void packIndexes();
};
diff --git a/llvm/lib/CodeGen/SlotIndexes.cpp b/llvm/lib/CodeGen/SlotIndexes.cpp
index 2fcc15744ab6e..500c396bc099f 100644
--- a/llvm/lib/CodeGen/SlotIndexes.cpp
+++ b/llvm/lib/CodeGen/SlotIndexes.cpp
@@ -165,6 +165,29 @@ void SlotIndexes::removeSingleMachineInstrFromMaps(MachineInstr &MI) {
}
}
+void SlotIndexes::removeMBBFromMaps(MachineBasicBlock &MBB) {
+ assert(&MBB != &MBB.getParent()->front() &&
+ "Can't remove the first block of a function.");
+
+ unsigned Num = MBB.getAnalysisNumber();
+ SlotIndex StartIdx = MBBRanges[Num].first;
+ SlotIndex EndIdx = MBBRanges[Num].second;
+
+ // Give MBB's slot range to its layout predecessor so blocks stay contiguous.
+ auto PrevMBB = std::prev(MBB.getIterator());
+ MBBRanges[PrevMBB->getAnalysisNumber()].second = EndIdx;
+
+ // Drop MBB's index -> MBB entry, which would dangle once MBB is erased.
+ auto It = getMBBLowerBound(StartIdx);
+ assert(It != MBBIndexEnd() && It->first == StartIdx && It->second == &MBB &&
+ "MBB not found in index -> MBB map");
+ idx2MBBMap.erase(It);
+
+ // Clear the block-start boundary entry. MBBRanges is never renumbered, so
+ // MBB's now-stale slot is simply left in place.
+ StartIdx.listEntry()->setInstr(nullptr);
+}
+
// Renumber indexes locally after curItr was inserted, but failed to get a new
// index.
void SlotIndexes::renumberIndexes(IndexList::iterator curItr) {
diff --git a/llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp b/llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp
index aab3e63f3e9d0..6c87ba5438f3d 100644
--- a/llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp
+++ b/llvm/lib/Target/AMDGPU/SILowerControlFlow.cpp
@@ -756,8 +756,24 @@ bool SILowerControlFlow::removeMBBifRedundant(MachineBasicBlock &MBB) {
}
MBB.removeSuccessor(Succ);
if (LIS) {
+ // Registers live across MBB have intervals spanning it, which must be
+ // recomputed once it is erased. removeMBBifRedundant only runs from
+ // optimizeEndCf, so defer to the pass-wide RecomputeRegs handling.
+ SlotIndex StartIdx = LIS->getMBBStartIdx(&MBB);
+ for (unsigned I = 0, E = MRI->getNumVirtRegs(); I != E; ++I) {
+ Register Reg = Register::index2VirtReg(I);
+ if (!LIS->hasInterval(Reg))
+ continue;
+ const LiveInterval &LI = LIS->getInterval(Reg);
+ if (LI.liveAt(StartIdx) || LI.liveAt(StartIdx.getPrevSlot()))
+ RecomputeRegs.insert(Reg);
+ }
+
for (auto &I : MBB.instrs())
LIS->RemoveMachineInstrFromMaps(I);
+
+ // Drop MBB from the slot index maps before it is erased.
+ LIS->getSlotIndexes()->removeMBBFromMaps(MBB);
}
if (MDT)
MDT->applyUpdates(DTUpdates);
diff --git a/llvm/test/CodeGen/AMDGPU/si-lower-control-flow-remove-redundant-block-liveintervals.mir b/llvm/test/CodeGen/AMDGPU/si-lower-control-flow-remove-redundant-block-liveintervals.mir
new file mode 100644
index 0000000000000..b69d1f51bb299
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/si-lower-control-flow-remove-redundant-block-liveintervals.mir
@@ -0,0 +1,95 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=amdgpu9.00 -run-pass=liveintervals,si-lower-control-flow -verify-machineinstrs -o - %s | FileCheck %s
+
+# SILowerControlFlow erases a redundant Flow block. With LiveIntervals
+# live, its slot range must be dropped from SlotIndexes, else
+# getMBBFromIndex trips on a stale entry in the verifier.
+
+---
+name: f
+tracksRegLiveness: true
+body: |
+ ; CHECK-LABEL: name: f
+ ; CHECK: bb.0:
+ ; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
+ ; CHECK-NEXT: liveins: $vgpr0, $vgpr1, $vgpr2
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:vgpr_32 = COPY $vgpr2
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:vgpr_32 = COPY $vgpr1
+ ; CHECK-NEXT: [[COPY2:%[0-9]+]]:vgpr_32 = COPY $vgpr0
+ ; CHECK-NEXT: [[V_CMP_EQ_U32_e64_:%[0-9]+]]:sreg_64 = V_CMP_EQ_U32_e64 0, [[COPY]], implicit $exec
+ ; CHECK-NEXT: [[COPY3:%[0-9]+]]:sreg_64 = COPY $exec, implicit-def $exec
+ ; CHECK-NEXT: [[S_AND_B64_:%[0-9]+]]:sreg_64 = S_AND_B64 [[COPY3]], [[V_CMP_EQ_U32_e64_]], implicit-def dead $scc
+ ; CHECK-NEXT: $exec = S_MOV_B64_term [[S_AND_B64_]]
+ ; CHECK-NEXT: S_CBRANCH_EXECZ %bb.2, implicit $exec
+ ; CHECK-NEXT: S_BRANCH %bb.1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1:
+ ; CHECK-NEXT: successors: %bb.3(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[S_MOV_B64_:%[0-9]+]]:sreg_64 = S_MOV_B64 0
+ ; CHECK-NEXT: [[COPY4:%[0-9]+]]:sreg_64 = COPY [[S_MOV_B64_]]
+ ; CHECK-NEXT: S_BRANCH %bb.3
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.2:
+ ; CHECK-NEXT: successors: %bb.5(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: $exec = S_OR_B64 $exec, [[COPY3]], implicit-def $scc
+ ; CHECK-NEXT: [[REG_SEQUENCE:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[COPY2]], %subreg.sub0, [[COPY1]], %subreg.sub1
+ ; CHECK-NEXT: S_BRANCH %bb.5
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.3:
+ ; CHECK-NEXT: successors: %bb.2(0x04000000), %bb.3(0x7c000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: INLINEASM &"v_mov_b32 $0, 0", sideeffect attdialect, regdef:VGPR_32, def %8
+ ; CHECK-NEXT: [[V_CMP_NE_U32_e64_:%[0-9]+]]:sreg_64 = V_CMP_NE_U32_e64 0, %8, implicit $exec
+ ; CHECK-NEXT: [[COPY5:%[0-9]+]]:sreg_64 = COPY [[COPY4]]
+ ; CHECK-NEXT: [[S_OR_B64_:%[0-9]+]]:sreg_64 = S_OR_B64 [[V_CMP_NE_U32_e64_]], [[COPY5]], implicit-def $scc
+ ; CHECK-NEXT: [[COPY4:%[0-9]+]]:sreg_64 = COPY [[S_OR_B64_]]
+ ; CHECK-NEXT: $exec = S_ANDN2_B64_term $exec, [[S_OR_B64_]], implicit-def $scc
+ ; CHECK-NEXT: S_CBRANCH_EXECNZ %bb.3, implicit $exec
+ ; CHECK-NEXT: S_BRANCH %bb.2
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.5:
+ ; CHECK-NEXT: GLOBAL_STORE_DWORD [[REG_SEQUENCE]], [[COPY]], 0, 0, implicit $exec :: (store (s32), addrspace 1)
+ ; CHECK-NEXT: SI_RETURN
+ bb.0:
+ successors: %bb.1, %bb.2
+ liveins: $vgpr0, $vgpr1, $vgpr2
+
+ %0:vgpr_32 = COPY killed $vgpr2
+ %1:vgpr_32 = COPY killed $vgpr1
+ %2:vgpr_32 = COPY killed $vgpr0
+ %3:sreg_64 = V_CMP_EQ_U32_e64 0, %0, implicit $exec
+ %4:sreg_64 = SI_IF killed %3, %bb.2, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+ S_BRANCH %bb.1
+
+ bb.1:
+ %5:sreg_64 = S_MOV_B64 0
+ %6:sreg_64 = COPY killed %5
+ S_BRANCH %bb.3
+
+ bb.2:
+ SI_END_CF killed %4, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+ %7:vreg_64 = REG_SEQUENCE killed %2, %subreg.sub0, killed %1, %subreg.sub1
+ S_BRANCH %bb.5
+
+ bb.3:
+ successors: %bb.4(0x04000000), %bb.3(0x7c000000)
+
+ INLINEASM &"v_mov_b32 $0, 0", sideeffect attdialect, regdef:VGPR_32, def %8:vgpr_32
+ %9:sreg_64 = V_CMP_NE_U32_e64 0, killed %8, implicit $exec
+ %10:sreg_64 = COPY killed %6
+ %11:sreg_64 = SI_IF_BREAK killed %9, killed %10, implicit-def dead $scc
+ %6:sreg_64 = COPY %11
+ SI_LOOP %11, %bb.3, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+ S_BRANCH %bb.4
+
+ bb.4:
+ SI_END_CF killed %11, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+ S_BRANCH %bb.2
+
+ bb.5:
+ GLOBAL_STORE_DWORD killed %7, killed %0, 0, 0, implicit $exec :: (store (s32), addrspace 1)
+ SI_RETURN
+...
More information about the llvm-commits
mailing list