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:
Peter Maydell 2020-06-16 23:54:49 -04:00 committed by Lioncash
parent 090426b120
commit 6383a2bd15
3 changed files with 49 additions and 58 deletions

View file

@ -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
VQDMULL_3d 1111 001 0 1 . .. .... .... 1101 . 0 . 0 .... @3diff
VMULL_P_3d 1111 001 0 1 . .. .... .... 1110 . 0 . 0 .... @3diff
]
}

View file

@ -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]);
}
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;
}

View file

@ -5305,7 +5305,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
TCGContext *tcg_ctx = s->uc->tcg_ctx;
int op;
int q;
int rd, rn, rm, rd_ofs, rn_ofs, rm_ofs;
int rd, rn, rm, rd_ofs, rm_ofs;
int size;
int pass;
int u;
@ -5339,7 +5339,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
size = (insn >> 20) & 3;
vec_size = q ? 16 : 8;
rd_ofs = neon_reg_offset(rd, 0);
rn_ofs = neon_reg_offset(rn, 0);
rm_ofs = neon_reg_offset(rm, 0);
if ((insn & (1 << 23)) == 0) {
@ -5352,62 +5351,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
if (size != 3) {
op = (insn >> 8) & 0xf;
if ((insn & (1 << 6)) == 0) {
/* Three registers of different lengths. */
/* undefreq: bit 0 : UNDEF if size == 0
* 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 */
/* Three registers of different lengths: handled by decodetree */
return 1;
} else {
/* 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