aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-06-03 15:49:50 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-06-04 14:58:30 +0100
commit1dbc8ddc49f82f8d115c35f391ac8fbd775816d1 (patch)
treee39b3bacf2fd02674f6b5753a1e3482753607791
parentc1501b3d2d877b4f7613e8f9ab60484e314bd654 (diff)
target/arm: Convert VABS to decodetree
Convert the VFP VABS instruction to decodetree. Unlike the 3-op versions, we don't pass fpst to the VFPGen2OpSPFn or VFPGen2OpDPFn because none of the operations which use this format and support short vectors will need it. Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--target/arm/translate-vfp.inc.c167
-rw-r--r--target/arm/translate.c12
-rw-r--r--target/arm/vfp.decode5
3 files changed, 180 insertions, 4 deletions
diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c
index 2bb51947c9..257fb5d2ab 100644
--- a/target/arm/translate-vfp.inc.c
+++ b/target/arm/translate-vfp.inc.c
@@ -1130,6 +1130,14 @@ typedef void VFPGen3OpDPFn(TCGv_i64 vd,
TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst);
/*
+ * Types for callbacks for do_vfp_2op_sp() and do_vfp_2op_dp().
+ * The callback should emit code to write a value to vd (which
+ * should be written to only).
+ */
+typedef void VFPGen2OpSPFn(TCGv_i32 vd, TCGv_i32 vm);
+typedef void VFPGen2OpDPFn(TCGv_i64 vd, TCGv_i64 vm);
+
+/*
* Perform a 3-operand VFP data processing instruction. fn is the
* callback to do the actual operation; this function deals with the
* code to handle looping around for VFP vector processing.
@@ -1292,6 +1300,155 @@ static bool do_vfp_3op_dp(DisasContext *s, VFPGen3OpDPFn *fn,
return true;
}
+static bool do_vfp_2op_sp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm)
+{
+ uint32_t delta_m = 0;
+ uint32_t delta_d = 0;
+ uint32_t bank_mask = 0;
+ int veclen = s->vec_len;
+ TCGv_i32 f0, fd;
+
+ if (!dc_isar_feature(aa32_fpshvec, s) &&
+ (veclen != 0 || s->vec_stride != 0)) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ if (veclen > 0) {
+ bank_mask = 0x18;
+
+ /* Figure out what type of vector operation this is. */
+ if ((vd & bank_mask) == 0) {
+ /* scalar */
+ veclen = 0;
+ } else {
+ delta_d = s->vec_stride + 1;
+
+ if ((vm & bank_mask) == 0) {
+ /* mixed scalar/vector */
+ delta_m = 0;
+ } else {
+ /* vector */
+ delta_m = delta_d;
+ }
+ }
+ }
+
+ f0 = tcg_temp_new_i32();
+ fd = tcg_temp_new_i32();
+
+ tcg_gen_ld_f32(f0, cpu_env, vfp_reg_offset(false, vm));
+
+ for (;;) {
+ fn(fd, f0);
+ tcg_gen_st_f32(fd, cpu_env, vfp_reg_offset(false, vd));
+
+ if (veclen == 0) {
+ break;
+ }
+
+ if (delta_m == 0) {
+ /* single source one-many */
+ while (veclen--) {
+ vd = ((vd + delta_d) & (bank_mask - 1)) | (vd & bank_mask);
+ tcg_gen_st_f32(fd, cpu_env, vfp_reg_offset(false, vd));
+ }
+ break;
+ }
+
+ /* Set up the operands for the next iteration */
+ veclen--;
+ vd = ((vd + delta_d) & (bank_mask - 1)) | (vd & bank_mask);
+ vm = ((vm + delta_m) & (bank_mask - 1)) | (vm & bank_mask);
+ tcg_gen_ld_f32(f0, cpu_env, vfp_reg_offset(false, vm));
+ }
+
+ tcg_temp_free_i32(f0);
+ tcg_temp_free_i32(fd);
+
+ return true;
+}
+
+static bool do_vfp_2op_dp(DisasContext *s, VFPGen2OpDPFn *fn, int vd, int vm)
+{
+ uint32_t delta_m = 0;
+ uint32_t delta_d = 0;
+ uint32_t bank_mask = 0;
+ int veclen = s->vec_len;
+ TCGv_i64 f0, fd;
+
+ /* UNDEF accesses to D16-D31 if they don't exist */
+ if (!dc_isar_feature(aa32_fp_d32, s) && ((vd | vm) & 0x10)) {
+ return false;
+ }
+
+ if (!dc_isar_feature(aa32_fpshvec, s) &&
+ (veclen != 0 || s->vec_stride != 0)) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ if (veclen > 0) {
+ bank_mask = 0xc;
+
+ /* Figure out what type of vector operation this is. */
+ if ((vd & bank_mask) == 0) {
+ /* scalar */
+ veclen = 0;
+ } else {
+ delta_d = (s->vec_stride >> 1) + 1;
+
+ if ((vm & bank_mask) == 0) {
+ /* mixed scalar/vector */
+ delta_m = 0;
+ } else {
+ /* vector */
+ delta_m = delta_d;
+ }
+ }
+ }
+
+ f0 = tcg_temp_new_i64();
+ fd = tcg_temp_new_i64();
+
+ tcg_gen_ld_f64(f0, cpu_env, vfp_reg_offset(true, vm));
+
+ for (;;) {
+ fn(fd, f0);
+ tcg_gen_st_f64(fd, cpu_env, vfp_reg_offset(true, vd));
+
+ if (veclen == 0) {
+ break;
+ }
+
+ if (delta_m == 0) {
+ /* single source one-many */
+ while (veclen--) {
+ vd = ((vd + delta_d) & (bank_mask - 1)) | (vd & bank_mask);
+ tcg_gen_st_f64(fd, cpu_env, vfp_reg_offset(true, vd));
+ }
+ break;
+ }
+
+ /* Set up the operands for the next iteration */
+ veclen--;
+ vd = ((vd + delta_d) & (bank_mask - 1)) | (vd & bank_mask);
+ vm = ((vm + delta_m) & (bank_mask - 1)) | (vm & bank_mask);
+ tcg_gen_ld_f64(f0, cpu_env, vfp_reg_offset(true, vm));
+ }
+
+ tcg_temp_free_i64(f0);
+ tcg_temp_free_i64(fd);
+
+ return true;
+}
+
static void gen_VMLA_sp(TCGv_i32 vd, TCGv_i32 vn, TCGv_i32 vm, TCGv_ptr fpst)
{
/* Note that order of inputs to the add matters for NaNs */
@@ -1749,3 +1906,13 @@ static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a)
tcg_temp_free_i64(fd);
return true;
}
+
+static bool trans_VABS_sp(DisasContext *s, arg_VABS_sp *a)
+{
+ return do_vfp_2op_sp(s, gen_helper_vfp_abss, a->vd, a->vm);
+}
+
+static bool trans_VABS_dp(DisasContext *s, arg_VABS_dp *a)
+{
+ return do_vfp_2op_dp(s, gen_helper_vfp_absd, a->vd, a->vm);
+}
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 6e48269313..36c9199e66 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -3086,6 +3086,14 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
case 0 ... 14:
/* Already handled by decodetree */
return 1;
+ case 15:
+ switch (rn) {
+ case 1:
+ /* Already handled by decodetree */
+ return 1;
+ default:
+ break;
+ }
default:
break;
}
@@ -3094,7 +3102,6 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
/* rn is opcode, encoded as per VFP_SREG_N. */
switch (rn) {
case 0x00: /* vmov */
- case 0x01: /* vabs */
case 0x02: /* vneg */
case 0x03: /* vsqrt */
break;
@@ -3274,9 +3281,6 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
case 0: /* cpy */
/* no-op */
break;
- case 1: /* abs */
- gen_vfp_abs(dp);
- break;
case 2: /* neg */
gen_vfp_neg(dp);
break;
diff --git a/target/arm/vfp.decode b/target/arm/vfp.decode
index ef8cb9a695..e99c0ce21a 100644
--- a/target/arm/vfp.decode
+++ b/target/arm/vfp.decode
@@ -144,3 +144,8 @@ VMOV_imm_sp ---- 1110 1.11 imm4h:4 .... 1010 0000 imm4l:4 \
vd=%vd_sp
VMOV_imm_dp ---- 1110 1.11 imm4h:4 .... 1011 0000 imm4l:4 \
vd=%vd_dp
+
+VABS_sp ---- 1110 1.11 0000 .... 1010 11.0 .... \
+ vd=%vd_sp vm=%vm_sp
+VABS_dp ---- 1110 1.11 0000 .... 1011 11.0 .... \
+ vd=%vd_dp vm=%vm_dp