target/arm: Convert float-to-integer VCVT insns to decodetree

Convert the float-to-integer VCVT instructions to decodetree.
Since these are the last unconverted instructions, we can
delete the old decoder structure entirely now.

Backports commit 3111bfc2da6ba0c8396dc97ca479942d711c6146 from qemu
This commit is contained in:
Peter Maydell 2019-06-13 19:39:58 -04:00 committed by Lioncash
parent f6c67559d4
commit 1a0d31c05e
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
3 changed files with 82 additions and 241 deletions

View file

@ -2622,3 +2622,77 @@ static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a)
tcg_temp_free_ptr(tcg_ctx, fpst);
return true;
}
static bool trans_VCVT_sp_int(DisasContext *s, arg_VCVT_sp_int *a)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv_i32 vm;
TCGv_ptr fpst;
if (!vfp_access_check(s)) {
return true;
}
fpst = get_fpstatus_ptr(s, false);
vm = tcg_temp_new_i32(tcg_ctx);
neon_load_reg32(s, vm, a->vm);
if (a->s) {
if (a->rz) {
gen_helper_vfp_tosizs(tcg_ctx, vm, vm, fpst);
} else {
gen_helper_vfp_tosis(tcg_ctx, vm, vm, fpst);
}
} else {
if (a->rz) {
gen_helper_vfp_touizs(tcg_ctx, vm, vm, fpst);
} else {
gen_helper_vfp_touis(tcg_ctx, vm, vm, fpst);
}
}
neon_store_reg32(s, vm, a->vd);
tcg_temp_free_i32(tcg_ctx, vm);
tcg_temp_free_ptr(tcg_ctx, fpst);
return true;
}
static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv_i32 vd;
TCGv_i64 vm;
TCGv_ptr fpst;
/* UNDEF accesses to D16-D31 if they don't exist. */
if (!dc_isar_feature(aa32_fp_d32, s) && (a->vm & 0x10)) {
return false;
}
if (!vfp_access_check(s)) {
return true;
}
fpst = get_fpstatus_ptr(s, false);
vm = tcg_temp_new_i64(tcg_ctx);
vd = tcg_temp_new_i32(tcg_ctx);
neon_load_reg64(s, vm, a->vm);
if (a->s) {
if (a->rz) {
gen_helper_vfp_tosizd(tcg_ctx, vd, vm, fpst);
} else {
gen_helper_vfp_tosid(tcg_ctx, vd, vm, fpst);
}
} else {
if (a->rz) {
gen_helper_vfp_touizd(tcg_ctx, vd, vm, fpst);
} else {
gen_helper_vfp_touid(tcg_ctx, vd, vm, fpst);
}
}
neon_store_reg32(s, vd, a->vd);
tcg_temp_free_i32(tcg_ctx, vd);
tcg_temp_free_i64(tcg_ctx, vm);
tcg_temp_free_ptr(tcg_ctx, fpst);
return true;
}

View file

@ -1477,9 +1477,7 @@ static inline void gen_vfp_##name(DisasContext *s, int dp, int neon) \
tcg_temp_free_ptr(tcg_ctx, statusptr); \
}
VFP_GEN_FTOI(toui)
VFP_GEN_FTOI(touiz)
VFP_GEN_FTOI(tosi)
VFP_GEN_FTOI(tosiz)
#undef VFP_GEN_FTOI
@ -1683,36 +1681,7 @@ static TCGv_ptr vfp_reg_ptr(DisasContext *s, bool dp, int reg)
}
#define tcg_gen_ld_f32 tcg_gen_ld_i32
#define tcg_gen_ld_f64 tcg_gen_ld_i64
#define tcg_gen_st_f32 tcg_gen_st_i32
#define tcg_gen_st_f64 tcg_gen_st_i64
static inline void gen_mov_F0_vreg(DisasContext *s, int dp, int reg)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
if (dp)
tcg_gen_ld_f64(tcg_ctx, s->F0d, tcg_ctx->cpu_env, vfp_reg_offset(dp, reg));
else
tcg_gen_ld_f32(tcg_ctx, s->F0s, tcg_ctx->cpu_env, vfp_reg_offset(dp, reg));
}
static inline void gen_mov_F1_vreg(DisasContext *s, int dp, int reg)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
if (dp)
tcg_gen_ld_f64(tcg_ctx, s->F1d, tcg_ctx->cpu_env, vfp_reg_offset(dp, reg));
else
tcg_gen_ld_f32(tcg_ctx, s->F1s, tcg_ctx->cpu_env, vfp_reg_offset(dp, reg));
}
static inline void gen_mov_vreg_F0(DisasContext *s, int dp, int reg)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
if (dp)
tcg_gen_st_f64(tcg_ctx, s->F0d, tcg_ctx->cpu_env, vfp_reg_offset(dp, reg));
else
tcg_gen_st_f32(tcg_ctx, s->F0s, tcg_ctx->cpu_env, vfp_reg_offset(dp, reg));
}
#define ARM_CP_RW_BIT (1 << 20)
@ -3077,9 +3046,6 @@ static void gen_neon_dup_high16(DisasContext *s, TCGv_i32 var)
*/
static int disas_vfp_insn(DisasContext *s, uint32_t insn)
{
uint32_t rd, rn, rm, op, delta_d, delta_m, bank_mask;
int dp, veclen;
if (!arm_dc_feature(s, ARM_FEATURE_VFP)) {
return 1;
}
@ -3100,213 +3066,8 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
}
}
if (extract32(insn, 28, 4) == 0xf) {
/*
* Encodings with T=1 (Thumb) or unconditional (ARM): these
* were all handled by the decodetree decoder, so any insn
* patterns which get here must be UNDEF.
*/
return 1;
}
/*
* FIXME: this access check should not take precedence over UNDEF
* for invalid encodings; we will generate incorrect syndrome information
* for attempts to execute invalid vfp/neon encodings with FP disabled.
*/
if (!vfp_access_check(s)) {
return 0;
}
dp = ((insn & 0xf00) == 0xb00);
switch ((insn >> 24) & 0xf) {
case 0xe:
if (insn & (1 << 4)) {
/* already handled by decodetree */
return 1;
} else {
/* data processing */
bool rd_is_dp = dp;
bool rm_is_dp = dp;
bool no_output = false;
/* The opcode is in bits 23, 21, 20 and 6. */
op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
rn = VFP_SREG_N(insn);
switch (op) {
case 0 ... 14:
/* Already handled by decodetree */
return 1;
case 15:
switch (rn) {
case 0 ... 23:
case 28 ... 31:
/* Already handled by decodetree */
return 1;
default:
break;
}
default:
break;
}
if (op == 15) {
/* rn is opcode, encoded as per VFP_SREG_N. */
switch (rn) {
case 0x18: /* vcvtr.u32.fxx */
case 0x19: /* vcvtz.u32.fxx */
case 0x1a: /* vcvtr.s32.fxx */
case 0x1b: /* vcvtz.s32.fxx */
rd_is_dp = false;
break;
default:
return 1;
}
} else if (dp) {
/* rn is register number */
VFP_DREG_N(rn, insn);
}
if (rd_is_dp) {
VFP_DREG_D(rd, insn);
} else {
rd = VFP_SREG_D(insn);
}
if (rm_is_dp) {
VFP_DREG_M(rm, insn);
} else {
rm = VFP_SREG_M(insn);
}
veclen = s->vec_len;
if (op == 15 && rn > 3) {
veclen = 0;
}
/* Shut up compiler warnings. */
delta_m = 0;
delta_d = 0;
bank_mask = 0;
if (veclen > 0) {
if (dp)
bank_mask = 0xc;
else
bank_mask = 0x18;
/* Figure out what type of vector operation this is. */
if ((rd & bank_mask) == 0) {
/* scalar */
veclen = 0;
} else {
if (dp)
delta_d = (s->vec_stride >> 1) + 1;
else
delta_d = s->vec_stride + 1;
if ((rm & bank_mask) == 0) {
/* mixed scalar/vector */
delta_m = 0;
} else {
/* vector */
delta_m = delta_d;
}
}
}
/* Load the initial operands. */
if (op == 15) {
switch (rn) {
default:
/* One source operand. */
gen_mov_F0_vreg(s, rm_is_dp, rm);
break;
}
} else {
/* Two source operands. */
gen_mov_F0_vreg(s, dp, rn);
gen_mov_F1_vreg(s, dp, rm);
}
for (;;) {
/* Perform the calculation. */
switch (op) {
case 15: /* extension space */
switch (rn) {
case 24: /* ftoui */
gen_vfp_toui(s, dp, 0);
break;
case 25: /* ftouiz */
gen_vfp_touiz(s, dp, 0);
break;
case 26: /* ftosi */
gen_vfp_tosi(s, dp, 0);
break;
case 27: /* ftosiz */
gen_vfp_tosiz(s, dp, 0);
break;
default: /* undefined */
g_assert_not_reached();
}
break;
default: /* undefined */
return 1;
}
/* Write back the result, if any. */
if (!no_output) {
gen_mov_vreg_F0(s, rd_is_dp, rd);
}
/* break out of the loop if we have finished */
if (veclen == 0) {
break;
}
if (op == 15 && delta_m == 0) {
/* single source one-many */
while (veclen--) {
rd = ((rd + delta_d) & (bank_mask - 1))
| (rd & bank_mask);
gen_mov_vreg_F0(s, dp, rd);
}
break;
}
/* Setup the next operands. */
veclen--;
rd = ((rd + delta_d) & (bank_mask - 1))
| (rd & bank_mask);
if (op == 15) {
/* One source operand. */
rm = ((rm + delta_m) & (bank_mask - 1))
| (rm & bank_mask);
gen_mov_F0_vreg(s, dp, rm);
} else {
/* Two source operands. */
rn = ((rn + delta_d) & (bank_mask - 1))
| (rn & bank_mask);
gen_mov_F0_vreg(s, dp, rn);
if (delta_m) {
rm = ((rm + delta_m) & (bank_mask - 1))
| (rm & bank_mask);
gen_mov_F1_vreg(s, dp, rm);
}
}
}
}
break;
case 0xc:
case 0xd:
/* Already handled by decodetree */
return 1;
default:
/* Should never happen. */
return 1;
}
return 0;
/* If the decodetree decoder didn't handle this insn, it must be UNDEF */
return 1;
}
static inline bool use_goto_tb(DisasContext *s, target_ulong dest)

View file

@ -234,3 +234,9 @@ VCVT_fix_sp ---- 1110 1.11 1.1. .... 1010 .1.0 .... \
vd=%vd_sp imm=%vm_sp opc=%vcvt_fix_op
VCVT_fix_dp ---- 1110 1.11 1.1. .... 1011 .1.0 .... \
vd=%vd_dp imm=%vm_sp opc=%vcvt_fix_op
# VCVT float to integer (VCVT and VCVTR): Vd always single; Vd depends on size
VCVT_sp_int ---- 1110 1.11 110 s:1 .... 1010 rz:1 1.0 .... \
vd=%vd_sp vm=%vm_sp
VCVT_dp_int ---- 1110 1.11 110 s:1 .... 1011 rz:1 1.0 .... \
vd=%vd_sp vm=%vm_dp