[llvm] PeepholeOpt: Clear kill flags in foldImmediate (PR #195680)

Frederik Harwath via llvm-commits llvm-commits at lists.llvm.org
Mon May 4 08:58:05 PDT 2026


https://github.com/frederik-h created https://github.com/llvm/llvm-project/pull/195680

When foldImmediate replaces a COPY destination with its source,
it extends the live range of the source, but it does not
update the kill flags.

Clear kill flags on the source register after replacement.

>From b8498092a977da9bb746688801407cf4915be225 Mon Sep 17 00:00:00 2001
From: Frederik Harwath <fharwath at amd.com>
Date: Mon, 4 May 2026 06:44:35 -0400
Subject: [PATCH 1/2] [AMDGPU] Add test for peephole kill flag bug

Add test case that shows that peephole-opt incorrectly
preserves kill flags.
---
 .../AMDGPU/peephole-fold-kill-flag-bug.mir    | 49 +++++++++++++++++++
 1 file changed, 49 insertions(+)
 create mode 100644 llvm/test/CodeGen/AMDGPU/peephole-fold-kill-flag-bug.mir

diff --git a/llvm/test/CodeGen/AMDGPU/peephole-fold-kill-flag-bug.mir b/llvm/test/CodeGen/AMDGPU/peephole-fold-kill-flag-bug.mir
new file mode 100644
index 0000000000000..5840ee720e436
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/peephole-fold-kill-flag-bug.mir
@@ -0,0 +1,49 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=amdgcn-- -run-pass=peephole-opt %s -o - | FileCheck %s
+# RUN: not --crash llc -mtriple=amdgcn-- -run-pass=peephole-opt -verify-machineinstrs %s -o - 2>&1 | FileCheck %s --check-prefix=VERIFY
+
+---
+name: coalescable_copy_kill_bug
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $sgpr0_sgpr1
+
+    ; CHECK-LABEL: name: coalescable_copy_kill_bug
+    ; CHECK: liveins: $sgpr0_sgpr1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+    ; CHECK-NEXT: [[V_MOV_B32_e32_1:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 42, implicit $exec
+    ; CHECK-NEXT: [[V_MOV_B32_e32_2:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 43, implicit $exec
+    ; CHECK-NEXT: [[REG_SEQUENCE:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[V_MOV_B32_e32_1]], %subreg.sub0, killed [[V_MOV_B32_e32_]], %subreg.sub1
+    ; CHECK-NEXT: [[REG_SEQUENCE1:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[V_MOV_B32_e32_2]], %subreg.sub0, [[V_MOV_B32_e32_]], %subreg.sub1
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:vreg_64 = COPY [[REG_SEQUENCE]]
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:vreg_64 = COPY [[REG_SEQUENCE1]]
+    ; CHECK-NEXT: [[V_MOV_B32_e32_3:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+    ; CHECK-NEXT: $m0 = S_MOV_B32 -1
+    ; CHECK-NEXT: DS_WRITE_B64 [[V_MOV_B32_e32_3]], killed [[COPY]], 0, 0, implicit $m0, implicit $exec :: (store (s64), addrspace 3)
+    ; CHECK-NEXT: DS_WRITE_B64 [[V_MOV_B32_e32_3]], killed [[COPY1]], 8, 0, implicit $m0, implicit $exec :: (store (s64), addrspace 3)
+    ; CHECK-NEXT: S_ENDPGM 0
+    %0:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+    %1:vgpr_32 = V_MOV_B32_e32 42, implicit $exec
+    %2:vgpr_32 = V_MOV_B32_e32 43, implicit $exec
+
+    %3:vgpr_32 = COPY %0:vgpr_32
+
+    %4:vreg_64 = REG_SEQUENCE %1:vgpr_32, %subreg.sub0, killed %3:vgpr_32, %subreg.sub1
+    %5:vreg_64 = REG_SEQUENCE %2:vgpr_32, %subreg.sub0, %0:vgpr_32, %subreg.sub1
+
+    %6:vreg_64 = COPY %4:vreg_64
+    %7:vreg_64 = COPY %5:vreg_64
+
+    %8:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+    $m0 = S_MOV_B32 -1
+    DS_WRITE_B64 %8:vgpr_32, killed %6:vreg_64, 0, 0, implicit $m0, implicit $exec :: (store (s64), addrspace 3)
+    DS_WRITE_B64 %8:vgpr_32, killed %7:vreg_64, 8, 0, implicit $m0, implicit $exec :: (store (s64), addrspace 3)
+
+    S_ENDPGM 0
+
+# VERIFY: *** Bad machine code: Using a killed virtual register ***
+# VERIFY: - function:    coalescable_copy_kill_bug
+# VERIFY: LLVM ERROR: Found 1 machine code errors.
+...

>From 22919b5c419a565053a53532cc4255b86f39b804 Mon Sep 17 00:00:00 2001
From: Frederik Harwath <fharwath at amd.com>
Date: Mon, 4 May 2026 08:56:25 -0400
Subject: [PATCH 2/2] PeepholeOpt: Clear kill flags in foldImmediate

When foldImmediate replaces a COPY destination with its source,
it extends the live range of the source, but it does not
update the kill flags.

Clear kill flags on the source register after replacement.
---
 llvm/lib/CodeGen/PeepholeOptimizer.cpp                   | 2 ++
 llvm/test/CodeGen/AMDGPU/peephole-fold-kill-flag-bug.mir | 9 ++-------
 2 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/CodeGen/PeepholeOptimizer.cpp b/llvm/lib/CodeGen/PeepholeOptimizer.cpp
index 9365ea883eec9..4d302c7f0b5ae 100644
--- a/llvm/lib/CodeGen/PeepholeOptimizer.cpp
+++ b/llvm/lib/CodeGen/PeepholeOptimizer.cpp
@@ -1440,6 +1440,8 @@ bool PeepholeOptimizer::foldImmediate(
         if (DstReg.isVirtual() &&
             MRI->getRegClass(DstReg) == MRI->getRegClass(Reg)) {
           MRI->replaceRegWith(DstReg, Reg);
+          // We may have extended the live range of Reg, clear any kill flags.
+          MRI->clearKillFlags(Reg);
           MI.eraseFromParent();
           Deleted = true;
         }
diff --git a/llvm/test/CodeGen/AMDGPU/peephole-fold-kill-flag-bug.mir b/llvm/test/CodeGen/AMDGPU/peephole-fold-kill-flag-bug.mir
index 5840ee720e436..3c92e15a85c1c 100644
--- a/llvm/test/CodeGen/AMDGPU/peephole-fold-kill-flag-bug.mir
+++ b/llvm/test/CodeGen/AMDGPU/peephole-fold-kill-flag-bug.mir
@@ -1,6 +1,5 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
-# RUN: llc -mtriple=amdgcn-- -run-pass=peephole-opt %s -o - | FileCheck %s
-# RUN: not --crash llc -mtriple=amdgcn-- -run-pass=peephole-opt -verify-machineinstrs %s -o - 2>&1 | FileCheck %s --check-prefix=VERIFY
+# RUN: llc -mtriple=amdgcn-- -run-pass=peephole-opt -verify-machineinstrs %s -o - | FileCheck %s
 
 ---
 name: coalescable_copy_kill_bug
@@ -15,7 +14,7 @@ body: |
     ; CHECK-NEXT: [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
     ; CHECK-NEXT: [[V_MOV_B32_e32_1:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 42, implicit $exec
     ; CHECK-NEXT: [[V_MOV_B32_e32_2:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 43, implicit $exec
-    ; CHECK-NEXT: [[REG_SEQUENCE:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[V_MOV_B32_e32_1]], %subreg.sub0, killed [[V_MOV_B32_e32_]], %subreg.sub1
+    ; CHECK-NEXT: [[REG_SEQUENCE:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[V_MOV_B32_e32_1]], %subreg.sub0, [[V_MOV_B32_e32_]], %subreg.sub1
     ; CHECK-NEXT: [[REG_SEQUENCE1:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[V_MOV_B32_e32_2]], %subreg.sub0, [[V_MOV_B32_e32_]], %subreg.sub1
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:vreg_64 = COPY [[REG_SEQUENCE]]
     ; CHECK-NEXT: [[COPY1:%[0-9]+]]:vreg_64 = COPY [[REG_SEQUENCE1]]
@@ -42,8 +41,4 @@ body: |
     DS_WRITE_B64 %8:vgpr_32, killed %7:vreg_64, 8, 0, implicit $m0, implicit $exec :: (store (s64), addrspace 3)
 
     S_ENDPGM 0
-
-# VERIFY: *** Bad machine code: Using a killed virtual register ***
-# VERIFY: - function:    coalescable_copy_kill_bug
-# VERIFY: LLVM ERROR: Found 1 machine code errors.
 ...



More information about the llvm-commits mailing list