From: Matheus Tavares Bernardino <[email protected]>
Add HVX IEEE floating-point arithmetic instructions: - vmpy_sf_sf, vmpy_sf_hf, vmpy_hf_hf: multiply operations - vdmpy_sf_hf: dot-product multiply - vmpy_sf_hf_acc, vmpy_hf_hf_acc, vdmpy_sf_hf_acc: multiply-accumulate - vadd_sf_sf, vsub_sf_sf, vadd_sf_hf, vsub_sf_hf: add/sub with sf output - vadd_hf_hf, vsub_hf_hf: add/sub with hf output Reviewed-by: Taylor Simpson <[email protected]> Signed-off-by: Matheus Tavares Bernardino <[email protected]> Reviewed-by: Brian Cain <[email protected]> Link: https://lore.kernel.org/qemu-devel/8923b6c6bc4fe750c07a07bcd490761f8bab52fe.1776339451.git.matheus.bernard...@oss.qualcomm.com Signed-off-by: Brian Cain <[email protected]> --- target/hexagon/cpu.h | 1 + target/hexagon/mmvec/hvx_ieee_fp.h | 18 ++++ target/hexagon/mmvec/macros.h | 1 + target/hexagon/mmvec/mmvec.h | 2 + target/hexagon/attribs_def.h.inc | 4 + target/hexagon/arch.c | 8 ++ target/hexagon/cpu.c | 3 + target/hexagon/mmvec/hvx_ieee_fp.c | 21 ++++ target/hexagon/hex_common.py | 1 + target/hexagon/imported/mmvec/encode_ext.def | 18 ++++ target/hexagon/imported/mmvec/ext.idef | 101 +++++++++++++++++++ target/hexagon/meson.build | 1 + 12 files changed, 179 insertions(+) create mode 100644 target/hexagon/mmvec/hvx_ieee_fp.h create mode 100644 target/hexagon/mmvec/hvx_ieee_fp.c diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index b0d726bf022..c50fbb3f72a 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -152,6 +152,7 @@ typedef struct CPUArchState { MemLog mem_log_stores[STORES_MAX]; float_status fp_status; + float_status hvx_fp_status; target_ulong llsc_addr; target_ulong llsc_val; diff --git a/target/hexagon/mmvec/hvx_ieee_fp.h b/target/hexagon/mmvec/hvx_ieee_fp.h new file mode 100644 index 00000000000..75008deb3b7 --- /dev/null +++ b/target/hexagon/mmvec/hvx_ieee_fp.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HEXAGON_HVX_IEEE_H +#define HEXAGON_HVX_IEEE_H + +#include "fpu/softfloat.h" + +#define f16_to_f32(A) float16_to_float32((A), true, &env->hvx_fp_status) + +float32 fp_mult_sf_hf(float16 a1, float16 a2, float_status *fp_status); +float32 fp_vdmpy(float16 a1, float16 a2, float16 a3, float16 a4, + float_status *fp_status); + +#endif diff --git a/target/hexagon/mmvec/macros.h b/target/hexagon/mmvec/macros.h index c7840fbf2e1..ac709d89938 100644 --- a/target/hexagon/mmvec/macros.h +++ b/target/hexagon/mmvec/macros.h @@ -23,6 +23,7 @@ #include "mmvec/system_ext_mmvec.h" #include "accel/tcg/getpc.h" #include "accel/tcg/probe.h" +#include "mmvec/hvx_ieee_fp.h" #ifndef QEMU_GENERATE #define VdV (*(MMVector *restrict)(VdV_void)) diff --git a/target/hexagon/mmvec/mmvec.h b/target/hexagon/mmvec/mmvec.h index 4a4f6cc9805..9841687f83f 100644 --- a/target/hexagon/mmvec/mmvec.h +++ b/target/hexagon/mmvec/mmvec.h @@ -41,6 +41,8 @@ typedef union { int16_t h[MAX_VEC_SIZE_BYTES / 2]; uint8_t ub[MAX_VEC_SIZE_BYTES / 1]; int8_t b[MAX_VEC_SIZE_BYTES / 1]; + float32 sf[MAX_VEC_SIZE_BYTES / 4]; + float16 hf[MAX_VEC_SIZE_BYTES / 2]; } MMVector; typedef union { diff --git a/target/hexagon/attribs_def.h.inc b/target/hexagon/attribs_def.h.inc index b1c155ea6d1..ecd08d02dff 100644 --- a/target/hexagon/attribs_def.h.inc +++ b/target/hexagon/attribs_def.h.inc @@ -198,6 +198,10 @@ DEF_ATTRIB(RESTRICT_LATEPRED, "Predicate can not be used as a .new.", "", "") /* HVX IEEE FP extension attributes */ DEF_ATTRIB(HVX_IEEE_FP, "HVX IEEE FP extension instruction", "", "") +DEF_ATTRIB(HVX_IEEE_FP_ACC, "HVX IEEE FP accumulate instruction", "", "") +DEF_ATTRIB(HVX_IEEE_FP_OUT_16, "HVX IEEE FP 16-bit output", "", "") +DEF_ATTRIB(HVX_IEEE_FP_OUT_32, "HVX IEEE FP 32-bit output", "", "") +DEF_ATTRIB(CVI_VX_NO_TMP_LD, "HVX multiply without tmp load", "", "") /* Keep this as the last attribute: */ DEF_ATTRIB(ZZ_LASTATTRIB, "Last attribute in the file", "", "") diff --git a/target/hexagon/arch.c b/target/hexagon/arch.c index 0a400bf7a77..3c417358e06 100644 --- a/target/hexagon/arch.c +++ b/target/hexagon/arch.c @@ -199,6 +199,10 @@ void arch_fpop_start(CPUHexagonState *env) set_float_rounding_mode( softfloat_roundingmodes[fREAD_REG_FIELD(USR, USR_FPRND)], &env->fp_status); + /* + * No need to check env->hvx_fp_status, these instructions don't + * raise exceptions nor interact with usr fields. + */ } #ifdef CONFIG_USER_ONLY @@ -237,6 +241,10 @@ void arch_fpop_end(CPUHexagonState *env, bool pkt_need_commit) SOFTFLOAT_TEST_FLAG(float_flag_overflow, FPOVFF, FPOVFE); SOFTFLOAT_TEST_FLAG(float_flag_underflow, FPUNFF, FPUNFE); } + /* + * No need to check env->hvx_fp_status, these instructions don't + * raise exceptions nor interact with usr fields. + */ } int arch_sf_recip_common(float32 *Rs, float32 *Rt, float32 *Rd, int *adjust, diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 666b0cad532..0ddd898e6e9 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -420,6 +420,9 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status); /* Default NaN value: sign bit set, all frac bits set */ set_float_default_nan_pattern(0b11111111, &env->fp_status); + + set_default_nan_mode(1, &env->hvx_fp_status); + set_float_default_nan_pattern(0b01111111, &env->hvx_fp_status); #ifndef CONFIG_USER_ONLY memset(env->t_sreg, 0, sizeof(uint32_t) * NUM_SREGS); memset(env->greg, 0, sizeof(uint32_t) * NUM_GREGS); diff --git a/target/hexagon/mmvec/hvx_ieee_fp.c b/target/hexagon/mmvec/hvx_ieee_fp.c new file mode 100644 index 00000000000..3367226998b --- /dev/null +++ b/target/hexagon/mmvec/hvx_ieee_fp.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hvx_ieee_fp.h" + +float32 fp_mult_sf_hf(float16 a1, float16 a2, float_status *fp_status) +{ + return float32_mul(float16_to_float32(a1, true, fp_status), + float16_to_float32(a2, true, fp_status), fp_status); +} + +float32 fp_vdmpy(float16 a1, float16 a2, float16 a3, float16 a4, + float_status *fp_status) +{ + return float32_add(fp_mult_sf_hf(a1, a3, fp_status), + fp_mult_sf_hf(a2, a4, fp_status), fp_status); +} diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py index ce5e38bea44..602f49e1f53 100755 --- a/target/hexagon/hex_common.py +++ b/target/hexagon/hex_common.py @@ -253,6 +253,7 @@ def need_env(tag): "A_LOAD" in attribdict[tag] or "A_CVI_GATHER" in attribdict[tag] or "A_CVI_SCATTER" in attribdict[tag] or + "A_HVX_IEEE_FP" in attribdict[tag] or "A_IMPLICIT_WRITES_USR" in attribdict[tag] or "A_PRIV" in attribdict[tag] or "J2_trap" in tag) diff --git a/target/hexagon/imported/mmvec/encode_ext.def b/target/hexagon/imported/mmvec/encode_ext.def index 6d70086b5f5..4ce87d09fdd 100644 --- a/target/hexagon/imported/mmvec/encode_ext.def +++ b/target/hexagon/imported/mmvec/encode_ext.def @@ -804,5 +804,23 @@ DEF_ENC(V6_vmpyewuh, ICLASS_CJ" 1 111 111 vvvvv PP 0 uuuuu 101 ddddd") DEF_ENC(V6_vmpyowh, ICLASS_CJ" 1 111 111 vvvvv PP 0 uuuuu 111 ddddd") DEF_ENC(V6_vmpyuhvs,"00011111110vvvvvPP1uuuuu111ddddd") +/* IEEE FP multiply instructions */ +DEF_ENC(V6_vmpy_sf_sf,"00011111100vvvvvPP1uuuuu001ddddd") +DEF_ENC(V6_vmpy_sf_hf,"00011111100vvvvvPP1uuuuu010ddddd") +DEF_ENC(V6_vmpy_hf_hf,"00011111100vvvvvPP1uuuuu011ddddd") +DEF_ENC(V6_vdmpy_sf_hf,"00011111101vvvvvPP1uuuuu110ddddd") + +/* IEEE FP multiply-accumulate instructions */ +DEF_ENC(V6_vmpy_sf_hf_acc,"00011100010vvvvvPP1uuuuu001xxxxx") +DEF_ENC(V6_vmpy_hf_hf_acc,"00011100010vvvvvPP1uuuuu010xxxxx") +DEF_ENC(V6_vdmpy_sf_hf_acc,"00011100010vvvvvPP1uuuuu011xxxxx") + +/* IEEE FP add/sub instructions */ +DEF_ENC(V6_vadd_sf_sf,"00011111100vvvvvPP1uuuuu110ddddd") +DEF_ENC(V6_vsub_sf_sf,"00011111100vvvvvPP1uuuuu111ddddd") +DEF_ENC(V6_vadd_sf_hf,"00011111100vvvvvPP1uuuuu100ddddd") +DEF_ENC(V6_vsub_sf_hf,"00011111100vvvvvPP1uuuuu101ddddd") +DEF_ENC(V6_vadd_hf_hf,"00011111101vvvvvPP1uuuuu111ddddd") +DEF_ENC(V6_vsub_hf_hf,"00011111011vvvvvPP1uuuuu000ddddd") #endif /* NO MMVEC */ diff --git a/target/hexagon/imported/mmvec/ext.idef b/target/hexagon/imported/mmvec/ext.idef index 03d31f6181d..14df8e47901 100644 --- a/target/hexagon/imported/mmvec/ext.idef +++ b/target/hexagon/imported/mmvec/ext.idef @@ -2895,9 +2895,110 @@ EXTINSN(V6_vprefixqw,"Vd32.w=prefixsum(Qv4)", ATTRIBS(A_EXTENSION,A_CVI,A_CVI_ } } ) +/* KVX - IEEE FP Instructions */ +/* Single pipe, 32-bit output */ +#define ITERATOR_INSN_IEEE_FP_32(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_32), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) +/* Single pipe, 16-bit output */ +#define ITERATOR_INSN_IEEE_FP_16(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), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) +/* Two pipes: P2 & P3, single output: P2, 32-bit output */ +#define ITERATOR_INSN_IEEE_FP_DOUBLE_SINGLE_32(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, \ +ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX_DV,A_HVX_IEEE_FP_OUT_32), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) + +/* Two pipes: P2 & P3, two outputs, 32-bit output */ +#define ITERATOR_INSN_IEEE_FP_DOUBLE_32(WIDTH,TAG,SYNTAX,DESCR,CODE) \ +EXTINSN(V6_##TAG, SYNTAX, \ +ATTRIBS(A_EXTENSION,A_HVX_IEEE_FP,A_CVI,A_CVI_VX_DV,A_HVX_IEEE_FP_OUT_32), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) + +/* + * single pipe, accumulate instruction, produces 16-bit output, requires 16-bit + * accumulate input + */ +#define ITERATOR_INSN_IEEE_FP_ACC_16(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_ACC,A_HVX_IEEE_FP_OUT_16,A_CVI_VX_NO_TMP_LD), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) + +/* + * single pipe, accumulate instruction, produces 32-bit output, requires 32-bit + * accumulate input + */ +#define ITERATOR_INSN_IEEE_FP_ACC_32(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_ACC,A_HVX_IEEE_FP_OUT_32,A_CVI_VX_NO_TMP_LD), \ +DESCR, DO_FOR_EACH_CODE(WIDTH, CODE)) + +/* IEEE FP multiply instructions */ +ITERATOR_INSN_IEEE_FP_DOUBLE_SINGLE_32(32, vmpy_sf_sf, + "Vd32.sf=vmpy(Vu32.sf,Vv32.sf)", "Vector IEEE mul: sf", + VdV.sf[i] = float32_mul(VuV.sf[i], VvV.sf[i], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vmpy_sf_hf, + "Vdd32.sf=vmpy(Vu32.hf,Vv32.hf)", "Vector IEEE mul: hf widen to sf", + VddV.v[0].sf[i] = fp_mult_sf_hf(VuV.hf[2*i], VvV.hf[2*i], &env->hvx_fp_status); + VddV.v[1].sf[i] = fp_mult_sf_hf(VuV.hf[2*i+1], VvV.hf[2*i+1], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_16(16, vmpy_hf_hf, "Vd32.hf=vmpy(Vu32.hf,Vv32.hf)", + "Vector IEEE mul: hf", + VdV.hf[i] = float16_mul(VuV.hf[i], VvV.hf[i], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_32(32, vdmpy_sf_hf, "Vd32.sf=vdmpy(Vu32.hf,Vv32.hf)", + "Vector IEEE mul reduction: hf widen to sf", + VdV.sf[i] = fp_vdmpy(VuV.hf[2*i+1], VuV.hf[2*i], VvV.hf[2*i+1], + VvV.hf[2*i], &env->hvx_fp_status)) + +/* IEEE FP multiply-accumulate instructions */ +ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vmpy_sf_hf_acc, + "Vxx32.sf+=vmpy(Vu32.hf,Vv32.hf)", "Vector IEEE fma: hf widen to sf", + VxxV.v[0].sf[i] = float32_muladd(f16_to_f32(VuV.hf[2*i]), + f16_to_f32(VvV.hf[2*i]), + VxxV.v[0].sf[i], 0, &env->hvx_fp_status); + VxxV.v[1].sf[i] = float32_muladd(f16_to_f32(VuV.hf[2*i+1]), + f16_to_f32(VvV.hf[2*i+1]), + VxxV.v[1].sf[i], 0, &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_ACC_16(16, vmpy_hf_hf_acc, + "Vx32.hf+=vmpy(Vu32.hf,Vv32.hf)", "Vector IEEE fma: hf", + VxV.hf[i] = float16_muladd(VuV.hf[i], VvV.hf[i], VxV.hf[i], 0, &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_ACC_32(32, vdmpy_sf_hf_acc, + "Vx32.sf+=vdmpy(Vu32.hf,Vv32.hf)", "Vector IEEE fma reduce: hf widen to sf", + VxV.sf[i] = float32_add(fp_vdmpy(VuV.hf[2*i+1], VuV.hf[2*i], + VvV.hf[2*i+1], VvV.hf[2*i], + &env->hvx_fp_status), + VxV.sf[i], &env->hvx_fp_status)) + +/* IEEE FP add/sub instructions */ +ITERATOR_INSN_IEEE_FP_32(32, vadd_sf_sf, "Vd32.sf=vadd(Vu32.sf,Vv32.sf)", + "Vector IEEE add: sf", + VdV.sf[i] = float32_add(VuV.sf[i], VvV.sf[i], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_32(32, vsub_sf_sf, "Vd32.sf=vsub(Vu32.sf,Vv32.sf)", + "Vector IEEE sub: sf", + VdV.sf[i] = float32_sub(VuV.sf[i], VvV.sf[i], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_16(16, vadd_hf_hf, "Vd32.hf=vadd(Vu32.hf,Vv32.hf)", + "Vector IEEE add: hf", + VdV.hf[i] = float16_add(VuV.hf[i], VvV.hf[i], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_16(16, vsub_hf_hf, "Vd32.hf=vsub(Vu32.hf,Vv32.hf)", + "Vector IEEE sub: hf", + VdV.hf[i] = float16_sub(VuV.hf[i], VvV.hf[i], &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vadd_sf_hf, + "Vdd32.sf=vadd(Vu32.hf,Vv32.hf)", "Vector IEEE add: hf widen to sf", + VddV.v[0].sf[i] = float32_add(f16_to_f32(VuV.hf[2*i]), + f16_to_f32(VvV.hf[2*i]), &env->hvx_fp_status); + VddV.v[1].sf[i] = float32_add(f16_to_f32(VuV.hf[2*i+1]), + f16_to_f32(VvV.hf[2*i+1]), &env->hvx_fp_status)) +ITERATOR_INSN_IEEE_FP_DOUBLE_32(32, vsub_sf_hf, + "Vdd32.sf=vsub(Vu32.hf,Vv32.hf)", "Vector IEEE sub: hf widen to sf", + VddV.v[0].sf[i] = float32_sub(f16_to_f32(VuV.hf[2*i]), + f16_to_f32(VvV.hf[2*i]), &env->hvx_fp_status); + VddV.v[1].sf[i] = float32_sub(f16_to_f32(VuV.hf[2*i+1]), + f16_to_f32(VvV.hf[2*i+1]), &env->hvx_fp_status)) /****************************************************************************** DEBUG Vector/Register Printing diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build index 59cb09c1070..4c921eee73b 100644 --- a/target/hexagon/meson.build +++ b/target/hexagon/meson.build @@ -252,6 +252,7 @@ hexagon_ss.add(files( 'fma_emu.c', 'mmvec/decode_ext_mmvec.c', 'mmvec/system_ext_mmvec.c', + 'mmvec/hvx_ieee_fp.c', )) hexagon_softmmu_ss.add(files( -- 2.34.1
