[llvm] [AMDGPU] Do not erase KILLs that redefine a register in SIPostRABundler (PR #218349)
Arseniy Obolenskiy via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 24 01:31:19 PDT 2026
https://github.com/aobolensk created https://github.com/llvm/llvm-project/pull/218349
None
>From 77c32c204e4081a6b80cd558956deae9a6e42fbe Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 24 Aug 2026 10:30:01 +0200
Subject: [PATCH] [AMDGPU] Do not erase KILLs that redefine a register in
SIPostRABundler
---
llvm/lib/Target/AMDGPU/SIPostRABundler.cpp | 14 +++--
.../CodeGen/AMDGPU/postra-bundle-memops.mir | 52 +++++++++++++++++++
.../splitkit-getsubrangeformask-phi-extend.ll | 23 ++++++++
3 files changed, 84 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/SIPostRABundler.cpp b/llvm/lib/Target/AMDGPU/SIPostRABundler.cpp
index 66dc17aa46e96..16d02b5fc7421 100644
--- a/llvm/lib/Target/AMDGPU/SIPostRABundler.cpp
+++ b/llvm/lib/Target/AMDGPU/SIPostRABundler.cpp
@@ -222,6 +222,12 @@ bool SIPostRABundler::run(MachineFunction &MF) {
while (Next != E && Next->isKill()) {
MachineInstr &Kill = *Next;
+
+ // KILL from an undef-source COPY keeps its def; must not erase it.
+ if (!Kill.all_defs().empty())
+ break;
+
+ KillUsedRegUnits.reset();
collectUsedRegUnits(Kill, KillUsedRegUnits);
KillUsedRegUnits &= BundleUsedRegUnits;
@@ -230,13 +236,11 @@ bool SIPostRABundler::run(MachineFunction &MF) {
//
// TODO: Should we just remove all kills? Is there any real reason to
// keep them after RA?
- if (KillUsedRegUnits.none()) {
- ++Next;
- Kill.eraseFromParent();
- } else
+ if (!KillUsedRegUnits.none())
break;
- KillUsedRegUnits.reset();
+ ++Next;
+ Kill.eraseFromParent();
}
BundleUsedRegUnits.reset();
diff --git a/llvm/test/CodeGen/AMDGPU/postra-bundle-memops.mir b/llvm/test/CodeGen/AMDGPU/postra-bundle-memops.mir
index 03f6d2607c842..c71bec6f7b2d2 100644
--- a/llvm/test/CodeGen/AMDGPU/postra-bundle-memops.mir
+++ b/llvm/test/CodeGen/AMDGPU/postra-bundle-memops.mir
@@ -352,6 +352,58 @@ body: |
KILL killed $vgpr3_vgpr4, killed $vgpr5_vgpr6
...
+# The trailing KILL defines $vgpr0 (lowerCopy'd from an undef COPY) and must not be erased.
+---
+name: post_bundle_kill_with_def
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr1, $vgpr2, $vgpr3_vgpr4, $vgpr5_vgpr6
+ ; GCN-LABEL: name: post_bundle_kill_with_def
+ ; GCN: liveins: $vgpr1, $vgpr2, $vgpr3_vgpr4, $vgpr5_vgpr6
+ ; GCN-NEXT: {{ $}}
+ ; GCN-NEXT: BUNDLE implicit $vgpr3_vgpr4, implicit killed $vgpr1, implicit $exec, implicit $vgpr5_vgpr6, implicit killed $vgpr2 {
+ ; GCN-NEXT: GLOBAL_STORE_DWORD $vgpr3_vgpr4, killed $vgpr1, 0, 0, implicit $exec
+ ; GCN-NEXT: GLOBAL_STORE_DWORD $vgpr5_vgpr6, killed $vgpr2, 0, 0, implicit $exec
+ ; GCN-NEXT: }
+ ; GCN-NEXT: $vgpr0 = KILL undef $sgpr4, implicit $exec
+ ; GCN-NEXT: S_NOP 0, implicit killed $vgpr0
+ GLOBAL_STORE_DWORD $vgpr3_vgpr4, killed $vgpr1, 0, 0, implicit $exec
+ GLOBAL_STORE_DWORD $vgpr5_vgpr6, killed $vgpr2, 0, 0, implicit $exec
+ $vgpr0 = KILL undef $sgpr4, implicit $exec
+ S_NOP 0, implicit killed $vgpr0
+...
+
+# A non-erasable KILL must not leak state that blocks erasing the next bundle's KILL.
+---
+name: post_bundle_kill_after_nonerasable_kill
+body: |
+ bb.0:
+ liveins: $vgpr1, $vgpr2, $vgpr3_vgpr4, $vgpr5_vgpr6, $vgpr7, $vgpr8, $vgpr9
+ ; GCN-LABEL: name: post_bundle_kill_after_nonerasable_kill
+ ; GCN: liveins: $vgpr1, $vgpr2, $vgpr3_vgpr4, $vgpr5_vgpr6, $vgpr7, $vgpr8, $vgpr9
+ ; GCN-NEXT: {{ $}}
+ ; GCN-NEXT: BUNDLE implicit $vgpr3_vgpr4, implicit killed $vgpr1, implicit $exec, implicit $vgpr5_vgpr6, implicit killed $vgpr2 {
+ ; GCN-NEXT: GLOBAL_STORE_DWORD $vgpr3_vgpr4, killed $vgpr1, 0, 0, implicit $exec
+ ; GCN-NEXT: GLOBAL_STORE_DWORD $vgpr5_vgpr6, killed $vgpr2, 0, 0, implicit $exec
+ ; GCN-NEXT: }
+ ; GCN-NEXT: KILL killed $vgpr7
+ ; GCN-NEXT: S_NOP 0
+ ; GCN-NEXT: BUNDLE implicit $vgpr3_vgpr4, implicit killed $vgpr8, implicit $exec, implicit $vgpr5_vgpr6, implicit killed $vgpr9 {
+ ; GCN-NEXT: GLOBAL_STORE_DWORD $vgpr3_vgpr4, killed $vgpr8, 0, 0, implicit $exec
+ ; GCN-NEXT: GLOBAL_STORE_DWORD $vgpr5_vgpr6, killed $vgpr9, 0, 0, implicit $exec
+ ; GCN-NEXT: }
+ ; GCN-NEXT: S_NOP 1
+ GLOBAL_STORE_DWORD $vgpr3_vgpr4, killed $vgpr1, 0, 0, implicit $exec
+ GLOBAL_STORE_DWORD $vgpr5_vgpr6, killed $vgpr2, 0, 0, implicit $exec
+ KILL killed $vgpr7
+ S_NOP 0
+ GLOBAL_STORE_DWORD $vgpr3_vgpr4, killed $vgpr8, 0, 0, implicit $exec
+ GLOBAL_STORE_DWORD $vgpr5_vgpr6, killed $vgpr9, 0, 0, implicit $exec
+ KILL killed $vgpr8
+ S_NOP 1
+...
+
# Avoid bundling if a MBB has SCHED_BARRIER
---
name: no_sched_barrier_within_bundle
diff --git a/llvm/test/CodeGen/AMDGPU/splitkit-getsubrangeformask-phi-extend.ll b/llvm/test/CodeGen/AMDGPU/splitkit-getsubrangeformask-phi-extend.ll
index c40e35bbe1754..35882965e2be0 100644
--- a/llvm/test/CodeGen/AMDGPU/splitkit-getsubrangeformask-phi-extend.ll
+++ b/llvm/test/CodeGen/AMDGPU/splitkit-getsubrangeformask-phi-extend.ll
@@ -271,6 +271,7 @@ define void @f(ptr %p, <16 x i1> %m, <16 x i63> %pt, <16 x i1> %sc,
; CHECK-NEXT: buffer_load_dword v32, off, s[0:3], s32 offset:148
; CHECK-NEXT: buffer_load_dword v31, off, s[0:3], s32 offset:144
; CHECK-NEXT: buffer_load_dword v30, off, s[0:3], s32 offset:140
+; CHECK-NEXT: ; kill: def $vgpr3 killed $sgpr4 killed $exec
; CHECK-NEXT: v_cmp_eq_u32_e64 s[42:43], 1, v18
; CHECK-NEXT: v_cmp_eq_u32_e64 s[28:29], 1, v20
; CHECK-NEXT: v_cmp_eq_u32_e64 s[26:27], 1, v17
@@ -278,6 +279,17 @@ define void @f(ptr %p, <16 x i1> %m, <16 x i63> %pt, <16 x i1> %sc,
; CHECK-NEXT: v_cmp_eq_u32_e64 s[18:19], 1, v21
; CHECK-NEXT: v_cmp_eq_u32_e64 s[24:25], 1, v23
; CHECK-NEXT: v_cmp_eq_u32_e64 s[20:21], 1, v25
+; CHECK-NEXT: ; kill: def $vgpr5 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr7 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr9 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr11 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr13 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr15 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr17 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr19 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr21 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr23 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr25 killed $sgpr4 killed $exec
; CHECK-NEXT: v_cmp_eq_u32_e64 s[16:17], 1, v27
; CHECK-NEXT: v_cmp_eq_u32_e64 s[12:13], 1, v26
; CHECK-NEXT: v_cmp_eq_u32_e64 s[8:9], 1, v29
@@ -384,6 +396,16 @@ define void @f(ptr %p, <16 x i1> %m, <16 x i63> %pt, <16 x i1> %sc,
; CHECK-NEXT: buffer_store_dword v61, off, s[0:3], s32 offset:1396 ; 4-byte Folded Spill
; CHECK-NEXT: v_and_b32_e32 v1, 1, v1
; CHECK-NEXT: v_cmp_ne_u32_e64 s[46:47], 1, v1
+; CHECK-NEXT: ; kill: def $vgpr1 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr57 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr49 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr43 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr51 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $agpr33 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $agpr35 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $vgpr59 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $agpr39 killed $sgpr4 killed $exec
+; CHECK-NEXT: ; kill: def $agpr37 killed $sgpr4 killed $exec
; CHECK-NEXT: s_waitcnt vmcnt(32)
; CHECK-NEXT: buffer_store_dword a0, off, s[0:3], s32 offset:1000 ; 4-byte Folded Spill
; CHECK-NEXT: s_nop 0
@@ -481,6 +503,7 @@ define void @f(ptr %p, <16 x i1> %m, <16 x i63> %pt, <16 x i1> %sc,
; CHECK-NEXT: buffer_load_dword v18, off, s[0:3], s32 offset:528
; CHECK-NEXT: s_nop 0
; CHECK-NEXT: buffer_load_dword v2, off, s[0:3], s32 offset:524
+; CHECK-NEXT: ; kill: def $vgpr3 killed $sgpr4 killed $exec
; CHECK-NEXT: s_nop 0
; CHECK-NEXT: buffer_store_dword v0, off, s[0:3], s32 offset:1504 ; 4-byte Folded Spill
; CHECK-NEXT: s_nop 0
More information about the llvm-commits
mailing list