target/arm: Implement VFMAL and VFMSL for aarch32

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20190219222952.22183-4-richard.henderson@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Richard Henderson 2019-02-28 10:55:17 +00:00 committed by Peter Maydell
parent 0caa5af802
commit 87732318c5
2 changed files with 101 additions and 33 deletions

View File

@ -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)
{
/*

View File

@ -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;