mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-03-23 05:25:11 +00:00
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:
parent
f6c67559d4
commit
1a0d31c05e
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue