Skip to content

Conversation

@kper
Copy link
Contributor

@kper kper commented Dec 27, 2025

The crash was triggered because %38 violates the assertion since WideTy is a scalar value and smaller than 128 bits.

LLC debug from referenced issue:
Select: %32:fpr(s16), %33:fpr(s16) = G_UNMERGE_VALUES %38:fpr(s32)

This PR replaces the assertion with a check that returns false which forces a different instruction selection.

Closes #173722

@llvmbot
Copy link
Member

llvmbot commented Dec 27, 2025

@llvm/pr-subscribers-backend-aarch64

Author: Kevin Per (kper)

Changes

The crash was triggered because %38 violates the assertion since WideTy is a scalar value and smaller than 128 bits.

LLC debug from referenced issue:
Select: %32:fpr(s16), %33:fpr(s16) = G_UNMERGE_VALUES %38:fpr(s32)

This PR replaces the assertion with a check that returns false which forces a different instruction selection.

Closes #173722


Full diff: https://github.com/llvm/llvm-project/pull/173737.diff

2 Files Affected:

  • (modified) llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp (+5-2)
  • (modified) llvm/test/CodeGen/AArch64/aarch64-avoid-illegal-extract-subvector.ll (+94-18)
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index f9db39e5f8622..f9f78c4242568 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -4085,8 +4085,11 @@ bool AArch64InstructionSelector::selectUnmergeValues(MachineInstr &I,
   const LLT NarrowTy = MRI.getType(I.getOperand(0).getReg());
   const LLT WideTy = MRI.getType(SrcReg);
   (void)WideTy;
-  assert((WideTy.isVector() || WideTy.getSizeInBits() == 128) &&
-         "can only unmerge from vector or s128 types!");
+  if (!(WideTy.isVector() || WideTy.getSizeInBits() == 128)) {
+    LLVM_DEBUG(dbgs() << "can only unmerge from vector or s128 types!.\n");
+    return false;
+  }
+
   assert(WideTy.getSizeInBits() > NarrowTy.getSizeInBits() &&
          "source register size too small!");
 
diff --git a/llvm/test/CodeGen/AArch64/aarch64-avoid-illegal-extract-subvector.ll b/llvm/test/CodeGen/AArch64/aarch64-avoid-illegal-extract-subvector.ll
index 925b4c87ec9a5..d19dcbb577aa3 100644
--- a/llvm/test/CodeGen/AArch64/aarch64-avoid-illegal-extract-subvector.ll
+++ b/llvm/test/CodeGen/AArch64/aarch64-avoid-illegal-extract-subvector.ll
@@ -1,13 +1,25 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=aarch64-none-linux-gnu < %s -o -| FileCheck %s
+; RUN: llc -mtriple=aarch64-none-linux-gnu < %s -o -| FileCheck %s --check-prefix=O2
+; RUN: llc -O0 -mtriple=aarch64-none-linux-gnu < %s -o -| FileCheck %s --check-prefix=O0
 define <2 x i64> @test1(<4 x i32> %x) #0 {
-; CHECK-LABEL: test1:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    mov w8, v0.s[1]
-; CHECK-NEXT:    mov w9, v0.s[2]
-; CHECK-NEXT:    fmov d0, x8
-; CHECK-NEXT:    mov v0.d[1], x9
-; CHECK-NEXT:    ret
+; O2-LABEL: test1:
+; O2:       // %bb.0:
+; O2-NEXT:    mov w8, v0.s[1]
+; O2-NEXT:    mov w9, v0.s[2]
+; O2-NEXT:    fmov d0, x8
+; O2-NEXT:    mov v0.d[1], x9
+; O2-NEXT:    ret
+;
+; O0-LABEL: test1:
+; O0:       // %bb.0:
+; O0-NEXT:    mov w8, v0.s[1]
+; O0-NEXT:    mov w9, w8
+; O0-NEXT:    mov w8, v0.s[2]
+; O0-NEXT:    // kill: def $x8 killed $w8
+; O0-NEXT:    // implicit-def: $q0
+; O0-NEXT:    fmov d0, x9
+; O0-NEXT:    mov v0.d[1], x8
+; O0-NEXT:    ret
   %i1 = extractelement <4 x i32> %x, i32 1
   %zi1 = zext i32 %i1 to i64
   %i2 = extractelement <4 x i32> %x, i32 2
@@ -18,16 +30,32 @@ define <2 x i64> @test1(<4 x i32> %x) #0 {
 }
 
 define <4 x i64> @test2(<4 x i32> %0) {
-; CHECK-LABEL: test2:
-; CHECK:       // %bb.0: // %entry
-; CHECK-NEXT:    adrp x8, .LCPI1_0
-; CHECK-NEXT:    ldr q1, [x8, :lo12:.LCPI1_0]
-; CHECK-NEXT:    add v0.4s, v0.4s, v1.4s
-; CHECK-NEXT:    mov w8, v0.s[1]
-; CHECK-NEXT:    mov w9, v0.s[2]
-; CHECK-NEXT:    fmov d1, x8
-; CHECK-NEXT:    mov v1.d[1], x9
-; CHECK-NEXT:    ret
+; O2-LABEL: test2:
+; O2:       // %bb.0: // %entry
+; O2-NEXT:    adrp x8, .LCPI1_0
+; O2-NEXT:    ldr q1, [x8, :lo12:.LCPI1_0]
+; O2-NEXT:    add v0.4s, v0.4s, v1.4s
+; O2-NEXT:    mov w8, v0.s[1]
+; O2-NEXT:    mov w9, v0.s[2]
+; O2-NEXT:    fmov d1, x8
+; O2-NEXT:    mov v1.d[1], x9
+; O2-NEXT:    ret
+;
+; O0-LABEL: test2:
+; O0:       // %bb.0: // %entry
+; O0-NEXT:    mov v1.16b, v0.16b
+; O0-NEXT:    adrp x8, .LCPI1_0
+; O0-NEXT:    ldr q2, [x8, :lo12:.LCPI1_0]
+; O0-NEXT:    // implicit-def: $q0
+; O0-NEXT:    add v1.4s, v1.4s, v2.4s
+; O0-NEXT:    mov w8, v1.s[1]
+; O0-NEXT:    mov w9, w8
+; O0-NEXT:    mov w8, v1.s[2]
+; O0-NEXT:    // kill: def $x8 killed $w8
+; O0-NEXT:    // implicit-def: $q1
+; O0-NEXT:    fmov d1, x9
+; O0-NEXT:    mov v1.d[1], x8
+; O0-NEXT:    ret
 entry:
   %1 = add <4 x i32> %0, <i32 -4, i32 -8, i32 -12, i32 -16>
   %2 = extractelement <4 x i32> %1, i32 1
@@ -38,3 +66,51 @@ entry:
   %5 = insertelement <4 x i64> %4, i64 %zext2, i32 3
   ret <4 x i64> %5
 }
+
+; This issue was only triggered with -O0
+define i2 @issue_173722(<1 x i16> %call) {
+; O2-LABEL: issue_173722:
+; O2:       // %bb.0: // %entry
+; O2-NEXT:    mov w0, wzr
+; O2-NEXT:    ret
+;
+; O0-LABEL: issue_173722:
+; O0:       // %bb.0: // %entry
+; O0-NEXT:    sub sp, sp, #16
+; O0-NEXT:    .cfi_def_cfa_offset 16
+; O0-NEXT:    str d0, [sp, #8] // 8-byte Spill
+; O0-NEXT:    mov w8, #1 // =0x1
+; O0-NEXT:    cbnz w8, .LBB2_2
+; O0-NEXT:    b .LBB2_1
+; O0-NEXT:  .LBB2_1: // %cond.true
+; O0-NEXT:    ldr d1, [sp, #8] // 8-byte Reload
+; O0-NEXT:    // implicit-def: $q0
+; O0-NEXT:    fmov d0, d1
+; O0-NEXT:    umov w0, v0.h[0]
+; O0-NEXT:    str w0, [sp, #4] // 4-byte Spill
+; O0-NEXT:    b .LBB2_3
+; O0-NEXT:  .LBB2_2: // %cond.false
+; O0-NEXT:    mov w0, wzr
+; O0-NEXT:    str w0, [sp, #4] // 4-byte Spill
+; O0-NEXT:    b .LBB2_3
+; O0-NEXT:  .LBB2_3: // %cond.end
+; O0-NEXT:    ldr w0, [sp, #4] // 4-byte Reload
+; O0-NEXT:    add sp, sp, #16
+; O0-NEXT:    ret
+entry:
+  br i1 false, label %cond.true, label %cond.false
+
+cond.true:                                        ; preds = %entry
+  %vecext = extractelement <1 x i16> %call, i32 0
+  %conv = trunc i16 %vecext to i2
+  br label %cond.end
+
+cond.false:                                       ; preds = %entry
+  %conv3 = zext i32 0 to i104
+  %conv4 = trunc i104 %conv3 to i2
+  br label %cond.end
+
+cond.end:                                         ; preds = %cond.false, %cond.true
+  %cond = phi i2 [ %conv, %cond.true ], [ %conv4, %cond.false ]
+  ret i2 %cond
+}

@kper
Copy link
Contributor Author

kper commented Dec 27, 2025

fyi @davemgreen @XChy

@XChy XChy requested a review from davemgreen December 28, 2025 04:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[AArch64][GISel] Assertion `(WideTy.isVector() || WideTy.getSizeInBits() == 128) && "can only unmerge from vector or s128 types!"' failed.

2 participants