diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 4acbea3b..12400840 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -3743,6 +3743,8 @@ #define helper_advsimd_mulh helper_advsimd_mulh_aarch64 #define helper_advsimd_mulx2h helper_advsimd_mulx2h_aarch64 #define helper_advsimd_mulxh helper_advsimd_mulxh_aarch64 +#define helper_advsimd_rinth helper_advsimd_rinth_aarch64 +#define helper_advsimd_rinth_exact helper_advsimd_rinth_exact_aarch64 #define helper_advsimd_sub2h helper_advsimd_sub2h_aarch64 #define helper_advsimd_subh helper_advsimd_subh_aarch64 #define helper_crc32_64 helper_crc32_64_aarch64 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index 5ed09652..e6359398 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -3743,6 +3743,8 @@ #define helper_advsimd_mulh helper_advsimd_mulh_aarch64eb #define helper_advsimd_mulx2h helper_advsimd_mulx2h_aarch64eb #define helper_advsimd_mulxh helper_advsimd_mulxh_aarch64eb +#define helper_advsimd_rinth helper_advsimd_rinth_aarch64eb +#define helper_advsimd_rinth_exact helper_advsimd_rinth_exact_aarch64eb #define helper_advsimd_sub2h helper_advsimd_sub2h_aarch64eb #define helper_advsimd_subh helper_advsimd_subh_aarch64eb #define helper_crc32_64 helper_crc32_64_aarch64eb diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 46869e18..9753ece5 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -3763,6 +3763,8 @@ aarch64_symbols = ( 'helper_advsimd_mulh', 'helper_advsimd_mulx2h', 'helper_advsimd_mulxh', + 'helper_advsimd_rinth', + 'helper_advsimd_rinth_exact', 'helper_advsimd_sub2h', 'helper_advsimd_subh', 'helper_crc32_64', diff --git a/qemu/target/arm/helper-a64.c b/qemu/target/arm/helper-a64.c index 1754683c..b3d99fab 100644 --- a/qemu/target/arm/helper-a64.c +++ b/qemu/target/arm/helper-a64.c @@ -791,3 +791,25 @@ uint32_t HELPER(advsimd_acgt_f16)(float16 a, float16 b, void *fpstp) int compare = float16_compare(f0, f1, fpst); return ADVSIMD_CMPRES(compare == float_relation_greater); } + +/* round to integral */ +float16 HELPER(advsimd_rinth_exact)(float16 x, void *fp_status) +{ + return float16_round_to_int(x, fp_status); +} + +float16 HELPER(advsimd_rinth)(float16 x, void *fp_status) +{ + int old_flags = get_float_exception_flags(fp_status), new_flags; + float16 ret; + + ret = float16_round_to_int(x, fp_status); + + /* Suppress any inexact exceptions the conversion produced */ + if (!(old_flags & float_flag_inexact)) { + new_flags = get_float_exception_flags(fp_status); + set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status); + } + + return ret; +} diff --git a/qemu/target/arm/helper-a64.h b/qemu/target/arm/helper-a64.h index 8d3ea6b0..4af4077c 100644 --- a/qemu/target/arm/helper-a64.h +++ b/qemu/target/arm/helper-a64.h @@ -71,3 +71,5 @@ DEF_HELPER_3(advsimd_maxnum2h, i32, i32, i32, ptr) DEF_HELPER_3(advsimd_minnum2h, i32, i32, i32, ptr) 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) diff --git a/qemu/target/arm/translate-a64.c b/qemu/target/arm/translate-a64.c index dc8997d0..666bddd3 100644 --- a/qemu/target/arm/translate-a64.c +++ b/qemu/target/arm/translate-a64.c @@ -11336,27 +11336,140 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) */ static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn) { - int fpop, opcode, a; + TCGContext *tcg_ctx = s->uc->tcg_ctx; + int fpop, opcode, a, u; + int rn, rd; + bool is_q; + bool is_scalar; + bool only_in_vector = false; + + int pass; + TCGv_i32 tcg_rmode = NULL; + TCGv_ptr tcg_fpstatus = NULL; + bool need_rmode = false; + int rmode; if (!arm_dc_feature(s, ARM_FEATURE_V8_FP16)) { unallocated_encoding(s); return; } - if (!fp_access_check(s)) { - return; - } + rd = extract32(insn, 0, 5); + rn = extract32(insn, 5, 5); - opcode = extract32(insn, 12, 4); a = extract32(insn, 23, 1); + u = extract32(insn, 29, 1); + is_scalar = extract32(insn, 28, 1); + is_q = extract32(insn, 30, 1); + + opcode = extract32(insn, 12, 5); fpop = deposit32(opcode, 5, 1, a); + fpop = deposit32(fpop, 6, 1, u); switch (fpop) { + case 0x18: /* FRINTN */ + need_rmode = true; + only_in_vector = true; + rmode = FPROUNDING_TIEEVEN; + break; + case 0x19: /* FRINTM */ + need_rmode = true; + only_in_vector = true; + rmode = FPROUNDING_NEGINF; + break; + case 0x38: /* FRINTP */ + need_rmode = true; + only_in_vector = true; + rmode = FPROUNDING_POSINF; + break; + case 0x39: /* FRINTZ */ + need_rmode = true; + only_in_vector = true; + rmode = FPROUNDING_ZERO; + break; + case 0x58: /* FRINTA */ + need_rmode = true; + only_in_vector = true; + rmode = FPROUNDING_TIEAWAY; + break; + case 0x59: /* FRINTX */ + case 0x79: /* FRINTI */ + only_in_vector = true; + /* current rounding mode */ + break; default: fprintf(stderr, "%s: insn %#04x fpop %#2x\n", __func__, insn, fpop); g_assert_not_reached(); } + /* Check additional constraints for the scalar encoding */ + if (is_scalar) { + if (!is_q) { + unallocated_encoding(s); + return; + } + /* FRINTxx is only in the vector form */ + if (only_in_vector) { + unallocated_encoding(s); + return; + } + } + + if (!fp_access_check(s)) { + return; + } + + if (need_rmode) { + tcg_fpstatus = get_fpstatus_ptr(tcg_ctx, true); + } + + if (need_rmode) { + tcg_rmode = tcg_const_i32(tcg_ctx, arm_rmode_to_sf(rmode)); + gen_helper_set_rmode(tcg_ctx, tcg_rmode, tcg_rmode, tcg_fpstatus); + } + + if (is_scalar) { + /* no operations yet */ + } else { + for (pass = 0; pass < (is_q ? 8 : 4); pass++) { + 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, pass, MO_16); + + switch (fpop) { + case 0x18: /* FRINTN */ + case 0x19: /* FRINTM */ + case 0x38: /* FRINTP */ + case 0x39: /* FRINTZ */ + case 0x58: /* FRINTA */ + case 0x79: /* FRINTI */ + gen_helper_advsimd_rinth(tcg_ctx, tcg_res, tcg_op, tcg_fpstatus); + break; + case 0x59: /* FRINTX */ + gen_helper_advsimd_rinth_exact(tcg_ctx, tcg_res, tcg_op, tcg_fpstatus); + break; + default: + g_assert_not_reached(); + } + + write_vec_element_i32(s, tcg_res, rd, pass, MO_16); + + tcg_temp_free_i32(tcg_ctx, tcg_res); + tcg_temp_free_i32(tcg_ctx, tcg_op); + } + + clear_vec_high(s, is_q, rd); + } + + if (tcg_rmode) { + gen_helper_set_rmode(tcg_ctx, tcg_rmode, tcg_rmode, tcg_fpstatus); + tcg_temp_free_i32(tcg_ctx, tcg_rmode); + } + + if (tcg_fpstatus) { + tcg_temp_free_ptr(tcg_ctx, tcg_fpstatus); + } } /* AdvSIMD scalar x indexed element