Add HVX IEEE floating-point min/max instructions:
- vfmin_hf, vfmin_sf: IEEE floating-point minimum
- vfmax_hf, vfmax_sf: IEEE floating-point maximum
- vmax_hf, vmax_sf: qfloat IEEE maximum
- vmin_hf, vmin_sf: qfloat IEEE minimum
The Hexagon qfloat variants are similar to the IEEE-754 ones, but they
handle NaN slightly differently. See comment on kvx_ieee.h
Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com>
---
target/hexagon/mmvec/kvx_ieee.h | 12 +++++
target/hexagon/mmvec/kvx_ieee.c | 46 ++++++++++++++++++++
target/hexagon/imported/mmvec/encode_ext.def | 11 +++++
target/hexagon/imported/mmvec/ext.idef | 28 +++++++++++-
4 files changed, 96 insertions(+), 1 deletion(-)
diff --git a/target/hexagon/mmvec/kvx_ieee.h b/target/hexagon/mmvec/kvx_ieee.h
index e92ddebeb9..78f546eb8e 100644
--- a/target/hexagon/mmvec/kvx_ieee.h
+++ b/target/hexagon/mmvec/kvx_ieee.h
@@ -44,4 +44,16 @@ uint32_t fp_vdmpy(uint16_t a1, uint16_t a2, uint16_t a3, uint16_t a4,
uint32_t fp_vdmpy_acc(uint32_t acc, uint16_t a1, uint16_t a2, uint16_t a3,
uint16_t a4, float_status *fp_status);
+/* IEEE - FP min/max instructions */
+uint32_t fp_min_sf(uint32_t a1, uint32_t a2, float_status *fp_status);
+uint32_t fp_max_sf(uint32_t a1, uint32_t a2, float_status *fp_status);
+uint16_t fp_min_hf(uint16_t a1, uint16_t a2, float_status *fp_status);
+uint16_t fp_max_hf(uint16_t a1, uint16_t a2, float_status *fp_status);
+
+/* Qfloat min/max treat +NaN as greater than +INF and -NaN as smaller than -INF */
+uint32_t qf_max_sf(uint32_t a1, uint32_t a2, float_status *fp_status);
+uint32_t qf_min_sf(uint32_t a1, uint32_t a2, float_status *fp_status);
+uint16_t qf_max_hf(uint16_t a1, uint16_t a2, float_status *fp_status);
+uint16_t qf_min_hf(uint16_t a1, uint16_t a2, float_status *fp_status);
+
#endif
diff --git a/target/hexagon/mmvec/kvx_ieee.c b/target/hexagon/mmvec/kvx_ieee.c
index b763899aa3..33621a15f3 100644
--- a/target/hexagon/mmvec/kvx_ieee.c
+++ b/target/hexagon/mmvec/kvx_ieee.c
@@ -85,3 +85,49 @@ uint32_t fp_vdmpy_acc(uint32_t acc, uint16_t a1, uint16_t a2,
float32 red = fp_vdmpy(a1, a2, a3, a4, fp_status);
return fp_add_sf_sf(float32_val(red), acc, fp_status);
}
+
+DEF_FP_INSN_2(min_sf, 32, 32, 32, float32_min(f1, f2, fp_status))
+DEF_FP_INSN_2(max_sf, 32, 32, 32, float32_max(f1, f2, fp_status))
+DEF_FP_INSN_2(min_hf, 16, 16, 16, float16_min(f1, f2, fp_status))
+DEF_FP_INSN_2(max_hf, 16, 16, 16, float16_max(f1, f2, fp_status))
+
+#define float32_is_pos_nan(X) (float32_is_any_nan(X) && !float32_is_neg(X))
+#define float32_is_neg_nan(X) (float32_is_any_nan(X) && float32_is_neg(X))
+#define float16_is_pos_nan(X) (float16_is_any_nan(X) && !float16_is_neg(X))
+#define float16_is_neg_nan(X) (float16_is_any_nan(X) && float16_is_neg(X))
+
+uint32_t qf_max_sf(uint32_t a1, uint32_t a2, float_status *fp_status)
+{
+ float32 f1 = make_float32(a1);
+ float32 f2 = make_float32(a2);
+ if (float32_is_pos_nan(f1) || float32_is_neg_nan(f2)) return a1;
+ if (float32_is_pos_nan(f2) || float32_is_neg_nan(f1)) return a2;
+ return fp_max_sf(a1, a2, fp_status);
+}
+
+uint32_t qf_min_sf(uint32_t a1, uint32_t a2, float_status *fp_status)
+{
+ float32 f1 = make_float32(a1);
+ float32 f2 = make_float32(a2);
+ if (float32_is_pos_nan(f1) || float32_is_neg_nan(f2)) return a2;
+ if (float32_is_pos_nan(f2) || float32_is_neg_nan(f1)) return a1;
+ return fp_min_sf(a1, a2, fp_status);
+}
+
+uint16_t qf_max_hf(uint16_t a1, uint16_t a2, float_status *fp_status)
+{
+ float16 f1 = make_float16(a1);
+ float16 f2 = make_float16(a2);
+ if (float16_is_pos_nan(f1) || float16_is_neg_nan(f2)) return a1;
+ if (float16_is_pos_nan(f2) || float16_is_neg_nan(f1)) return a2;
+ return fp_max_hf(a1, a2, fp_status);
+}
+
+uint16_t qf_min_hf(uint16_t a1, uint16_t a2, float_status *fp_status)
+{
+ float16 f1 = make_float16(a1);
+ float16 f2 = make_float16(a2);
+ if (float16_is_pos_nan(f1) || float16_is_neg_nan(f2)) return a2;
+ if (float16_is_pos_nan(f2) || float16_is_neg_nan(f1)) return a1;
+ return fp_min_hf(a1, a2, fp_status);
+}
diff --git a/target/hexagon/imported/mmvec/encode_ext.def b/target/hexagon/imported/mmvec/encode_ext.def
index 4ce87d09fd..23fbb75743 100644
--- a/target/hexagon/imported/mmvec/encode_ext.def
+++ b/target/hexagon/imported/mmvec/encode_ext.def
@@ -823,4 +823,15 @@ DEF_ENC(V6_vsub_sf_hf,"00011111100vvvvvPP1uuuuu101ddddd")
DEF_ENC(V6_vadd_hf_hf,"00011111101vvvvvPP1uuuuu111ddddd")
DEF_ENC(V6_vsub_hf_hf,"00011111011vvvvvPP1uuuuu000ddddd")
+/* IEEE FP min/max instructions */
+DEF_ENC(V6_vfmin_hf,"00011100011vvvvvPP1uuuuu000ddddd")
+DEF_ENC(V6_vfmin_sf,"00011100011vvvvvPP1uuuuu001ddddd")
+DEF_ENC(V6_vfmax_hf,"00011100011vvvvvPP1uuuuu010ddddd")
+DEF_ENC(V6_vfmax_sf,"00011100011vvvvvPP1uuuuu011ddddd")
+DEF_ENC(V6_vmax_sf,"00011111110vvvvvPP1uuuuu001ddddd")
+DEF_ENC(V6_vmin_sf,"00011111110vvvvvPP1uuuuu010ddddd")
+DEF_ENC(V6_vmax_hf,"00011111110vvvvvPP1uuuuu011ddddd")
+DEF_ENC(V6_vmin_hf,"00011111110vvvvvPP1uuuuu100ddddd")
+DEF_ENC(V6_vcvt_ub_hf,"00011111110vvvvvPP1uuuuu101ddddd")
+
#endif /* NO MMVEC */
diff --git a/target/hexagon/imported/mmvec/ext.idef b/target/hexagon/imported/mmvec/ext.idef
index 3f0d8e366e..43153366b1 100644
--- a/target/hexagon/imported/mmvec/ext.idef
+++ b/target/hexagon/imported/mmvec/ext.idef
@@ -43,7 +43,9 @@
EXTINSN(V6_##TAG, SYNTAX, ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA), \
DESCR, DO_FOR_EACH_CODE(WIDTH, CODE))
-
+#define ITERATOR_INSN_ANY_SLOT_2SRC(WIDTH,TAG,SYNTAX,DESCR,CODE) \
+EXTINSN(V6_##TAG, SYNTAX, ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \
+DESCR, DO_FOR_EACH_CODE(WIDTH, CODE))
#define ITERATOR_INSN2_ANY_SLOT(WIDTH,TAG,SYNTAX,SYNTAX2,DESCR,CODE) \
ITERATOR_INSN_ANY_SLOT(WIDTH,TAG,SYNTAX2,DESCR,CODE)
@@ -2992,6 +2994,30 @@ ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vsub_sf_hf,
VddV.v[0].sf[i] = fp_sub_sf_hf(VuV.hf[2*i], VvV.hf[2*i], &env->fp_status);
VddV.v[1].sf[i] = fp_sub_sf_hf(VuV.hf[2*i+1], VvV.hf[2*i+1], &env->fp_status))
+#define ITERATOR_INSN_IEEE_FP_16_32_LATE(WIDTH,TAG,SYNTAX,DESCR,CODE) \
+EXTINSN(V6_##TAG, SYNTAX, \
+ ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX,A_HVX_IEEE_FP_OUT_16,A_HVX_IEEE_FP_OUT_32), \
+ DESCR, DO_FOR_EACH_CODE(WIDTH, CODE))
+
+/* IEEE FP min/max instructions */
+ITERATOR_INSN_IEEE_FP_16_32_LATE(16, vfmin_hf, "Vd32.hf=vfmin(Vu32.hf,Vv32.hf)", \
+ "Vector IEEE min: hf", VdV.hf[i] = fp_min_hf(VuV.hf[i], VvV.hf[i], &env->fp_status))
+ITERATOR_INSN_IEEE_FP_16_32_LATE(32, vfmin_sf, "Vd32.sf=vfmin(Vu32.sf,Vv32.sf)", \
+ "Vector IEEE min: sf", VdV.sf[i] = fp_min_sf(VuV.sf[i], VvV.sf[i], &env->fp_status))
+ITERATOR_INSN_IEEE_FP_16_32_LATE(16, vfmax_hf, "Vd32.hf=vfmax(Vu32.hf,Vv32.hf)", \
+ "Vector IEEE max: hf", VdV.hf[i] = fp_max_hf(VuV.hf[i], VvV.hf[i], &env->fp_status))
+ITERATOR_INSN_IEEE_FP_16_32_LATE(32, vfmax_sf, "Vd32.sf=vfmax(Vu32.sf,Vv32.sf)", \
+ "Vector IEEE max: sf", VdV.sf[i] = fp_max_sf(VuV.sf[i], VvV.sf[i], &env->fp_status))
+
+ITERATOR_INSN_ANY_SLOT_2SRC(32,vmax_sf,"Vd32.sf=vmax(Vu32.sf,Vv32.sf)", \
+ "Vector max of sf input", VdV.sf[i] = qf_max_sf(VuV.sf[i], VvV.sf[i], &env->fp_status))
+ITERATOR_INSN_ANY_SLOT_2SRC(32,vmin_sf,"Vd32.sf=vmin(Vu32.sf,Vv32.sf)", \
+ "Vector min of sf input", VdV.sf[i] = qf_min_sf(VuV.sf[i], VvV.sf[i], &env->fp_status))
+ITERATOR_INSN_ANY_SLOT_2SRC(16,vmax_hf,"Vd32.hf=vmax(Vu32.hf,Vv32.hf)", \
+ "Vector max of hf input", VdV.hf[i] = qf_max_hf(VuV.hf[i], VvV.hf[i], &env->fp_status))
+ITERATOR_INSN_ANY_SLOT_2SRC(16,vmin_hf,"Vd32.hf=vmin(Vu32.hf,Vv32.hf)", \
+ "Vector min of hf input", VdV.hf[i] = qf_min_hf(VuV.hf[i], VvV.hf[i], &env->fp_status))
+
/******************************************************************************
DEBUG Vector/Register Printing
******************************************************************************/
--
2.37.2
On Mon, Mar 23, 2026 at 7:15 AM Matheus Tavares Bernardino < matheus.bernardino@oss.qualcomm.com> wrote: > Add HVX IEEE floating-point min/max instructions: > - vfmin_hf, vfmin_sf: IEEE floating-point minimum > - vfmax_hf, vfmax_sf: IEEE floating-point maximum > - vmax_hf, vmax_sf: qfloat IEEE maximum > - vmin_hf, vmin_sf: qfloat IEEE minimum > > The Hexagon qfloat variants are similar to the IEEE-754 ones, but they > handle NaN slightly differently. See comment on kvx_ieee.h > > Signed-off-by: Matheus Tavares Bernardino < > matheus.bernardino@oss.qualcomm.com> > --- > target/hexagon/mmvec/kvx_ieee.h | 12 +++++ > target/hexagon/mmvec/kvx_ieee.c | 46 ++++++++++++++++++++ > target/hexagon/imported/mmvec/encode_ext.def | 11 +++++ > target/hexagon/imported/mmvec/ext.idef | 28 +++++++++++- > 4 files changed, 96 insertions(+), 1 deletion(-) > > diff --git a/target/hexagon/mmvec/kvx_ieee.h > b/target/hexagon/mmvec/kvx_ieee.h > index e92ddebeb9..78f546eb8e 100644 > --- a/target/hexagon/mmvec/kvx_ieee.h > +++ b/target/hexagon/mmvec/kvx_ieee.h > @@ -44,4 +44,16 @@ uint32_t fp_vdmpy(uint16_t a1, uint16_t a2, uint16_t > a3, uint16_t a4, > uint32_t fp_vdmpy_acc(uint32_t acc, uint16_t a1, uint16_t a2, uint16_t a3, > uint16_t a4, float_status *fp_status); > > +/* IEEE - FP min/max instructions */ > +uint32_t fp_min_sf(uint32_t a1, uint32_t a2, float_status *fp_status); > +uint32_t fp_max_sf(uint32_t a1, uint32_t a2, float_status *fp_status); > +uint16_t fp_min_hf(uint16_t a1, uint16_t a2, float_status *fp_status); > +uint16_t fp_max_hf(uint16_t a1, uint16_t a2, float_status *fp_status); > + > +/* Qfloat min/max treat +NaN as greater than +INF and -NaN as smaller > than -INF */ > +uint32_t qf_max_sf(uint32_t a1, uint32_t a2, float_status *fp_status); > +uint32_t qf_min_sf(uint32_t a1, uint32_t a2, float_status *fp_status); > +uint16_t qf_max_hf(uint16_t a1, uint16_t a2, float_status *fp_status); > +uint16_t qf_min_hf(uint16_t a1, uint16_t a2, float_status *fp_status); > Why are we including Qfloat stuff in a patch series for IEEE float? > + > #endif > diff --git a/target/hexagon/imported/mmvec/encode_ext.def > b/target/hexagon/imported/mmvec/encode_ext.def > index 4ce87d09fd..23fbb75743 100644 > --- a/target/hexagon/imported/mmvec/encode_ext.def > +++ b/target/hexagon/imported/mmvec/encode_ext.def > @@ -823,4 +823,15 @@ > DEF_ENC(V6_vsub_sf_hf,"00011111100vvvvvPP1uuuuu101ddddd") > DEF_ENC(V6_vadd_hf_hf,"00011111101vvvvvPP1uuuuu111ddddd") > DEF_ENC(V6_vsub_hf_hf,"00011111011vvvvvPP1uuuuu000ddddd") > > +/* IEEE FP min/max instructions */ > +DEF_ENC(V6_vfmin_hf,"00011100011vvvvvPP1uuuuu000ddddd") > +DEF_ENC(V6_vfmin_sf,"00011100011vvvvvPP1uuuuu001ddddd") > +DEF_ENC(V6_vfmax_hf,"00011100011vvvvvPP1uuuuu010ddddd") > +DEF_ENC(V6_vfmax_sf,"00011100011vvvvvPP1uuuuu011ddddd") > +DEF_ENC(V6_vmax_sf,"00011111110vvvvvPP1uuuuu001ddddd") > +DEF_ENC(V6_vmin_sf,"00011111110vvvvvPP1uuuuu010ddddd") > +DEF_ENC(V6_vmax_hf,"00011111110vvvvvPP1uuuuu011ddddd") > +DEF_ENC(V6_vmin_hf,"00011111110vvvvvPP1uuuuu100ddddd") > +DEF_ENC(V6_vcvt_ub_hf,"00011111110vvvvvPP1uuuuu101ddddd") > Minor nit - this is a conversion instruction and is repeated in patch 7. Remove it from this patch. Thanks, Taylor
On Mon, Mar 23, 2026 at 5:48 PM Taylor Simpson <ltaylorsimpson@gmail.com> wrote: > > > > On Mon, Mar 23, 2026 at 7:15 AM Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com> wrote: >> >> Add HVX IEEE floating-point min/max instructions: >> - vfmin_hf, vfmin_sf: IEEE floating-point minimum >> - vfmax_hf, vfmax_sf: IEEE floating-point maximum >> - vmax_hf, vmax_sf: qfloat IEEE maximum >> - vmin_hf, vmin_sf: qfloat IEEE minimum >> >> The Hexagon qfloat variants are similar to the IEEE-754 ones, but they >> handle NaN slightly differently. See comment on kvx_ieee.h >> >> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com> >> --- >> target/hexagon/mmvec/kvx_ieee.h | 12 +++++ >> target/hexagon/mmvec/kvx_ieee.c | 46 ++++++++++++++++++++ >> target/hexagon/imported/mmvec/encode_ext.def | 11 +++++ >> target/hexagon/imported/mmvec/ext.idef | 28 +++++++++++- >> 4 files changed, 96 insertions(+), 1 deletion(-) >> >> diff --git a/target/hexagon/mmvec/kvx_ieee.h b/target/hexagon/mmvec/kvx_ieee.h >> index e92ddebeb9..78f546eb8e 100644 >> --- a/target/hexagon/mmvec/kvx_ieee.h >> +++ b/target/hexagon/mmvec/kvx_ieee.h >> @@ -44,4 +44,16 @@ uint32_t fp_vdmpy(uint16_t a1, uint16_t a2, uint16_t a3, uint16_t a4, >> uint32_t fp_vdmpy_acc(uint32_t acc, uint16_t a1, uint16_t a2, uint16_t a3, >> uint16_t a4, float_status *fp_status); >> >> +/* IEEE - FP min/max instructions */ >> +uint32_t fp_min_sf(uint32_t a1, uint32_t a2, float_status *fp_status); >> +uint32_t fp_max_sf(uint32_t a1, uint32_t a2, float_status *fp_status); >> +uint16_t fp_min_hf(uint16_t a1, uint16_t a2, float_status *fp_status); >> +uint16_t fp_max_hf(uint16_t a1, uint16_t a2, float_status *fp_status); >> + >> +/* Qfloat min/max treat +NaN as greater than +INF and -NaN as smaller than -INF */ >> +uint32_t qf_max_sf(uint32_t a1, uint32_t a2, float_status *fp_status); >> +uint32_t qf_min_sf(uint32_t a1, uint32_t a2, float_status *fp_status); >> +uint16_t qf_max_hf(uint16_t a1, uint16_t a2, float_status *fp_status); >> +uint16_t qf_min_hf(uint16_t a1, uint16_t a2, float_status *fp_status); > > > Why are we including Qfloat stuff in a patch series for IEEE float? Well, good point. We can separate those. I've only included them here because their semantics are very similar to the respective IEEE variants, and they are more common in Hexagon code as the IEEE variants need the extension, which is not available in all cores. >> >> + >> #endif >> diff --git a/target/hexagon/imported/mmvec/encode_ext.def b/target/hexagon/imported/mmvec/encode_ext.def >> index 4ce87d09fd..23fbb75743 100644 >> --- a/target/hexagon/imported/mmvec/encode_ext.def >> +++ b/target/hexagon/imported/mmvec/encode_ext.def >> @@ -823,4 +823,15 @@ DEF_ENC(V6_vsub_sf_hf,"00011111100vvvvvPP1uuuuu101ddddd") >> DEF_ENC(V6_vadd_hf_hf,"00011111101vvvvvPP1uuuuu111ddddd") >> DEF_ENC(V6_vsub_hf_hf,"00011111011vvvvvPP1uuuuu000ddddd") >> >> +/* IEEE FP min/max instructions */ >> +DEF_ENC(V6_vfmin_hf,"00011100011vvvvvPP1uuuuu000ddddd") >> +DEF_ENC(V6_vfmin_sf,"00011100011vvvvvPP1uuuuu001ddddd") >> +DEF_ENC(V6_vfmax_hf,"00011100011vvvvvPP1uuuuu010ddddd") >> +DEF_ENC(V6_vfmax_sf,"00011100011vvvvvPP1uuuuu011ddddd") >> +DEF_ENC(V6_vmax_sf,"00011111110vvvvvPP1uuuuu001ddddd") >> +DEF_ENC(V6_vmin_sf,"00011111110vvvvvPP1uuuuu010ddddd") >> +DEF_ENC(V6_vmax_hf,"00011111110vvvvvPP1uuuuu011ddddd") >> +DEF_ENC(V6_vmin_hf,"00011111110vvvvvPP1uuuuu100ddddd") >> +DEF_ENC(V6_vcvt_ub_hf,"00011111110vvvvvPP1uuuuu101ddddd") > > > Minor nit - this is a conversion instruction and is repeated in patch 7. Remove it from this patch. Will do, thanks.
© 2016 - 2026 Red Hat, Inc.