mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-03-23 23:35:14 +00:00
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:
parent
35d8a3e83f
commit
48d57d0dc7
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue