target/arm: Implement MVE FP max/min across vector
Implement the MVE VMAXNMV, VMINNMV, VMAXNMAV, VMINNMAV insns. These calculate the maximum or minimum of floating point elements across a vector, starting with a value in a general purpose register and returning the result there. The pseudocode silences a possible SNaN in the accumulating result on every iteration (by calling FPConvertNaN), but we do it only on the input ra, because if none of the inputs to float*_maxnum or float*_minnum are SNaNs then the result can't be an SNaN. Note that we can't use the float*_maxnuma() etc functions we defined earlier for VMAXNMA and VMINNMA, because we mustn't take the absolute value of the starting general-purpose register value, which could be negative. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
2c8cb5888e
commit
29f80e7d83
@ -614,6 +614,18 @@ DEF_HELPER_FLAGS_3(mve_vminavb, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_vminavh, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_vminavw, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(mve_vmaxnmvh, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_vmaxnmvs, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(mve_vminnmvh, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_vminnmvs, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(mve_vmaxnmavh, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_vmaxnmavs, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(mve_vminnmavh, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
DEF_HELPER_FLAGS_3(mve_vminnmavs, TCG_CALL_NO_WG, i32, env, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(mve_vaddlv_s, TCG_CALL_NO_WG, i64, env, ptr, i64)
|
||||
DEF_HELPER_FLAGS_3(mve_vaddlv_u, TCG_CALL_NO_WG, i64, env, ptr, i64)
|
||||
|
||||
|
@ -137,6 +137,10 @@
|
||||
@vmaxnma .... .... .... .... .... .... .... .... &2op \
|
||||
qd=%qd qn=%qd qm=%qm
|
||||
|
||||
# Here also we don't decode the bit 28 size in the format to avoid
|
||||
# awkward nested overlap groups
|
||||
@vmaxnmv .... .... .... .... rda:4 .... .... .... &vmaxv qm=%qm
|
||||
|
||||
@2op_fp_scalar .... .... .... .... .... .... .... rm:4 &2scalar \
|
||||
qd=%qd qn=%qn size=%2op_fp_scalar_size
|
||||
|
||||
@ -440,17 +444,33 @@ VMLADAV_S 1110 1110 1111 ... 0 ... . 1111 . 0 . 0 ... 1 @vmladav_nosz
|
||||
VMLADAV_U 1111 1110 1111 ... 0 ... . 1111 . 0 . 0 ... 1 @vmladav_nosz
|
||||
|
||||
{
|
||||
VMAXV_S 1110 1110 1110 .. 10 .... 1111 0 0 . 0 ... 0 @vmaxv
|
||||
VMINV_S 1110 1110 1110 .. 10 .... 1111 1 0 . 0 ... 0 @vmaxv
|
||||
VMAXAV 1110 1110 1110 .. 00 .... 1111 0 0 . 0 ... 0 @vmaxv
|
||||
VMINAV 1110 1110 1110 .. 00 .... 1111 1 0 . 0 ... 0 @vmaxv
|
||||
[
|
||||
VMAXNMAV 1110 1110 1110 11 00 .... 1111 0 0 . 0 ... 0 @vmaxnmv size=2
|
||||
VMINNMAV 1110 1110 1110 11 00 .... 1111 1 0 . 0 ... 0 @vmaxnmv size=2
|
||||
VMAXNMV 1110 1110 1110 11 10 .... 1111 0 0 . 0 ... 0 @vmaxnmv size=2
|
||||
VMINNMV 1110 1110 1110 11 10 .... 1111 1 0 . 0 ... 0 @vmaxnmv size=2
|
||||
]
|
||||
[
|
||||
VMAXV_S 1110 1110 1110 .. 10 .... 1111 0 0 . 0 ... 0 @vmaxv
|
||||
VMINV_S 1110 1110 1110 .. 10 .... 1111 1 0 . 0 ... 0 @vmaxv
|
||||
VMAXAV 1110 1110 1110 .. 00 .... 1111 0 0 . 0 ... 0 @vmaxv
|
||||
VMINAV 1110 1110 1110 .. 00 .... 1111 1 0 . 0 ... 0 @vmaxv
|
||||
]
|
||||
VMLADAV_S 1110 1110 1111 ... 0 ... . 1111 . 0 . 0 ... 0 @vmladav_nosz
|
||||
VRMLALDAVH_S 1110 1110 1 ... ... 0 ... . 1111 . 0 . 0 ... 0 @vmlaldav_nosz
|
||||
}
|
||||
|
||||
{
|
||||
VMAXV_U 1111 1110 1110 .. 10 .... 1111 0 0 . 0 ... 0 @vmaxv
|
||||
VMINV_U 1111 1110 1110 .. 10 .... 1111 1 0 . 0 ... 0 @vmaxv
|
||||
[
|
||||
VMAXNMAV 1111 1110 1110 11 00 .... 1111 0 0 . 0 ... 0 @vmaxnmv size=1
|
||||
VMINNMAV 1111 1110 1110 11 00 .... 1111 1 0 . 0 ... 0 @vmaxnmv size=1
|
||||
VMAXNMV 1111 1110 1110 11 10 .... 1111 0 0 . 0 ... 0 @vmaxnmv size=1
|
||||
VMINNMV 1111 1110 1110 11 10 .... 1111 1 0 . 0 ... 0 @vmaxnmv size=1
|
||||
]
|
||||
[
|
||||
VMAXV_U 1111 1110 1110 .. 10 .... 1111 0 0 . 0 ... 0 @vmaxv
|
||||
VMINV_U 1111 1110 1110 .. 10 .... 1111 1 0 . 0 ... 0 @vmaxv
|
||||
]
|
||||
VMLADAV_U 1111 1110 1111 ... 0 ... . 1111 . 0 . 0 ... 0 @vmladav_nosz
|
||||
VRMLALDAVH_U 1111 1110 1 ... ... 0 ... . 1111 . 0 . 0 ... 0 @vmlaldav_nosz
|
||||
}
|
||||
|
@ -3112,3 +3112,47 @@ DO_2OP_FP_ACC_SCALAR(vfma_scalarh, 2, float16, float16_muladd)
|
||||
DO_2OP_FP_ACC_SCALAR(vfma_scalars, 4, float32, float32_muladd)
|
||||
DO_2OP_FP_ACC_SCALAR(vfmas_scalarh, 2, float16, DO_VFMAS_SCALARH)
|
||||
DO_2OP_FP_ACC_SCALAR(vfmas_scalars, 4, float32, DO_VFMAS_SCALARS)
|
||||
|
||||
/* Floating point max/min across vector. */
|
||||
#define DO_FP_VMAXMINV(OP, ESIZE, TYPE, ABS, FN) \
|
||||
uint32_t HELPER(glue(mve_, OP))(CPUARMState *env, void *vm, \
|
||||
uint32_t ra_in) \
|
||||
{ \
|
||||
uint16_t mask = mve_element_mask(env); \
|
||||
unsigned e; \
|
||||
TYPE *m = vm; \
|
||||
TYPE ra = (TYPE)ra_in; \
|
||||
float_status *fpst = (ESIZE == 2) ? \
|
||||
&env->vfp.standard_fp_status_f16 : \
|
||||
&env->vfp.standard_fp_status; \
|
||||
for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE) { \
|
||||
if (mask & 1) { \
|
||||
TYPE v = m[H##ESIZE(e)]; \
|
||||
if (TYPE##_is_signaling_nan(ra, fpst)) { \
|
||||
ra = TYPE##_silence_nan(ra, fpst); \
|
||||
float_raise(float_flag_invalid, fpst); \
|
||||
} \
|
||||
if (TYPE##_is_signaling_nan(v, fpst)) { \
|
||||
v = TYPE##_silence_nan(v, fpst); \
|
||||
float_raise(float_flag_invalid, fpst); \
|
||||
} \
|
||||
if (ABS) { \
|
||||
v = TYPE##_abs(v); \
|
||||
} \
|
||||
ra = FN(ra, v, fpst); \
|
||||
} \
|
||||
} \
|
||||
mve_advance_vpt(env); \
|
||||
return ra; \
|
||||
} \
|
||||
|
||||
#define NOP(X) (X)
|
||||
|
||||
DO_FP_VMAXMINV(vmaxnmvh, 2, float16, false, float16_maxnum)
|
||||
DO_FP_VMAXMINV(vmaxnmvs, 4, float32, false, float32_maxnum)
|
||||
DO_FP_VMAXMINV(vminnmvh, 2, float16, false, float16_minnum)
|
||||
DO_FP_VMAXMINV(vminnmvs, 4, float32, false, float32_minnum)
|
||||
DO_FP_VMAXMINV(vmaxnmavh, 2, float16, true, float16_maxnum)
|
||||
DO_FP_VMAXMINV(vmaxnmavs, 4, float32, true, float32_maxnum)
|
||||
DO_FP_VMAXMINV(vminnmavh, 2, float16, true, float16_minnum)
|
||||
DO_FP_VMAXMINV(vminnmavs, 4, float32, true, float32_minnum)
|
||||
|
@ -1806,6 +1806,26 @@ DO_VMAXV(VMINV_S, vminvs)
|
||||
DO_VMAXV(VMINV_U, vminvu)
|
||||
DO_VMAXV(VMINAV, vminav)
|
||||
|
||||
#define DO_VMAXV_FP(INSN, FN) \
|
||||
static bool trans_##INSN(DisasContext *s, arg_vmaxv *a) \
|
||||
{ \
|
||||
static MVEGenVADDVFn * const fns[] = { \
|
||||
NULL, \
|
||||
gen_helper_mve_##FN##h, \
|
||||
gen_helper_mve_##FN##s, \
|
||||
NULL, \
|
||||
}; \
|
||||
if (!dc_isar_feature(aa32_mve_fp, s)) { \
|
||||
return false; \
|
||||
} \
|
||||
return do_vmaxv(s, a, fns[a->size]); \
|
||||
}
|
||||
|
||||
DO_VMAXV_FP(VMAXNMV, vmaxnmv)
|
||||
DO_VMAXV_FP(VMINNMV, vminnmv)
|
||||
DO_VMAXV_FP(VMAXNMAV, vmaxnmav)
|
||||
DO_VMAXV_FP(VMINNMAV, vminnmav)
|
||||
|
||||
static bool do_vabav(DisasContext *s, arg_vabav *a, MVEGenVABAVFn *fn)
|
||||
{
|
||||
/* Absolute difference accumulated across vector */
|
||||
|
Loading…
Reference in New Issue
Block a user