[llvm] [CodeGen] Ensure `undef` propogation when an undef copy is eliminated if used as a subregister def (PR #204039)
Ryan Buchner via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 16 12:56:35 PDT 2026
https://github.com/bababuck updated https://github.com/llvm/llvm-project/pull/204039
>From 6e8816144471f743161f69bb9a47d41b8c9ceb5b Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Mon, 15 Jun 2026 16:09:49 -0700
Subject: [PATCH 1/8] [CodeGen] Add test for undef propogation bug
---
llvm/test/CodeGen/ARM/copy-undef.ll | 45 +++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
create mode 100644 llvm/test/CodeGen/ARM/copy-undef.ll
diff --git a/llvm/test/CodeGen/ARM/copy-undef.ll b/llvm/test/CodeGen/ARM/copy-undef.ll
new file mode 100644
index 0000000000000..d85b2de636ace
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/copy-undef.ll
@@ -0,0 +1,45 @@
+; RUN: llc < %s | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
+target triple = "thumbv7-unknown-linux-android29"
+
+ at test_crash_format = dso_local local_unnamed_addr global i32 0, align 4
+ at global_out = external local_unnamed_addr global ptr, align 4
+
+; Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind optsize memory(readwrite, argmem: write, inaccessiblemem: none, target_mem: none)
+define dso_local void @_Z10test_crashv() local_unnamed_addr #0 {
+entry:
+ %0 = load i32, ptr @test_crash_format, align 4, !tbaa !5
+ %1 = insertelement <8 x i32> <i32 undef, i32 undef, i32 undef, i32 undef, i32 poison, i32 poison, i32 poison, i32 undef>, i32 %0, i64 6
+ br label %for.cond
+
+for.cond: ; preds = %for.cond, %entry
+ %i.0 = phi i32 [ undef, %entry ], [ %inc, %for.cond ]
+ %2 = insertelement <8 x i32> %1, i32 %i.0, i64 4
+ %3 = insertelement <8 x i32> %2, i32 %i.0, i64 5
+ %4 = load ptr, ptr @global_out, align 4, !tbaa !9
+ store <8 x i32> %3, ptr %4, align 32, !tbaa !11
+ %inc = add nsw i32 %i.0, 1
+ br label %for.cond, !llvm.loop !12
+}
+
+attributes #0 = { mustprogress nofree norecurse noreturn nosync nounwind optsize memory(readwrite, argmem: write, inaccessiblemem: none, target_mem: none) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+armv7-a,+d32,+dsp,+fp64,+neon,+read-tp-tpidruro,+thumb-mode,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-aes,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-sha2,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
+
+!llvm.module.flags = !{!0, !1, !2, !3}
+!llvm.ident = !{!4}
+!llvm.errno.tbaa = !{!5}
+
+!0 = !{i32 1, !"min_enum_size", i32 4}
+!1 = !{i32 8, !"PIC Level", i32 2}
+!2 = !{i32 7, !"PIE Level", i32 2}
+!3 = !{i32 7, !"frame-pointer", i32 2}
+!4 = !{!"clang version 23.0.0git (git at github.com:bababuck/llvm-project.git a6351d882ca3086c62e052fbc4f7f585e157213b)"}
+!5 = !{!6, !6, i64 0}
+!6 = !{!"int", !7, i64 0}
+!7 = !{!"omnipotent char", !8, i64 0}
+!8 = !{!"Simple C++ TBAA"}
+!9 = !{!10, !10, i64 0}
+!10 = !{!"any pointer", !7, i64 0}
+!11 = !{!7, !7, i64 0}
+!12 = distinct !{!12, !13}
+!13 = !{!"llvm.loop.mustprogress"}
>From be8a8f44015f4db4f363cd0772787f332903fc35 Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Mon, 15 Jun 2026 16:02:25 -0700
Subject: [PATCH 2/8] [SLP] Ensure `undef` propogation when an undef copy is
eliminated if used as a subregister def
---
llvm/lib/CodeGen/RegisterCoalescer.cpp | 4 +++-
llvm/test/CodeGen/ARM/copy-undef.ll | 22 ++++++++++++++++++++++
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/CodeGen/RegisterCoalescer.cpp b/llvm/lib/CodeGen/RegisterCoalescer.cpp
index eb43eddfa081e..667f357c79579 100644
--- a/llvm/lib/CodeGen/RegisterCoalescer.cpp
+++ b/llvm/lib/CodeGen/RegisterCoalescer.cpp
@@ -1816,11 +1816,13 @@ MachineInstr *RegisterCoalescer::eliminateUndefCopy(MachineInstr *CopyMI) {
// Mark uses as undef.
for (MachineOperand &MO : MRI->reg_nodbg_operands(DstReg)) {
- if (MO.isDef() /*|| MO.isUndef()*/)
+ if (MO.isDef() && !MO.getSubReg())
continue;
const MachineInstr &MI = *MO.getParent();
SlotIndex UseIdx = LIS->getInstructionIndex(MI);
LaneBitmask UseMask = TRI->getSubRegIndexLaneMask(MO.getSubReg());
+ if (MO.isDef())
+ UseMask = ~UseMask;
bool isLive;
if (!UseMask.all() && DstLI.hasSubRanges()) {
isLive = false;
diff --git a/llvm/test/CodeGen/ARM/copy-undef.ll b/llvm/test/CodeGen/ARM/copy-undef.ll
index d85b2de636ace..bdb0e485ece88 100644
--- a/llvm/test/CodeGen/ARM/copy-undef.ll
+++ b/llvm/test/CodeGen/ARM/copy-undef.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc < %s | FileCheck %s
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
@@ -8,6 +9,27 @@ target triple = "thumbv7-unknown-linux-android29"
; Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind optsize memory(readwrite, argmem: write, inaccessiblemem: none, target_mem: none)
define dso_local void @_Z10test_crashv() local_unnamed_addr #0 {
+; CHECK-LABEL: _Z10test_crashv:
+; CHECK: @ %bb.0: @ %entry
+; CHECK-NEXT: .save {r7, lr}
+; CHECK-NEXT: push {r7, lr}
+; CHECK-NEXT: .setfp r7, sp
+; CHECK-NEXT: mov r7, sp
+; CHECK-NEXT: movw r0, :lower16:test_crash_format
+; CHECK-NEXT: @ implicit-def: $r1
+; CHECK-NEXT: movt r0, :upper16:test_crash_format
+; CHECK-NEXT: vld1.32 {d17[0]}, [r0:32]
+; CHECK-NEXT: movw r0, :lower16:global_out
+; CHECK-NEXT: movt r0, :upper16:global_out
+; CHECK-NEXT: .LBB0_1: @ %for.cond
+; CHECK-NEXT: @ =>This Inner Loop Header: Depth=1
+; CHECK-NEXT: vmov.32 d16[0], r1
+; CHECK-NEXT: ldr r2, [r0]
+; CHECK-NEXT: vmov.32 d16[1], r1
+; CHECK-NEXT: adds r1, #1
+; CHECK-NEXT: vst1.32 {d16, d17}, [r2:128]!
+; CHECK-NEXT: vst1.64 {d16, d17}, [r2:128]
+; CHECK-NEXT: b .LBB0_1
entry:
%0 = load i32, ptr @test_crash_format, align 4, !tbaa !5
%1 = insertelement <8 x i32> <i32 undef, i32 undef, i32 undef, i32 undef, i32 poison, i32 poison, i32 poison, i32 undef>, i32 %0, i64 6
>From e1fc4020f23ed73a91ee34c27e3749b5f6e128a6 Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Tue, 16 Jun 2026 11:57:56 -0700
Subject: [PATCH 3/8] Simplify .ll test
---
llvm/test/CodeGen/ARM/copy-undef.ll | 63 ++++++-----------------------
1 file changed, 13 insertions(+), 50 deletions(-)
diff --git a/llvm/test/CodeGen/ARM/copy-undef.ll b/llvm/test/CodeGen/ARM/copy-undef.ll
index bdb0e485ece88..773ce0f8825ef 100644
--- a/llvm/test/CodeGen/ARM/copy-undef.ll
+++ b/llvm/test/CodeGen/ARM/copy-undef.ll
@@ -1,67 +1,30 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc < %s | FileCheck %s
+; RUN: llc -mtriple=armv7-- < %s | FileCheck %s
-target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
-target triple = "thumbv7-unknown-linux-android29"
-
- at test_crash_format = dso_local local_unnamed_addr global i32 0, align 4
- at global_out = external local_unnamed_addr global ptr, align 4
-
-; Function Attrs: mustprogress nofree norecurse noreturn nosync nounwind optsize memory(readwrite, argmem: write, inaccessiblemem: none, target_mem: none)
-define dso_local void @_Z10test_crashv() local_unnamed_addr #0 {
-; CHECK-LABEL: _Z10test_crashv:
+define void @copy_undef_propogate(i32 %in, ptr %out) {
+; CHECK-LABEL: copy_undef_propogate:
; CHECK: @ %bb.0: @ %entry
-; CHECK-NEXT: .save {r7, lr}
-; CHECK-NEXT: push {r7, lr}
-; CHECK-NEXT: .setfp r7, sp
-; CHECK-NEXT: mov r7, sp
-; CHECK-NEXT: movw r0, :lower16:test_crash_format
-; CHECK-NEXT: @ implicit-def: $r1
-; CHECK-NEXT: movt r0, :upper16:test_crash_format
-; CHECK-NEXT: vld1.32 {d17[0]}, [r0:32]
-; CHECK-NEXT: movw r0, :lower16:global_out
-; CHECK-NEXT: movt r0, :upper16:global_out
+; CHECK-NEXT: vmov.32 d17[0], r0
+; CHECK-NEXT: @ implicit-def: $r0
; CHECK-NEXT: .LBB0_1: @ %for.cond
; CHECK-NEXT: @ =>This Inner Loop Header: Depth=1
-; CHECK-NEXT: vmov.32 d16[0], r1
-; CHECK-NEXT: ldr r2, [r0]
-; CHECK-NEXT: vmov.32 d16[1], r1
-; CHECK-NEXT: adds r1, #1
+; CHECK-NEXT: vmov.32 d16[0], r0
+; CHECK-NEXT: mov r2, r1
+; CHECK-NEXT: vmov.32 d16[1], r0
+; CHECK-NEXT: add r0, r0, #1
; CHECK-NEXT: vst1.32 {d16, d17}, [r2:128]!
; CHECK-NEXT: vst1.64 {d16, d17}, [r2:128]
; CHECK-NEXT: b .LBB0_1
entry:
- %0 = load i32, ptr @test_crash_format, align 4, !tbaa !5
- %1 = insertelement <8 x i32> <i32 undef, i32 undef, i32 undef, i32 undef, i32 poison, i32 poison, i32 poison, i32 undef>, i32 %0, i64 6
+ %1 = insertelement <8 x i32> <i32 undef, i32 undef, i32 undef, i32 undef, i32 poison, i32 poison, i32 poison, i32 undef>, i32 %in, i64 6
br label %for.cond
-for.cond: ; preds = %for.cond, %entry
+for.cond:
%i.0 = phi i32 [ undef, %entry ], [ %inc, %for.cond ]
%2 = insertelement <8 x i32> %1, i32 %i.0, i64 4
%3 = insertelement <8 x i32> %2, i32 %i.0, i64 5
- %4 = load ptr, ptr @global_out, align 4, !tbaa !9
- store <8 x i32> %3, ptr %4, align 32, !tbaa !11
+ store <8 x i32> %3, ptr %out
%inc = add nsw i32 %i.0, 1
- br label %for.cond, !llvm.loop !12
+ br label %for.cond
}
-attributes #0 = { mustprogress nofree norecurse noreturn nosync nounwind optsize memory(readwrite, argmem: write, inaccessiblemem: none, target_mem: none) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+armv7-a,+d32,+dsp,+fp64,+neon,+read-tp-tpidruro,+thumb-mode,+vfp2,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,-aes,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fullfp16,-sha2,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp" }
-
-!llvm.module.flags = !{!0, !1, !2, !3}
-!llvm.ident = !{!4}
-!llvm.errno.tbaa = !{!5}
-
-!0 = !{i32 1, !"min_enum_size", i32 4}
-!1 = !{i32 8, !"PIC Level", i32 2}
-!2 = !{i32 7, !"PIE Level", i32 2}
-!3 = !{i32 7, !"frame-pointer", i32 2}
-!4 = !{!"clang version 23.0.0git (git at github.com:bababuck/llvm-project.git a6351d882ca3086c62e052fbc4f7f585e157213b)"}
-!5 = !{!6, !6, i64 0}
-!6 = !{!"int", !7, i64 0}
-!7 = !{!"omnipotent char", !8, i64 0}
-!8 = !{!"Simple C++ TBAA"}
-!9 = !{!10, !10, i64 0}
-!10 = !{!"any pointer", !7, i64 0}
-!11 = !{!7, !7, i64 0}
-!12 = distinct !{!12, !13}
-!13 = !{!"llvm.loop.mustprogress"}
>From 7ae9c486b71c26d8825480a713f296c54aeef507 Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Tue, 16 Jun 2026 12:09:41 -0700
Subject: [PATCH 4/8] Add .mir test
---
llvm/test/CodeGen/ARM/copy-undef.mir | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 llvm/test/CodeGen/ARM/copy-undef.mir
diff --git a/llvm/test/CodeGen/ARM/copy-undef.mir b/llvm/test/CodeGen/ARM/copy-undef.mir
new file mode 100644
index 0000000000000..97ee1d3575bea
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/copy-undef.mir
@@ -0,0 +1,18 @@
+# RUN: llc -o - %s -mtriple=armv7-- -run-pass=register-coalescer | FileCheck %s
+
+# Make sure we don't crash on this input
+
+---
+---
+name: copy_undef_propogate
+tracksRegLiveness: true
+body: |
+ bb.0.entry:
+ liveins: $r0
+
+ %4:gpr = COPY killed $r0
+ %7:dpr = VSETLNi32 undef %7, killed %4, 0, 14 /* CC::al */, $noreg
+ undef %9.dsub_0:qpr = COPY undef %10:dpr
+ %9.dsub_1:qpr = COPY killed %7
+ %12:dpr = COPY %9.dsub_0
+...
>From 419da911b9188d52c28066eea999215d0506fe72 Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Tue, 16 Jun 2026 12:43:01 -0700
Subject: [PATCH 5/8] undef -> poison in .ll test
---
llvm/test/CodeGen/ARM/copy-undef.ll | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/test/CodeGen/ARM/copy-undef.ll b/llvm/test/CodeGen/ARM/copy-undef.ll
index 773ce0f8825ef..50a9131e2c044 100644
--- a/llvm/test/CodeGen/ARM/copy-undef.ll
+++ b/llvm/test/CodeGen/ARM/copy-undef.ll
@@ -16,11 +16,11 @@ define void @copy_undef_propogate(i32 %in, ptr %out) {
; CHECK-NEXT: vst1.64 {d16, d17}, [r2:128]
; CHECK-NEXT: b .LBB0_1
entry:
- %1 = insertelement <8 x i32> <i32 undef, i32 undef, i32 undef, i32 undef, i32 poison, i32 poison, i32 poison, i32 undef>, i32 %in, i64 6
+ %1 = insertelement <8 x i32> <i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>, i32 %in, i64 6
br label %for.cond
for.cond:
- %i.0 = phi i32 [ undef, %entry ], [ %inc, %for.cond ]
+ %i.0 = phi i32 [ poison, %entry ], [ %inc, %for.cond ]
%2 = insertelement <8 x i32> %1, i32 %i.0, i64 4
%3 = insertelement <8 x i32> %2, i32 %i.0, i64 5
store <8 x i32> %3, ptr %out
>From 95e977dd236246cba6c9789da4f9a6b4575cf058 Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Tue, 16 Jun 2026 12:47:23 -0700
Subject: [PATCH 6/8] Compress reg numbers in .mir
---
llvm/test/CodeGen/ARM/copy-undef.mir | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/llvm/test/CodeGen/ARM/copy-undef.mir b/llvm/test/CodeGen/ARM/copy-undef.mir
index 97ee1d3575bea..7dd3c757ecef8 100644
--- a/llvm/test/CodeGen/ARM/copy-undef.mir
+++ b/llvm/test/CodeGen/ARM/copy-undef.mir
@@ -10,9 +10,9 @@ body: |
bb.0.entry:
liveins: $r0
- %4:gpr = COPY killed $r0
- %7:dpr = VSETLNi32 undef %7, killed %4, 0, 14 /* CC::al */, $noreg
- undef %9.dsub_0:qpr = COPY undef %10:dpr
- %9.dsub_1:qpr = COPY killed %7
- %12:dpr = COPY %9.dsub_0
+ %0:gpr = COPY killed $r0
+ %1:dpr = VSETLNi32 undef %1, killed %0, 0, 14 /* CC::al */, $noreg
+ undef %2.dsub_0:qpr = COPY undef %3:dpr
+ %2.dsub_1:qpr = COPY killed %1
+ %4:dpr = COPY %2.dsub_0
...
>From aec777037be05ae66447936d99ef35f251784509 Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Tue, 16 Jun 2026 12:55:20 -0700
Subject: [PATCH 7/8] Add checks to .mir
---
llvm/test/CodeGen/ARM/copy-undef.mir | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/llvm/test/CodeGen/ARM/copy-undef.mir b/llvm/test/CodeGen/ARM/copy-undef.mir
index 7dd3c757ecef8..4374ccecfd279 100644
--- a/llvm/test/CodeGen/ARM/copy-undef.mir
+++ b/llvm/test/CodeGen/ARM/copy-undef.mir
@@ -1,15 +1,19 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
# RUN: llc -o - %s -mtriple=armv7-- -run-pass=register-coalescer | FileCheck %s
# Make sure we don't crash on this input
----
---
name: copy_undef_propogate
tracksRegLiveness: true
body: |
bb.0.entry:
liveins: $r0
-
+
+ ; CHECK-LABEL: name: copy_undef_propogate
+ ; CHECK: liveins: $r0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: KILL $r0
%0:gpr = COPY killed $r0
%1:dpr = VSETLNi32 undef %1, killed %0, 0, 14 /* CC::al */, $noreg
undef %2.dsub_0:qpr = COPY undef %3:dpr
>From 0f6dd5e64a206336f28a08631414368730947e3d Mon Sep 17 00:00:00 2001
From: bababuck <buchner.ryan at gmail.com>
Date: Tue, 16 Jun 2026 12:55:56 -0700
Subject: [PATCH 8/8] Remove .entry
---
llvm/test/CodeGen/ARM/copy-undef.mir | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/ARM/copy-undef.mir b/llvm/test/CodeGen/ARM/copy-undef.mir
index 4374ccecfd279..75432cab06222 100644
--- a/llvm/test/CodeGen/ARM/copy-undef.mir
+++ b/llvm/test/CodeGen/ARM/copy-undef.mir
@@ -7,7 +7,7 @@
name: copy_undef_propogate
tracksRegLiveness: true
body: |
- bb.0.entry:
+ bb.0:
liveins: $r0
; CHECK-LABEL: name: copy_undef_propogate
More information about the llvm-commits
mailing list