[llvm] [MIPS] fix assert on `undef` first mask element (PR #203390)

Folkert de Vries via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 11 13:47:05 PDT 2026


https://github.com/folkertdev updated https://github.com/llvm/llvm-project/pull/203390

>From f4320c37c7d6412a4cb745fe5a7791073cda23be Mon Sep 17 00:00:00 2001
From: Folkert de Vries <folkert at folkertdev.nl>
Date: Thu, 11 Jun 2026 22:32:31 +0200
Subject: [PATCH] [MIPS] fix assert on `undef` first mask element

---
 llvm/lib/Target/Mips/MipsSEISelLowering.cpp   |  24 +--
 .../msa/shuffle-undef-first-mask-element.ll   | 164 ++++++++++++++++++
 2 files changed, 178 insertions(+), 10 deletions(-)
 create mode 100644 llvm/test/CodeGen/Mips/msa/shuffle-undef-first-mask-element.ll

diff --git a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
index 7c49838732032..3be9a3d217a83 100644
--- a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
@@ -3132,11 +3132,8 @@ static SDValue lowerVECTOR_SHUFFLE_VSHF(SDValue Op, EVT ResTy,
   SDLoc DL(Op);
   int ResTyNumElts = ResTy.getVectorNumElements();
 
-  assert(Indices[0] >= 0 &&
-         "shuffle mask starts with an UNDEF, which is not expected");
-
   for (int i = 0; i < ResTyNumElts; ++i) {
-    // Idx == -1 means UNDEF
+    // Idx == -1 means UNDEF/poison
     int Idx = Indices[i];
 
     if (0 <= Idx && Idx < ResTyNumElts)
@@ -3144,15 +3141,22 @@ static SDValue lowerVECTOR_SHUFFLE_VSHF(SDValue Op, EVT ResTy,
     if (ResTyNumElts <= Idx && Idx < ResTyNumElts * 2)
       Using2ndVec = true;
   }
+
+  // Find the first non-undef index use as a default when there is a leading
+  // UNDEF/poison.
   int LastValidIndex = 0;
-  for (size_t i = 0; i < Indices.size(); i++) {
-    int Idx = Indices[i];
-    if (Idx < 0) {
-      // Continue using splati index or use the last valid index.
-      Idx = isSPLATI ? Indices[0] : LastValidIndex;
-    } else {
+  for (int Idx : Indices)
+    if (Idx >= 0) {
       LastValidIndex = Idx;
+      break;
     }
+
+  for (int Idx : Indices) {
+    if (Idx < 0)
+      Idx = LastValidIndex;
+    else
+      // Continue using splati index or use the last valid index.
+      LastValidIndex = isSPLATI ? LastValidIndex : Idx;
     Ops.push_back(DAG.getTargetConstant(Idx, DL, MaskEltTy));
   }
 
diff --git a/llvm/test/CodeGen/Mips/msa/shuffle-undef-first-mask-element.ll b/llvm/test/CodeGen/Mips/msa/shuffle-undef-first-mask-element.ll
new file mode 100644
index 0000000000000..ef3776935e639
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/msa/shuffle-undef-first-mask-element.ll
@@ -0,0 +1,164 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=mipsisa64r6el-unknown-linux-gnuabi64 -O3 < %s | FileCheck %s --check-prefixes=NOMSA
+; RUN: llc -mtriple=mipsisa64r6el-unknown-linux-gnuabi64 -mattr=+msa -O3 < %s | FileCheck %s --check-prefixes=MSA
+
+; Check that undef/poison (leading) lanes are filled with a valid index.
+; The lowerVECTOR_SHUFFLE_VSHF function used to crash on such inputs,
+; but leading undef/poison can be created by DAGCombiner.
+
+define void @shuffle_poison_first_mask_element(ptr %res, ptr %a, ptr %b) {
+; NOMSA-LABEL: shuffle_poison_first_mask_element:
+; NOMSA:       # %bb.0:
+; NOMSA-NEXT:    lw $1, 0($6)
+; NOMSA-NEXT:    sw $1, 12($4)
+; NOMSA-NEXT:    lw $1, 0($5)
+; NOMSA-NEXT:    jr $ra
+; NOMSA-NEXT:    sw $1, 8($4)
+;
+; MSA-LABEL: shuffle_poison_first_mask_element:
+; MSA:       # %bb.0:
+; MSA-NEXT:    lui $1, %highest(.LCPI0_0)
+; MSA-NEXT:    ld.w $w0, 0($5)
+; MSA-NEXT:    ld.w $w1, 0($6)
+; MSA-NEXT:    daddiu $1, $1, %higher(.LCPI0_0)
+; MSA-NEXT:    dsll $1, $1, 16
+; MSA-NEXT:    daddiu $1, $1, %hi(.LCPI0_0)
+; MSA-NEXT:    dsll $1, $1, 16
+; MSA-NEXT:    daddiu $1, $1, %lo(.LCPI0_0)
+; MSA-NEXT:    ld.w $w2, 0($1)
+; MSA-NEXT:    vshf.w $w2, $w1, $w0
+; MSA-NEXT:    jr $ra
+; MSA-NEXT:    st.w $w2, 0($4)
+  %va = load <4 x i32>, ptr %a
+  %vb = load <4 x i32>, ptr %b
+  %shuf = shufflevector <4 x i32> %va, <4 x i32> %vb, <4 x i32> <i32 poison, i32 poison, i32 0, i32 4>
+  store <4 x i32> %shuf, ptr %res
+  ret void
+}
+
+; For this example the DAGCombiner would introduce a mask with a leading poison index.
+define i4 @inserted_poison_first_mask_element(<4 x i128> %0) {
+; NOMSA-LABEL: inserted_poison_first_mask_element:
+; NOMSA:       # %bb.0: # %start
+; NOMSA-NEXT:    or $1, $8, $9
+; NOMSA-NEXT:    or $3, $10, $11
+; NOMSA-NEXT:    or $2, $4, $5
+; NOMSA-NEXT:    sltu $1, $zero, $1
+; NOMSA-NEXT:    sltu $3, $zero, $3
+; NOMSA-NEXT:    sltu $2, $zero, $2
+; NOMSA-NEXT:    sll $1, $1, 2
+; NOMSA-NEXT:    sll $3, $3, 3
+; NOMSA-NEXT:    or $1, $3, $1
+; NOMSA-NEXT:    or $3, $6, $7
+; NOMSA-NEXT:    sltu $3, $zero, $3
+; NOMSA-NEXT:    sll $3, $3, 1
+; NOMSA-NEXT:    or $2, $2, $3
+; NOMSA-NEXT:    jr $ra
+; NOMSA-NEXT:    or $2, $2, $1
+;
+; MSA-LABEL: inserted_poison_first_mask_element:
+; MSA:       # %bb.0: # %start
+; MSA-NEXT:    daddiu $sp, $sp, -16
+; MSA-NEXT:    .cfi_def_cfa_offset 16
+; MSA-NEXT:    or $1, $10, $11
+; MSA-NEXT:    or $2, $8, $9
+; MSA-NEXT:    or $3, $4, $5
+; MSA-NEXT:    or $4, $6, $7
+; MSA-NEXT:    sltu $1, $zero, $1
+; MSA-NEXT:    sltu $2, $zero, $2
+; MSA-NEXT:    sltu $3, $zero, $3
+; MSA-NEXT:    sltu $4, $zero, $4
+; MSA-NEXT:    dext $1, $1, 0, 32
+; MSA-NEXT:    dext $2, $2, 0, 32
+; MSA-NEXT:    dext $3, $3, 0, 32
+; MSA-NEXT:    dext $4, $4, 0, 32
+; MSA-NEXT:    dnegu $1, $1
+; MSA-NEXT:    dnegu $2, $2
+; MSA-NEXT:    dnegu $3, $3
+; MSA-NEXT:    dnegu $4, $4
+; MSA-NEXT:    fill.d $w1, $1
+; MSA-NEXT:    lui $1, %highest(.LCPI1_0)
+; MSA-NEXT:    fill.d $w0, $2
+; MSA-NEXT:    daddiu $1, $1, %higher(.LCPI1_0)
+; MSA-NEXT:    dsll $1, $1, 16
+; MSA-NEXT:    daddiu $1, $1, %hi(.LCPI1_0)
+; MSA-NEXT:    dsll $1, $1, 16
+; MSA-NEXT:    daddiu $1, $1, %lo(.LCPI1_0)
+; MSA-NEXT:    ld.w $w2, 0($1)
+; MSA-NEXT:    vshf.w $w2, $w1, $w0
+; MSA-NEXT:    fill.d $w0, $3
+; MSA-NEXT:    copy_s.w $3, $w0[0]
+; MSA-NEXT:    fill.d $w0, $4
+; MSA-NEXT:    copy_s.w $2, $w2[2]
+; MSA-NEXT:    copy_s.w $1, $w2[3]
+; MSA-NEXT:    splati.w $w0, $w0[0]
+; MSA-NEXT:    andi $2, $2, 1
+; MSA-NEXT:    sll $1, $1, 3
+; MSA-NEXT:    sll $2, $2, 2
+; MSA-NEXT:    copy_s.w $4, $w0[1]
+; MSA-NEXT:    andi $4, $4, 1
+; MSA-NEXT:    sll $4, $4, 1
+; MSA-NEXT:    subu $3, $4, $3
+; MSA-NEXT:    or $2, $3, $2
+; MSA-NEXT:    or $1, $2, $1
+; MSA-NEXT:    andi $2, $1, 15
+; MSA-NEXT:    jr $ra
+; MSA-NEXT:    daddiu $sp, $sp, 16
+start:
+  %1 = icmp ne <4 x i128> %0, zeroinitializer
+  %2 = bitcast <4 x i1> %1 to i4
+  ret i4 %2
+}
+
+define void @splati_with_poison(ptr %res, ptr %a) {
+; NOMSA-LABEL: splati_with_poison:
+; NOMSA:       # %bb.0:
+; NOMSA-NEXT:    lw $1, 4($5)
+; NOMSA-NEXT:    sw $1, 12($4)
+; NOMSA-NEXT:    sw $1, 8($4)
+; NOMSA-NEXT:    jr $ra
+; NOMSA-NEXT:    sw $1, 0($4)
+;
+; MSA-LABEL: splati_with_poison:
+; MSA:       # %bb.0:
+; MSA-NEXT:    ld.w $w0, 0($5)
+; MSA-NEXT:    splati.w $w0, $w0[1]
+; MSA-NEXT:    jr $ra
+; MSA-NEXT:    st.w $w0, 0($4)
+  %va = load <4 x i32>, ptr %a
+  %shuf = shufflevector <4 x i32> %va, <4 x i32> poison, <4 x i32> <i32 1, i32 poison, i32 1, i32 1>
+  store <4 x i32> %shuf, ptr %res
+  ret void
+}
+
+define void @shuffle_poison_middle(ptr %res, ptr %a, ptr %b) {
+; NOMSA-LABEL: shuffle_poison_middle:
+; NOMSA:       # %bb.0:
+; NOMSA-NEXT:    lw $1, 0($6)
+; NOMSA-NEXT:    sw $1, 12($4)
+; NOMSA-NEXT:    ld $1, 4($5)
+; NOMSA-NEXT:    sd $1, 4($4)
+; NOMSA-NEXT:    lw $1, 0($5)
+; NOMSA-NEXT:    jr $ra
+; NOMSA-NEXT:    sw $1, 0($4)
+;
+; MSA-LABEL: shuffle_poison_middle:
+; MSA:       # %bb.0:
+; MSA-NEXT:    lui $1, %highest(.LCPI3_0)
+; MSA-NEXT:    ld.w $w0, 0($5)
+; MSA-NEXT:    ld.w $w1, 0($6)
+; MSA-NEXT:    daddiu $1, $1, %higher(.LCPI3_0)
+; MSA-NEXT:    dsll $1, $1, 16
+; MSA-NEXT:    daddiu $1, $1, %hi(.LCPI3_0)
+; MSA-NEXT:    dsll $1, $1, 16
+; MSA-NEXT:    daddiu $1, $1, %lo(.LCPI3_0)
+; MSA-NEXT:    ld.w $w2, 0($1)
+; MSA-NEXT:    vshf.w $w2, $w1, $w0
+; MSA-NEXT:    jr $ra
+; MSA-NEXT:    st.w $w2, 0($4)
+  %va = load <4 x i32>, ptr %a
+  %vb = load <4 x i32>, ptr %b
+  %shuf = shufflevector <4 x i32> %va, <4 x i32> %vb, <4 x i32> <i32 0, i32 poison, i32 2, i32 4>
+  store <4 x i32> %shuf, ptr %res
+  ret void
+}



More information about the llvm-commits mailing list