[llvm] [Mips] Promote MSA half-vector shuffles to integer vectors (PR #226105)

Jiaxun Yang via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 24 03:12:21 PDT 2026


https://github.com/FlyGoat created https://github.com/llvm/llvm-project/pull/226105

Promote v8f16 VECTOR_SHUFFLE operations to v8i16 to avoid expanding them through EXTRACT_VECTOR_ELT and BUILD_VECTOR with an illegal scalar f16 type.

Fixes: #223618
Assisted-by: Codex # Tests

>From 922c8f03ede6e8f411c7a84b55f9662370b47d42 Mon Sep 17 00:00:00 2001
From: Jiaxun Yang <jiaxun.yang at flygoat.com>
Date: Thu, 24 Sep 2026 10:42:25 +0100
Subject: [PATCH] [Mips] Promote MSA half-vector shuffles to integer vectors

Promote v8f16 VECTOR_SHUFFLE operations to v8i16 to avoid expanding
them through EXTRACT_VECTOR_ELT and BUILD_VECTOR with an illegal
scalar f16 type.

Fixes: #223618
Assisted-by: Codex # Tests
---
 llvm/lib/Target/Mips/MipsSEISelLowering.cpp  |   4 +
 llvm/test/CodeGen/Mips/msa/f16vec-shuffle.ll | 304 +++++++++++++++++++
 2 files changed, 308 insertions(+)
 create mode 100644 llvm/test/CodeGen/Mips/msa/f16vec-shuffle.ll

diff --git a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
index 474e956e9ca02e..2d17cab760ac48 100644
--- a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
@@ -154,6 +154,10 @@ MipsSETargetLowering::MipsSETargetLowering(const MipsTargetMachine &TM,
     addMSAFloatType(MVT::v4f32, &Mips::MSA128WRegClass);
     addMSAFloatType(MVT::v2f64, &Mips::MSA128DRegClass);
 
+    // Shuffle half vectors as integers to avoid expanding them through
+    // EXTRACT_VECTOR_ELT and BUILD_VECTOR with an illegal scalar f16 type.
+    setOperationPromotedToType(ISD::VECTOR_SHUFFLE, MVT::v8f16, MVT::v8i16);
+
     // We're using soft promotion for f16, but msa has some instructions for
     // conversion to/from f16. Mark those conversions as custom so we can take
     // advantage of these instructions.
diff --git a/llvm/test/CodeGen/Mips/msa/f16vec-shuffle.ll b/llvm/test/CodeGen/Mips/msa/f16vec-shuffle.ll
new file mode 100644
index 00000000000000..37f1d7e374a4f3
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/msa/f16vec-shuffle.ll
@@ -0,0 +1,304 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=mips-linux-gnu -mcpu=mips32r5 -mattr=+msa,+fp64 -verify-machineinstrs < %s | FileCheck %s --check-prefixes=ALL,MIPS32,MIPS32BE
+; RUN: llc -mtriple=mipsel-linux-gnu -mcpu=mips32r5 -mattr=+msa,+fp64 -verify-machineinstrs < %s | FileCheck %s --check-prefixes=ALL,MIPS32,MIPS32LE
+; RUN: llc -mtriple=mips64-linux-gnu -mcpu=mips64r5 -mattr=+msa -verify-machineinstrs < %s | FileCheck %s --check-prefixes=ALL,MIPS64,MIPS64BE
+; RUN: llc -mtriple=mips64el-linux-gnu -mcpu=mips64r5 -mattr=+msa -verify-machineinstrs < %s | FileCheck %s --check-prefixes=ALL,MIPS64,MIPS64LE
+
+; Scalar f16 is soft promoted, but v8f16 is a legal MSA type. Shuffle
+; through v8i16 to preserve the half bits without introducing scalar f16.
+; Also cover shuffles that are widened from v4f16.
+
+define <8 x half> @splat_v8f16(<8 x half> %a) {
+; MIPS32-LABEL: splat_v8f16:
+; MIPS32:       # %bb.0:
+; MIPS32-NEXT:    addiu $sp, $sp, -32
+; MIPS32-NEXT:    .cfi_def_cfa_offset 32
+; MIPS32-NEXT:    sw $ra, 28($sp) # 4-byte Folded Spill
+; MIPS32-NEXT:    sw $fp, 24($sp) # 4-byte Folded Spill
+; MIPS32-NEXT:    .cfi_offset 31, -4
+; MIPS32-NEXT:    .cfi_offset 30, -8
+; MIPS32-NEXT:    move $fp, $sp
+; MIPS32-NEXT:    .cfi_def_cfa_register 30
+; MIPS32-NEXT:    addiu $1, $zero, -16
+; MIPS32-NEXT:    and $sp, $sp, $1
+; MIPS32-NEXT:    sw $6, 0($sp)
+; MIPS32-NEXT:    ld.h $w0, 0($sp)
+; MIPS32-NEXT:    splati.h $w0, $w0[0]
+; MIPS32-NEXT:    st.h $w0, 0($4)
+; MIPS32-NEXT:    move $sp, $fp
+; MIPS32-NEXT:    lw $fp, 24($sp) # 4-byte Folded Reload
+; MIPS32-NEXT:    lw $ra, 28($sp) # 4-byte Folded Reload
+; MIPS32-NEXT:    jr $ra
+; MIPS32-NEXT:    addiu $sp, $sp, 32
+;
+; MIPS64BE-LABEL: splat_v8f16:
+; MIPS64BE:       # %bb.0:
+; MIPS64BE-NEXT:    daddiu $sp, $sp, -16
+; MIPS64BE-NEXT:    .cfi_def_cfa_offset 16
+; MIPS64BE-NEXT:    sd $4, 0($sp)
+; MIPS64BE-NEXT:    ld.h $w0, 0($sp)
+; MIPS64BE-NEXT:    splati.h $w0, $w0[0]
+; MIPS64BE-NEXT:    shf.h $w0, $w0, 27
+; MIPS64BE-NEXT:    copy_s.d $2, $w0[0]
+; MIPS64BE-NEXT:    copy_s.d $3, $w0[1]
+; MIPS64BE-NEXT:    jr $ra
+; MIPS64BE-NEXT:    daddiu $sp, $sp, 16
+;
+; MIPS64LE-LABEL: splat_v8f16:
+; MIPS64LE:       # %bb.0:
+; MIPS64LE-NEXT:    daddiu $sp, $sp, -16
+; MIPS64LE-NEXT:    .cfi_def_cfa_offset 16
+; MIPS64LE-NEXT:    sd $4, 0($sp)
+; MIPS64LE-NEXT:    ld.h $w0, 0($sp)
+; MIPS64LE-NEXT:    splati.h $w0, $w0[0]
+; MIPS64LE-NEXT:    copy_s.d $2, $w0[0]
+; MIPS64LE-NEXT:    copy_s.d $3, $w0[1]
+; MIPS64LE-NEXT:    jr $ra
+; MIPS64LE-NEXT:    daddiu $sp, $sp, 16
+  %s = shufflevector <8 x half> %a, <8 x half> poison, <8 x i32> zeroinitializer
+  ret <8 x half> %s
+}
+
+define void @reverse_v8f16(ptr %dst, ptr %src) {
+; MIPS32-LABEL: reverse_v8f16:
+; MIPS32:       # %bb.0:
+; MIPS32-NEXT:    lui $1, %hi($CPI1_0)
+; MIPS32-NEXT:    addiu $1, $1, %lo($CPI1_0)
+; MIPS32-NEXT:    ld.h $w0, 0($5)
+; MIPS32-NEXT:    ld.h $w1, 0($1)
+; MIPS32-NEXT:    vshf.h $w1, $w0, $w0
+; MIPS32-NEXT:    jr $ra
+; MIPS32-NEXT:    st.h $w1, 0($4)
+;
+; MIPS64-LABEL: reverse_v8f16:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    lui $1, %highest(.LCPI1_0)
+; MIPS64-NEXT:    daddiu $1, $1, %higher(.LCPI1_0)
+; MIPS64-NEXT:    dsll $1, $1, 16
+; MIPS64-NEXT:    daddiu $1, $1, %hi(.LCPI1_0)
+; MIPS64-NEXT:    dsll $1, $1, 16
+; MIPS64-NEXT:    daddiu $1, $1, %lo(.LCPI1_0)
+; MIPS64-NEXT:    ld.h $w0, 0($5)
+; MIPS64-NEXT:    ld.h $w1, 0($1)
+; MIPS64-NEXT:    vshf.h $w1, $w0, $w0
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    st.h $w1, 0($4)
+  %a = load <8 x half>, ptr %src
+  %s = shufflevector <8 x half> %a, <8 x half> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  store <8 x half> %s, ptr %dst
+  ret void
+}
+
+define void @swap_v8f16(ptr %dst, ptr %src) {
+; ALL-LABEL: swap_v8f16:
+; ALL:       # %bb.0:
+; ALL-NEXT:    ld.h $w0, 0($5)
+; ALL-NEXT:    shf.h $w0, $w0, 225
+; ALL-NEXT:    jr $ra
+; ALL-NEXT:    st.h $w0, 0($4)
+  %a = load <8 x half>, ptr %src
+  %s = shufflevector <8 x half> %a, <8 x half> poison, <8 x i32> <i32 1, i32 0, i32 2, i32 3, i32 5, i32 4, i32 6, i32 7>
+  store <8 x half> %s, ptr %dst
+  ret void
+}
+
+define void @shuffle_v8f16(ptr %dst, ptr %src1, ptr %src2) {
+; MIPS32-LABEL: shuffle_v8f16:
+; MIPS32:       # %bb.0:
+; MIPS32-NEXT:    lui $1, %hi($CPI3_0)
+; MIPS32-NEXT:    addiu $1, $1, %lo($CPI3_0)
+; MIPS32-NEXT:    ld.h $w0, 0($5)
+; MIPS32-NEXT:    ld.h $w1, 0($6)
+; MIPS32-NEXT:    ld.h $w2, 0($1)
+; MIPS32-NEXT:    vshf.h $w2, $w1, $w0
+; MIPS32-NEXT:    jr $ra
+; MIPS32-NEXT:    st.h $w2, 0($4)
+;
+; MIPS64-LABEL: shuffle_v8f16:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    lui $1, %highest(.LCPI3_0)
+; MIPS64-NEXT:    daddiu $1, $1, %higher(.LCPI3_0)
+; MIPS64-NEXT:    dsll $1, $1, 16
+; MIPS64-NEXT:    daddiu $1, $1, %hi(.LCPI3_0)
+; MIPS64-NEXT:    dsll $1, $1, 16
+; MIPS64-NEXT:    daddiu $1, $1, %lo(.LCPI3_0)
+; MIPS64-NEXT:    ld.h $w0, 0($5)
+; MIPS64-NEXT:    ld.h $w1, 0($6)
+; MIPS64-NEXT:    ld.h $w2, 0($1)
+; MIPS64-NEXT:    vshf.h $w2, $w1, $w0
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    st.h $w2, 0($4)
+  %a = load <8 x half>, ptr %src1
+  %b = load <8 x half>, ptr %src2
+  %s = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 poison, i32 9, i32 2, i32 15, i32 0, i32 13, i32 6, i32 11>
+  store <8 x half> %s, ptr %dst
+  ret void
+}
+
+define <4 x half> @splat_v4f16(<4 x half> %a) {
+; MIPS32BE-LABEL: splat_v4f16:
+; MIPS32BE:       # %bb.0:
+; MIPS32BE-NEXT:    addiu $sp, $sp, -32
+; MIPS32BE-NEXT:    .cfi_def_cfa_offset 32
+; MIPS32BE-NEXT:    sw $ra, 28($sp) # 4-byte Folded Spill
+; MIPS32BE-NEXT:    sw $fp, 24($sp) # 4-byte Folded Spill
+; MIPS32BE-NEXT:    .cfi_offset 31, -4
+; MIPS32BE-NEXT:    .cfi_offset 30, -8
+; MIPS32BE-NEXT:    move $fp, $sp
+; MIPS32BE-NEXT:    .cfi_def_cfa_register 30
+; MIPS32BE-NEXT:    addiu $1, $zero, -16
+; MIPS32BE-NEXT:    and $sp, $sp, $1
+; MIPS32BE-NEXT:    sw $6, 0($sp)
+; MIPS32BE-NEXT:    ld.h $w0, 0($sp)
+; MIPS32BE-NEXT:    splati.h $w0, $w0[0]
+; MIPS32BE-NEXT:    shf.h $w0, $w0, 177
+; MIPS32BE-NEXT:    copy_s.w $1, $w0[0]
+; MIPS32BE-NEXT:    copy_s.w $2, $w0[1]
+; MIPS32BE-NEXT:    sw $2, 4($4)
+; MIPS32BE-NEXT:    sw $1, 0($4)
+; MIPS32BE-NEXT:    move $sp, $fp
+; MIPS32BE-NEXT:    lw $fp, 24($sp) # 4-byte Folded Reload
+; MIPS32BE-NEXT:    lw $ra, 28($sp) # 4-byte Folded Reload
+; MIPS32BE-NEXT:    jr $ra
+; MIPS32BE-NEXT:    addiu $sp, $sp, 32
+;
+; MIPS32LE-LABEL: splat_v4f16:
+; MIPS32LE:       # %bb.0:
+; MIPS32LE-NEXT:    addiu $sp, $sp, -32
+; MIPS32LE-NEXT:    .cfi_def_cfa_offset 32
+; MIPS32LE-NEXT:    sw $ra, 28($sp) # 4-byte Folded Spill
+; MIPS32LE-NEXT:    sw $fp, 24($sp) # 4-byte Folded Spill
+; MIPS32LE-NEXT:    .cfi_offset 31, -4
+; MIPS32LE-NEXT:    .cfi_offset 30, -8
+; MIPS32LE-NEXT:    move $fp, $sp
+; MIPS32LE-NEXT:    .cfi_def_cfa_register 30
+; MIPS32LE-NEXT:    addiu $1, $zero, -16
+; MIPS32LE-NEXT:    and $sp, $sp, $1
+; MIPS32LE-NEXT:    sw $6, 0($sp)
+; MIPS32LE-NEXT:    ld.h $w0, 0($sp)
+; MIPS32LE-NEXT:    splati.h $w0, $w0[0]
+; MIPS32LE-NEXT:    copy_s.w $1, $w0[0]
+; MIPS32LE-NEXT:    copy_s.w $2, $w0[1]
+; MIPS32LE-NEXT:    sw $2, 4($4)
+; MIPS32LE-NEXT:    sw $1, 0($4)
+; MIPS32LE-NEXT:    move $sp, $fp
+; MIPS32LE-NEXT:    lw $fp, 24($sp) # 4-byte Folded Reload
+; MIPS32LE-NEXT:    lw $ra, 28($sp) # 4-byte Folded Reload
+; MIPS32LE-NEXT:    jr $ra
+; MIPS32LE-NEXT:    addiu $sp, $sp, 32
+;
+; MIPS64BE-LABEL: splat_v4f16:
+; MIPS64BE:       # %bb.0:
+; MIPS64BE-NEXT:    daddiu $sp, $sp, -16
+; MIPS64BE-NEXT:    .cfi_def_cfa_offset 16
+; MIPS64BE-NEXT:    sd $4, 0($sp)
+; MIPS64BE-NEXT:    ld.h $w0, 0($sp)
+; MIPS64BE-NEXT:    splati.h $w0, $w0[0]
+; MIPS64BE-NEXT:    shf.h $w0, $w0, 27
+; MIPS64BE-NEXT:    copy_s.d $2, $w0[0]
+; MIPS64BE-NEXT:    jr $ra
+; MIPS64BE-NEXT:    daddiu $sp, $sp, 16
+;
+; MIPS64LE-LABEL: splat_v4f16:
+; MIPS64LE:       # %bb.0:
+; MIPS64LE-NEXT:    daddiu $sp, $sp, -16
+; MIPS64LE-NEXT:    .cfi_def_cfa_offset 16
+; MIPS64LE-NEXT:    sd $4, 0($sp)
+; MIPS64LE-NEXT:    ld.h $w0, 0($sp)
+; MIPS64LE-NEXT:    splati.h $w0, $w0[0]
+; MIPS64LE-NEXT:    copy_s.d $2, $w0[0]
+; MIPS64LE-NEXT:    jr $ra
+; MIPS64LE-NEXT:    daddiu $sp, $sp, 16
+  %s = shufflevector <4 x half> %a, <4 x half> poison, <4 x i32> zeroinitializer
+  ret <4 x half> %s
+}
+
+define void @reverse_v4f16(ptr %dst, ptr %src) {
+; MIPS32BE-LABEL: reverse_v4f16:
+; MIPS32BE:       # %bb.0:
+; MIPS32BE-NEXT:    addiu $sp, $sp, -32
+; MIPS32BE-NEXT:    .cfi_def_cfa_offset 32
+; MIPS32BE-NEXT:    sw $ra, 28($sp) # 4-byte Folded Spill
+; MIPS32BE-NEXT:    sw $fp, 24($sp) # 4-byte Folded Spill
+; MIPS32BE-NEXT:    .cfi_offset 31, -4
+; MIPS32BE-NEXT:    .cfi_offset 30, -8
+; MIPS32BE-NEXT:    move $fp, $sp
+; MIPS32BE-NEXT:    .cfi_def_cfa_register 30
+; MIPS32BE-NEXT:    addiu $1, $zero, -16
+; MIPS32BE-NEXT:    and $sp, $sp, $1
+; MIPS32BE-NEXT:    lw $1, 4($5)
+; MIPS32BE-NEXT:    sw $1, 4($sp)
+; MIPS32BE-NEXT:    lw $1, 0($5)
+; MIPS32BE-NEXT:    sw $1, 0($sp)
+; MIPS32BE-NEXT:    ld.h $w0, 0($sp)
+; MIPS32BE-NEXT:    shf.h $w0, $w0, 27
+; MIPS32BE-NEXT:    shf.h $w0, $w0, 177
+; MIPS32BE-NEXT:    copy_s.w $1, $w0[1]
+; MIPS32BE-NEXT:    copy_s.w $2, $w0[0]
+; MIPS32BE-NEXT:    sw $2, 0($4)
+; MIPS32BE-NEXT:    sw $1, 4($4)
+; MIPS32BE-NEXT:    move $sp, $fp
+; MIPS32BE-NEXT:    lw $fp, 24($sp) # 4-byte Folded Reload
+; MIPS32BE-NEXT:    lw $ra, 28($sp) # 4-byte Folded Reload
+; MIPS32BE-NEXT:    jr $ra
+; MIPS32BE-NEXT:    addiu $sp, $sp, 32
+;
+; MIPS32LE-LABEL: reverse_v4f16:
+; MIPS32LE:       # %bb.0:
+; MIPS32LE-NEXT:    addiu $sp, $sp, -32
+; MIPS32LE-NEXT:    .cfi_def_cfa_offset 32
+; MIPS32LE-NEXT:    sw $ra, 28($sp) # 4-byte Folded Spill
+; MIPS32LE-NEXT:    sw $fp, 24($sp) # 4-byte Folded Spill
+; MIPS32LE-NEXT:    .cfi_offset 31, -4
+; MIPS32LE-NEXT:    .cfi_offset 30, -8
+; MIPS32LE-NEXT:    move $fp, $sp
+; MIPS32LE-NEXT:    .cfi_def_cfa_register 30
+; MIPS32LE-NEXT:    addiu $1, $zero, -16
+; MIPS32LE-NEXT:    and $sp, $sp, $1
+; MIPS32LE-NEXT:    lw $1, 4($5)
+; MIPS32LE-NEXT:    sw $1, 4($sp)
+; MIPS32LE-NEXT:    lw $1, 0($5)
+; MIPS32LE-NEXT:    sw $1, 0($sp)
+; MIPS32LE-NEXT:    ld.h $w0, 0($sp)
+; MIPS32LE-NEXT:    shf.h $w0, $w0, 27
+; MIPS32LE-NEXT:    copy_s.w $1, $w0[1]
+; MIPS32LE-NEXT:    copy_s.w $2, $w0[0]
+; MIPS32LE-NEXT:    sw $2, 0($4)
+; MIPS32LE-NEXT:    sw $1, 4($4)
+; MIPS32LE-NEXT:    move $sp, $fp
+; MIPS32LE-NEXT:    lw $fp, 24($sp) # 4-byte Folded Reload
+; MIPS32LE-NEXT:    lw $ra, 28($sp) # 4-byte Folded Reload
+; MIPS32LE-NEXT:    jr $ra
+; MIPS32LE-NEXT:    addiu $sp, $sp, 32
+;
+; MIPS64BE-LABEL: reverse_v4f16:
+; MIPS64BE:       # %bb.0:
+; MIPS64BE-NEXT:    daddiu $sp, $sp, -16
+; MIPS64BE-NEXT:    .cfi_def_cfa_offset 16
+; MIPS64BE-NEXT:    ld $1, 0($5)
+; MIPS64BE-NEXT:    sd $1, 0($sp)
+; MIPS64BE-NEXT:    ld.h $w0, 0($sp)
+; MIPS64BE-NEXT:    shf.h $w0, $w0, 27
+; MIPS64BE-NEXT:    shf.h $w0, $w0, 27
+; MIPS64BE-NEXT:    copy_s.d $1, $w0[0]
+; MIPS64BE-NEXT:    sd $1, 0($4)
+; MIPS64BE-NEXT:    jr $ra
+; MIPS64BE-NEXT:    daddiu $sp, $sp, 16
+;
+; MIPS64LE-LABEL: reverse_v4f16:
+; MIPS64LE:       # %bb.0:
+; MIPS64LE-NEXT:    daddiu $sp, $sp, -16
+; MIPS64LE-NEXT:    .cfi_def_cfa_offset 16
+; MIPS64LE-NEXT:    ld $1, 0($5)
+; MIPS64LE-NEXT:    sd $1, 0($sp)
+; MIPS64LE-NEXT:    ld.h $w0, 0($sp)
+; MIPS64LE-NEXT:    shf.h $w0, $w0, 27
+; MIPS64LE-NEXT:    copy_s.d $1, $w0[0]
+; MIPS64LE-NEXT:    sd $1, 0($4)
+; MIPS64LE-NEXT:    jr $ra
+; MIPS64LE-NEXT:    daddiu $sp, $sp, 16
+  %a = load <4 x half>, ptr %src
+  %s = shufflevector <4 x half> %a, <4 x half> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  store <4 x half> %s, ptr %dst
+  ret void
+}



More information about the llvm-commits mailing list