Commit 18fb58d5 authored by Peter Maydell's avatar Peter Maydell
Browse files

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.

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Reviewed-by: default avatarRichard Henderson <richard.henderson@linaro.org>
parent 9546ca59
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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
  ]
}
+43 −0
Original line number Diff line number Diff line
@@ -2304,3 +2304,46 @@ 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)
{
    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(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;
}
+3 −57
Original line number Diff line number Diff line
@@ -5181,7 +5181,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
{
    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;
@@ -5215,7 +5215,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) {
@@ -5228,61 +5227,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(rd_ofs, rn_ofs, rm_ofs, 16, 16,
                                           0, gen_helper_neon_pmull_h);
                    } else {
                        /* VMULL.P64 */
                        if (!dc_isar_feature(aa32_pmull, s)) {
                /* Three registers of different lengths: handled by decodetree */
                return 1;
                        }
                        tcg_gen_gvec_3_ool(rd_ofs, rn_ofs, rm_ofs, 16, 16,
                                           0, gen_helper_gvec_pmull_q);
                    }
                    return 0;
                }
                abort(); /* all others handled by decodetree */
            } 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