mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-01-11 14:15:35 +00:00
target/arm: Convert Neon 3-reg-diff long multiplies
Convert the Neon 3-reg-diff insns VMULL, VMLAL and VMLSL; these perform a 32x32->64 multiply with possible accumulate. Note that for VMLSL we do the accumulate directly with a subtraction rather than doing a negate-then-add as the old code did. Backports commit 3a1d9eb07b767a7592abca642af80906f9eab0ed from qemu
This commit is contained in:
parent
21044a1d11
commit
5464405d5c
|
@ -450,5 +450,14 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
|
||||||
|
|
||||||
VABDL_S_3d 1111 001 0 1 . .. .... .... 0111 . 0 . 0 .... @3diff
|
VABDL_S_3d 1111 001 0 1 . .. .... .... 0111 . 0 . 0 .... @3diff
|
||||||
VABDL_U_3d 1111 001 1 1 . .. .... .... 0111 . 0 . 0 .... @3diff
|
VABDL_U_3d 1111 001 1 1 . .. .... .... 0111 . 0 . 0 .... @3diff
|
||||||
|
|
||||||
|
VMLAL_S_3d 1111 001 0 1 . .. .... .... 1000 . 0 . 0 .... @3diff
|
||||||
|
VMLAL_U_3d 1111 001 1 1 . .. .... .... 1000 . 0 . 0 .... @3diff
|
||||||
|
|
||||||
|
VMLSL_S_3d 1111 001 0 1 . .. .... .... 1010 . 0 . 0 .... @3diff
|
||||||
|
VMLSL_U_3d 1111 001 1 1 . .. .... .... 1010 . 0 . 0 .... @3diff
|
||||||
|
|
||||||
|
VMULL_S_3d 1111 001 0 1 . .. .... .... 1100 . 0 . 0 .... @3diff
|
||||||
|
VMULL_U_3d 1111 001 1 1 . .. .... .... 1100 . 0 . 0 .... @3diff
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -2178,3 +2178,74 @@ static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a)
|
||||||
|
|
||||||
return do_long_3d(s, a, opfn[a->size], addfn[a->size]);
|
return do_long_3d(s, a, opfn[a->size], addfn[a->size]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gen_mull_s32(TCGContext *s, TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
|
||||||
|
{
|
||||||
|
TCGv_i32 lo = tcg_temp_new_i32(s);
|
||||||
|
TCGv_i32 hi = tcg_temp_new_i32(s);
|
||||||
|
|
||||||
|
tcg_gen_muls2_i32(s, lo, hi, rn, rm);
|
||||||
|
tcg_gen_concat_i32_i64(s, rd, lo, hi);
|
||||||
|
|
||||||
|
tcg_temp_free_i32(s, lo);
|
||||||
|
tcg_temp_free_i32(s, hi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_mull_u32(TCGContext *s, TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm)
|
||||||
|
{
|
||||||
|
TCGv_i32 lo = tcg_temp_new_i32(s);
|
||||||
|
TCGv_i32 hi = tcg_temp_new_i32(s);
|
||||||
|
|
||||||
|
tcg_gen_mulu2_i32(s, lo, hi, rn, rm);
|
||||||
|
tcg_gen_concat_i32_i64(s, rd, lo, hi);
|
||||||
|
|
||||||
|
tcg_temp_free_i32(s, lo);
|
||||||
|
tcg_temp_free_i32(s, hi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a)
|
||||||
|
{
|
||||||
|
static NeonGenTwoOpWidenFn * const opfn[] = {
|
||||||
|
gen_helper_neon_mull_s8,
|
||||||
|
gen_helper_neon_mull_s16,
|
||||||
|
gen_mull_s32,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
return do_long_3d(s, a, opfn[a->size], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a)
|
||||||
|
{
|
||||||
|
static NeonGenTwoOpWidenFn * const opfn[] = {
|
||||||
|
gen_helper_neon_mull_u8,
|
||||||
|
gen_helper_neon_mull_u16,
|
||||||
|
gen_mull_u32,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
return do_long_3d(s, a, opfn[a->size], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DO_VMLAL(INSN,MULL,ACC) \
|
||||||
|
static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \
|
||||||
|
{ \
|
||||||
|
static NeonGenTwoOpWidenFn * const opfn[] = { \
|
||||||
|
gen_helper_neon_##MULL##8, \
|
||||||
|
gen_helper_neon_##MULL##16, \
|
||||||
|
gen_##MULL##32, \
|
||||||
|
NULL, \
|
||||||
|
}; \
|
||||||
|
static NeonGenTwo64OpFn * const accfn[] = { \
|
||||||
|
gen_helper_neon_##ACC##l_u16, \
|
||||||
|
gen_helper_neon_##ACC##l_u32, \
|
||||||
|
tcg_gen_##ACC##_i64, \
|
||||||
|
NULL, \
|
||||||
|
}; \
|
||||||
|
return do_long_3d(s, a, opfn[a->size], accfn[a->size]); \
|
||||||
|
}
|
||||||
|
|
||||||
|
DO_VMLAL(VMLAL_S,mull_s,add)
|
||||||
|
DO_VMLAL(VMLAL_U,mull_u,add)
|
||||||
|
DO_VMLAL(VMLSL_S,mull_s,sub)
|
||||||
|
DO_VMLAL(VMLSL_U,mull_u,sub)
|
||||||
|
|
|
@ -5370,11 +5370,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
||||||
{0, 0, 0, 7}, /* VABAL */
|
{0, 0, 0, 7}, /* VABAL */
|
||||||
{0, 0, 0, 7}, /* VSUBHN: handled by decodetree */
|
{0, 0, 0, 7}, /* VSUBHN: handled by decodetree */
|
||||||
{0, 0, 0, 7}, /* VABDL */
|
{0, 0, 0, 7}, /* VABDL */
|
||||||
{0, 0, 0, 0}, /* VMLAL */
|
{0, 0, 0, 7}, /* VMLAL */
|
||||||
{0, 0, 0, 9}, /* VQDMLAL */
|
{0, 0, 0, 9}, /* VQDMLAL */
|
||||||
{0, 0, 0, 0}, /* VMLSL */
|
{0, 0, 0, 7}, /* VMLSL */
|
||||||
{0, 0, 0, 9}, /* VQDMLSL */
|
{0, 0, 0, 9}, /* VQDMLSL */
|
||||||
{0, 0, 0, 0}, /* Integer VMULL */
|
{0, 0, 0, 7}, /* Integer VMULL */
|
||||||
{0, 0, 0, 9}, /* VQDMULL */
|
{0, 0, 0, 9}, /* VQDMULL */
|
||||||
{0, 0, 0, 0xa}, /* Polynomial VMULL */
|
{0, 0, 0, 0xa}, /* Polynomial VMULL */
|
||||||
{0, 0, 0, 7}, /* Reserved: always UNDEF */
|
{0, 0, 0, 7}, /* Reserved: always UNDEF */
|
||||||
|
@ -5430,8 +5430,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
||||||
tmp2 = neon_load_reg(s, rm, pass);
|
tmp2 = neon_load_reg(s, rm, pass);
|
||||||
}
|
}
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case 8: case 9: case 10: case 11: case 12: case 13:
|
case 9: case 11: case 13:
|
||||||
/* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
|
/* VQDMLAL, VQDMLSL, VQDMULL */
|
||||||
gen_neon_mull(s, s->V0, tmp, tmp2, size, u);
|
gen_neon_mull(s, s->V0, tmp, tmp2, size, u);
|
||||||
break;
|
break;
|
||||||
default: /* 15 is RESERVED: caught earlier */
|
default: /* 15 is RESERVED: caught earlier */
|
||||||
|
@ -5441,16 +5441,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
||||||
/* VQDMULL */
|
/* VQDMULL */
|
||||||
gen_neon_addl_saturate(s, s->V0, s->V0, size);
|
gen_neon_addl_saturate(s, s->V0, s->V0, size);
|
||||||
neon_store_reg64(s, s->V0, rd + pass);
|
neon_store_reg64(s, s->V0, rd + pass);
|
||||||
} else if (op == 5 || (op >= 8 && op <= 11)) {
|
} else {
|
||||||
/* Accumulate. */
|
/* Accumulate. */
|
||||||
neon_load_reg64(s, s->V1, rd + pass);
|
neon_load_reg64(s, s->V1, rd + pass);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case 10: /* VMLSL */
|
|
||||||
gen_neon_negl(s, s->V0, size);
|
|
||||||
/* Fall through */
|
|
||||||
case 8: /* VABAL, VMLAL */
|
|
||||||
gen_neon_addl(s, size);
|
|
||||||
break;
|
|
||||||
case 9: case 11: /* VQDMLAL, VQDMLSL */
|
case 9: case 11: /* VQDMLAL, VQDMLSL */
|
||||||
gen_neon_addl_saturate(s, s->V0, s->V0, size);
|
gen_neon_addl_saturate(s, s->V0, s->V0, size);
|
||||||
if (op == 11) {
|
if (op == 11) {
|
||||||
|
@ -5462,9 +5456,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
neon_store_reg64(s, s->V0, rd + pass);
|
neon_store_reg64(s, s->V0, rd + pass);
|
||||||
} else {
|
|
||||||
/* Write back the result. */
|
|
||||||
neon_store_reg64(s, s->V0, rd + pass);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue