From e6cc2616d27b6f2a9ba865bd3cd6142e71f7cdd2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 13 Jun 2019 18:54:16 -0400 Subject: [PATCH] target/arm: Convert VFP comparison insns to decodetree Convert the VFP comparison instructions to decodetree. Note that comparison instructions should not honour the VFP short-vector length and stride information: they are scalar-only operations. This applies to all the 2-operand instructions except for VMOV, VABS, VNEG and VSQRT. (In the old decoder this is implemented via the "if (op == 15 && rn > 3) { veclen = 0; }" check.) Backports commit 386bba2368842fc74388a3c1651c6c0c0c70adbd from qemu --- qemu/target/arm/translate-vfp.inc.c | 77 +++++++++++++++++++++++++++++ qemu/target/arm/translate.c | 54 +------------------- qemu/target/arm/vfp.decode | 5 ++ 3 files changed, 83 insertions(+), 53 deletions(-) diff --git a/qemu/target/arm/translate-vfp.inc.c b/qemu/target/arm/translate-vfp.inc.c index e9f50a06..ee4df32c 100644 --- a/qemu/target/arm/translate-vfp.inc.c +++ b/qemu/target/arm/translate-vfp.inc.c @@ -1963,3 +1963,80 @@ static bool trans_VSQRT_dp(DisasContext *s, arg_VSQRT_dp *a) { return do_vfp_2op_dp(s, gen_VSQRT_dp, a->vd, a->vm); } + +static bool trans_VCMP_sp(DisasContext *s, arg_VCMP_sp *a) +{ + TCGContext *tcg_ctx = s->uc->tcg_ctx; + TCGv_i32 vd, vm; + + /* Vm/M bits must be zero for the Z variant */ + if (a->z && a->vm != 0) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + vd = tcg_temp_new_i32(tcg_ctx); + vm = tcg_temp_new_i32(tcg_ctx); + + neon_load_reg32(s, vd, a->vd); + if (a->z) { + tcg_gen_movi_i32(tcg_ctx, vm, 0); + } else { + neon_load_reg32(s, vm, a->vm); + } + + if (a->e) { + gen_helper_vfp_cmpes(tcg_ctx, vd, vm, tcg_ctx->cpu_env); + } else { + gen_helper_vfp_cmps(tcg_ctx, vd, vm, tcg_ctx->cpu_env); + } + + tcg_temp_free_i32(tcg_ctx, vd); + tcg_temp_free_i32(tcg_ctx, vm); + + return true; +} + +static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a) +{ + TCGContext *tcg_ctx = s->uc->tcg_ctx; + TCGv_i64 vd, vm; + + /* Vm/M bits must be zero for the Z variant */ + if (a->z && a->vm != 0) { + return false; + } + + /* UNDEF accesses to D16-D31 if they don't exist. */ + if (!dc_isar_feature(aa32_fp_d32, s) && ((a->vd | a->vm) & 0x10)) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + vd = tcg_temp_new_i64(tcg_ctx); + vm = tcg_temp_new_i64(tcg_ctx); + + neon_load_reg64(s, vd, a->vd); + if (a->z) { + tcg_gen_movi_i64(tcg_ctx, vm, 0); + } else { + neon_load_reg64(s, vm, a->vm); + } + + if (a->e) { + gen_helper_vfp_cmped(tcg_ctx, vd, vm, tcg_ctx->cpu_env); + } else { + gen_helper_vfp_cmpd(tcg_ctx, vd, vm, tcg_ctx->cpu_env); + } + + tcg_temp_free_i64(tcg_ctx, vd); + tcg_temp_free_i64(tcg_ctx, vm); + + return true; +} diff --git a/qemu/target/arm/translate.c b/qemu/target/arm/translate.c index 2db51730..dadf654c 100644 --- a/qemu/target/arm/translate.c +++ b/qemu/target/arm/translate.c @@ -1447,33 +1447,6 @@ static inline void gen_vfp_neg(DisasContext *s, int dp) gen_helper_vfp_negs(tcg_ctx, s->F0s, s->F0s); } -static inline void gen_vfp_cmp(DisasContext *s, int dp) -{ - TCGContext *tcg_ctx = s->uc->tcg_ctx; - if (dp) - gen_helper_vfp_cmpd(tcg_ctx, s->F0d, s->F1d, tcg_ctx->cpu_env); - else - gen_helper_vfp_cmps(tcg_ctx, s->F0s, s->F1s, tcg_ctx->cpu_env); -} - -static inline void gen_vfp_cmpe(DisasContext *s, int dp) -{ - TCGContext *tcg_ctx = s->uc->tcg_ctx; - if (dp) - gen_helper_vfp_cmped(tcg_ctx, s->F0d, s->F1d, tcg_ctx->cpu_env); - else - gen_helper_vfp_cmpes(tcg_ctx, s->F0s, s->F1s, tcg_ctx->cpu_env); -} - -static inline void gen_vfp_F1_ld0(DisasContext *s, int dp) -{ - TCGContext *tcg_ctx = s->uc->tcg_ctx; - if (dp) - tcg_gen_movi_i64(tcg_ctx, s->F1d, 0); - else - tcg_gen_movi_i32(tcg_ctx, s->F1s, 0); -} - #define VFP_GEN_ITOF(name) \ static inline void gen_vfp_##name(DisasContext *s, int dp, int neon) \ { \ @@ -3191,6 +3164,7 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) case 15: switch (rn) { case 0 ... 3: + case 8 ... 11: /* Already handled by decodetree */ return 1; default: @@ -3235,11 +3209,6 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) rd_is_dp = false; break; - case 0x08: case 0x0a: /* vcmp, vcmpz */ - case 0x09: case 0x0b: /* vcmpe, vcmpez */ - no_output = true; - break; - case 0x0c: /* vrintr */ case 0x0d: /* vrintz */ case 0x0e: /* vrintx */ @@ -3340,14 +3309,6 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) /* Load the initial operands. */ if (op == 15) { switch (rn) { - case 0x08: case 0x09: /* Compare */ - gen_mov_F0_vreg(s, dp, rd); - gen_mov_F1_vreg(s, dp, rm); - break; - case 0x0a: case 0x0b: /* Compare with zero */ - gen_mov_F0_vreg(s, dp, rd); - gen_vfp_F1_ld0(s, dp); - break; case 0x14: /* vcvt fp <-> fixed */ case 0x15: case 0x16: @@ -3457,19 +3418,6 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) gen_vfp_msr(s, tmp); break; } - case 8: /* cmp */ - gen_vfp_cmp(s, dp); - break; - case 9: /* cmpe */ - gen_vfp_cmpe(s, dp); - break; - case 10: /* cmpz */ - gen_vfp_cmp(s, dp); - break; - case 11: /* cmpez */ - gen_vfp_F1_ld0(s, dp); - gen_vfp_cmpe(s, dp); - break; case 12: /* vrintr */ { TCGv_ptr fpst = get_fpstatus_ptr(s, 0); diff --git a/qemu/target/arm/vfp.decode b/qemu/target/arm/vfp.decode index b72ab8b8..9db7aa70 100644 --- a/qemu/target/arm/vfp.decode +++ b/qemu/target/arm/vfp.decode @@ -176,3 +176,8 @@ VSQRT_sp ---- 1110 1.11 0001 .... 1010 11.0 .... \ vd=%vd_sp vm=%vm_sp VSQRT_dp ---- 1110 1.11 0001 .... 1011 11.0 .... \ vd=%vd_dp vm=%vm_dp + +VCMP_sp ---- 1110 1.11 010 z:1 .... 1010 e:1 1.0 .... \ + vd=%vd_sp vm=%vm_sp +VCMP_dp ---- 1110 1.11 010 z:1 .... 1011 e:1 1.0 .... \ + vd=%vd_dp vm=%vm_dp