target/riscv: vector integer add-with-carry / subtract-with-borrow instructions

Signed-off-by: LIU Zhiwei <zhiwei_liu@c-sky.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20200701152549.1218-13-zhiwei_liu@c-sky.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
LIU Zhiwei 2020-07-01 23:25:00 +08:00 committed by Alistair Francis
parent 8fcdf77630
commit 3a6f8f68ad
4 changed files with 294 additions and 0 deletions

View file

@ -1249,3 +1249,116 @@ GEN_OPIWX_WIDEN_TRANS(vwaddu_wx)
GEN_OPIWX_WIDEN_TRANS(vwadd_wx)
GEN_OPIWX_WIDEN_TRANS(vwsubu_wx)
GEN_OPIWX_WIDEN_TRANS(vwsub_wx)
/* Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions */
/* OPIVV without GVEC IR */
#define GEN_OPIVV_TRANS(NAME, CHECK) \
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
{ \
if (CHECK(s, a)) { \
uint32_t data = 0; \
static gen_helper_gvec_4_ptr * const fns[4] = { \
gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
}; \
TCGLabel *over = gen_new_label(); \
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); \
\
data = FIELD_DP32(data, VDATA, MLEN, s->mlen); \
data = FIELD_DP32(data, VDATA, VM, a->vm); \
data = FIELD_DP32(data, VDATA, LMUL, s->lmul); \
tcg_gen_gvec_4_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, 0), \
vreg_ofs(s, a->rs1), \
vreg_ofs(s, a->rs2), cpu_env, 0, \
s->vlen / 8, data, fns[s->sew]); \
gen_set_label(over); \
return true; \
} \
return false; \
}
/*
* For vadc and vsbc, an illegal instruction exception is raised if the
* destination vector register is v0 and LMUL > 1. (Section 12.3)
*/
static bool opivv_vadc_check(DisasContext *s, arg_rmrr *a)
{
return (vext_check_isa_ill(s) &&
vext_check_reg(s, a->rd, false) &&
vext_check_reg(s, a->rs2, false) &&
vext_check_reg(s, a->rs1, false) &&
((a->rd != 0) || (s->lmul == 0)));
}
GEN_OPIVV_TRANS(vadc_vvm, opivv_vadc_check)
GEN_OPIVV_TRANS(vsbc_vvm, opivv_vadc_check)
/*
* For vmadc and vmsbc, an illegal instruction exception is raised if the
* destination vector register overlaps a source vector register group.
*/
static bool opivv_vmadc_check(DisasContext *s, arg_rmrr *a)
{
return (vext_check_isa_ill(s) &&
vext_check_reg(s, a->rs2, false) &&
vext_check_reg(s, a->rs1, false) &&
vext_check_overlap_group(a->rd, 1, a->rs1, 1 << s->lmul) &&
vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul));
}
GEN_OPIVV_TRANS(vmadc_vvm, opivv_vmadc_check)
GEN_OPIVV_TRANS(vmsbc_vvm, opivv_vmadc_check)
static bool opivx_vadc_check(DisasContext *s, arg_rmrr *a)
{
return (vext_check_isa_ill(s) &&
vext_check_reg(s, a->rd, false) &&
vext_check_reg(s, a->rs2, false) &&
((a->rd != 0) || (s->lmul == 0)));
}
/* OPIVX without GVEC IR */
#define GEN_OPIVX_TRANS(NAME, CHECK) \
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
{ \
if (CHECK(s, a)) { \
static gen_helper_opivx * const fns[4] = { \
gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
gen_helper_##NAME##_w, gen_helper_##NAME##_d, \
}; \
\
return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fns[s->sew], s);\
} \
return false; \
}
GEN_OPIVX_TRANS(vadc_vxm, opivx_vadc_check)
GEN_OPIVX_TRANS(vsbc_vxm, opivx_vadc_check)
static bool opivx_vmadc_check(DisasContext *s, arg_rmrr *a)
{
return (vext_check_isa_ill(s) &&
vext_check_reg(s, a->rs2, false) &&
vext_check_overlap_group(a->rd, 1, a->rs2, 1 << s->lmul));
}
GEN_OPIVX_TRANS(vmadc_vxm, opivx_vmadc_check)
GEN_OPIVX_TRANS(vmsbc_vxm, opivx_vmadc_check)
/* OPIVI without GVEC IR */
#define GEN_OPIVI_TRANS(NAME, ZX, OPIVX, CHECK) \
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
{ \
if (CHECK(s, a)) { \
static gen_helper_opivx * const fns[4] = { \
gen_helper_##OPIVX##_b, gen_helper_##OPIVX##_h, \
gen_helper_##OPIVX##_w, gen_helper_##OPIVX##_d, \
}; \
return opivi_trans(a->rd, a->rs1, a->rs2, a->vm, \
fns[s->sew], s, ZX); \
} \
return false; \
}
GEN_OPIVI_TRANS(vadc_vim, 0, vadc_vxm, opivx_vadc_check)
GEN_OPIVI_TRANS(vmadc_vim, 0, vmadc_vxm, opivx_vmadc_check)