From 39a68548d13caacbafa15d26a3c578d1487b0fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 8 Mar 2018 18:24:36 -0500 Subject: [PATCH] arm/translate-a64: add FCVTxx to simd_two_reg_misc_fp16 This covers all the floating point convert operations. Backports commit 2df581304193d70eaf0d22cf4cb4613f74b6e59b from qemu --- qemu/aarch64.h | 2 + qemu/aarch64eb.h | 2 + qemu/header_gen.py | 2 + qemu/target/arm/helper-a64.c | 32 +++++++++++++ qemu/target/arm/helper-a64.h | 3 ++ qemu/target/arm/translate-a64.c | 85 ++++++++++++++++++++++++++++++++- 6 files changed, 125 insertions(+), 1 deletion(-) diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 12400840..14ddb556 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -3729,6 +3729,8 @@ #define helper_advsimd_cgt_f16 helper_advsimd_cgt_f16_aarch64 #define helper_advsimd_div2h helper_advsimd_div2h_aarch64 #define helper_advsimd_divh helper_advsimd_divh_aarch64 +#define helper_advsimd_f16tosinth helper_advsimd_f16tosinth_aarch64 +#define helper_advsimd_f16touinth helper_advsimd_f16touinth_aarch64 #define helper_advsimd_max2h helper_advsimd_max2h_aarch64 #define helper_advsimd_maxh helper_advsimd_maxh_aarch64 #define helper_advsimd_maxnum2h helper_advsimd_maxnum2h_aarch64 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index e6359398..40394c37 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -3729,6 +3729,8 @@ #define helper_advsimd_cgt_f16 helper_advsimd_cgt_f16_aarch64eb #define helper_advsimd_div2h helper_advsimd_div2h_aarch64eb #define helper_advsimd_divh helper_advsimd_divh_aarch64eb +#define helper_advsimd_f16tosinth helper_advsimd_f16tosinth_aarch64eb +#define helper_advsimd_f16touinth helper_advsimd_f16touinth_aarch64eb #define helper_advsimd_max2h helper_advsimd_max2h_aarch64eb #define helper_advsimd_maxh helper_advsimd_maxh_aarch64eb #define helper_advsimd_maxnum2h helper_advsimd_maxnum2h_aarch64eb diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 9753ece5..b328cacd 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -3749,6 +3749,8 @@ aarch64_symbols = ( 'helper_advsimd_cgt_f16', 'helper_advsimd_div2h', 'helper_advsimd_divh', + 'helper_advsimd_f16tosinth', + 'helper_advsimd_f16touinth', 'helper_advsimd_max2h', 'helper_advsimd_maxh', 'helper_advsimd_maxnum2h', diff --git a/qemu/target/arm/helper-a64.c b/qemu/target/arm/helper-a64.c index b3d99fab..5e918f02 100644 --- a/qemu/target/arm/helper-a64.c +++ b/qemu/target/arm/helper-a64.c @@ -813,3 +813,35 @@ float16 HELPER(advsimd_rinth)(float16 x, void *fp_status) return ret; } + +/* + * Half-precision floating point conversion functions + * + * There are a multitude of conversion functions with various + * different rounding modes. This is dealt with by the calling code + * setting the mode appropriately before calling the helper. + */ + +uint32_t HELPER(advsimd_f16tosinth)(float16 a, void *fpstp) +{ + float_status *fpst = fpstp; + + /* Invalid if we are passed a NaN */ + if (float16_is_any_nan(a)) { + float_raise(float_flag_invalid, fpst); + return 0; + } + return float16_to_int16(a, fpst); +} + +uint32_t HELPER(advsimd_f16touinth)(float16 a, void *fpstp) +{ + float_status *fpst = fpstp; + + /* Invalid if we are passed a NaN */ + if (float16_is_any_nan(a)) { + float_raise(float_flag_invalid, fpst); + return 0; + } + return float16_to_uint16(a, fpst); +} diff --git a/qemu/target/arm/helper-a64.h b/qemu/target/arm/helper-a64.h index 4af4077c..00cd5b2c 100644 --- a/qemu/target/arm/helper-a64.h +++ b/qemu/target/arm/helper-a64.h @@ -73,3 +73,6 @@ DEF_HELPER_3(advsimd_mulx2h, i32, i32, i32, ptr) DEF_HELPER_4(advsimd_muladd2h, i32, i32, i32, i32, ptr) DEF_HELPER_2(advsimd_rinth_exact, f16, f16, ptr) DEF_HELPER_2(advsimd_rinth, f16, f16, ptr) +DEF_HELPER_2(advsimd_f16tosinth, i32, f16, ptr) +DEF_HELPER_2(advsimd_f16touinth, i32, f16, ptr) + diff --git a/qemu/target/arm/translate-a64.c b/qemu/target/arm/translate-a64.c index 666bddd3..1cf59571 100644 --- a/qemu/target/arm/translate-a64.c +++ b/qemu/target/arm/translate-a64.c @@ -11397,6 +11397,46 @@ static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn) only_in_vector = true; /* current rounding mode */ break; + case 0x1a: /* FCVTNS */ + need_rmode = true; + rmode = FPROUNDING_TIEEVEN; + break; + case 0x1b: /* FCVTMS */ + need_rmode = true; + rmode = FPROUNDING_NEGINF; + break; + case 0x1c: /* FCVTAS */ + need_rmode = true; + rmode = FPROUNDING_TIEAWAY; + break; + case 0x3a: /* FCVTPS */ + need_rmode = true; + rmode = FPROUNDING_POSINF; + break; + case 0x3b: /* FCVTZS */ + need_rmode = true; + rmode = FPROUNDING_ZERO; + break; + case 0x5a: /* FCVTNU */ + need_rmode = true; + rmode = FPROUNDING_TIEEVEN; + break; + case 0x5b: /* FCVTMU */ + need_rmode = true; + rmode = FPROUNDING_NEGINF; + break; + case 0x5c: /* FCVTAU */ + need_rmode = true; + rmode = FPROUNDING_TIEAWAY; + break; + case 0x7a: /* FCVTPU */ + need_rmode = true; + rmode = FPROUNDING_POSINF; + break; + case 0x7b: /* FCVTZU */ + need_rmode = true; + rmode = FPROUNDING_ZERO; + break; default: fprintf(stderr, "%s: insn %#04x fpop %#2x\n", __func__, insn, fpop); g_assert_not_reached(); @@ -11429,7 +11469,36 @@ static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn) } if (is_scalar) { - /* no operations yet */ + TCGv_i32 tcg_op = tcg_temp_new_i32(tcg_ctx); + TCGv_i32 tcg_res = tcg_temp_new_i32(tcg_ctx); + + read_vec_element_i32(s, tcg_op, rn, 0, MO_16); + + switch (fpop) { + case 0x1a: /* FCVTNS */ + case 0x1b: /* FCVTMS */ + case 0x1c: /* FCVTAS */ + case 0x3a: /* FCVTPS */ + case 0x3b: /* FCVTZS */ + gen_helper_advsimd_f16tosinth(tcg_ctx, tcg_res, tcg_op, tcg_fpstatus); + break; + case 0x5a: /* FCVTNU */ + case 0x5b: /* FCVTMU */ + case 0x5c: /* FCVTAU */ + case 0x7a: /* FCVTPU */ + case 0x7b: /* FCVTZU */ + gen_helper_advsimd_f16touinth(tcg_ctx, tcg_res, tcg_op, tcg_fpstatus); + break; + default: + g_assert_not_reached(); + } + + /* limit any sign extension going on */ + tcg_gen_andi_i32(tcg_ctx, tcg_res, tcg_res, 0xffff); + write_fp_sreg(s, rd, tcg_res); + + tcg_temp_free_i32(tcg_ctx, tcg_res); + tcg_temp_free_i32(tcg_ctx, tcg_op); } else { for (pass = 0; pass < (is_q ? 8 : 4); pass++) { TCGv_i32 tcg_op = tcg_temp_new_i32(tcg_ctx); @@ -11438,6 +11507,20 @@ static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn) read_vec_element_i32(s, tcg_op, rn, pass, MO_16); switch (fpop) { + case 0x1a: /* FCVTNS */ + case 0x1b: /* FCVTMS */ + case 0x1c: /* FCVTAS */ + case 0x3a: /* FCVTPS */ + case 0x3b: /* FCVTZS */ + gen_helper_advsimd_f16tosinth(tcg_ctx, tcg_res, tcg_op, tcg_fpstatus); + break; + case 0x5a: /* FCVTNU */ + case 0x5b: /* FCVTMU */ + case 0x5c: /* FCVTAU */ + case 0x7a: /* FCVTPU */ + case 0x7b: /* FCVTZU */ + gen_helper_advsimd_f16touinth(tcg_ctx, tcg_res, tcg_op, tcg_fpstatus); + break; case 0x18: /* FRINTN */ case 0x19: /* FRINTM */ case 0x38: /* FRINTP */