aboutsummaryrefslogtreecommitdiff
path: root/target/arm
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-04-30 19:09:40 +0100
committerPeter Maydell <peter.maydell@linaro.org>2020-05-04 12:57:56 +0100
commit123ce4e3daba26b760b472687e1fb1ad82cf1993 (patch)
tree50a4748ff827df3ff8f434bccec551c3c95b7403 /target/arm
parent3698747c48db871d876a398592c5a23d7580ed4a (diff)
target/arm: Convert Neon 'load/store single structure' to decodetree
Convert the Neon "load/store single structure to one lane" insns to decodetree. As this is the last set of insns in the neon load/store group, we can remove the whole disas_neon_ls_insn() function. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20200430181003.21682-14-peter.maydell@linaro.org
Diffstat (limited to 'target/arm')
-rw-r--r--target/arm/neon-ls.decode11
-rw-r--r--target/arm/translate-neon.inc.c89
-rw-r--r--target/arm/translate.c147
3 files changed, 100 insertions, 147 deletions
diff --git a/target/arm/neon-ls.decode b/target/arm/neon-ls.decode
index f0ab6d2c98..c7b03a72e8 100644
--- a/target/arm/neon-ls.decode
+++ b/target/arm/neon-ls.decode
@@ -39,3 +39,14 @@ VLDST_multiple 1111 0100 0 . l:1 0 rn:4 .... itype:4 size:2 align:2 rm:4 \
VLD_all_lanes 1111 0100 1 . 1 0 rn:4 .... 11 n:2 size:2 t:1 a:1 rm:4 \
vd=%vd_dp
+
+# Neon load/store single structure to one lane
+%imm1_5_p1 5:1 !function=plus1
+%imm1_6_p1 6:1 !function=plus1
+
+VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 00 n:2 reg_idx:3 align:1 rm:4 \
+ vd=%vd_dp size=0 stride=1
+VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 01 n:2 reg_idx:2 align:2 rm:4 \
+ vd=%vd_dp size=1 stride=%imm1_5_p1
+VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 10 n:2 reg_idx:1 align:3 rm:4 \
+ vd=%vd_dp size=2 stride=%imm1_6_p1
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
index e60e9559ba..c881d1cf60 100644
--- a/target/arm/translate-neon.inc.c
+++ b/target/arm/translate-neon.inc.c
@@ -26,6 +26,11 @@
* It might be possible to convert it to a standalone .c file eventually.
*/
+static inline int plus1(DisasContext *s, int x)
+{
+ return x + 1;
+}
+
/* Include the generated Neon decoder */
#include "decode-neon-dp.inc.c"
#include "decode-neon-ls.inc.c"
@@ -471,3 +476,87 @@ static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a)
return true;
}
+
+static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a)
+{
+ /* Neon load/store single structure to one lane */
+ int reg;
+ int nregs = a->n + 1;
+ int vd = a->vd;
+ TCGv_i32 addr, tmp;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
+ /* UNDEF accesses to D16-D31 if they don't exist */
+ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
+ return false;
+ }
+
+ /* Catch the UNDEF cases. This is unavoidably a bit messy. */
+ switch (nregs) {
+ case 1:
+ if (((a->align & (1 << a->size)) != 0) ||
+ (a->size == 2 && ((a->align & 3) == 1 || (a->align & 3) == 2))) {
+ return false;
+ }
+ break;
+ case 3:
+ if ((a->align & 1) != 0) {
+ return false;
+ }
+ /* fall through */
+ case 2:
+ if (a->size == 2 && (a->align & 2) != 0) {
+ return false;
+ }
+ break;
+ case 4:
+ if ((a->size == 2) && ((a->align & 3) == 3)) {
+ return false;
+ }
+ break;
+ default:
+ abort();
+ }
+ if ((vd + a->stride * (nregs - 1)) > 31) {
+ /*
+ * Attempts to write off the end of the register file are
+ * UNPREDICTABLE; we choose to UNDEF because otherwise we would
+ * access off the end of the array that holds the register data.
+ */
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ tmp = tcg_temp_new_i32();
+ addr = tcg_temp_new_i32();
+ load_reg_var(s, addr, a->rn);
+ /*
+ * TODO: if we implemented alignment exceptions, we should check
+ * addr against the alignment encoded in a->align here.
+ */
+ for (reg = 0; reg < nregs; reg++) {
+ if (a->l) {
+ gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
+ s->be_data | a->size);
+ neon_store_element(vd, a->reg_idx, a->size, tmp);
+ } else { /* Store */
+ neon_load_element(tmp, vd, a->reg_idx, a->size);
+ gen_aa32_st_i32(s, tmp, addr, get_mem_index(s),
+ s->be_data | a->size);
+ }
+ vd += a->stride;
+ tcg_gen_addi_i32(addr, addr, 1 << a->size);
+ }
+ tcg_temp_free_i32(addr);
+ tcg_temp_free_i32(tmp);
+
+ gen_neon_ldst_base_update(s, a->rm, a->rn, (1 << a->size) * nregs);
+
+ return true;
+}
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 7099274c92..613be39ef3 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -3213,140 +3213,6 @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
tcg_temp_free_i32(rd);
}
-
-/* Translate a NEON load/store element instruction. Return nonzero if the
- instruction is invalid. */
-static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
-{
- int rd, rn, rm;
- int nregs;
- int stride;
- int size;
- int reg;
- int load;
- TCGv_i32 addr;
- TCGv_i32 tmp;
-
- if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
- 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 (s->fp_excp_el) {
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
- syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
- return 0;
- }
-
- if (!s->vfp_enabled)
- return 1;
- VFP_DREG_D(rd, insn);
- rn = (insn >> 16) & 0xf;
- rm = insn & 0xf;
- load = (insn & (1 << 21)) != 0;
- if ((insn & (1 << 23)) == 0) {
- /* Load store all elements -- handled already by decodetree */
- return 1;
- } else {
- size = (insn >> 10) & 3;
- if (size == 3) {
- /* Load single element to all lanes -- handled by decodetree */
- return 1;
- } else {
- /* Single element. */
- int idx = (insn >> 4) & 0xf;
- int reg_idx;
- switch (size) {
- case 0:
- reg_idx = (insn >> 5) & 7;
- stride = 1;
- break;
- case 1:
- reg_idx = (insn >> 6) & 3;
- stride = (insn & (1 << 5)) ? 2 : 1;
- break;
- case 2:
- reg_idx = (insn >> 7) & 1;
- stride = (insn & (1 << 6)) ? 2 : 1;
- break;
- default:
- abort();
- }
- nregs = ((insn >> 8) & 3) + 1;
- /* Catch the UNDEF cases. This is unavoidably a bit messy. */
- switch (nregs) {
- case 1:
- if (((idx & (1 << size)) != 0) ||
- (size == 2 && ((idx & 3) == 1 || (idx & 3) == 2))) {
- return 1;
- }
- break;
- case 3:
- if ((idx & 1) != 0) {
- return 1;
- }
- /* fall through */
- case 2:
- if (size == 2 && (idx & 2) != 0) {
- return 1;
- }
- break;
- case 4:
- if ((size == 2) && ((idx & 3) == 3)) {
- return 1;
- }
- break;
- default:
- abort();
- }
- if ((rd + stride * (nregs - 1)) > 31) {
- /* Attempts to write off the end of the register file
- * are UNPREDICTABLE; we choose to UNDEF because otherwise
- * the neon_load_reg() would write off the end of the array.
- */
- return 1;
- }
- tmp = tcg_temp_new_i32();
- addr = tcg_temp_new_i32();
- load_reg_var(s, addr, rn);
- for (reg = 0; reg < nregs; reg++) {
- if (load) {
- gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s),
- s->be_data | size);
- neon_store_element(rd, reg_idx, size, tmp);
- } else { /* Store */
- neon_load_element(tmp, rd, reg_idx, size);
- gen_aa32_st_i32(s, tmp, addr, get_mem_index(s),
- s->be_data | size);
- }
- rd += stride;
- tcg_gen_addi_i32(addr, addr, 1 << size);
- }
- tcg_temp_free_i32(addr);
- tcg_temp_free_i32(tmp);
- stride = nregs * (1 << size);
- }
- }
- if (rm != 15) {
- TCGv_i32 base;
-
- base = load_reg(s, rn);
- if (rm == 13) {
- tcg_gen_addi_i32(base, base, stride);
- } else {
- TCGv_i32 index;
- index = load_reg(s, rm);
- tcg_gen_add_i32(base, base, index);
- tcg_temp_free_i32(index);
- }
- store_reg(s, rn, base);
- }
- return 0;
-}
-
static inline void gen_neon_narrow(int size, TCGv_i32 dest, TCGv_i64 src)
{
switch (size) {
@@ -10596,13 +10462,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
}
return;
}
- if ((insn & 0x0f100000) == 0x04000000) {
- /* NEON load/store. */
- if (disas_neon_ls_insn(s, insn)) {
- goto illegal_op;
- }
- return;
- }
if ((insn & 0x0e000f00) == 0x0c000100) {
if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
/* iWMMXt register transfer. */
@@ -10807,12 +10666,6 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
}
break;
case 12:
- if ((insn & 0x01100000) == 0x01000000) {
- if (disas_neon_ls_insn(s, insn)) {
- goto illegal_op;
- }
- break;
- }
goto illegal_op;
default:
illegal_op: