diff --git a/qemu/aarch64.h b/qemu/aarch64.h index aeb78832..8878ea11 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -1107,6 +1107,10 @@ #define helper_exception_with_syndrome helper_exception_with_syndrome_aarch64 #define helper_exit_atomic helper_exit_atomic_aarch64 #define helper_fcos helper_fcos_aarch64 +#define helper_frint32_d helper_frint32_d_aarch64 +#define helper_frint32_s helper_frint32_s_aarch64 +#define helper_frint64_d helper_frint64_d_aarch64 +#define helper_frint64_s helper_frint64_s_aarch64 #define helper_fscale helper_fscale_aarch64 #define helper_fsincos helper_fsincos_aarch64 #define helper_fsin helper_fsin_aarch64 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index e1b8b676..8f4dc17f 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -1107,6 +1107,10 @@ #define helper_exception_with_syndrome helper_exception_with_syndrome_aarch64eb #define helper_exit_atomic helper_exit_atomic_aarch64eb #define helper_fcos helper_fcos_aarch64eb +#define helper_frint32_d helper_frint32_d_aarch64eb +#define helper_frint32_s helper_frint32_s_aarch64eb +#define helper_frint64_d helper_frint64_d_aarch64eb +#define helper_frint64_s helper_frint64_s_aarch64eb #define helper_fscale helper_fscale_aarch64eb #define helper_fsincos helper_fsincos_aarch64eb #define helper_fsin helper_fsin_aarch64eb diff --git a/qemu/arm.h b/qemu/arm.h index a1e33c0a..023968b9 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -1107,6 +1107,10 @@ #define helper_exception_with_syndrome helper_exception_with_syndrome_arm #define helper_exit_atomic helper_exit_atomic_arm #define helper_fcos helper_fcos_arm +#define helper_frint32_d helper_frint32_d_arm +#define helper_frint32_s helper_frint32_s_arm +#define helper_frint64_d helper_frint64_d_arm +#define helper_frint64_s helper_frint64_s_arm #define helper_fscale helper_fscale_arm #define helper_fsincos helper_fsincos_arm #define helper_fsin helper_fsin_arm diff --git a/qemu/armeb.h b/qemu/armeb.h index 673fca51..c4be0631 100644 --- a/qemu/armeb.h +++ b/qemu/armeb.h @@ -1107,6 +1107,10 @@ #define helper_exception_with_syndrome helper_exception_with_syndrome_armeb #define helper_exit_atomic helper_exit_atomic_armeb #define helper_fcos helper_fcos_armeb +#define helper_frint32_d helper_frint32_d_armeb +#define helper_frint32_s helper_frint32_s_armeb +#define helper_frint64_d helper_frint64_d_armeb +#define helper_frint64_s helper_frint64_s_armeb #define helper_fscale helper_fscale_armeb #define helper_fsincos helper_fsincos_armeb #define helper_fsin helper_fsin_armeb diff --git a/qemu/header_gen.py b/qemu/header_gen.py index b073b9dc..15f1b4aa 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -1113,6 +1113,10 @@ symbols = ( 'helper_exception_with_syndrome', 'helper_exit_atomic', 'helper_fcos', + 'helper_frint32_d', + 'helper_frint32_s', + 'helper_frint64_d', + 'helper_frint64_s', 'helper_fscale', 'helper_fsincos', 'helper_fsin', diff --git a/qemu/m68k.h b/qemu/m68k.h index df416fd5..2b29d0a3 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -1107,6 +1107,10 @@ #define helper_exception_with_syndrome helper_exception_with_syndrome_m68k #define helper_exit_atomic helper_exit_atomic_m68k #define helper_fcos helper_fcos_m68k +#define helper_frint32_d helper_frint32_d_m68k +#define helper_frint32_s helper_frint32_s_m68k +#define helper_frint64_d helper_frint64_d_m68k +#define helper_frint64_s helper_frint64_s_m68k #define helper_fscale helper_fscale_m68k #define helper_fsincos helper_fsincos_m68k #define helper_fsin helper_fsin_m68k diff --git a/qemu/mips.h b/qemu/mips.h index b1b9f637..fed6c34f 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -1107,6 +1107,10 @@ #define helper_exception_with_syndrome helper_exception_with_syndrome_mips #define helper_exit_atomic helper_exit_atomic_mips #define helper_fcos helper_fcos_mips +#define helper_frint32_d helper_frint32_d_mips +#define helper_frint32_s helper_frint32_s_mips +#define helper_frint64_d helper_frint64_d_mips +#define helper_frint64_s helper_frint64_s_mips #define helper_fscale helper_fscale_mips #define helper_fsincos helper_fsincos_mips #define helper_fsin helper_fsin_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index dc69ee2b..273f6d84 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -1107,6 +1107,10 @@ #define helper_exception_with_syndrome helper_exception_with_syndrome_mips64 #define helper_exit_atomic helper_exit_atomic_mips64 #define helper_fcos helper_fcos_mips64 +#define helper_frint32_d helper_frint32_d_mips64 +#define helper_frint32_s helper_frint32_s_mips64 +#define helper_frint64_d helper_frint64_d_mips64 +#define helper_frint64_s helper_frint64_s_mips64 #define helper_fscale helper_fscale_mips64 #define helper_fsincos helper_fsincos_mips64 #define helper_fsin helper_fsin_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 84835476..529e8b75 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -1107,6 +1107,10 @@ #define helper_exception_with_syndrome helper_exception_with_syndrome_mips64el #define helper_exit_atomic helper_exit_atomic_mips64el #define helper_fcos helper_fcos_mips64el +#define helper_frint32_d helper_frint32_d_mips64el +#define helper_frint32_s helper_frint32_s_mips64el +#define helper_frint64_d helper_frint64_d_mips64el +#define helper_frint64_s helper_frint64_s_mips64el #define helper_fscale helper_fscale_mips64el #define helper_fsincos helper_fsincos_mips64el #define helper_fsin helper_fsin_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 967405b9..1816978b 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -1107,6 +1107,10 @@ #define helper_exception_with_syndrome helper_exception_with_syndrome_mipsel #define helper_exit_atomic helper_exit_atomic_mipsel #define helper_fcos helper_fcos_mipsel +#define helper_frint32_d helper_frint32_d_mipsel +#define helper_frint32_s helper_frint32_s_mipsel +#define helper_frint64_d helper_frint64_d_mipsel +#define helper_frint64_s helper_frint64_s_mipsel #define helper_fscale helper_fscale_mipsel #define helper_fsincos helper_fsincos_mipsel #define helper_fsin helper_fsin_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index ae74a823..ee5eb5bc 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -1107,6 +1107,10 @@ #define helper_exception_with_syndrome helper_exception_with_syndrome_powerpc #define helper_exit_atomic helper_exit_atomic_powerpc #define helper_fcos helper_fcos_powerpc +#define helper_frint32_d helper_frint32_d_powerpc +#define helper_frint32_s helper_frint32_s_powerpc +#define helper_frint64_d helper_frint64_d_powerpc +#define helper_frint64_s helper_frint64_s_powerpc #define helper_fscale helper_fscale_powerpc #define helper_fsincos helper_fsincos_powerpc #define helper_fsin helper_fsin_powerpc diff --git a/qemu/sparc.h b/qemu/sparc.h index 26513875..61724cfc 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -1107,6 +1107,10 @@ #define helper_exception_with_syndrome helper_exception_with_syndrome_sparc #define helper_exit_atomic helper_exit_atomic_sparc #define helper_fcos helper_fcos_sparc +#define helper_frint32_d helper_frint32_d_sparc +#define helper_frint32_s helper_frint32_s_sparc +#define helper_frint64_d helper_frint64_d_sparc +#define helper_frint64_s helper_frint64_s_sparc #define helper_fscale helper_fscale_sparc #define helper_fsincos helper_fsincos_sparc #define helper_fsin helper_fsin_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 838a2019..9cdf2191 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -1107,6 +1107,10 @@ #define helper_exception_with_syndrome helper_exception_with_syndrome_sparc64 #define helper_exit_atomic helper_exit_atomic_sparc64 #define helper_fcos helper_fcos_sparc64 +#define helper_frint32_d helper_frint32_d_sparc64 +#define helper_frint32_s helper_frint32_s_sparc64 +#define helper_frint64_d helper_frint64_d_sparc64 +#define helper_frint64_s helper_frint64_s_sparc64 #define helper_fscale helper_fscale_sparc64 #define helper_fsincos helper_fsincos_sparc64 #define helper_fsin helper_fsin_sparc64 diff --git a/qemu/target/arm/cpu.h b/qemu/target/arm/cpu.h index a04fe1fa..093a9dc9 100644 --- a/qemu/target/arm/cpu.h +++ b/qemu/target/arm/cpu.h @@ -3456,6 +3456,11 @@ static inline bool isar_feature_aa64_predinv(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SPECRES) != 0; } +static inline bool isar_feature_aa64_frint(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FRINTTS) != 0; +} + static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id) { /* We always set the AdvSIMD and FP fields identically wrt FP16. */ diff --git a/qemu/target/arm/cpu64.c b/qemu/target/arm/cpu64.c index 975d8d39..2ebd3ee8 100644 --- a/qemu/target/arm/cpu64.c +++ b/qemu/target/arm/cpu64.c @@ -266,6 +266,7 @@ static void aarch64_max_initfn(struct uc_struct *uc, Object *obj, void *opaque) t = FIELD_DP64(t, ID_AA64ISAR1, GPI, 0); t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); + t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); cpu->isar.id_aa64isar1 = t; t = cpu->isar.id_aa64pfr0; diff --git a/qemu/target/arm/helper.h b/qemu/target/arm/helper.h index 3a9db3d2..d4d10451 100644 --- a/qemu/target/arm/helper.h +++ b/qemu/target/arm/helper.h @@ -685,6 +685,11 @@ DEF_HELPER_FLAGS_5(gvec_fmlal_idx_a32, TCG_CALL_NO_RWG, DEF_HELPER_FLAGS_5(gvec_fmlal_idx_a64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_2(frint32_s, TCG_CALL_NO_RWG, f32, f32, ptr) +DEF_HELPER_FLAGS_2(frint64_s, TCG_CALL_NO_RWG, f32, f32, ptr) +DEF_HELPER_FLAGS_2(frint32_d, TCG_CALL_NO_RWG, f64, f64, ptr) +DEF_HELPER_FLAGS_2(frint64_d, TCG_CALL_NO_RWG, f64, f64, ptr) + #ifdef TARGET_ARM #define helper_clz helper_clz_arm #define gen_helper_clz gen_helper_clz_arm diff --git a/qemu/target/arm/translate-a64.c b/qemu/target/arm/translate-a64.c index 54affc83..fd222f20 100644 --- a/qemu/target/arm/translate-a64.c +++ b/qemu/target/arm/translate-a64.c @@ -5839,6 +5839,20 @@ static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn) case 0xf: /* FRINTI */ gen_fpst = gen_helper_rints; break; + case 0x10: /* FRINT32Z */ + rmode = float_round_to_zero; + gen_fpst = gen_helper_frint32_s; + break; + case 0x11: /* FRINT32X */ + gen_fpst = gen_helper_frint32_s; + break; + case 0x12: /* FRINT64Z */ + rmode = float_round_to_zero; + gen_fpst = gen_helper_frint64_s; + break; + case 0x13: /* FRINT64X */ + gen_fpst = gen_helper_frint64_s; + break; default: g_assert_not_reached(); } @@ -5903,6 +5917,20 @@ static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn) case 0xf: /* FRINTI */ gen_fpst = gen_helper_rintd; break; + case 0x10: /* FRINT32Z */ + rmode = float_round_to_zero; + gen_fpst = gen_helper_frint32_d; + break; + case 0x11: /* FRINT32X */ + gen_fpst = gen_helper_frint32_d; + break; + case 0x12: /* FRINT64Z */ + rmode = float_round_to_zero; + gen_fpst = gen_helper_frint64_d; + break; + case 0x13: /* FRINT64X */ + gen_fpst = gen_helper_frint64_d; + break; default: g_assert_not_reached(); } @@ -6041,6 +6069,13 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn) handle_fp_fcvt(s, opcode, rd, rn, dtype, type); break; } + case 0x10: case 0x11: case 0x12: case 0x13: /* FRINT{32,64}{X,Z} */ + if (type > 1 || !dc_isar_feature(aa64_frint, s)) { + unallocated_encoding(s); + return; + } + /* fall through */ + case 0x0: case 0x1: case 0x2: case 0x3: case 0x8: case 0x9: case 0xa: case 0xb: case 0xc: case 0xe: case 0xf: @@ -6050,14 +6085,12 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn) if (!fp_access_check(s)) { return; } - handle_fp_1src_single(s, opcode, rd, rn); break; case 1: if (!fp_access_check(s)) { return; } - handle_fp_1src_double(s, opcode, rd, rn); break; case 3: @@ -6069,13 +6102,13 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn) if (!fp_access_check(s)) { return; } - handle_fp_1src_half(s, opcode, rd, rn); break; default: unallocated_encoding(s); } break; + default: unallocated_encoding(s); break; @@ -9643,6 +9676,14 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, case 0x59: /* FRINTX */ gen_helper_rintd_exact(tcg_ctx, tcg_rd, tcg_rn, tcg_fpstatus); break; + case 0x1e: /* FRINT32Z */ + case 0x5e: /* FRINT32X */ + gen_helper_frint32_d(tcg_ctx, tcg_rd, tcg_rn, tcg_fpstatus); + break; + case 0x1f: /* FRINT64Z */ + case 0x5f: /* FRINT64X */ + gen_helper_frint64_d(tcg_ctx, tcg_rd, tcg_rn, tcg_fpstatus); + break; default: g_assert_not_reached(); } @@ -12462,6 +12503,19 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) } need_fpstatus = true; break; + case 0x1e: /* FRINT32Z */ + case 0x1f: /* FRINT64Z */ + need_rmode = true; + rmode = FPROUNDING_ZERO; + /* fall through */ + case 0x5e: /* FRINT32X */ + case 0x5f: /* FRINT64X */ + need_fpstatus = true; + if ((size == 3 && !is_q) || !dc_isar_feature(aa64_frint, s)) { + unallocated_encoding(s); + return; + } + break; default: unallocated_encoding(s); return; @@ -12627,6 +12681,14 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) case 0x7c: /* URSQRTE */ gen_helper_rsqrte_u32(tcg_ctx, tcg_res, tcg_op, tcg_fpstatus); break; + case 0x1e: /* FRINT32Z */ + case 0x5e: /* FRINT32X */ + gen_helper_frint32_s(tcg_ctx, tcg_res, tcg_op, tcg_fpstatus); + break; + case 0x1f: /* FRINT64Z */ + case 0x5f: /* FRINT64X */ + gen_helper_frint64_s(tcg_ctx, tcg_res, tcg_op, tcg_fpstatus); + break; default: g_assert_not_reached(); } diff --git a/qemu/target/arm/vfp_helper.c b/qemu/target/arm/vfp_helper.c index 2dc9283c..d36ceb51 100644 --- a/qemu/target/arm/vfp_helper.c +++ b/qemu/target/arm/vfp_helper.c @@ -1176,3 +1176,99 @@ uint32_t HELPER(vjcvt)(float64 value, CPUARMState *env) return result; } + +/* Round a float32 to an integer that fits in int32_t or int64_t. */ +static float32 frint_s(float32 f, float_status *fpst, int intsize) +{ + int old_flags = get_float_exception_flags(fpst); + uint32_t exp = extract32(f, 23, 8); + + if (unlikely(exp == 0xff)) { + /* NaN or Inf. */ + goto overflow; + } + + /* Round and re-extract the exponent. */ + f = float32_round_to_int(f, fpst); + exp = extract32(f, 23, 8); + + /* Validate the range of the result. */ + if (exp < 126 + intsize) { + /* abs(F) <= INT{N}_MAX */ + return f; + } + if (exp == 126 + intsize) { + uint32_t sign = extract32(f, 31, 1); + uint32_t frac = extract32(f, 0, 23); + if (sign && frac == 0) { + /* F == INT{N}_MIN */ + return f; + } + } + + overflow: + /* + * Raise Invalid and return INT{N}_MIN as a float. Revert any + * inexact exception float32_round_to_int may have raised. + */ + set_float_exception_flags(old_flags | float_flag_invalid, fpst); + return (0x100u + 126u + intsize) << 23; +} + +float32 HELPER(frint32_s)(float32 f, void *fpst) +{ + return frint_s(f, fpst, 32); +} + +float32 HELPER(frint64_s)(float32 f, void *fpst) +{ + return frint_s(f, fpst, 64); +} + +/* Round a float64 to an integer that fits in int32_t or int64_t. */ +static float64 frint_d(float64 f, float_status *fpst, int intsize) +{ + int old_flags = get_float_exception_flags(fpst); + uint32_t exp = extract64(f, 52, 11); + + if (unlikely(exp == 0x7ff)) { + /* NaN or Inf. */ + goto overflow; + } + + /* Round and re-extract the exponent. */ + f = float64_round_to_int(f, fpst); + exp = extract64(f, 52, 11); + + /* Validate the range of the result. */ + if (exp < 1022 + intsize) { + /* abs(F) <= INT{N}_MAX */ + return f; + } + if (exp == 1022 + intsize) { + uint64_t sign = extract64(f, 63, 1); + uint64_t frac = extract64(f, 0, 52); + if (sign && frac == 0) { + /* F == INT{N}_MIN */ + return f; + } + } + + overflow: + /* + * Raise Invalid and return INT{N}_MIN as a float. Revert any + * inexact exception float64_round_to_int may have raised. + */ + set_float_exception_flags(old_flags | float_flag_invalid, fpst); + return (uint64_t)(0x800 + 1022 + intsize) << 52; +} + +float64 HELPER(frint32_d)(float64 f, void *fpst) +{ + return frint_d(f, fpst, 32); +} + +float64 HELPER(frint64_d)(float64 f, void *fpst) +{ + return frint_d(f, fpst, 64); +} diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 982d403c..40ee4dcf 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -1107,6 +1107,10 @@ #define helper_exception_with_syndrome helper_exception_with_syndrome_x86_64 #define helper_exit_atomic helper_exit_atomic_x86_64 #define helper_fcos helper_fcos_x86_64 +#define helper_frint32_d helper_frint32_d_x86_64 +#define helper_frint32_s helper_frint32_s_x86_64 +#define helper_frint64_d helper_frint64_d_x86_64 +#define helper_frint64_s helper_frint64_s_x86_64 #define helper_fscale helper_fscale_x86_64 #define helper_fsincos helper_fsincos_x86_64 #define helper_fsin helper_fsin_x86_64