[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