target/arm: Implement FEAT_FAMINMAX for SVE Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260522220306.235200-5-richard.henderson@linaro.org [PMM: add comments for TRANS_ macros] Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index 21b91b1..a7ab7e2 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h
@@ -1568,6 +1568,11 @@ return isar_feature_aa64_sme(id) || isar_feature_aa64_sve2(id); } +static inline bool isar_feature_aa64_sme2_or_sve2(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme2(id) || isar_feature_aa64_sve2(id); +} + static inline bool isar_feature_aa64_sme_or_sve2p1(const ARMISARegisters *id) { return isar_feature_aa64_sme(id) || isar_feature_aa64_sve2p1(id); @@ -1608,6 +1613,12 @@ return isar_feature_aa64_sve(id) && isar_feature_aa64_sme_sve_bf16(id); } +static inline bool +isar_feature_aa64_sme2_or_sve2_faminmax(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme2_or_sve2(id) && isar_feature_aa64_faminmax(id); +} + /* * Feature tests for "does this exist in either 32-bit or 64-bit?" */
diff --git a/target/arm/tcg/helper-sve-defs.h b/target/arm/tcg/helper-sve-defs.h index cd05dd0..f97c317 100644 --- a/target/arm/tcg/helper-sve-defs.h +++ b/target/arm/tcg/helper-sve-defs.h
@@ -3180,3 +3180,17 @@ DEF_HELPER_FLAGS_5(sve2p1_st1ss_be_c, TCG_CALL_NO_WG, void, env, ptr, tl, i32, i64) DEF_HELPER_FLAGS_5(sve2p1_st1dd_le_c, TCG_CALL_NO_WG, void, env, ptr, tl, i32, i64) DEF_HELPER_FLAGS_5(sve2p1_st1dd_be_c, TCG_CALL_NO_WG, void, env, ptr, tl, i32, i64) + +DEF_HELPER_FLAGS_6(sve2_famax_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(sve2_famax_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(sve2_famax_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_6(sve2_famin_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(sve2_famin_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(sve2_famin_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32)
diff --git a/target/arm/tcg/sve.decode b/target/arm/tcg/sve.decode index ab63cfa..078a085 100644 --- a/target/arm/tcg/sve.decode +++ b/target/arm/tcg/sve.decode
@@ -1130,6 +1130,8 @@ FMULX 01100101 .. 00 1010 100 ... ..... ..... @rdn_pg_rm FDIV 01100101 .. 00 1100 100 ... ..... ..... @rdm_pg_rn # FDIVR FDIV 01100101 .. 00 1101 100 ... ..... ..... @rdn_pg_rm +FAMAX 01100101 .. 00 1110 100 ... ..... ..... @rdn_pg_rm +FAMIN 01100101 .. 00 1111 100 ... ..... ..... @rdn_pg_rm # SVE floating-point arithmetic with immediate (predicated) FADD_zpzi 01100101 .. 011 000 100 ... 0000 . ..... @rdn_i1
diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c index d884ba4..9490f03 100644 --- a/target/arm/tcg/sve_helper.c +++ b/target/arm/tcg/sve_helper.c
@@ -4750,6 +4750,14 @@ DO_ZPZZ_FP(sve_fmulx_s, uint32_t, H1_4, helper_vfp_mulxs) DO_ZPZZ_FP(sve_fmulx_d, uint64_t, H1_8, helper_vfp_mulxd) +DO_ZPZZ_FP(sve2_famax_h, uint16_t, H1_2, float16_famax) +DO_ZPZZ_FP(sve2_famax_s, uint32_t, H1_4, float32_famax) +DO_ZPZZ_FP(sve2_famax_d, uint64_t, H1_8, float64_famax) + +DO_ZPZZ_FP(sve2_famin_h, uint16_t, H1_2, float16_famin) +DO_ZPZZ_FP(sve2_famin_s, uint32_t, H1_4, float32_famin) +DO_ZPZZ_FP(sve2_famin_d, uint64_t, H1_8, float64_famin) + #undef DO_ZPZZ_FP /* Three-operand expander, with one scalar operand, controlled by
diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index 59b8c49..d04ef2d 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c
@@ -4254,6 +4254,26 @@ DO_ZPZZ_FP(FDIV, aa64_sme_or_sve, sve_fdiv) DO_ZPZZ_FP(FMULX, aa64_sme_or_sve, sve_fmulx) +static gen_helper_gvec_4_ptr * const sve2_famax_zpzz_fns[4] = { + NULL, + gen_helper_sve2_famax_h, + gen_helper_sve2_famax_s, + gen_helper_sve2_famax_d +}; +TRANS_FEAT_STREAMING_SME2(FAMAX, aa64_sme2_or_sve2_faminmax, + gen_gvec_fpst_arg_zpzz, + sve2_famax_zpzz_fns[a->esz], a) + +static gen_helper_gvec_4_ptr * const sve2_famin_zpzz_fns[4] = { + NULL, + gen_helper_sve2_famin_h, + gen_helper_sve2_famin_s, + gen_helper_sve2_famin_d +}; +TRANS_FEAT_STREAMING_SME2(FAMIN, aa64_sme2_or_sve2_faminmax, + gen_gvec_fpst_arg_zpzz, + sve2_famin_zpzz_fns[a->esz], a) + typedef void gen_helper_sve_fp2scalar(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, TCGv_i32);
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index 77fdc5f..2a58632 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h
@@ -865,6 +865,7 @@ static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ { return dc_isar_feature(FEAT, s) && FUNC(s, __VA_ARGS__); } +/* For SVE insns which are not valid in Streaming SVE mode */ #define TRANS_FEAT_NONSTREAMING(NAME, FEAT, FUNC, ...) \ static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ { \ @@ -872,4 +873,15 @@ return dc_isar_feature(FEAT, s) && FUNC(s, __VA_ARGS__); \ } +/* + * For SVE insns which are only valid in Streaming SVE mode when + * SME2 is implemented + */ +#define TRANS_FEAT_STREAMING_SME2(NAME, FEAT, FUNC, ...) \ + static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ + { \ + s->is_nonstreaming = !dc_isar_feature(aa64_sme2, s); \ + return dc_isar_feature(FEAT, s) && FUNC(s, __VA_ARGS__); \ + } + #endif /* TARGET_ARM_TRANSLATE_H */