mirror of https://gitee.com/openkylin/qemu.git
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
This commit is contained in:
parent
3698747c48
commit
123ce4e3da
|
@ -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 \
|
VLD_all_lanes 1111 0100 1 . 1 0 rn:4 .... 11 n:2 size:2 t:1 a:1 rm:4 \
|
||||||
vd=%vd_dp
|
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
|
||||||
|
|
|
@ -26,6 +26,11 @@
|
||||||
* It might be possible to convert it to a standalone .c file eventually.
|
* 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 the generated Neon decoder */
|
||||||
#include "decode-neon-dp.inc.c"
|
#include "decode-neon-dp.inc.c"
|
||||||
#include "decode-neon-ls.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;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -3213,140 +3213,6 @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
|
||||||
tcg_temp_free_i32(rd);
|
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)
|
static inline void gen_neon_narrow(int size, TCGv_i32 dest, TCGv_i64 src)
|
||||||
{
|
{
|
||||||
switch (size) {
|
switch (size) {
|
||||||
|
@ -10596,13 +10462,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((insn & 0x0f100000) == 0x04000000) {
|
|
||||||
/* NEON load/store. */
|
|
||||||
if (disas_neon_ls_insn(s, insn)) {
|
|
||||||
goto illegal_op;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((insn & 0x0e000f00) == 0x0c000100) {
|
if ((insn & 0x0e000f00) == 0x0c000100) {
|
||||||
if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
|
if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
|
||||||
/* iWMMXt register transfer. */
|
/* iWMMXt register transfer. */
|
||||||
|
@ -10807,12 +10666,6 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 12:
|
case 12:
|
||||||
if ((insn & 0x01100000) == 0x01000000) {
|
|
||||||
if (disas_neon_ls_insn(s, insn)) {
|
|
||||||
goto illegal_op;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
goto illegal_op;
|
goto illegal_op;
|
||||||
default:
|
default:
|
||||||
illegal_op:
|
illegal_op:
|
||||||
|
|
Loading…
Reference in New Issue