Commit 87732318 authored by Richard Henderson's avatar Richard Henderson Committed by Peter Maydell
Browse files

target/arm: Implement VFMAL and VFMSL for aarch32



Signed-off-by: default avatarRichard Henderson <richard.henderson@linaro.org>
Message-id: 20190219222952.22183-4-richard.henderson@linaro.org
Reviewed-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parent 0caa5af8
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -3296,6 +3296,11 @@ static inline bool isar_feature_aa32_dp(const ARMISARegisters *id)
    return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0;
}

static inline bool isar_feature_aa32_fhm(const ARMISARegisters *id)
{
    return FIELD_EX32(id->id_isar6, ID_ISAR6, FHM) != 0;
}

static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id)
{
    /*
+96 −33
Original line number Diff line number Diff line
@@ -8383,15 +8383,9 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn)
    gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL;
    int rd, rn, rm, opr_sz;
    int data = 0;
    bool q;

    q = extract32(insn, 6, 1);
    VFP_DREG_D(rd, insn);
    VFP_DREG_N(rn, insn);
    VFP_DREG_M(rm, insn);
    if ((rd | rn | rm) & q) {
        return 1;
    }
    int off_rn, off_rm;
    bool is_long = false, q = extract32(insn, 6, 1);
    bool ptr_is_env = false;

    if ((insn & 0xfe200f10) == 0xfc200800) {
        /* VCMLA -- 1111 110R R.1S .... .... 1000 ...0 .... */
@@ -8418,10 +8412,39 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn)
            return 1;
        }
        fn_gvec = u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b;
    } else if ((insn & 0xff300f10) == 0xfc200810) {
        /* VFM[AS]L -- 1111 1100 S.10 .... .... 1000 .Q.1 .... */
        int is_s = extract32(insn, 23, 1);
        if (!dc_isar_feature(aa32_fhm, s)) {
            return 1;
        }
        is_long = true;
        data = is_s; /* is_2 == 0 */
        fn_gvec_ptr = gen_helper_gvec_fmlal_a32;
        ptr_is_env = true;
    } else {
        return 1;
    }

    VFP_DREG_D(rd, insn);
    if (rd & q) {
        return 1;
    }
    if (q || !is_long) {
        VFP_DREG_N(rn, insn);
        VFP_DREG_M(rm, insn);
        if ((rn | rm) & q & !is_long) {
            return 1;
        }
        off_rn = vfp_reg_offset(1, rn);
        off_rm = vfp_reg_offset(1, rm);
    } else {
        rn = VFP_SREG_N(insn);
        rm = VFP_SREG_M(insn);
        off_rn = vfp_reg_offset(0, rn);
        off_rm = vfp_reg_offset(0, rm);
    }

    if (s->fp_excp_el) {
        gen_exception_insn(s, 4, EXCP_UDEF,
                           syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
@@ -8433,16 +8456,19 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn)

    opr_sz = (1 + q) * 8;
    if (fn_gvec_ptr) {
        TCGv_ptr fpst = get_fpstatus_ptr(1);
        tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd),
                           vfp_reg_offset(1, rn),
                           vfp_reg_offset(1, rm), fpst,
        TCGv_ptr ptr;
        if (ptr_is_env) {
            ptr = cpu_env;
        } else {
            ptr = get_fpstatus_ptr(1);
        }
        tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), off_rn, off_rm, ptr,
                           opr_sz, opr_sz, data, fn_gvec_ptr);
        tcg_temp_free_ptr(fpst);
        if (!ptr_is_env) {
            tcg_temp_free_ptr(ptr);
        }
    } else {
        tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd),
                           vfp_reg_offset(1, rn),
                           vfp_reg_offset(1, rm),
        tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), off_rn, off_rm,
                           opr_sz, opr_sz, data, fn_gvec);
    }
    return 0;
@@ -8461,14 +8487,9 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn)
    gen_helper_gvec_3 *fn_gvec = NULL;
    gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL;
    int rd, rn, rm, opr_sz, data;
    bool q;

    q = extract32(insn, 6, 1);
    VFP_DREG_D(rd, insn);
    VFP_DREG_N(rn, insn);
    if ((rd | rn) & q) {
        return 1;
    }
    int off_rn, off_rm;
    bool is_long = false, q = extract32(insn, 6, 1);
    bool ptr_is_env = false;

    if ((insn & 0xff000f10) == 0xfe000800) {
        /* VCMLA (indexed) -- 1111 1110 S.RR .... .... 1000 ...0 .... */
@@ -8497,6 +8518,7 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn)
    } else if ((insn & 0xffb00f00) == 0xfe200d00) {
        /* V[US]DOT -- 1111 1110 0.10 .... .... 1101 .Q.U .... */
        int u = extract32(insn, 4, 1);

        if (!dc_isar_feature(aa32_dp, s)) {
            return 1;
        }
@@ -8504,10 +8526,48 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn)
        /* rm is just Vm, and index is M.  */
        data = extract32(insn, 5, 1); /* index */
        rm = extract32(insn, 0, 4);
    } else if ((insn & 0xffa00f10) == 0xfe000810) {
        /* VFM[AS]L -- 1111 1110 0.0S .... .... 1000 .Q.1 .... */
        int is_s = extract32(insn, 20, 1);
        int vm20 = extract32(insn, 0, 3);
        int vm3 = extract32(insn, 3, 1);
        int m = extract32(insn, 5, 1);
        int index;

        if (!dc_isar_feature(aa32_fhm, s)) {
            return 1;
        }
        if (q) {
            rm = vm20;
            index = m * 2 + vm3;
        } else {
            rm = vm20 * 2 + m;
            index = vm3;
        }
        is_long = true;
        data = (index << 2) | is_s; /* is_2 == 0 */
        fn_gvec_ptr = gen_helper_gvec_fmlal_idx_a32;
        ptr_is_env = true;
    } else {
        return 1;
    }

    VFP_DREG_D(rd, insn);
    if (rd & q) {
        return 1;
    }
    if (q || !is_long) {
        VFP_DREG_N(rn, insn);
        if (rn & q & !is_long) {
            return 1;
        }
        off_rn = vfp_reg_offset(1, rn);
        off_rm = vfp_reg_offset(1, rm);
    } else {
        rn = VFP_SREG_N(insn);
        off_rn = vfp_reg_offset(0, rn);
        off_rm = vfp_reg_offset(0, rm);
    }
    if (s->fp_excp_el) {
        gen_exception_insn(s, 4, EXCP_UDEF,
                           syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
@@ -8519,16 +8579,19 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn)

    opr_sz = (1 + q) * 8;
    if (fn_gvec_ptr) {
        TCGv_ptr fpst = get_fpstatus_ptr(1);
        tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd),
                           vfp_reg_offset(1, rn),
                           vfp_reg_offset(1, rm), fpst,
        TCGv_ptr ptr;
        if (ptr_is_env) {
            ptr = cpu_env;
        } else {
            ptr = get_fpstatus_ptr(1);
        }
        tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), off_rn, off_rm, ptr,
                           opr_sz, opr_sz, data, fn_gvec_ptr);
        tcg_temp_free_ptr(fpst);
        if (!ptr_is_env) {
            tcg_temp_free_ptr(ptr);
        }
    } else {
        tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd),
                           vfp_reg_offset(1, rn),
                           vfp_reg_offset(1, rm),
        tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), off_rn, off_rm,
                           opr_sz, opr_sz, data, fn_gvec);
    }
    return 0;