Signed-off-by: Richard Henderson <[email protected]>
---
target/arm/cpu-features.h | 5 +++++
target/arm/tcg/helper-a64-defs.h | 7 +++++++
target/arm/tcg/vec_internal.h | 7 +++++++
target/arm/tcg/translate-a64.c | 14 +++++++++++++
target/arm/tcg/vec_helper64.c | 35 ++++++++++++++++++++++++++++++++
target/arm/tcg/a64.decode | 5 +++++
6 files changed, 73 insertions(+)
diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index 252044b057..21d0be73cd 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1061,6 +1061,11 @@ static inline bool isar_feature_aa64_ats1a(const
ARMISARegisters *id)
return FIELD_EX64_IDREG(id, ID_AA64ISAR2, ATS1A);
}
+static inline bool isar_feature_aa64_faminmax(const ARMISARegisters *id)
+{
+ return FIELD_EX64_IDREG(id, ID_AA64ISAR3, FAMINMAX) != 0;
+}
+
static inline bool isar_feature_aa64_fp_simd(const ARMISARegisters *id)
{
/* We always set the AdvSIMD and FP fields identically. */
diff --git a/target/arm/tcg/helper-a64-defs.h b/target/arm/tcg/helper-a64-defs.h
index 3c3c5dddb7..215df1201b 100644
--- a/target/arm/tcg/helper-a64-defs.h
+++ b/target/arm/tcg/helper-a64-defs.h
@@ -145,6 +145,13 @@ DEF_HELPER_FLAGS_5(gvec_fmulx_idx_h, TCG_CALL_NO_RWG,
void, ptr, ptr, ptr, fpst,
DEF_HELPER_FLAGS_5(gvec_fmulx_idx_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr,
fpst, i32)
DEF_HELPER_FLAGS_5(gvec_fmulx_idx_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr,
fpst, i32)
+DEF_HELPER_FLAGS_5(gvec_famax_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst,
i32)
+DEF_HELPER_FLAGS_5(gvec_famin_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst,
i32)
+DEF_HELPER_FLAGS_5(gvec_famax_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst,
i32)
+DEF_HELPER_FLAGS_5(gvec_famin_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst,
i32)
+DEF_HELPER_FLAGS_5(gvec_famax_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst,
i32)
+DEF_HELPER_FLAGS_5(gvec_famin_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst,
i32)
+
#ifndef CONFIG_USER_ONLY
DEF_HELPER_2(exception_return, void, env, i64)
#endif
diff --git a/target/arm/tcg/vec_internal.h b/target/arm/tcg/vec_internal.h
index c7ccb28b18..cc2691b2f6 100644
--- a/target/arm/tcg/vec_internal.h
+++ b/target/arm/tcg/vec_internal.h
@@ -338,6 +338,13 @@ bfloat16 helper_sme2_ah_fmin_b16(bfloat16 a, bfloat16 b,
float_status *fpst);
float32 sve_f16_to_f32(float16 f, float_status *fpst);
float16 sve_f32_to_f16(float32 f, float_status *fpst);
+float16 float16_famax(float16, float16, float_status *);
+float16 float16_famin(float16, float16, float_status *);
+float32 float32_famax(float32, float32, float_status *);
+float32 float32_famin(float32, float32, float_status *);
+float64 float64_famax(float64, float64, float_status *);
+float64 float64_famin(float64, float64, float_status *);
+
/*
* Decode helper functions for predicate as counter.
*/
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 9a27c4c6ec..3c6559964b 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -6478,6 +6478,20 @@ static gen_helper_gvec_3_ptr * const f_vector_fminnmp[3]
= {
};
TRANS(FMINNMP_v, do_fp3_vector, a, 0, f_vector_fminnmp)
+static gen_helper_gvec_3_ptr * const f_vector_famax[3] = {
+ gen_helper_gvec_famax_h,
+ gen_helper_gvec_famax_s,
+ gen_helper_gvec_famax_d,
+};
+TRANS_FEAT(FAMAX, aa64_faminmax, do_fp3_vector, a, 0, f_vector_famax)
+
+static gen_helper_gvec_3_ptr * const f_vector_famin[3] = {
+ gen_helper_gvec_famin_h,
+ gen_helper_gvec_famin_s,
+ gen_helper_gvec_famin_d,
+};
+TRANS_FEAT(FAMIN, aa64_faminmax, do_fp3_vector, a, 0, f_vector_famin)
+
static bool do_fmlal(DisasContext *s, arg_qrrr_e *a, bool is_s, bool is_2)
{
if (fp_access_check(s)) {
diff --git a/target/arm/tcg/vec_helper64.c b/target/arm/tcg/vec_helper64.c
index 249a257177..b5ad67b5e0 100644
--- a/target/arm/tcg/vec_helper64.c
+++ b/target/arm/tcg/vec_helper64.c
@@ -140,3 +140,38 @@ void HELPER(simd_tblx)(void *vd, void *vm, CPUARMState
*env, uint32_t desc)
memcpy(vd, &result, 16);
clear_tail(vd, oprsz, simd_maxsz(desc));
}
+
+#define DO_FAMINMAX(NAME, TYPE, FN) \
+TYPE TYPE##_##NAME(TYPE a, TYPE b, float_status *s) \
+{ \
+ bool save_fz = get_flush_to_zero(s); \
+ bool save_fiz = get_flush_inputs_to_zero(s); \
+ int new_flags, save_flags = get_float_exception_flags(s); \
+ \
+ set_flush_to_zero(0, s); \
+ set_flush_inputs_to_zero(0, s); \
+ TYPE r = TYPE##_##FN(TYPE##_abs(a), TYPE##_abs(b), s); \
+ \
+ set_flush_to_zero(save_fz, s); \
+ set_flush_inputs_to_zero(save_fiz, s); \
+ new_flags = get_float_exception_flags(s); \
+ new_flags = (save_flags & float_flag_input_denormal_used) \
+ | (new_flags & ~float_flag_input_denormal_used); \
+ set_float_exception_flags(new_flags, s); \
+ \
+ return r; \
+}
+
+DO_FAMINMAX(famax, float16, max)
+DO_FAMINMAX(famin, float16, min)
+DO_FAMINMAX(famax, float32, max)
+DO_FAMINMAX(famin, float32, min)
+DO_FAMINMAX(famax, float64, max)
+DO_FAMINMAX(famin, float64, min)
+
+DO_3OP(gvec_famax_h, float16_famax, float16)
+DO_3OP(gvec_famin_h, float16_famin, float16)
+DO_3OP(gvec_famax_s, float32_famax, float32)
+DO_3OP(gvec_famin_s, float32_famin, float32)
+DO_3OP(gvec_famax_d, float64_famax, float64)
+DO_3OP(gvec_famin_d, float64_famin, float64)
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
index 01b1b3e38b..666a293540 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -1193,6 +1193,11 @@ RSUBHN 0.10 1110 ..1 ..... 01100 0 ..... .....
@qrrr_e
PMULL_p8 0.00 1110 001 ..... 11100 0 ..... ..... @qrrr_b
PMULL_p64 0.00 1110 111 ..... 11100 0 ..... ..... @qrrr_b
+FAMAX 0.00 1110 110 ..... 00011 1 ..... ..... @qrrr_h
+FAMAX 0.00 1110 1.1 ..... 11011 1 ..... ..... @qrrr_sd
+FAMIN 0.10 1110 110 ..... 00011 1 ..... ..... @qrrr_h
+FAMIN 0.10 1110 1.1 ..... 11011 1 ..... ..... @qrrr_sd
+
### Advanced SIMD scalar x indexed element
FMUL_si 0101 1111 00 .. .... 1001 . 0 ..... ..... @rrx_h
--
2.43.0