arm/translate-a64: add FP16 FPRINTx to simd_two_reg_misc_fp16

This adds the full range of half-precision floating point to integral
instructions.

Backports commit 6109aea2d954891027acba64a13f1f1c7463cfac from qemu
This commit is contained in:
Alex Bennée 2018-03-08 18:20:37 -05:00 committed by Lioncash
parent 33eda0f5d4
commit d5f002b39a
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
6 changed files with 148 additions and 5 deletions

View file

@ -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

View file

@ -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

View file

@ -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',

View file

@ -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;
}

View file

@ -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)

View file

@ -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