mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-07-09 22:07:25 +00:00
target/arm: Implement fp16 for Neon VMUL, VMLA, VMLS
Convert the Neon floating-point VMUL, VMLA and VMLS to use gvec, and use this to implement fp16 support. Backports fc8ae790311882afa3c7816df004daf978c40e9a
This commit is contained in:
parent
8c6affbca4
commit
b948636c4a
|
@ -2466,70 +2466,71 @@ static bool trans_VMLS_2sc(DisasContext *s, arg_2scalar *a)
|
||||||
return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
|
return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static bool do_2scalar_fp_vec(DisasContext *s, arg_2scalar *a,
|
||||||
* Rather than have a float-specific version of do_2scalar just for
|
gen_helper_gvec_3_ptr *fn)
|
||||||
* three insns, we wrap a NeonGenTwoSingleOpFn to turn it into
|
{
|
||||||
* a NeonGenTwoOpFn.
|
/* Two registers and a scalar, using gvec */
|
||||||
*/
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
#define WRAP_FP_FN(WRAPNAME, FUNC) \
|
int vec_size = a->q ? 16 : 8;
|
||||||
static void WRAPNAME(TCGContext *s, TCGv_i32 rd, TCGv_i32 rn, TCGv_i32 rm) \
|
int rd_ofs = neon_reg_offset(a->vd, 0);
|
||||||
{ \
|
int rn_ofs = neon_reg_offset(a->vn, 0);
|
||||||
TCGv_ptr fpstatus = fpstatus_ptr(s, FPST_STD); \
|
int rm_ofs;
|
||||||
FUNC(s, rd, rn, rm, fpstatus); \
|
int idx;
|
||||||
tcg_temp_free_ptr(s, fpstatus); \
|
TCGv_ptr fpstatus;
|
||||||
|
|
||||||
|
if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
WRAP_FP_FN(gen_VMUL_F_mul, gen_helper_vfp_muls)
|
/* UNDEF accesses to D16-D31 if they don't exist. */
|
||||||
WRAP_FP_FN(gen_VMUL_F_add, gen_helper_vfp_adds)
|
if (!dc_isar_feature(aa32_simd_r32, s) &&
|
||||||
WRAP_FP_FN(gen_VMUL_F_sub, gen_helper_vfp_subs)
|
((a->vd | a->vn | a->vm) & 0x10)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool trans_VMUL_F_2sc(DisasContext *s, arg_2scalar *a)
|
if (!fn) {
|
||||||
{
|
/* Bad size (including size == 3, which is a different insn group) */
|
||||||
static NeonGenTwoOpFn * const opfn[] = {
|
return false;
|
||||||
NULL,
|
}
|
||||||
NULL, /* TODO: fp16 support */
|
|
||||||
gen_VMUL_F_mul,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
return do_2scalar(s, a, opfn[a->size], NULL);
|
if (a->q && ((a->vd | a->vn) & 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vfp_access_check(s)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a->vm is M:Vm, which encodes both register and index */
|
||||||
|
idx = extract32(a->vm, a->size + 2, 2);
|
||||||
|
a->vm = extract32(a->vm, 0, a->size + 2);
|
||||||
|
rm_ofs = neon_reg_offset(a->vm, 0);
|
||||||
|
|
||||||
|
fpstatus = fpstatus_ptr(tcg_ctx, a->size == 1 ? FPST_STD_F16 : FPST_STD);
|
||||||
|
tcg_gen_gvec_3_ptr(tcg_ctx, rd_ofs, rn_ofs, rm_ofs, fpstatus,
|
||||||
|
vec_size, vec_size, idx, fn);
|
||||||
|
tcg_temp_free_ptr(tcg_ctx, fpstatus);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool trans_VMLA_F_2sc(DisasContext *s, arg_2scalar *a)
|
#define DO_VMUL_F_2sc(NAME, FUNC) \
|
||||||
{
|
static bool trans_##NAME##_F_2sc(DisasContext *s, arg_2scalar *a) \
|
||||||
static NeonGenTwoOpFn * const opfn[] = {
|
{ \
|
||||||
NULL,
|
static gen_helper_gvec_3_ptr * const opfn[] = { \
|
||||||
NULL, /* TODO: fp16 support */
|
NULL, \
|
||||||
gen_VMUL_F_mul,
|
gen_helper_##FUNC##_h, \
|
||||||
NULL,
|
gen_helper_##FUNC##_s, \
|
||||||
};
|
NULL, \
|
||||||
static NeonGenTwoOpFn * const accfn[] = {
|
}; \
|
||||||
NULL,
|
if (a->size == MO_16 && !dc_isar_feature(aa32_fp16_arith, s)) { \
|
||||||
NULL, /* TODO: fp16 support */
|
return false; \
|
||||||
gen_VMUL_F_add,
|
} \
|
||||||
NULL,
|
return do_2scalar_fp_vec(s, a, opfn[a->size]); \
|
||||||
};
|
}
|
||||||
|
|
||||||
return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
|
DO_VMUL_F_2sc(VMUL, gvec_fmul_idx)
|
||||||
}
|
DO_VMUL_F_2sc(VMLA, gvec_fmla_nf_idx)
|
||||||
|
DO_VMUL_F_2sc(VMLS, gvec_fmls_nf_idx)
|
||||||
static bool trans_VMLS_F_2sc(DisasContext *s, arg_2scalar *a)
|
|
||||||
{
|
|
||||||
static NeonGenTwoOpFn * const opfn[] = {
|
|
||||||
NULL,
|
|
||||||
NULL, /* TODO: fp16 support */
|
|
||||||
gen_VMUL_F_mul,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
static NeonGenTwoOpFn * const accfn[] = {
|
|
||||||
NULL,
|
|
||||||
NULL, /* TODO: fp16 support */
|
|
||||||
gen_VMUL_F_sub,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
return do_2scalar(s, a, opfn[a->size], accfn[a->size]);
|
|
||||||
}
|
|
||||||
|
|
||||||
WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16)
|
WRAP_ENV_FN(gen_VQDMULH_16, gen_helper_neon_qdmulh_s16)
|
||||||
WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32)
|
WRAP_ENV_FN(gen_VQDMULH_32, gen_helper_neon_qdmulh_s32)
|
||||||
|
|
Loading…
Reference in a new issue