[llvm] [SelectionDAG] Fix soft-promotion of f16 BUILD_VECTOR for MSA targets (PR #210515)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 14 20:56:54 PDT 2026
https://github.com/fo40225 updated https://github.com/llvm/llvm-project/pull/210515
>From f02b484bfc68604e3c41d0531277650a20c93240 Mon Sep 17 00:00:00 2001
From: fo4025 <fo40225 at hotmail.com>
Date: Thu, 13 Aug 2026 17:37:01 +0800
Subject: [PATCH 1/2] [Mips] Add f16 BUILD_VECTOR regression tests for MSA
targets
Test that f16 vectors (v8f16, v4f16, v2f16) can be built from scalar
f16 values on MIPS with +msa. Without the corresponding fix, llc
crashes with "Do not know how to soft promote this operator's
operand!" in SoftPromoteHalfOperand.
Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
---
llvm/test/CodeGen/Mips/msa/f16vec.ll | 135 +++++++++++++++++++++++++++
1 file changed, 135 insertions(+)
create mode 100644 llvm/test/CodeGen/Mips/msa/f16vec.ll
diff --git a/llvm/test/CodeGen/Mips/msa/f16vec.ll b/llvm/test/CodeGen/Mips/msa/f16vec.ll
new file mode 100644
index 0000000000000..53bfd967f0a8f
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/msa/f16vec.ll
@@ -0,0 +1,135 @@
+; RUN: llc -mtriple=mipsel-unknown-linux-gnu -mcpu=mips32r5 -mattr=+fp64,+msa < %s | FileCheck %s --check-prefix=MIPS32
+; RUN: llc -mtriple=mips64el-unknown-linux-gnuabi64 -mcpu=mips64r5 -mattr=+fp64,+msa < %s | FileCheck %s --check-prefix=MIPS64
+
+; Test that f16 vectors can be built from scalar f16 values without crashing.
+; This is a regression test for a crash in soft-promotion of BUILD_VECTOR
+; operands.
+
+define <8 x half> @build_v8f16(half %a, half %b, half %c, half %d, half %e, half %f, half %g, half %h) nounwind {
+; MIPS32-LABEL: build_v8f16:
+; MIPS32: # %bb.0:
+; MIPS32-NEXT: insert.h $w0[0], $5
+; MIPS32-NEXT: insert.h $w0[1], $6
+; MIPS32-NEXT: insert.h $w0[2], $7
+; MIPS32-NEXT: lhu $1, 16($sp)
+; MIPS32-NEXT: insert.h $w0[3], $1
+; MIPS32-NEXT: lhu $1, 20($sp)
+; MIPS32-NEXT: insert.h $w0[4], $1
+; MIPS32-NEXT: lhu $1, 24($sp)
+; MIPS32-NEXT: insert.h $w0[5], $1
+; MIPS32-NEXT: lhu $1, 28($sp)
+; MIPS32-NEXT: insert.h $w0[6], $1
+; MIPS32-NEXT: lhu $1, 32($sp)
+; MIPS32-NEXT: insert.h $w0[7], $1
+; MIPS32-NEXT: jr $ra
+; MIPS32-NEXT: st.h $w0, 0($4)
+;
+; MIPS64-LABEL: build_v8f16:
+; MIPS64: # %bb.0:
+; MIPS64-NEXT: sll $1, $5, 0
+; MIPS64-NEXT: sll $2, $4, 0
+; MIPS64-NEXT: insert.h $w0[0], $2
+; MIPS64-NEXT: insert.h $w0[1], $1
+; MIPS64-NEXT: sll $1, $6, 0
+; MIPS64-NEXT: insert.h $w0[2], $1
+; MIPS64-NEXT: sll $1, $7, 0
+; MIPS64-NEXT: insert.h $w0[3], $1
+; MIPS64-NEXT: sll $1, $8, 0
+; MIPS64-NEXT: insert.h $w0[4], $1
+; MIPS64-NEXT: sll $1, $9, 0
+; MIPS64-NEXT: insert.h $w0[5], $1
+; MIPS64-NEXT: sll $1, $11, 0
+; MIPS64-NEXT: sll $2, $10, 0
+; MIPS64-NEXT: insert.h $w0[6], $2
+; MIPS64-NEXT: insert.h $w0[7], $1
+; MIPS64-NEXT: copy_s.d $2, $w0[0]
+; MIPS64-NEXT: jr $ra
+; MIPS64-NEXT: copy_s.d $3, $w0[1]
+ %v0 = insertelement <8 x half> poison, half %a, i32 0
+ %v1 = insertelement <8 x half> %v0, half %b, i32 1
+ %v2 = insertelement <8 x half> %v1, half %c, i32 2
+ %v3 = insertelement <8 x half> %v2, half %d, i32 3
+ %v4 = insertelement <8 x half> %v3, half %e, i32 4
+ %v5 = insertelement <8 x half> %v4, half %f, i32 5
+ %v6 = insertelement <8 x half> %v5, half %g, i32 6
+ %v7 = insertelement <8 x half> %v6, half %h, i32 7
+ ret <8 x half> %v7
+}
+
+define <4 x half> @build_v4f16(half %a, half %b, half %c, half %d) nounwind {
+; MIPS32-LABEL: build_v4f16:
+; MIPS32: # %bb.0:
+; MIPS32-NEXT: addiu $sp, $sp, -32
+; MIPS32-NEXT: sw $ra, 28($sp) # 4-byte Folded Spill
+; MIPS32-NEXT: sw $fp, 24($sp) # 4-byte Folded Spill
+; MIPS32-NEXT: move $fp, $sp
+; MIPS32-NEXT: addiu $1, $zero, -16
+; MIPS32-NEXT: and $sp, $sp, $1
+; MIPS32-NEXT: lhu $1, 48($fp)
+; MIPS32-NEXT: sh $1, 6($sp)
+; MIPS32-NEXT: sh $7, 4($sp)
+; MIPS32-NEXT: sh $6, 2($sp)
+; MIPS32-NEXT: sh $5, 0($sp)
+; MIPS32-NEXT: ld.w $w0, 0($sp)
+; MIPS32-NEXT: copy_s.w $1, $w0[0]
+; MIPS32-NEXT: copy_s.w $2, $w0[1]
+; MIPS32-NEXT: sw $2, 4($4)
+; MIPS32-NEXT: sw $1, 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
+;
+; MIPS64-LABEL: build_v4f16:
+; MIPS64: # %bb.0:
+; MIPS64-NEXT: daddiu $sp, $sp, -16
+; MIPS64-NEXT: sh $7, 6($sp)
+; MIPS64-NEXT: sh $6, 4($sp)
+; MIPS64-NEXT: sh $5, 2($sp)
+; MIPS64-NEXT: sh $4, 0($sp)
+; MIPS64-NEXT: ld.d $w0, 0($sp)
+; MIPS64-NEXT: copy_s.d $2, $w0[0]
+; MIPS64-NEXT: jr $ra
+; MIPS64-NEXT: daddiu $sp, $sp, 16
+ %v0 = insertelement <4 x half> poison, half %a, i32 0
+ %v1 = insertelement <4 x half> %v0, half %b, i32 1
+ %v2 = insertelement <4 x half> %v1, half %c, i32 2
+ %v3 = insertelement <4 x half> %v2, half %d, i32 3
+ ret <4 x half> %v3
+}
+
+define <2 x half> @build_v2f16(half %a, half %b) nounwind {
+; MIPS32-LABEL: build_v2f16:
+; MIPS32: # %bb.0:
+; MIPS32-NEXT: addiu $sp, $sp, -32
+; MIPS32-NEXT: sw $ra, 28($sp) # 4-byte Folded Spill
+; MIPS32-NEXT: sw $fp, 24($sp) # 4-byte Folded Spill
+; MIPS32-NEXT: move $fp, $sp
+; MIPS32-NEXT: addiu $1, $zero, -16
+; MIPS32-NEXT: and $sp, $sp, $1
+; MIPS32-NEXT: sh $6, 2($sp)
+; MIPS32-NEXT: sh $5, 0($sp)
+; MIPS32-NEXT: ld.w $w0, 0($sp)
+; MIPS32-NEXT: copy_s.w $1, $w0[0]
+; MIPS32-NEXT: sw $1, 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
+;
+; MIPS64-LABEL: build_v2f16:
+; MIPS64: # %bb.0:
+; MIPS64-NEXT: daddiu $sp, $sp, -16
+; MIPS64-NEXT: sh $6, 2($sp)
+; MIPS64-NEXT: sh $5, 0($sp)
+; MIPS64-NEXT: ld.w $w0, 0($sp)
+; MIPS64-NEXT: copy_s.w $1, $w0[0]
+; MIPS64-NEXT: sw $1, 0($4)
+; MIPS64-NEXT: jr $ra
+; MIPS64-NEXT: daddiu $sp, $sp, 16
+ %v0 = insertelement <2 x half> poison, half %a, i32 0
+ %v1 = insertelement <2 x half> %v0, half %b, i32 1
+ ret <2 x half> %v1
+}
>From b9a825dc7454ec039bdb38cb5ecd49748e7e7385 Mon Sep 17 00:00:00 2001
From: fo4025 <fo40225 at hotmail.com>
Date: Thu, 13 Aug 2026 17:37:29 +0800
Subject: [PATCH 2/2] [Mips] Fix soft-promotion of f16 BUILD_VECTOR for MSA
targets
When compiling for MIPS with +msa and f16 vectors (v8f16, v4f16, v2f16),
LLVM would crash with "Do not know how to soft promote this operator's
operand!" because BUILD_VECTOR was missing from the SoftPromoteHalfOperand
switch statement in LegalizeFloatTypes.cpp.
On MIPS, f16 is not natively supported by default, so LLVM soft-promotes
it: stores as i16, computes as f32. Building f16 vectors requires handling
BUILD_VECTOR with soft-promoted i16 operands. This patch adds the missing
BUILD_VECTOR case and implements SoftPromoteHalfOp_BUILD_VECTOR, which:
(1) retrieves soft-promoted i16 operands via GetSoftPromotedHalf,
(2) builds a v{N}i16 integer vector,
(3) bitcasts to the original v{N}f16 type.
This matches the soft-promotion pattern used in the BITCAST handler,
where f16 storage is represented as i16 and only operations promote to f32.
Fixes compilation of Rust libcore/compiler_builtins with global +msa.
Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
---
.../CodeGen/SelectionDAG/LegalizeFloatTypes.cpp | 17 +++++++++++++++++
llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h | 1 +
2 files changed, 18 insertions(+)
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index 64af9a4757505..30c67bda6d8d2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -2979,6 +2979,9 @@ bool DAGTypeLegalizer::SoftPromoteHalfOperand(SDNode *N, unsigned OpNo) {
"operand!");
case ISD::BITCAST: Res = SoftPromoteHalfOp_BITCAST(N); break;
+ case ISD::BUILD_VECTOR:
+ Res = SoftPromoteHalfOp_BUILD_VECTOR(N);
+ break;
case ISD::FAKE_USE:
Res = SoftPromoteHalfOp_FAKE_USE(N, OpNo);
break;
@@ -3042,6 +3045,20 @@ SDValue DAGTypeLegalizer::SoftPromoteHalfOp_BITCAST(SDNode *N) {
return DAG.getNode(ISD::BITCAST, SDLoc(N), N->getValueType(0), Op0);
}
+SDValue DAGTypeLegalizer::SoftPromoteHalfOp_BUILD_VECTOR(SDNode *N) {
+ SDLoc dl(N);
+ EVT VT = N->getValueType(0);
+
+ SmallVector<SDValue, 8> Ops(N->getNumOperands());
+ for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i)
+ Ops[i] = GetSoftPromotedHalf(N->getOperand(i));
+
+ EVT IVT =
+ EVT::getVectorVT(*DAG.getContext(), MVT::i16, VT.getVectorElementCount());
+ SDValue Res = DAG.getBuildVector(IVT, dl, Ops);
+ return DAG.getNode(ISD::BITCAST, dl, VT, Res);
+}
+
SDValue DAGTypeLegalizer::SoftPromoteHalfOp_FAKE_USE(SDNode *N, unsigned OpNo) {
assert(OpNo == 1 && "Only Operand 1 must need promotion here");
SDValue Op = GetSoftPromotedHalf(N->getOperand(OpNo));
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
index 08e51ecc86c8b..ab252f5db2dcf 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -808,6 +808,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
bool SoftPromoteHalfOperand(SDNode *N, unsigned OpNo);
SDValue SoftPromoteHalfOp_BITCAST(SDNode *N);
+ SDValue SoftPromoteHalfOp_BUILD_VECTOR(SDNode *N);
SDValue SoftPromoteHalfOp_FAKE_USE(SDNode *N, unsigned OpNo);
SDValue SoftPromoteHalfOp_FCOPYSIGN(SDNode *N, unsigned OpNo);
SDValue SoftPromoteHalfOp_FP_EXTEND(SDNode *N);
More information about the llvm-commits
mailing list