target/arm: Convert Neon narrowing moves to decodetree

Convert the Neon narrowing moves VMQNV, VQMOVN, VQMOVUN in the 2-reg-misc
group to decodetree.

Backports commit 3882bdacb0ad548864b9f2582a32bb5c785e3165 from qemu
This commit is contained in:
Peter Maydell 2021-02-25 12:17:59 -05:00 committed by Lioncash
parent 35d8a3e83f
commit 48d57d0dc7
3 changed files with 71 additions and 83 deletions

View file

@ -439,6 +439,8 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
@2misc .... ... .. . .. size:2 .. .... . .... q:1 . . .... \
&2misc vm=%vm_dp vd=%vd_dp
@2misc_q0 .... ... .. . .. size:2 .. .... . .... . . . .... \
&2misc vm=%vm_dp vd=%vd_dp q=0
VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc
@ -450,6 +452,13 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc
VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc
VMOVN 1111 001 11 . 11 .. 10 .... 0 0100 0 . 0 .... @2misc_q0
# VQMOVUN: unsigned result (source is always signed)
VQMOVUN 1111 001 11 . 11 .. 10 .... 0 0100 1 . 0 .... @2misc_q0
# VQMOVN: signed result, source may be signed (_S) or unsigned (_U)
VQMOVN_S 1111 001 11 . 11 .. 10 .... 0 0101 0 . 0 .... @2misc_q0
VQMOVN_U 1111 001 11 . 11 .. 10 .... 0 0101 1 . 0 .... @2misc_q0
]
# Subgroup for size != 0b11

View file

@ -3283,3 +3283,63 @@ static bool trans_VZIP(DisasContext *s, arg_2misc *a)
};
return do_zip_uzp(s, a, fn[a->q][a->size]);
}
static bool do_vmovn(DisasContext *s, arg_2misc *a,
NeonGenNarrowEnvFn *narrowfn)
{
TCGv_i64 rm;
TCGv_i32 rd0, rd1;
TCGContext *tcg_ctx = s->uc->tcg_ctx;
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 | a->vm) & 0x10)) {
return false;
}
if (a->vm & 1) {
return false;
}
if (!narrowfn) {
return false;
}
if (!vfp_access_check(s)) {
return true;
}
rm = tcg_temp_new_i64(tcg_ctx);
rd0 = tcg_temp_new_i32(tcg_ctx);
rd1 = tcg_temp_new_i32(tcg_ctx);
neon_load_reg64(s, rm, a->vm);
narrowfn(tcg_ctx, rd0, tcg_ctx->cpu_env, rm);
neon_load_reg64(s, rm, a->vm + 1);
narrowfn(tcg_ctx, rd1, tcg_ctx->cpu_env, rm);
neon_store_reg(s, a->vd, 0, rd0);
neon_store_reg(s, a->vd, 1, rd1);
tcg_temp_free_i64(tcg_ctx, rm);
return true;
}
#define DO_VMOVN(INSN, FUNC) \
static bool trans_##INSN(DisasContext *s, arg_2misc *a) \
{ \
static NeonGenNarrowEnvFn * const narrowfn[] = { \
FUNC##8, \
FUNC##16, \
FUNC##32, \
NULL, \
}; \
return do_vmovn(s, a, narrowfn[a->size]); \
}
DO_VMOVN(VMOVN, gen_neon_narrow_u)
DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat)
DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s)
DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u)

View file

@ -3081,50 +3081,6 @@ static void gen_neon_trn_u16(DisasContext *s, TCGv_i32 t0, TCGv_i32 t1)
tcg_temp_free_i32(tcg_ctx, rd);
}
static inline void gen_neon_narrow(DisasContext *s, int size, TCGv_i32 dest, TCGv_i64 src)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
switch (size) {
case 0: gen_helper_neon_narrow_u8(tcg_ctx, dest, src); break;
case 1: gen_helper_neon_narrow_u16(tcg_ctx, dest, src); break;
case 2: tcg_gen_extrl_i64_i32(tcg_ctx, dest, src); break;
default: abort();
}
}
static inline void gen_neon_narrow_sats(DisasContext *s, int size, TCGv_i32 dest, TCGv_i64 src)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
switch (size) {
case 0: gen_helper_neon_narrow_sat_s8(tcg_ctx, dest, tcg_ctx->cpu_env, src); break;
case 1: gen_helper_neon_narrow_sat_s16(tcg_ctx, dest, tcg_ctx->cpu_env, src); break;
case 2: gen_helper_neon_narrow_sat_s32(tcg_ctx, dest, tcg_ctx->cpu_env, src); break;
default: abort();
}
}
static inline void gen_neon_narrow_satu(DisasContext *s, int size, TCGv_i32 dest, TCGv_i64 src)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
switch (size) {
case 0: gen_helper_neon_narrow_sat_u8(tcg_ctx, dest, tcg_ctx->cpu_env, src); break;
case 1: gen_helper_neon_narrow_sat_u16(tcg_ctx, dest, tcg_ctx->cpu_env, src); break;
case 2: gen_helper_neon_narrow_sat_u32(tcg_ctx, dest, tcg_ctx->cpu_env, src); break;
default: abort();
}
}
static inline void gen_neon_unarrow_sats(DisasContext *s, int size, TCGv_i32 dest, TCGv_i64 src)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
switch (size) {
case 0: gen_helper_neon_unarrow_sat8(tcg_ctx, dest, tcg_ctx->cpu_env, src); break;
case 1: gen_helper_neon_unarrow_sat16(tcg_ctx, dest, tcg_ctx->cpu_env, src); break;
case 2: gen_helper_neon_unarrow_sat32(tcg_ctx, dest, tcg_ctx->cpu_env, src); break;
default: abort();
}
}
static inline void gen_neon_widen(DisasContext *s, TCGv_i64 dest, TCGv_i32 src, int size, int u)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
@ -3146,24 +3102,6 @@ static inline void gen_neon_widen(DisasContext *s, TCGv_i64 dest, TCGv_i32 src,
tcg_temp_free_i32(tcg_ctx, src);
}
static void gen_neon_narrow_op(DisasContext *s, int op, int u, int size,
TCGv_i32 dest, TCGv_i64 src)
{
if (op) {
if (u) {
gen_neon_unarrow_sats(s, size, dest, src);
} else {
gen_neon_narrow(s, size, dest, src);
}
} else {
if (u) {
gen_neon_narrow_satu(s, size, dest, src);
} else {
gen_neon_narrow_sats(s, size, dest, src);
}
}
}
/* Symbolic constants for op fields for Neon 2-register miscellaneous.
* The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B
* table A7-13.
@ -5104,8 +5042,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
!arm_dc_feature(s, ARM_FEATURE_V8)) {
return 1;
}
if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) &&
q && ((rm | rd) & 1)) {
if (q && ((rm | rd) & 1)) {
return 1;
}
switch (op) {
@ -5114,6 +5051,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:
case NEON_2RM_VUZP:
case NEON_2RM_VZIP:
case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
/* handled by decodetree */
return 1;
case NEON_2RM_VTRN:
@ -5129,25 +5067,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
goto elementwise;
}
break;
case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
/* also VQMOVUN; op field and mnemonics don't line up */
if (rm & 1) {
return 1;
}
tmp2 = NULL;
for (pass = 0; pass < 2; pass++) {
neon_load_reg64(s, s->V0, rm + pass);
tmp = tcg_temp_new_i32(tcg_ctx);
gen_neon_narrow_op(s, op == NEON_2RM_VMOVN, q, size,
tmp, s->V0);
if (pass == 0) {
tmp2 = tmp;
} else {
neon_store_reg(s, rd, 0, tmp2);
neon_store_reg(s, rd, 1, tmp);
}
}
break;
case NEON_2RM_VSHLL:
if (q || (rd & 1)) {
return 1;