@samitouri / QOSamiQemu / commits / 05a8d242e3

target/arm/tcg: Implement new instructions for FPRCVT

Adds the opcode format for the SIMD versions of FCVTXX and [US]CVTF. These use very similar logic to the FP-to-general and general-to-FP register versions which exist, but use another SIMD/FP register as source or destination. The source and destination size rules are slightly different. Signed-off-by: Jim MacArthur <jim.macarthur@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260630-jmac-fprcvt-v3-1-f4840d5e0a7f@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Jim MacArthur committed Jun 30, 2026 at 14:16 UTC 05a8d242e3bac93914f4f5d0ef1a200d57421c37
3 files changed +76 -27
target/arm/cpu-features.h
+5
@@ -1685,6 +1685,11 @@ static inline bool isar_feature_aa64_f8mm4(const ARMISARegisters *id)
1685 return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8MM4);
1686 }
1687
1688 +static inline bool isar_feature_aa64_fprcvt(const ARMISARegisters *id)
1689 +{
1690 + return FIELD_EX64_IDREG(id, ID_AA64ISAR3, FPRCVT);
1691 +}
1692 +
1693 /*
1694 * Combinations of feature tests, for ease of use with TRANS_FEAT.
1695 */
target/arm/tcg/a64.decode
+15
@@ -1456,6 +1456,21 @@ FCVTZU_g . 0011110 .. 111001 000000 ..... ..... @icvt
1456 FCVTAS_g . 0011110 .. 100100 000000 ..... ..... @icvt
1457 FCVTAU_g . 0011110 .. 100101 000000 ..... ..... @icvt
1458
1459 +# Conversion between floating-point and integer (SIMD & FP)
1460 +SCVTF_simd . 0011110 .. 111100 000000 ..... ..... @icvt
1461 +UCVTF_simd . 0011110 .. 111101 000000 ..... ..... @icvt
1462 +
1463 +FCVTAS_g_simd . 0011110 .. 111010 000000 ..... ..... @icvt
1464 +FCVTAU_g_simd . 0011110 .. 111011 000000 ..... ..... @icvt
1465 +FCVTMS_g_simd . 0011110 .. 110100 000000 ..... ..... @icvt
1466 +FCVTMU_g_simd . 0011110 .. 110101 000000 ..... ..... @icvt
1467 +FCVTNS_g_simd . 0011110 .. 101010 000000 ..... ..... @icvt
1468 +FCVTNU_g_simd . 0011110 .. 101011 000000 ..... ..... @icvt
1469 +FCVTPS_g_simd . 0011110 .. 110010 000000 ..... ..... @icvt
1470 +FCVTPU_g_simd . 0011110 .. 110011 000000 ..... ..... @icvt
1471 +FCVTZS_g_simd . 0011110 .. 110110 000000 ..... ..... @icvt
1472 +FCVTZU_g_simd . 0011110 .. 110111 000000 ..... ..... @icvt
1473 +
1474 FJCVTZS 0 0011110 01 111110 000000 ..... ..... @rr
1475
1476 FMOV_ws 0 0011110 00 100110 000000 ..... ..... @rr
target/arm/tcg/translate-a64.c
+56 -27
@@ -9905,12 +9905,14 @@ TRANS(SCVTF_g, do_cvtf_g, a, true)
9905 TRANS(UCVTF_g, do_cvtf_g, a, false)
9906
9907 /*
9908 - * [US]CVTF (vector), scalar version.
9909 - * Which sounds weird, but really just means input from fp register
9908 + * [US]CVTF (vector), scalar or SIMD version.
9909 + * Which sounds weird, but really just means input from FP/SIMD register
9910 * instead of input from general register. Input and output element
9911 - * size are always equal.
9911 + * size are always equal for the scalar version and different for the
9912 + * SIMD version.
9913 */
9913 -static bool do_cvtf_f(DisasContext *s, arg_fcvt *a, bool is_signed)
9914 +static bool do_cvtf_f(DisasContext *s, arg_fcvt *a, MemOp src_mop_int,
9915 + bool is_signed)
9916 {
9917 TCGv_i64 tcg_int;
9918 int check = fp_access_check_scalar_hsd(s, a->esz);
@@ -9918,14 +9920,18 @@ static bool do_cvtf_f(DisasContext *s, arg_fcvt *a, bool is_signed)
9920 if (check <= 0) {
9921 return check == 0;
9922 }
9921 -
9923 tcg_int = tcg_temp_new_i64();
9923 - read_vec_element(s, tcg_int, a->rn, 0, a->esz | (is_signed ? MO_SIGN : 0));
9924 + read_vec_element(s, tcg_int, a->rn, 0,
9925 + src_mop_int | (is_signed ? MO_SIGN : 0));
9926 return do_cvtf_scalar(s, a->esz, a->rd, a->shift, tcg_int, is_signed);
9927 }
9928
9927 -TRANS(SCVTF_f, do_cvtf_f, a, true)
9928 -TRANS(UCVTF_f, do_cvtf_f, a, false)
9929 +TRANS(SCVTF_f, do_cvtf_f, a, a->esz, true)
9930 +TRANS(UCVTF_f, do_cvtf_f, a, a->esz, false)
9931 +TRANS_FEAT(SCVTF_simd, aa64_fprcvt, do_cvtf_f, a,
9932 + a->sf ? MO_64 : MO_32, true)
9933 +TRANS_FEAT(UCVTF_simd, aa64_fprcvt, do_cvtf_f, a,
9934 + a->sf ? MO_64 : MO_32, false)
9935
9936 static void do_fcvt_scalar(DisasContext *s, MemOp out, MemOp esz,
9937 TCGv_i64 tcg_out, int shift, int rn,
@@ -10044,6 +10050,7 @@ static bool do_fcvt_g(DisasContext *s, arg_fcvt *a,
10050 return true;
10051 }
10052
10053 +
10054 TRANS(FCVTNS_g, do_fcvt_g, a, FPROUNDING_TIEEVEN, true)
10055 TRANS(FCVTNU_g, do_fcvt_g, a, FPROUNDING_TIEEVEN, false)
10056 TRANS(FCVTPS_g, do_fcvt_g, a, FPROUNDING_POSINF, true)
@@ -10056,13 +10063,14 @@ TRANS(FCVTAS_g, do_fcvt_g, a, FPROUNDING_TIEAWAY, true)
10063 TRANS(FCVTAU_g, do_fcvt_g, a, FPROUNDING_TIEAWAY, false)
10064
10065 /*
10059 - * FCVT* (vector), scalar version.
10060 - * Which sounds weird, but really just means output to fp register
10066 + * FCVT* (vector), scalar or SIMD/FP version.
10067 + * Which sounds weird, but really just means output to fp or SIMD register
10068 * instead of output to general register. Input and output element
10062 - * size are always equal.
10069 + * size are always equal for the scalar version and different for the
10070 + * SIMD version.
10071 */
10072 static bool do_fcvt_f(DisasContext *s, arg_fcvt *a,
10065 - ARMFPRounding rmode, bool is_signed)
10073 + ARMFPRounding rmode, MemOp dst_mop_int, bool is_signed)
10074 {
10075 TCGv_i64 tcg_int;
10076 int check = fp_access_check_scalar_hsd(s, a->esz);
@@ -10072,26 +10080,47 @@ static bool do_fcvt_f(DisasContext *s, arg_fcvt *a,
10080 }
10081
10082 tcg_int = tcg_temp_new_i64();
10075 - do_fcvt_scalar(s, a->esz | (is_signed ? MO_SIGN : 0),
10083 + do_fcvt_scalar(s, dst_mop_int | (is_signed ? MO_SIGN : 0),
10084 a->esz, tcg_int, a->shift, a->rn, rmode);
10085
10086 if (!s->fpcr_nep) {
10087 clear_vec(s, a->rd);
10088 }
10081 - write_vec_element(s, tcg_int, a->rd, 0, a->esz);
10082 - return true;
10083 -}
10084 -
10085 -TRANS(FCVTNS_f, do_fcvt_f, a, FPROUNDING_TIEEVEN, true)
10086 -TRANS(FCVTNU_f, do_fcvt_f, a, FPROUNDING_TIEEVEN, false)
10087 -TRANS(FCVTPS_f, do_fcvt_f, a, FPROUNDING_POSINF, true)
10088 -TRANS(FCVTPU_f, do_fcvt_f, a, FPROUNDING_POSINF, false)
10089 -TRANS(FCVTMS_f, do_fcvt_f, a, FPROUNDING_NEGINF, true)
10090 -TRANS(FCVTMU_f, do_fcvt_f, a, FPROUNDING_NEGINF, false)
10091 -TRANS(FCVTZS_f, do_fcvt_f, a, FPROUNDING_ZERO, true)
10092 -TRANS(FCVTZU_f, do_fcvt_f, a, FPROUNDING_ZERO, false)
10093 -TRANS(FCVTAS_f, do_fcvt_f, a, FPROUNDING_TIEAWAY, true)
10094 -TRANS(FCVTAU_f, do_fcvt_f, a, FPROUNDING_TIEAWAY, false)
10089 + write_vec_element(s, tcg_int, a->rd, 0, dst_mop_int);
10090 + return true;
10091 +}
10092 +
10093 +TRANS(FCVTNS_f, do_fcvt_f, a, FPROUNDING_TIEEVEN, a->esz, true)
10094 +TRANS(FCVTNU_f, do_fcvt_f, a, FPROUNDING_TIEEVEN, a->esz, false)
10095 +TRANS(FCVTPS_f, do_fcvt_f, a, FPROUNDING_POSINF, a->esz, true)
10096 +TRANS(FCVTPU_f, do_fcvt_f, a, FPROUNDING_POSINF, a->esz, false)
10097 +TRANS(FCVTMS_f, do_fcvt_f, a, FPROUNDING_NEGINF, a->esz, true)
10098 +TRANS(FCVTMU_f, do_fcvt_f, a, FPROUNDING_NEGINF, a->esz, false)
10099 +TRANS(FCVTZS_f, do_fcvt_f, a, FPROUNDING_ZERO, a->esz, true)
10100 +TRANS(FCVTZU_f, do_fcvt_f, a, FPROUNDING_ZERO, a->esz, false)
10101 +TRANS(FCVTAS_f, do_fcvt_f, a, FPROUNDING_TIEAWAY, a->esz, true)
10102 +TRANS(FCVTAU_f, do_fcvt_f, a, FPROUNDING_TIEAWAY, a->esz, false)
10103 +
10104 +TRANS_FEAT(FCVTNS_g_simd, aa64_fprcvt, do_fcvt_f, a,
10105 + FPROUNDING_TIEEVEN, a->sf ? MO_64 : MO_32, true)
10106 +TRANS_FEAT(FCVTNU_g_simd, aa64_fprcvt, do_fcvt_f, a,
10107 + FPROUNDING_TIEEVEN, a->sf ? MO_64 : MO_32, false)
10108 +TRANS_FEAT(FCVTPS_g_simd, aa64_fprcvt, do_fcvt_f, a,
10109 + FPROUNDING_POSINF, a->sf ? MO_64 : MO_32, true)
10110 +TRANS_FEAT(FCVTPU_g_simd, aa64_fprcvt, do_fcvt_f, a,
10111 + FPROUNDING_POSINF, a->sf ? MO_64 : MO_32, false)
10112 +TRANS_FEAT(FCVTMS_g_simd, aa64_fprcvt, do_fcvt_f, a,
10113 + FPROUNDING_NEGINF, a->sf ? MO_64 : MO_32, true)
10114 +TRANS_FEAT(FCVTMU_g_simd, aa64_fprcvt, do_fcvt_f, a,
10115 + FPROUNDING_NEGINF, a->sf ? MO_64 : MO_32, false)
10116 +TRANS_FEAT(FCVTZS_g_simd, aa64_fprcvt, do_fcvt_f, a,
10117 + FPROUNDING_ZERO, a->sf ? MO_64 : MO_32, true)
10118 +TRANS_FEAT(FCVTZU_g_simd, aa64_fprcvt, do_fcvt_f, a,
10119 + FPROUNDING_ZERO, a->sf ? MO_64 : MO_32, false)
10120 +TRANS_FEAT(FCVTAS_g_simd, aa64_fprcvt, do_fcvt_f, a,
10121 + FPROUNDING_TIEAWAY, a->sf ? MO_64 : MO_32, true)
10122 +TRANS_FEAT(FCVTAU_g_simd, aa64_fprcvt, do_fcvt_f, a,
10123 + FPROUNDING_TIEAWAY, a->sf ? MO_64 : MO_32, false)
10124
10125 static bool trans_FJCVTZS(DisasContext *s, arg_FJCVTZS *a)
10126 {