@samitouri / QOSamiQemu / commits / 2843fc5feb

target/hexagon: add v68 HVX IEEE float min/max insns

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 hvx_ieee_fp.h Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com> Signed-off-by: Matheus Tavares Bernardino <matheus.bernardino@oss.qualcomm.com> Reviewed-by: Brian Cain <brian.cain@oss.qualcomm.com> Link: https://lore.kernel.org/qemu-devel/8e274a7a10a5aae23eb1250db0b4f4250c81f3ef.1776339451.git.matheus.bernardino@oss.qualcomm.com Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>

Matheus Tavares Bernardino committed Apr 16, 2026 at 04:38 UTC 2843fc5feb5336a313b906d898037ef6dab94578
6 files changed +104 -1
target/hexagon/attribs_def.h.inc
+2
@@ -84,6 +84,7 @@ DEF_ATTRIB(CVI_SCATTER, "CVI Scatter operation", "", "")
84 DEF_ATTRIB(CVI_SCATTER_RELEASE, "CVI Store Release for scatter", "", "")
85 DEF_ATTRIB(CVI_TMP_DST, "CVI instruction that doesn't write a register", "", "")
86 DEF_ATTRIB(CVI_SLOT23, "Can execute in slot 2 or slot 3 (HVX)", "", "")
87 +DEF_ATTRIB(CVI_VA_2SRC, "Execs on multimedia vector engine; requires two srcs", "", "")
88
89 DEF_ATTRIB(VTCM_ALLBANK_ACCESS, "Allocates in all VTCM schedulers.", "", "")
90
@@ -202,6 +203,7 @@ DEF_ATTRIB(HVX_IEEE_FP_ACC, "HVX IEEE FP accumulate instruction", "", "")
203 DEF_ATTRIB(HVX_IEEE_FP_OUT_16, "HVX IEEE FP 16-bit output", "", "")
204 DEF_ATTRIB(HVX_IEEE_FP_OUT_32, "HVX IEEE FP 32-bit output", "", "")
205 DEF_ATTRIB(CVI_VX_NO_TMP_LD, "HVX multiply without tmp load", "", "")
206 +DEF_ATTRIB(HVX_FLT, "This a floating point HVX instruction.", "", "")
207
208 /* Keep this as the last attribute: */
209 DEF_ATTRIB(ZZ_LASTATTRIB, "Last attribute in the file", "", "")
target/hexagon/hex_common.py
+1
@@ -254,6 +254,7 @@ def need_env(tag):
254 "A_CVI_GATHER" in attribdict[tag] or
255 "A_CVI_SCATTER" in attribdict[tag] or
256 "A_HVX_IEEE_FP" in attribdict[tag] or
257 + "A_HVX_FLT" in attribdict[tag] or
258 "A_IMPLICIT_WRITES_USR" in attribdict[tag] or
259 "A_PRIV" in attribdict[tag] or
260 "J2_trap" in tag)
target/hexagon/imported/mmvec/encode_ext.def
+10
@@ -823,4 +823,14 @@ DEF_ENC(V6_vsub_sf_hf,"00011111100vvvvvPP1uuuuu101ddddd")
823 DEF_ENC(V6_vadd_hf_hf,"00011111101vvvvvPP1uuuuu111ddddd")
824 DEF_ENC(V6_vsub_hf_hf,"00011111011vvvvvPP1uuuuu000ddddd")
825
826 +/* IEEE FP min/max instructions */
827 +DEF_ENC(V6_vfmin_hf,"00011100011vvvvvPP1uuuuu000ddddd")
828 +DEF_ENC(V6_vfmin_sf,"00011100011vvvvvPP1uuuuu001ddddd")
829 +DEF_ENC(V6_vfmax_hf,"00011100011vvvvvPP1uuuuu010ddddd")
830 +DEF_ENC(V6_vfmax_sf,"00011100011vvvvvPP1uuuuu011ddddd")
831 +DEF_ENC(V6_vmax_sf,"00011111110vvvvvPP1uuuuu001ddddd")
832 +DEF_ENC(V6_vmin_sf,"00011111110vvvvvPP1uuuuu010ddddd")
833 +DEF_ENC(V6_vmax_hf,"00011111110vvvvvPP1uuuuu011ddddd")
834 +DEF_ENC(V6_vmin_hf,"00011111110vvvvvPP1uuuuu100ddddd")
835 +
836 #endif /* NO MMVEC */
target/hexagon/imported/mmvec/ext.idef
+35 -1
@@ -43,7 +43,9 @@
43 EXTINSN(V6_##TAG, SYNTAX, ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA), \
44 DESCR, DO_FOR_EACH_CODE(WIDTH, CODE))
45
46 -
46 +#define ITERATOR_INSN_ANY_SLOT_2SRC(WIDTH,TAG,SYNTAX,DESCR,CODE) \
47 +EXTINSN(V6_##TAG, SYNTAX, ATTRIBS(A_EXTENSION,A_CVI,A_CVI_VA,A_CVI_VA_2SRC,A_HVX_FLT), \
48 +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE))
49
50 #define ITERATOR_INSN2_ANY_SLOT(WIDTH,TAG,SYNTAX,SYNTAX2,DESCR,CODE) \
51 ITERATOR_INSN_ANY_SLOT(WIDTH,TAG,SYNTAX2,DESCR,CODE)
@@ -3000,6 +3002,38 @@ ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vsub_sf_hf,
3002 VddV.v[1].sf[i] = float32_sub(f16_to_f32(VuV.hf[2*i+1]),
3003 f16_to_f32(VvV.hf[2*i+1]), &env->hvx_fp_status))
3004
3005 +#define ITERATOR_INSN_IEEE_FP_16_32_LATE(WIDTH,TAG,SYNTAX,DESCR,CODE) \
3006 +EXTINSN(V6_##TAG, SYNTAX, \
3007 + ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX,A_HVX_IEEE_FP_OUT_16,A_HVX_IEEE_FP_OUT_32), \
3008 + DESCR, DO_FOR_EACH_CODE(WIDTH, CODE))
3009 +
3010 +/* IEEE FP min/max instructions */
3011 +ITERATOR_INSN_IEEE_FP_16_32_LATE(16, vfmin_hf, "Vd32.hf=vfmin(Vu32.hf,Vv32.hf)", \
3012 + "Vector IEEE min: hf", VdV.hf[i] = float16_min(VuV.hf[i], VvV.hf[i], \
3013 + &env->hvx_fp_status))
3014 +ITERATOR_INSN_IEEE_FP_16_32_LATE(32, vfmin_sf, "Vd32.sf=vfmin(Vu32.sf,Vv32.sf)", \
3015 + "Vector IEEE min: sf", VdV.sf[i] = float32_min(VuV.sf[i], VvV.sf[i], \
3016 + &env->hvx_fp_status))
3017 +ITERATOR_INSN_IEEE_FP_16_32_LATE(16, vfmax_hf, "Vd32.hf=vfmax(Vu32.hf,Vv32.hf)", \
3018 + "Vector IEEE max: hf", VdV.hf[i] = float16_max(VuV.hf[i], VvV.hf[i], \
3019 + &env->hvx_fp_status))
3020 +ITERATOR_INSN_IEEE_FP_16_32_LATE(32, vfmax_sf, "Vd32.sf=vfmax(Vu32.sf,Vv32.sf)", \
3021 + "Vector IEEE max: sf", VdV.sf[i] = float32_max(VuV.sf[i], VvV.sf[i], \
3022 + &env->hvx_fp_status))
3023 +
3024 +ITERATOR_INSN_ANY_SLOT_2SRC(32,vmax_sf,"Vd32.sf=vmax(Vu32.sf,Vv32.sf)", \
3025 + "Vector max of sf input", VdV.sf[i] = qf_max_sf(VuV.sf[i], VvV.sf[i], \
3026 + &env->hvx_fp_status))
3027 +ITERATOR_INSN_ANY_SLOT_2SRC(32,vmin_sf,"Vd32.sf=vmin(Vu32.sf,Vv32.sf)", \
3028 + "Vector min of sf input", VdV.sf[i] = qf_min_sf(VuV.sf[i], VvV.sf[i], \
3029 + &env->hvx_fp_status))
3030 +ITERATOR_INSN_ANY_SLOT_2SRC(16,vmax_hf,"Vd32.hf=vmax(Vu32.hf,Vv32.hf)", \
3031 + "Vector max of hf input", VdV.hf[i] = qf_max_hf(VuV.hf[i], VvV.hf[i], \
3032 + &env->hvx_fp_status))
3033 +ITERATOR_INSN_ANY_SLOT_2SRC(16,vmin_hf,"Vd32.hf=vmin(Vu32.hf,Vv32.hf)", \
3034 + "Vector min of hf input", VdV.hf[i] = qf_min_hf(VuV.hf[i], VvV.hf[i], \
3035 + &env->hvx_fp_status))
3036 +
3037 /******************************************************************************
3038 DEBUG Vector/Register Printing
3039 ******************************************************************************/
target/hexagon/mmvec/hvx_ieee_fp.c
+50
@@ -19,3 +19,53 @@ float32 fp_vdmpy(float16 a1, float16 a2, float16 a3, float16 a4,
19 return float32_add(fp_mult_sf_hf(a1, a3, fp_status),
20 fp_mult_sf_hf(a2, a4, fp_status), fp_status);
21 }
22 +
23 +#define float32_is_pos_nan(X) (float32_is_any_nan(X) && !float32_is_neg(X))
24 +#define float32_is_neg_nan(X) (float32_is_any_nan(X) && float32_is_neg(X))
25 +#define float16_is_pos_nan(X) (float16_is_any_nan(X) && !float16_is_neg(X))
26 +#define float16_is_neg_nan(X) (float16_is_any_nan(X) && float16_is_neg(X))
27 +
28 +/* Qfloat min/max treat +NaN as greater than +INF and -NaN as smaller than -INF */
29 +float32 qf_max_sf(float32 a1, float32 a2, float_status *fp_status)
30 +{
31 + if (float32_is_pos_nan(a1) || float32_is_neg_nan(a2)) {
32 + return a1;
33 + }
34 + if (float32_is_pos_nan(a2) || float32_is_neg_nan(a1)) {
35 + return a2;
36 + }
37 + return float32_max(a1, a2, fp_status);
38 +}
39 +
40 +float32 qf_min_sf(float32 a1, float32 a2, float_status *fp_status)
41 +{
42 + if (float32_is_pos_nan(a1) || float32_is_neg_nan(a2)) {
43 + return a2;
44 + }
45 + if (float32_is_pos_nan(a2) || float32_is_neg_nan(a1)) {
46 + return a1;
47 + }
48 + return float32_min(a1, a2, fp_status);
49 +}
50 +
51 +float16 qf_max_hf(float16 a1, float16 a2, float_status *fp_status)
52 +{
53 + if (float16_is_pos_nan(a1) || float16_is_neg_nan(a2)) {
54 + return a1;
55 + }
56 + if (float16_is_pos_nan(a2) || float16_is_neg_nan(a1)) {
57 + return a2;
58 + }
59 + return float16_max(a1, a2, fp_status);
60 +}
61 +
62 +float16 qf_min_hf(float16 a1, float16 a2, float_status *fp_status)
63 +{
64 + if (float16_is_pos_nan(a1) || float16_is_neg_nan(a2)) {
65 + return a2;
66 + }
67 + if (float16_is_pos_nan(a2) || float16_is_neg_nan(a1)) {
68 + return a1;
69 + }
70 + return float16_min(a1, a2, fp_status);
71 +}
target/hexagon/mmvec/hvx_ieee_fp.h
+6
@@ -15,4 +15,10 @@ float32 fp_mult_sf_hf(float16 a1, float16 a2, float_status *fp_status);
15 float32 fp_vdmpy(float16 a1, float16 a2, float16 a3, float16 a4,
16 float_status *fp_status);
17
18 +/* Qfloat min/max treat +NaN as greater than +INF and -NaN as smaller than -INF */
19 +float32 qf_max_sf(float32 a1, float32 a2, float_status *fp_status);
20 +float32 qf_min_sf(float32 a1, float32 a2, float_status *fp_status);
21 +float16 qf_max_hf(float16 a1, float16 a2, float_status *fp_status);
22 +float16 qf_min_hf(float16 a1, float16 a2, float_status *fp_status);
23 +
24 #endif