target/arm: Implement vector shifted FCVT for fp16

While we have some of the scalar paths for FCVT for fp16,
we failed to decode the fp16 version of these instructions.

Backports commit d0ba8e74acd299b092786ffc30b306638d395a9e from qemu
This commit is contained in:
Richard Henderson 2018-05-14 08:34:37 -04:00 committed by Lioncash
parent ad6c191d96
commit e403957a5e
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -7571,19 +7571,28 @@ static void handle_simd_shift_fpint_conv(DisasContext *s, bool is_scalar,
int immh, int immb, int rn, int rd)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
bool is_double = extract32(immh, 3, 1);
int immhb = immh << 3 | immb;
int fracbits = (is_double ? 128 : 64) - immhb;
int pass;
int pass, size, fracbits;
TCGv_ptr tcg_fpstatus;
TCGv_i32 tcg_rmode, tcg_shift;
if (!extract32(immh, 2, 2)) {
unallocated_encoding(s);
return;
}
if (!is_scalar && !is_q && is_double) {
if (immh & 0x8) {
size = MO_64;
if (!is_scalar && !is_q) {
unallocated_encoding(s);
return;
}
} else if (immh & 0x4) {
size = MO_32;
} else if (immh & 0x2) {
size = MO_16;
if (!arm_dc_feature(s, ARM_FEATURE_V8_FP16)) {
unallocated_encoding(s);
return;
}
} else {
/* Should have split out AdvSIMD modified immediate earlier. */
assert(immh == 1);
unallocated_encoding(s);
return;
}
@ -7595,11 +7604,12 @@ static void handle_simd_shift_fpint_conv(DisasContext *s, bool is_scalar,
assert(!(is_scalar && is_q));
tcg_rmode = tcg_const_i32(tcg_ctx, arm_rmode_to_sf(FPROUNDING_ZERO));
tcg_fpstatus = get_fpstatus_ptr(tcg_ctx, false);
tcg_fpstatus = get_fpstatus_ptr(tcg_ctx, size == MO_16);
gen_helper_set_rmode(tcg_ctx, tcg_rmode, tcg_rmode, tcg_fpstatus);
fracbits = (16 << size) - immhb;
tcg_shift = tcg_const_i32(tcg_ctx, fracbits);
if (is_double) {
if (size == MO_64) {
int maxpass = is_scalar ? 1 : 2;
for (pass = 0; pass < maxpass; pass++) {
@ -7616,20 +7626,37 @@ static void handle_simd_shift_fpint_conv(DisasContext *s, bool is_scalar,
}
clear_vec_high(s, is_q, rd);
} else {
int maxpass = is_scalar ? 1 : is_q ? 4 : 2;
void (*fn)(TCGContext *, TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
int maxpass = is_scalar ? 1 : ((8 << is_q) >> size);
switch (size) {
case MO_16:
if (is_u) {
fn = gen_helper_vfp_toulh;
} else {
fn = gen_helper_vfp_toslh;
}
break;
case MO_32:
if (is_u) {
fn = gen_helper_vfp_touls;
} else {
fn = gen_helper_vfp_tosls;
}
break;
default:
g_assert_not_reached();
}
for (pass = 0; pass < maxpass; pass++) {
TCGv_i32 tcg_op = tcg_temp_new_i32(tcg_ctx);
read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
if (is_u) {
gen_helper_vfp_touls(tcg_ctx, tcg_op, tcg_op, tcg_shift, tcg_fpstatus);
} else {
gen_helper_vfp_tosls(tcg_ctx, tcg_op, tcg_op, tcg_shift, tcg_fpstatus);
}
read_vec_element_i32(s, tcg_op, rn, pass, size);
fn(tcg_ctx, tcg_op, tcg_op, tcg_shift, tcg_fpstatus);
if (is_scalar) {
write_fp_sreg(s, rd, tcg_op);
} else {
write_vec_element_i32(s, tcg_op, rd, pass, MO_32);
write_vec_element_i32(s, tcg_op, rd, pass, size);
}
tcg_temp_free_i32(tcg_ctx, tcg_op);
}