mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-03-24 22:15:07 +00:00
target/arm: Convert Neon 3-reg-diff polynomial VMULL
Convert the Neon 3-reg-diff insn polynomial VMULL. This is the last insn in this group to be converted. Backports commit 18fb58d588898550919392277787979ee7d0d84e from qemu
This commit is contained in:
parent
090426b120
commit
6383a2bd15
|
@ -465,5 +465,7 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
|
||||||
VMULL_U_3d 1111 001 1 1 . .. .... .... 1100 . 0 . 0 .... @3diff
|
VMULL_U_3d 1111 001 1 1 . .. .... .... 1100 . 0 . 0 .... @3diff
|
||||||
|
|
||||||
VQDMULL_3d 1111 001 0 1 . .. .... .... 1101 . 0 . 0 .... @3diff
|
VQDMULL_3d 1111 001 0 1 . .. .... .... 1101 . 0 . 0 .... @3diff
|
||||||
|
|
||||||
|
VMULL_P_3d 1111 001 0 1 . .. .... .... 1110 . 0 . 0 .... @3diff
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -2331,3 +2331,47 @@ static bool trans_VQDMLSL_3d(DisasContext *s, arg_3diff *a)
|
||||||
|
|
||||||
return do_long_3d(s, a, opfn[a->size], accfn[a->size]);
|
return do_long_3d(s, a, opfn[a->size], accfn[a->size]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool trans_VMULL_P_3d(DisasContext *s, arg_3diff *a)
|
||||||
|
{
|
||||||
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
|
gen_helper_gvec_3 *fn_gvec;
|
||||||
|
|
||||||
|
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->vn | a->vm) & 0x10)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a->vd & 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (a->size) {
|
||||||
|
case 0:
|
||||||
|
fn_gvec = gen_helper_neon_pmull_h;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!dc_isar_feature(aa32_pmull, s)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fn_gvec = gen_helper_gvec_pmull_q;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vfp_access_check(s)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcg_gen_gvec_3_ool(tcg_ctx, neon_reg_offset(a->vd, 0),
|
||||||
|
neon_reg_offset(a->vn, 0),
|
||||||
|
neon_reg_offset(a->vm, 0),
|
||||||
|
16, 16, 0, fn_gvec);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -5305,7 +5305,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
||||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
int op;
|
int op;
|
||||||
int q;
|
int q;
|
||||||
int rd, rn, rm, rd_ofs, rn_ofs, rm_ofs;
|
int rd, rn, rm, rd_ofs, rm_ofs;
|
||||||
int size;
|
int size;
|
||||||
int pass;
|
int pass;
|
||||||
int u;
|
int u;
|
||||||
|
@ -5339,7 +5339,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
||||||
size = (insn >> 20) & 3;
|
size = (insn >> 20) & 3;
|
||||||
vec_size = q ? 16 : 8;
|
vec_size = q ? 16 : 8;
|
||||||
rd_ofs = neon_reg_offset(rd, 0);
|
rd_ofs = neon_reg_offset(rd, 0);
|
||||||
rn_ofs = neon_reg_offset(rn, 0);
|
|
||||||
rm_ofs = neon_reg_offset(rm, 0);
|
rm_ofs = neon_reg_offset(rm, 0);
|
||||||
|
|
||||||
if ((insn & (1 << 23)) == 0) {
|
if ((insn & (1 << 23)) == 0) {
|
||||||
|
@ -5352,62 +5351,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
||||||
if (size != 3) {
|
if (size != 3) {
|
||||||
op = (insn >> 8) & 0xf;
|
op = (insn >> 8) & 0xf;
|
||||||
if ((insn & (1 << 6)) == 0) {
|
if ((insn & (1 << 6)) == 0) {
|
||||||
/* Three registers of different lengths. */
|
/* Three registers of different lengths: handled by decodetree */
|
||||||
/* undefreq: bit 0 : UNDEF if size == 0
|
return 1;
|
||||||
* bit 1 : UNDEF if size == 1
|
|
||||||
* bit 2 : UNDEF if size == 2
|
|
||||||
* bit 3 : UNDEF if U == 1
|
|
||||||
* Note that [2:0] set implies 'always UNDEF'
|
|
||||||
*/
|
|
||||||
int undefreq;
|
|
||||||
/* prewiden, src1_wide, src2_wide, undefreq */
|
|
||||||
static const int neon_3reg_wide[16][4] = {
|
|
||||||
{0, 0, 0, 7}, /* VADDL: handled by decodetree */
|
|
||||||
{0, 0, 0, 7}, /* VADDW: handled by decodetree */
|
|
||||||
{0, 0, 0, 7}, /* VSUBL: handled by decodetree */
|
|
||||||
{0, 0, 0, 7}, /* VSUBW: handled by decodetree */
|
|
||||||
{0, 0, 0, 7}, /* VADDHN: handled by decodetree */
|
|
||||||
{0, 0, 0, 7}, /* VABAL */
|
|
||||||
{0, 0, 0, 7}, /* VSUBHN: handled by decodetree */
|
|
||||||
{0, 0, 0, 7}, /* VABDL */
|
|
||||||
{0, 0, 0, 7}, /* VMLAL */
|
|
||||||
{0, 0, 0, 7}, /* VQDMLAL */
|
|
||||||
{0, 0, 0, 7}, /* VMLSL */
|
|
||||||
{0, 0, 0, 7}, /* VQDMLSL */
|
|
||||||
{0, 0, 0, 7}, /* Integer VMULL */
|
|
||||||
{0, 0, 0, 7}, /* VQDMULL */
|
|
||||||
{0, 0, 0, 0xa}, /* Polynomial VMULL */
|
|
||||||
{0, 0, 0, 7}, /* Reserved: always UNDEF */
|
|
||||||
};
|
|
||||||
|
|
||||||
undefreq = neon_3reg_wide[op][3];
|
|
||||||
|
|
||||||
if ((undefreq & (1 << size)) ||
|
|
||||||
((undefreq & 8) && u)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (rd & 1) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle polynomial VMULL in a single pass. */
|
|
||||||
if (op == 14) {
|
|
||||||
if (size == 0) {
|
|
||||||
/* VMULL.P8 */
|
|
||||||
tcg_gen_gvec_3_ool(tcg_ctx, rd_ofs, rn_ofs, rm_ofs, 16, 16,
|
|
||||||
0, gen_helper_neon_pmull_h);
|
|
||||||
} else {
|
|
||||||
/* VMULL.P64 */
|
|
||||||
if (!dc_isar_feature(aa32_pmull, s)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
tcg_gen_gvec_3_ool(tcg_ctx, rd_ofs, rn_ofs, rm_ofs, 16, 16,
|
|
||||||
0, gen_helper_gvec_pmull_q);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
abort(); /* all others handled by decodetree */
|
|
||||||
} else {
|
} else {
|
||||||
/* Two registers and a scalar. NB that for ops of this form
|
/* Two registers and a scalar. NB that for ops of this form
|
||||||
* the ARM ARM labels bit 24 as Q, but it is in our variable
|
* the ARM ARM labels bit 24 as Q, but it is in our variable
|
||||||
|
|
Loading…
Reference in a new issue