[llvm] [DAG] Support soft half promotion of insert_vector_elt (PR #194994)

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 29 19:58:36 PDT 2026


https://github.com/preames updated https://github.com/llvm/llvm-project/pull/194994

>From 5f6e3edbbb72b724145555dae87563a74856675c Mon Sep 17 00:00:00 2001
From: Philip Reames <listmail at philipreames.com>
Date: Fri, 24 Apr 2026 07:00:48 -0700
Subject: [PATCH 1/3] [DAG] Support soft half promotion of insert_vector_elt

This is relevant when we have _either_ fp16 or bf16 minimal
support, but not the other and we need to lower an insert
for the other.  We already have existing support for extract
but the insert case appears to get missed.

Note that if _neither_ are legal we fit an entirely
different codepath.  This seems non-ideal, but starting
to untangle that got complicated fast.  I'll also note
that some of the legalization results for V look a bit
suspicious (memory offsets changing between rv32/64?)
---
 .../SelectionDAG/LegalizeFloatTypes.cpp       | 11 +++
 llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h |  1 +
 .../fixed-vectors-insert-soft-promote-half.ll | 77 +++++++++++++++++++
 3 files changed, 89 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/rvv/fixed-vectors-insert-soft-promote-half.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index 25f4f75eaedea..9467f6406293a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -3198,6 +3198,8 @@ bool DAGTypeLegalizer::SoftPromoteHalfOperand(SDNode *N, unsigned OpNo) {
   case ISD::FP_EXTEND:  Res = SoftPromoteHalfOp_FP_EXTEND(N); break;
   case ISD::SELECT_CC:  Res = SoftPromoteHalfOp_SELECT_CC(N, OpNo); break;
   case ISD::SETCC:      Res = SoftPromoteHalfOp_SETCC(N); break;
+  case ISD::INSERT_VECTOR_ELT:
+    Res = SoftPromoteHalfOp_INSERT_VECTOR_ELT(N); break;
   case ISD::STORE:      Res = SoftPromoteHalfOp_STORE(N, OpNo); break;
   case ISD::ATOMIC_STORE:
     Res = SoftPromoteHalfOp_ATOMIC_STORE(N, OpNo);
@@ -3351,6 +3353,15 @@ SDValue DAGTypeLegalizer::SoftPromoteHalfOp_SETCC(SDNode *N) {
   return DAG.getSetCC(SDLoc(N), N->getValueType(0), Op0, Op1, CCCode);
 }
 
+SDValue DAGTypeLegalizer::SoftPromoteHalfOp_INSERT_VECTOR_ELT(SDNode *N) {
+  SDValue NewVec = BitConvertVectorToIntegerVector(N->getOperand(0));
+  SDValue NewElt = GetSoftPromotedHalf(N->getOperand(1));
+  SDValue NewIns = DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N),
+                               NewVec.getValueType(), NewVec, NewElt,
+                               N->getOperand(2));
+  return DAG.getNode(ISD::BITCAST, SDLoc(N), N->getValueType(0), NewIns);
+}
+
 SDValue DAGTypeLegalizer::SoftPromoteHalfOp_STORE(SDNode *N, unsigned OpNo) {
   assert(OpNo == 1 && "Can only soften the stored value!");
   StoreSDNode *ST = cast<StoreSDNode>(N);
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
index 89698a2c77123..1b29e38513fb9 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -806,6 +806,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
   SDValue SoftPromoteHalfOp_FP_TO_XINT_SAT(SDNode *N);
   SDValue SoftPromoteHalfOp_SETCC(SDNode *N);
   SDValue SoftPromoteHalfOp_SELECT_CC(SDNode *N, unsigned OpNo);
+  SDValue SoftPromoteHalfOp_INSERT_VECTOR_ELT(SDNode *N);
   SDValue SoftPromoteHalfOp_STORE(SDNode *N, unsigned OpNo);
   SDValue SoftPromoteHalfOp_ATOMIC_STORE(SDNode *N, unsigned OpNo);
   SDValue SoftPromoteHalfOp_STACKMAP(SDNode *N, unsigned OpNo);
diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-insert-soft-promote-half.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-insert-soft-promote-half.ll
new file mode 100644
index 0000000000000..6d0b4536b489b
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-insert-soft-promote-half.ll
@@ -0,0 +1,77 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv64 -mattr=+v -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefix=V
+; RUN: llc -mtriple=riscv64 -mattr=+v,+zvfbfmin -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefix=ZVFBFMIN
+; RUN: llc -mtriple=riscv64 -mattr=+v,+zvfhmin -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefix=ZVFHMIN
+
+define <4 x bfloat> @insertelt_v4bf16(<4 x bfloat> %v, bfloat %elt) {
+; V-LABEL: insertelt_v4bf16:
+; V:       # %bb.0:
+; V-NEXT:    fmv.x.w a1, fa4
+; V-NEXT:    fmv.x.w a2, fa1
+; V-NEXT:    fmv.x.w a3, fa2
+; V-NEXT:    fmv.x.w a4, fa3
+; V-NEXT:    sh a1, 0(a0)
+; V-NEXT:    sh a2, 2(a0)
+; V-NEXT:    sh a3, 4(a0)
+; V-NEXT:    sh a4, 6(a0)
+; V-NEXT:    ret
+;
+; ZVFBFMIN-LABEL: insertelt_v4bf16:
+; ZVFBFMIN:       # %bb.0:
+; ZVFBFMIN-NEXT:    fmv.x.w a0, fa0
+; ZVFBFMIN-NEXT:    vsetivli zero, 4, e16, m1, tu, ma
+; ZVFBFMIN-NEXT:    vmv.s.x v8, a0
+; ZVFBFMIN-NEXT:    ret
+;
+; ZVFHMIN-LABEL: insertelt_v4bf16:
+; ZVFHMIN:       # %bb.0:
+; ZVFHMIN-NEXT:    fmv.x.w a1, fa4
+; ZVFHMIN-NEXT:    fmv.x.w a2, fa1
+; ZVFHMIN-NEXT:    fmv.x.w a3, fa2
+; ZVFHMIN-NEXT:    fmv.x.w a4, fa3
+; ZVFHMIN-NEXT:    sh a1, 0(a0)
+; ZVFHMIN-NEXT:    sh a2, 2(a0)
+; ZVFHMIN-NEXT:    sh a3, 4(a0)
+; ZVFHMIN-NEXT:    sh a4, 6(a0)
+; ZVFHMIN-NEXT:    ret
+  %r = insertelement <4 x bfloat> %v, bfloat %elt, i32 0
+  ret <4 x bfloat> %r
+}
+
+define <4 x half> @insertelt_v4f16(<4 x half> %v, half %elt) {
+; V-LABEL: insertelt_v4f16:
+; V:       # %bb.0:
+; V-NEXT:    fmv.x.w a2, fa0
+; V-NEXT:    lh a3, 8(a1)
+; V-NEXT:    lh a4, 16(a1)
+; V-NEXT:    lh a1, 24(a1)
+; V-NEXT:    sh a2, 0(a0)
+; V-NEXT:    sh a3, 2(a0)
+; V-NEXT:    sh a4, 4(a0)
+; V-NEXT:    sh a1, 6(a0)
+; V-NEXT:    ret
+;
+; ZVFBFMIN-LABEL: insertelt_v4f16:
+; ZVFBFMIN:       # %bb.0:
+; ZVFBFMIN-NEXT:    fmv.x.w a2, fa0
+; ZVFBFMIN-NEXT:    lh a3, 8(a1)
+; ZVFBFMIN-NEXT:    lh a4, 16(a1)
+; ZVFBFMIN-NEXT:    lh a1, 24(a1)
+; ZVFBFMIN-NEXT:    sh a2, 0(a0)
+; ZVFBFMIN-NEXT:    sh a3, 2(a0)
+; ZVFBFMIN-NEXT:    sh a4, 4(a0)
+; ZVFBFMIN-NEXT:    sh a1, 6(a0)
+; ZVFBFMIN-NEXT:    ret
+;
+; ZVFHMIN-LABEL: insertelt_v4f16:
+; ZVFHMIN:       # %bb.0:
+; ZVFHMIN-NEXT:    fmv.x.w a0, fa0
+; ZVFHMIN-NEXT:    vsetivli zero, 4, e16, m1, tu, ma
+; ZVFHMIN-NEXT:    vmv.s.x v8, a0
+; ZVFHMIN-NEXT:    ret
+  %r = insertelement <4 x half> %v, half %elt, i32 0
+  ret <4 x half> %r
+}

>From 1456e98f1e404cef053de0e38ad713760eb99d0a Mon Sep 17 00:00:00 2001
From: Philip Reames <listmail at philipreames.com>
Date: Wed, 29 Apr 2026 19:57:38 -0700
Subject: [PATCH 2/3] Accidental test update

---
 .../fixed-vectors-insert-soft-promote-half.ll | 78 +++++++++++++------
 1 file changed, 54 insertions(+), 24 deletions(-)

diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-insert-soft-promote-half.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-insert-soft-promote-half.ll
index 6d0b4536b489b..83e1c44609132 100644
--- a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-insert-soft-promote-half.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-insert-soft-promote-half.ll
@@ -1,8 +1,14 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+v -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefixes=V,V32
+; RUN: llc -mtriple=riscv32 -mattr=+v,+zvfbfmin -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefixes=ZVFBFMIN,ZVFBFMIN32
+; RUN: llc -mtriple=riscv32 -mattr=+v,+zvfhmin -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s --check-prefix=ZVFHMIN
 ; RUN: llc -mtriple=riscv64 -mattr=+v -verify-machineinstrs < %s \
-; RUN:   | FileCheck %s --check-prefix=V
+; RUN:   | FileCheck %s --check-prefixes=V,V64
 ; RUN: llc -mtriple=riscv64 -mattr=+v,+zvfbfmin -verify-machineinstrs < %s \
-; RUN:   | FileCheck %s --check-prefix=ZVFBFMIN
+; RUN:   | FileCheck %s --check-prefixes=ZVFBFMIN,ZVFBFMIN64
 ; RUN: llc -mtriple=riscv64 -mattr=+v,+zvfhmin -verify-machineinstrs < %s \
 ; RUN:   | FileCheck %s --check-prefix=ZVFHMIN
 
@@ -42,29 +48,29 @@ define <4 x bfloat> @insertelt_v4bf16(<4 x bfloat> %v, bfloat %elt) {
 }
 
 define <4 x half> @insertelt_v4f16(<4 x half> %v, half %elt) {
-; V-LABEL: insertelt_v4f16:
-; V:       # %bb.0:
-; V-NEXT:    fmv.x.w a2, fa0
-; V-NEXT:    lh a3, 8(a1)
-; V-NEXT:    lh a4, 16(a1)
-; V-NEXT:    lh a1, 24(a1)
-; V-NEXT:    sh a2, 0(a0)
-; V-NEXT:    sh a3, 2(a0)
-; V-NEXT:    sh a4, 4(a0)
-; V-NEXT:    sh a1, 6(a0)
-; V-NEXT:    ret
+; V32-LABEL: insertelt_v4f16:
+; V32:       # %bb.0:
+; V32-NEXT:    fmv.x.w a2, fa0
+; V32-NEXT:    lh a3, 4(a1)
+; V32-NEXT:    lh a4, 8(a1)
+; V32-NEXT:    lh a1, 12(a1)
+; V32-NEXT:    sh a2, 0(a0)
+; V32-NEXT:    sh a3, 2(a0)
+; V32-NEXT:    sh a4, 4(a0)
+; V32-NEXT:    sh a1, 6(a0)
+; V32-NEXT:    ret
 ;
-; ZVFBFMIN-LABEL: insertelt_v4f16:
-; ZVFBFMIN:       # %bb.0:
-; ZVFBFMIN-NEXT:    fmv.x.w a2, fa0
-; ZVFBFMIN-NEXT:    lh a3, 8(a1)
-; ZVFBFMIN-NEXT:    lh a4, 16(a1)
-; ZVFBFMIN-NEXT:    lh a1, 24(a1)
-; ZVFBFMIN-NEXT:    sh a2, 0(a0)
-; ZVFBFMIN-NEXT:    sh a3, 2(a0)
-; ZVFBFMIN-NEXT:    sh a4, 4(a0)
-; ZVFBFMIN-NEXT:    sh a1, 6(a0)
-; ZVFBFMIN-NEXT:    ret
+; ZVFBFMIN32-LABEL: insertelt_v4f16:
+; ZVFBFMIN32:       # %bb.0:
+; ZVFBFMIN32-NEXT:    fmv.x.w a2, fa0
+; ZVFBFMIN32-NEXT:    lh a3, 4(a1)
+; ZVFBFMIN32-NEXT:    lh a4, 8(a1)
+; ZVFBFMIN32-NEXT:    lh a1, 12(a1)
+; ZVFBFMIN32-NEXT:    sh a2, 0(a0)
+; ZVFBFMIN32-NEXT:    sh a3, 2(a0)
+; ZVFBFMIN32-NEXT:    sh a4, 4(a0)
+; ZVFBFMIN32-NEXT:    sh a1, 6(a0)
+; ZVFBFMIN32-NEXT:    ret
 ;
 ; ZVFHMIN-LABEL: insertelt_v4f16:
 ; ZVFHMIN:       # %bb.0:
@@ -72,6 +78,30 @@ define <4 x half> @insertelt_v4f16(<4 x half> %v, half %elt) {
 ; ZVFHMIN-NEXT:    vsetivli zero, 4, e16, m1, tu, ma
 ; ZVFHMIN-NEXT:    vmv.s.x v8, a0
 ; ZVFHMIN-NEXT:    ret
+;
+; V64-LABEL: insertelt_v4f16:
+; V64:       # %bb.0:
+; V64-NEXT:    fmv.x.w a2, fa0
+; V64-NEXT:    lh a3, 8(a1)
+; V64-NEXT:    lh a4, 16(a1)
+; V64-NEXT:    lh a1, 24(a1)
+; V64-NEXT:    sh a2, 0(a0)
+; V64-NEXT:    sh a3, 2(a0)
+; V64-NEXT:    sh a4, 4(a0)
+; V64-NEXT:    sh a1, 6(a0)
+; V64-NEXT:    ret
+;
+; ZVFBFMIN64-LABEL: insertelt_v4f16:
+; ZVFBFMIN64:       # %bb.0:
+; ZVFBFMIN64-NEXT:    fmv.x.w a2, fa0
+; ZVFBFMIN64-NEXT:    lh a3, 8(a1)
+; ZVFBFMIN64-NEXT:    lh a4, 16(a1)
+; ZVFBFMIN64-NEXT:    lh a1, 24(a1)
+; ZVFBFMIN64-NEXT:    sh a2, 0(a0)
+; ZVFBFMIN64-NEXT:    sh a3, 2(a0)
+; ZVFBFMIN64-NEXT:    sh a4, 4(a0)
+; ZVFBFMIN64-NEXT:    sh a1, 6(a0)
+; ZVFBFMIN64-NEXT:    ret
   %r = insertelement <4 x half> %v, half %elt, i32 0
   ret <4 x half> %r
 }

>From 3b051ce0740ed338acdadebc6b4c37e350d56f85 Mon Sep 17 00:00:00 2001
From: Philip Reames <listmail at philipreames.com>
Date: Wed, 29 Apr 2026 19:58:22 -0700
Subject: [PATCH 3/3] clang-format

---
 llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index 9467f6406293a..10150e72f821b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -3199,7 +3199,8 @@ bool DAGTypeLegalizer::SoftPromoteHalfOperand(SDNode *N, unsigned OpNo) {
   case ISD::SELECT_CC:  Res = SoftPromoteHalfOp_SELECT_CC(N, OpNo); break;
   case ISD::SETCC:      Res = SoftPromoteHalfOp_SETCC(N); break;
   case ISD::INSERT_VECTOR_ELT:
-    Res = SoftPromoteHalfOp_INSERT_VECTOR_ELT(N); break;
+    Res = SoftPromoteHalfOp_INSERT_VECTOR_ELT(N);
+    break;
   case ISD::STORE:      Res = SoftPromoteHalfOp_STORE(N, OpNo); break;
   case ISD::ATOMIC_STORE:
     Res = SoftPromoteHalfOp_ATOMIC_STORE(N, OpNo);
@@ -3356,9 +3357,9 @@ SDValue DAGTypeLegalizer::SoftPromoteHalfOp_SETCC(SDNode *N) {
 SDValue DAGTypeLegalizer::SoftPromoteHalfOp_INSERT_VECTOR_ELT(SDNode *N) {
   SDValue NewVec = BitConvertVectorToIntegerVector(N->getOperand(0));
   SDValue NewElt = GetSoftPromotedHalf(N->getOperand(1));
-  SDValue NewIns = DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N),
-                               NewVec.getValueType(), NewVec, NewElt,
-                               N->getOperand(2));
+  SDValue NewIns =
+      DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(N), NewVec.getValueType(),
+                  NewVec, NewElt, N->getOperand(2));
   return DAG.getNode(ISD::BITCAST, SDLoc(N), N->getValueType(0), NewIns);
 }
 



More information about the llvm-commits mailing list