[llvm] [CodeGen][ARM] Add regression tests for #202263 (PR #202599)

Aochang Liu via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 29 04:42:28 PDT 2026


https://github.com/HelloWorldU updated https://github.com/llvm/llvm-project/pull/202599

>From 210ed985def673e5386563edfe719d29468d2f3a Mon Sep 17 00:00:00 2001
From: HelloWorldU <asd001liu at gmail.com>
Date: Thu, 23 Jul 2026 22:28:08 +0800
Subject: [PATCH 1/3] [CodeGen][ARM] Add regression tests for #202263

The root cause - RegisterCoalescer eliminating an undef COPY and leaving
a partial subregister redef reading a value that no longer exists - was
fixed by #204039. Add the regression tests originally developed in
#202599 so the pattern stays covered:

- an end-to-end IR test whose assembly output is checked with FileCheck;
- a focused single-pass -run-pass=register-coalescer MIR test using
  -verify-coalescing, which hits the "Instruction is reading nonexistent
  value" assertion without #204039 and passes with it.
---
 .../regcoalesce-undef-copy-subreg-redef.ll    |  38 ++++++
 .../regcoalesce-undef-copy-subreg-redef.mir   | 112 ++++++++++++++++++
 2 files changed, 150 insertions(+)
 create mode 100644 llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.ll
 create mode 100644 llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.mir

diff --git a/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.ll b/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.ll
new file mode 100644
index 0000000000000..74a4101ad5dbf
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.ll
@@ -0,0 +1,38 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=armv8a-unknown-linux < %s | FileCheck %s
+
+; Regression test for issue #202263. Lowering the REG_SEQUENCE that builds the
+; <2 x i64> keeps a COPY of an undefined value which feeds a later partial
+; subregister redef. When RegisterCoalescer eliminates that copy, the redef
+; must be turned into a read-undef def. Otherwise the coalescer asserts with
+; "Instruction is reading nonexistent value" on targets that do not track
+; subregister liveness (armv8a A-profile has no MVE).
+
+target triple = "armv8a-unknown-linux"
+
+define void @init(i64 %x, i1 %c, ptr %p) {
+; CHECK-LABEL: init:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    tst r2, #1
+; CHECK-NEXT:    bxne lr
+; CHECK-NEXT:  .LBB0_1: @ %body
+; CHECK-NEXT:    vmov.32 d17[0], r0
+; CHECK-NEXT:    mov r0, #1
+; CHECK-NEXT:    vmov.32 d17[1], r1
+; CHECK-NEXT:    vmov.32 d16[0], r0
+; CHECK-NEXT:    mov r0, #0
+; CHECK-NEXT:    vmov.32 d16[1], r0
+; CHECK-NEXT:    vst1.64 {d16, d17}, [r3]
+; CHECK-NEXT:    bx lr
+entry:
+  %v0 = insertelement <2 x i64> poison, i64 %x, i64 1
+  br i1 %c, label %exit, label %body
+
+body:
+  %v1 = insertelement <2 x i64> %v0, i64 1, i64 0
+  store <2 x i64> %v1, ptr %p, align 8
+  br label %exit
+
+exit:
+  ret void
+}
diff --git a/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.mir b/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.mir
new file mode 100644
index 0000000000000..47060a1398051
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.mir
@@ -0,0 +1,112 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=armv8a-unknown-linux -run-pass=register-coalescer -verify-coalescing -o - %s | FileCheck %s
+
+# Regression test for issue #202263 (and the long-standing #200378). After
+# RegisterCoalescer eliminates the COPY of an undefined value, the partial
+# subregister redef that implicitly read it must become a read-undef def;
+# otherwise the coalescer asserts "Instruction is reading nonexistent value"
+# on targets that do not track subregister liveness.
+#
+# The original failures reach this pattern through REG_SEQUENCE lowering.
+# This focused test starts at the RegisterCoalescer boundary, after that
+# lowering has produced the undef COPY and partial redef sequence.
+
+--- |
+  define void @init(i64 %0, i1 %c, ptr %1) {
+    ret void
+  }
+...
+---
+name:            init
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: dpair }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+  - { id: 3, class: gpr }
+  - { id: 4, class: gpr }
+  - { id: 5, class: dpr }
+  - { id: 7, class: dpr }
+  - { id: 8, class: qpr }
+  - { id: 9, class: dpr }
+  - { id: 11, class: gpr }
+  - { id: 12, class: dpr }
+  - { id: 13, class: dpr }
+  - { id: 14, class: gpr }
+  - { id: 15, class: qpr }
+  - { id: 16, class: dpr }
+  - { id: 17, class: dpr }
+  - { id: 18, class: qpr }
+liveins:
+  - { reg: '$r0', virtual-reg: '%1' }
+  - { reg: '$r1', virtual-reg: '%2' }
+  - { reg: '$r2', virtual-reg: '%3' }
+  - { reg: '$r3', virtual-reg: '%4' }
+body:             |
+  ; CHECK-LABEL: name: init
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.2(0x40000000)
+  ; CHECK-NEXT:   liveins: $r0, $r1, $r2, $r3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gpr = COPY $r3
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gpr = COPY $r2
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gpr = COPY $r1
+  ; CHECK-NEXT:   [[COPY3:%[0-9]+]]:gpr = COPY $r0
+  ; CHECK-NEXT:   TSTri [[COPY1]], 1, 14 /* CC::al */, $noreg, implicit-def $cpsr
+  ; CHECK-NEXT:   Bcc %bb.2, 0 /* CC::eq */, killed $cpsr
+  ; CHECK-NEXT:   B %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   BX_RET 14 /* CC::al */, $noreg
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   undef [[VSETLNi32_:%[0-9]+]].dsub_1:qpr = VSETLNi32 undef [[VSETLNi32_]].dsub_1, [[COPY3]], 0, 14 /* CC::al */, $noreg
+  ; CHECK-NEXT:   [[VSETLNi32_:%[0-9]+]].dsub_1:qpr = VSETLNi32 [[VSETLNi32_]].dsub_1, [[COPY2]], 1, 14 /* CC::al */, $noreg
+  ; CHECK-NEXT:   [[MOVi:%[0-9]+]]:gpr = MOVi 1, 14 /* CC::al */, $noreg, $noreg
+  ; CHECK-NEXT:   [[VSETLNi32_:%[0-9]+]].dsub_0:qpr = VSETLNi32 [[VSETLNi32_]].dsub_0, [[MOVi]], 0, 14 /* CC::al */, $noreg
+  ; CHECK-NEXT:   [[MOVi1:%[0-9]+]]:gpr = MOVi 0, 14 /* CC::al */, $noreg, $noreg
+  ; CHECK-NEXT:   [[VSETLNi32_:%[0-9]+]].dsub_0:qpr = VSETLNi32 [[VSETLNi32_]].dsub_0, [[MOVi1]], 1, 14 /* CC::al */, $noreg
+  ; CHECK-NEXT:   VST1q64 [[COPY]], 0, [[VSETLNi32_]], 14 /* CC::al */, $noreg :: (store (s128) into %ir.1, align 8)
+  ; CHECK-NEXT:   B %bb.1
+  bb.0:
+    successors: %bb.1, %bb.2
+    liveins: $r0, $r1, $r2, $r3
+
+    %4:gpr = COPY killed $r3
+    %3:gpr = COPY killed $r2
+    %2:gpr = COPY killed $r1
+    %1:gpr = COPY killed $r0
+    TSTri killed %3, 1, 14 /* CC::al */, $noreg, implicit-def $cpsr
+    Bcc %bb.2, 0 /* CC::eq */, killed $cpsr
+    B %bb.1
+
+  bb.1:
+    BX_RET 14 /* CC::al */, $noreg
+
+  bb.2:
+    successors: %bb.1
+
+    ; The COPY of an undef value below feeds the dsub_1 partial redef. After the
+    ; copy is eliminated, that redef must become a read-undef def.
+    %5:dpr = VSETLNi32 undef %5, killed %1, 0, 14 /* CC::al */, $noreg
+    %7:dpr = COPY killed %5
+    %7:dpr = VSETLNi32 %7, killed %2, 1, 14 /* CC::al */, $noreg
+    undef %8.dsub_0:qpr = COPY undef %9:dpr
+    %8.dsub_1:qpr = COPY killed %7
+    %11:gpr = MOVi 1, 14 /* CC::al */, $noreg, $noreg
+    %12:dpr = COPY %8.dsub_0
+    %13:dpr = COPY killed %12
+    %13:dpr = VSETLNi32 %13, killed %11, 0, 14 /* CC::al */, $noreg
+    %14:gpr = MOVi 0, 14 /* CC::al */, $noreg, $noreg
+    %15:qpr = COPY killed %8
+    %15.dsub_0:qpr = COPY %13
+    %16:dpr = COPY killed %13
+    %17:dpr = COPY killed %16
+    %17:dpr = VSETLNi32 %17, killed %14, 1, 14 /* CC::al */, $noreg
+    %18:qpr = COPY killed %15
+    %18.dsub_0:qpr = COPY killed %17
+    VST1q64 killed %4, 0, killed %18, 14 /* CC::al */, $noreg :: (store (s128) into %ir.1, align 8)
+    B %bb.1
+...

>From d1472c15072da674ae316ea71f00754517a0b68c Mon Sep 17 00:00:00 2001
From: HelloWorldU <asd001liu at gmail.com>
Date: Wed, 29 Jul 2026 14:31:12 +0800
Subject: [PATCH 2/3] Drop redundant target triple; the RUN line already
 specifies it

---
 llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.ll | 2 --
 1 file changed, 2 deletions(-)

diff --git a/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.ll b/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.ll
index 74a4101ad5dbf..7cb2a68a18d73 100644
--- a/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.ll
+++ b/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.ll
@@ -8,8 +8,6 @@
 ; "Instruction is reading nonexistent value" on targets that do not track
 ; subregister liveness (armv8a A-profile has no MVE).
 
-target triple = "armv8a-unknown-linux"
-
 define void @init(i64 %x, i1 %c, ptr %p) {
 ; CHECK-LABEL: init:
 ; CHECK:       @ %bb.0: @ %entry

>From 053b5171c9c0a86153304bd1c798d2a378999b87 Mon Sep 17 00:00:00 2001
From: HelloWorldU <asd001liu at gmail.com>
Date: Wed, 29 Jul 2026 19:40:02 +0800
Subject: [PATCH 3/3] Minimize the MIR test per review: drop the IR section,
 MMO, registers and liveins blocks

---
 .../regcoalesce-undef-copy-subreg-redef.mir   | 32 ++-----------------
 1 file changed, 2 insertions(+), 30 deletions(-)

diff --git a/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.mir b/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.mir
index 47060a1398051..d13b6c6f883ce 100644
--- a/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.mir
+++ b/llvm/test/CodeGen/ARM/regcoalesce-undef-copy-subreg-redef.mir
@@ -11,37 +11,9 @@
 # This focused test starts at the RegisterCoalescer boundary, after that
 # lowering has produced the undef COPY and partial redef sequence.
 
---- |
-  define void @init(i64 %0, i1 %c, ptr %1) {
-    ret void
-  }
-...
 ---
 name:            init
 tracksRegLiveness: true
-registers:
-  - { id: 0, class: dpair }
-  - { id: 1, class: gpr }
-  - { id: 2, class: gpr }
-  - { id: 3, class: gpr }
-  - { id: 4, class: gpr }
-  - { id: 5, class: dpr }
-  - { id: 7, class: dpr }
-  - { id: 8, class: qpr }
-  - { id: 9, class: dpr }
-  - { id: 11, class: gpr }
-  - { id: 12, class: dpr }
-  - { id: 13, class: dpr }
-  - { id: 14, class: gpr }
-  - { id: 15, class: qpr }
-  - { id: 16, class: dpr }
-  - { id: 17, class: dpr }
-  - { id: 18, class: qpr }
-liveins:
-  - { reg: '$r0', virtual-reg: '%1' }
-  - { reg: '$r1', virtual-reg: '%2' }
-  - { reg: '$r2', virtual-reg: '%3' }
-  - { reg: '$r3', virtual-reg: '%4' }
 body:             |
   ; CHECK-LABEL: name: init
   ; CHECK: bb.0:
@@ -68,7 +40,7 @@ body:             |
   ; CHECK-NEXT:   [[VSETLNi32_:%[0-9]+]].dsub_0:qpr = VSETLNi32 [[VSETLNi32_]].dsub_0, [[MOVi]], 0, 14 /* CC::al */, $noreg
   ; CHECK-NEXT:   [[MOVi1:%[0-9]+]]:gpr = MOVi 0, 14 /* CC::al */, $noreg, $noreg
   ; CHECK-NEXT:   [[VSETLNi32_:%[0-9]+]].dsub_0:qpr = VSETLNi32 [[VSETLNi32_]].dsub_0, [[MOVi1]], 1, 14 /* CC::al */, $noreg
-  ; CHECK-NEXT:   VST1q64 [[COPY]], 0, [[VSETLNi32_]], 14 /* CC::al */, $noreg :: (store (s128) into %ir.1, align 8)
+  ; CHECK-NEXT:   VST1q64 [[COPY]], 0, [[VSETLNi32_]], 14 /* CC::al */, $noreg
   ; CHECK-NEXT:   B %bb.1
   bb.0:
     successors: %bb.1, %bb.2
@@ -107,6 +79,6 @@ body:             |
     %17:dpr = VSETLNi32 %17, killed %14, 1, 14 /* CC::al */, $noreg
     %18:qpr = COPY killed %15
     %18.dsub_0:qpr = COPY killed %17
-    VST1q64 killed %4, 0, killed %18, 14 /* CC::al */, $noreg :: (store (s128) into %ir.1, align 8)
+    VST1q64 killed %4, 0, killed %18, 14 /* CC::al */, $noreg
     B %bb.1
 ...



More information about the llvm-commits mailing list