Re: [PATCH 3/5] target/riscv: rvv: Add SiFive custom int8 matmul instructions
Daniel Henrique Barboza <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <[email protected]> |
On 7/21/2026 9:20 AM, Max Chou wrote: > From: Frank Chang <[email protected]> > > Add the 8 SiFive custom int8 matrix-multiply vector instructions: > sf.vqmacc{u,,us,su}.4x8x4 and sf.vqmacc{u,,us,su}.2x8x2. Each name > suffix encodes the signedness of vs1/vs2. > The 4x8x4 forms multiply-accumulate a 4x8 by 8x4 int8 tile into a > 4x4 int32 result; the 2x8x2 forms use a 2x8 by 8x2 tile producing a > 2x2 int32 result. Both Xsfvqmaccqoq/Xsfvqmaccdod extensions are > gated on vlenb >= 32, sew == 8 and vm == 1, per the SiFive Int8 > Matrix Multiplication Extensions Specification. > > Signed-off-by: Frank Chang <[email protected]> > Signed-off-by: Max Chou <[email protected]> > --- One thing that caught my attention is adding what is, at least for now, a vendor specific helper in vector_helper.c which is a common code helper. Existing vendor extensions in QEMU doesn't do that, at least from what I can see. All this said, I have a suspicion that the code for this extension will be re-used in zvldot/zvbdot, so keeping this helper in vector_helper.c is ok to me. Reviewed-by: Daniel Henrique Barboza <[email protected]> > MAINTAINERS | 7 ++ > target/riscv/cpu_cfg.h | 5 ++ > target/riscv/helper.h | 10 +++ > target/riscv/meson.build | 1 + > target/riscv/tcg/insn_trans/trans_xsf.c.inc | 98 +++++++++++++++++++++ > target/riscv/tcg/translate.c | 3 + > target/riscv/tcg/vector_helper.c | 74 ++++++++++++++++ > target/riscv/xsf.decode | 30 +++++++ > 8 files changed, 228 insertions(+) > create mode 100644 target/riscv/tcg/insn_trans/trans_xsf.c.inc > create mode 100644 target/riscv/xsf.decode > > diff --git a/MAINTAINERS b/MAINTAINERS > index 97dcc78ded..94cd63eeba 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -389,6 +389,13 @@ F: target/riscv/XVentanaCondOps.decode > F: target/riscv/insn_trans/trans_xventanacondops.c.inc > F: disas/riscv-xventana* > > +RISC-V SiFive (Xsf*) extensions > +M: Max Chou <[email protected]> > +L: [email protected] > +S: Supported > +F: target/riscv/xsf.decode > +F: target/riscv/tcg/insn_trans/trans_xsf.c.inc > + > RENESAS RX CPUs > R: Yoshinori Sato <[email protected]> > S: Orphan > diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h > index 211d0708ba..d6db1cfb7c 100644 > --- a/target/riscv/cpu_cfg.h > +++ b/target/riscv/cpu_cfg.h > @@ -51,6 +51,11 @@ static inline bool has_xthead_p(const RISCVCPUConfig *cfg) > cfg->ext_xtheadmempair || cfg->ext_xtheadsync; > } > > +static inline bool has_xsf_p(const RISCVCPUConfig *cfg) > +{ > + return cfg->ext_xsfvqmaccdod || cfg->ext_xsfvqmaccqoq; > +} > + > #define MATERIALISE_EXT_PREDICATE(ext) \ > static inline bool has_ ## ext ## _p(const RISCVCPUConfig *cfg) \ > { \ > diff --git a/target/riscv/helper.h b/target/riscv/helper.h > index 542b7c264f..4234f46271 100644 > --- a/target/riscv/helper.h > +++ b/target/riscv/helper.h > @@ -1358,3 +1358,13 @@ DEF_HELPER_1(ssamoswap_disabled, void, env) > > /* Zalrsc SC write probe */ > DEF_HELPER_FLAGS_3(sc_probe_write, TCG_CALL_NO_WG, void, env, tl, tl) > + > +/* SiFive Custom int8 Matrix-Multiply */ > +DEF_HELPER_5(sf_vqmaccu_4x8x4, void, ptr, ptr, ptr, env, i32) > +DEF_HELPER_5(sf_vqmacc_4x8x4, void, ptr, ptr, ptr, env, i32) > +DEF_HELPER_5(sf_vqmaccus_4x8x4, void, ptr, ptr, ptr, env, i32) > +DEF_HELPER_5(sf_vqmaccsu_4x8x4, void, ptr, ptr, ptr, env, i32) > +DEF_HELPER_5(sf_vqmaccu_2x8x2, void, ptr, ptr, ptr, env, i32) > +DEF_HELPER_5(sf_vqmacc_2x8x2, void, ptr, ptr, ptr, env, i32) > +DEF_HELPER_5(sf_vqmaccus_2x8x2, void, ptr, ptr, ptr, env, i32) > +DEF_HELPER_5(sf_vqmaccsu_2x8x2, void, ptr, ptr, ptr, env, i32) > diff --git a/target/riscv/meson.build b/target/riscv/meson.build > index 42d0f6d538..c06526adb2 100644 > --- a/target/riscv/meson.build > +++ b/target/riscv/meson.build > @@ -6,6 +6,7 @@ gen = [ > decodetree.process('XVentanaCondOps.decode', extra_args: '--static-decode=decode_XVentanaCodeOps'), > decodetree.process('xmips.decode', extra_args: '--static-decode=decode_xmips'), > decodetree.process('xlrbr.decode', extra_args: '--static-decode=decode_xlrbr'), > + decodetree.process('xsf.decode', extra_args: '--static-decode=decode_xsf'), > ] > > riscv_ss = ss.source_set() > diff --git a/target/riscv/tcg/insn_trans/trans_xsf.c.inc b/target/riscv/tcg/insn_trans/trans_xsf.c.inc > new file mode 100644 > index 0000000000..1677352689 > --- /dev/null > +++ b/target/riscv/tcg/insn_trans/trans_xsf.c.inc > @@ -0,0 +1,98 @@ > +/* > + * RISC-V translation routines for the SiFive vendor extensions (xsf*) > + * > + * Copyright (c) 2023 SiFive, Inc. > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + */ > + > + > +/* > + * SiFive Xsfvqmaccdod/Xsfvqmaccqoq custom int8 matrix-multiply extensions > + */ > +static bool sf_int8_matmul_check(DisasContext *s, arg_rmrr *a) > +{ > + return require_rvv(s) && > + vext_check_isa_ill(s) && > + s->vstart_eq_zero && > + (s->cfg_ptr->vlenb >= 32) && > + (s->sew == MO_8) && > + (a->vm == 1); > +} > + > +static bool sf_int8_matmul_4x8x4_check(DisasContext *s, arg_rmrr *a) > +{ > + /* > + * vd has EMUL=2*LMUL > + * vs2 has EMUL=LMUL > + * vs1 has EMUL=1 > + * vd must not overlap vs1 > + */ > + return sf_int8_matmul_check(s, a) && > + (s->cfg_ptr->ext_xsfvqmaccqoq) && > + (s->lmul <= 2) && > + require_align(a->rd, s->lmul + 1) && > + require_align(a->rs2, s->lmul) && > + require_align(a->rs1, 0) && > + require_noover(a->rd, s->lmul + 1, a->rs2, s->lmul) && > + !is_overlapped(a->rd, 1 << MAX(s->lmul + 1, 0), a->rs1, 1); > +} > + > +static bool sf_int8_matmul_2x8x2_check(DisasContext *s, arg_rmrr *a) > +{ > + /* > + * vd has EMUL=LMUL > + * vs2 has EMUL=LMUL > + * vs1 has EMUL=1 > + * vd must not overlap vs1 > + */ > + return sf_int8_matmul_check(s, a) && > + (s->cfg_ptr->ext_xsfvqmaccdod) && > + require_align(a->rd, s->lmul) && > + require_align(a->rs2, s->lmul) && > + require_align(a->rs1, 0) && > + !is_overlapped(a->rd, 1 << MAX(s->lmul, 0), a->rs1, 1); > +} > + > +static bool sf_int8_matmul_op(DisasContext *s, arg_rmrr *a, uint8_t seq) > +{ > + static gen_helper_gvec_3_ptr * const fns[8] = { > + gen_helper_sf_vqmaccu_4x8x4, gen_helper_sf_vqmacc_4x8x4, > + gen_helper_sf_vqmaccus_4x8x4, gen_helper_sf_vqmaccsu_4x8x4, > + gen_helper_sf_vqmaccu_2x8x2, gen_helper_sf_vqmacc_2x8x2, > + gen_helper_sf_vqmaccus_2x8x2, gen_helper_sf_vqmaccsu_2x8x2, > + }; > + > + /* > + * The helper raises an illegal-instruction exception when vl is not a > + * multiple of the tile size; save the opcode so mtval/stval report the > + * faulting instruction if that exception is thrown. > + */ > + decode_save_opc(s, 0); > + > + tcg_gen_gvec_3_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), > + vreg_ofs(s, a->rs2), tcg_env, > + s->cfg_ptr->vlenb, s->cfg_ptr->vlenb, 0, fns[seq]); > + > + finalize_rvv_inst(s); > + > + return true; > +} > + > +#define GEN_SF_INT8_MATMUL_TRANS(NAME, CHECK, SEQ) \ > +static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ > +{ \ > + if (CHECK(s, a)) { \ > + return sf_int8_matmul_op(s, a, SEQ); \ > + } \ > + return false; \ > +} > + > +GEN_SF_INT8_MATMUL_TRANS(sf_vqmaccu_4x8x4, sf_int8_matmul_4x8x4_check, 0) > +GEN_SF_INT8_MATMUL_TRANS(sf_vqmacc_4x8x4, sf_int8_matmul_4x8x4_check, 1) > +GEN_SF_INT8_MATMUL_TRANS(sf_vqmaccus_4x8x4, sf_int8_matmul_4x8x4_check, 2) > +GEN_SF_INT8_MATMUL_TRANS(sf_vqmaccsu_4x8x4, sf_int8_matmul_4x8x4_check, 3) > +GEN_SF_INT8_MATMUL_TRANS(sf_vqmaccu_2x8x2, sf_int8_matmul_2x8x2_check, 4) > +GEN_SF_INT8_MATMUL_TRANS(sf_vqmacc_2x8x2, sf_int8_matmul_2x8x2_check, 5) > +GEN_SF_INT8_MATMUL_TRANS(sf_vqmaccus_2x8x2, sf_int8_matmul_2x8x2_check, 6) > +GEN_SF_INT8_MATMUL_TRANS(sf_vqmaccsu_2x8x2, sf_int8_matmul_2x8x2_check, 7) > diff --git a/target/riscv/tcg/translate.c b/target/riscv/tcg/translate.c > index 9684dbe752..41e3dd2fe2 100644 > --- a/target/riscv/tcg/translate.c > +++ b/target/riscv/tcg/translate.c > @@ -1216,10 +1216,12 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) > #include "decode-xthead.c.inc" > #include "decode-xmips.c.inc" > #include "decode-xlrbr.c.inc" > +#include "decode-xsf.c.inc" > #include "insn_trans/trans_xthead.c.inc" > #include "insn_trans/trans_xventanacondops.c.inc" > #include "insn_trans/trans_xmips.c.inc" > #include "insn_trans/trans_xlrbr.c.inc" > +#include "insn_trans/trans_xsf.c.inc" > > /* Include the auto-generated decoder for 16 bit insn */ > #include "decode-insn16.c.inc" > @@ -1240,6 +1242,7 @@ const RISCVDecoder decoder_table[] = { > { has_xthead_p, decode_xthead}, > { has_XVentanaCondOps_p, decode_XVentanaCodeOps}, > { has_xlrbr_p, decode_xlrbr}, > + { has_xsf_p, decode_xsf }, > }; > > const size_t decoder_table_size = ARRAY_SIZE(decoder_table); > diff --git a/target/riscv/tcg/vector_helper.c b/target/riscv/tcg/vector_helper.c > index e321ca2616..a9b5d861dc 100644 > --- a/target/riscv/tcg/vector_helper.c > +++ b/target/riscv/tcg/vector_helper.c > @@ -5871,3 +5871,77 @@ GEN_VEXT_INT_EXT(vsext_vf2_d, int64_t, int32_t, H8, H4) > GEN_VEXT_INT_EXT(vsext_vf4_w, int32_t, int8_t, H4, H1) > GEN_VEXT_INT_EXT(vsext_vf4_d, int64_t, int16_t, H8, H2) > GEN_VEXT_INT_EXT(vsext_vf8_d, int64_t, int8_t, H8, H1) > + > +/* SiFive Custom int8 Matrix-Multiply */ > +#define SF_QOP_SUU_B int32_t, uint8_t, uint8_t, int32_t, int32_t > +#define SF_QOP_SUS_B int32_t, uint8_t, int8_t, int32_t, int32_t > +#define SF_QOP_SSU_B int32_t, int8_t, uint8_t, int32_t, int32_t > +#define SF_QOP_SSS_B int32_t, int8_t, int8_t, int32_t, int32_t > + > +/* > + * vd may overlap vs2, we need to allocate an additional vd array > + * to save temporary results of vd and write them back at the end. > + */ > +#define GEN_VEXT_SF_INT8_MATMUL(NAME, TD, T1, T2, TX1, TX2, \ > + HD, HS1, HS2, ROWS, COLS, TILE_SIZE) \ > +void HELPER(NAME)(void *vd, void *vs1, void *vs2, \ > + CPURISCVState *env, uint32_t desc) \ > +{ \ > + int it, il, in, im, ivd, ivs1, ivs2; \ > + TD *vds; \ > + \ > + if (env->vl % TILE_SIZE) { \ > + riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); \ > + return; \ > + } \ > + \ > + VSTART_CHECK_EARLY_EXIT(env, env->vl); \ > + \ > + vds = g_malloc0(sizeof(TD) * \ > + ROWS * ROWS * (env->vl / TILE_SIZE)); \ > + \ > + for (it = 0; it < (env->vl / TILE_SIZE); it++) { \ > + for (il = 0; il < ROWS; il++) { \ > + for (in = 0; in < ROWS; in++) { \ > + ivd = ROWS * ROWS * it + ROWS * il + in; \ > + vds[ivd] = *((TD *)vd + HD(ivd)); \ > + for (im = 0; im < COLS; im++) { \ > + ivs1 = il * COLS + im; \ > + ivs2 = TILE_SIZE * it + im * ROWS + in; \ > + T1 s1 = *((T1 *)vs1 + HS1(ivs1)); \ > + T2 s2 = *((T2 *)vs2 + HS2(ivs2)); \ > + vds[ivd] += (TX1)s1 * (TX2)s2; \ > + } \ > + } \ > + } \ > + } \ > + \ > + for (it = 0; it < (env->vl / TILE_SIZE); it++) { \ > + for (il = 0; il < ROWS; il++) { \ > + for (in = 0; in < ROWS; in++) { \ > + ivd = ROWS * ROWS * it + ROWS * il + in; \ > + *((TD *)vd + HD(ivd)) = vds[ivd]; \ > + } \ > + } \ > + } \ > + \ > + env->vstart = 0; \ > + g_free(vds); \ > +} > + > +RVVCALL(GEN_VEXT_SF_INT8_MATMUL, sf_vqmaccu_4x8x4, SF_QOP_SUU_B, > + H4, H1, H1, 4, 8, 32) > +RVVCALL(GEN_VEXT_SF_INT8_MATMUL, sf_vqmacc_4x8x4, SF_QOP_SSS_B, > + H4, H1, H1, 4, 8, 32) > +RVVCALL(GEN_VEXT_SF_INT8_MATMUL, sf_vqmaccus_4x8x4, SF_QOP_SUS_B, > + H4, H1, H1, 4, 8, 32) > +RVVCALL(GEN_VEXT_SF_INT8_MATMUL, sf_vqmaccsu_4x8x4, SF_QOP_SSU_B, > + H4, H1, H1, 4, 8, 32) > +RVVCALL(GEN_VEXT_SF_INT8_MATMUL, sf_vqmaccu_2x8x2, SF_QOP_SUU_B, > + H4, H1, H1, 2, 8, 16) > +RVVCALL(GEN_VEXT_SF_INT8_MATMUL, sf_vqmacc_2x8x2, SF_QOP_SSS_B, > + H4, H1, H1, 2, 8, 16) > +RVVCALL(GEN_VEXT_SF_INT8_MATMUL, sf_vqmaccus_2x8x2, SF_QOP_SUS_B, > + H4, H1, H1, 2, 8, 16) > +RVVCALL(GEN_VEXT_SF_INT8_MATMUL, sf_vqmaccsu_2x8x2, SF_QOP_SSU_B, > + H4, H1, H1, 2, 8, 16) > diff --git a/target/riscv/xsf.decode b/target/riscv/xsf.decode > new file mode 100644 > index 0000000000..bb585046ab > --- /dev/null > +++ b/target/riscv/xsf.decode > @@ -0,0 +1,30 @@ > +# > +# RISC-V translation routines for the SiFive vendor extensions > +# > +# Copyright (c) 2023 SiFive, Inc. > +# > +# SPDX-License-Identifier: GPL-2.0-or-later > + > +# Fields: > +%rs2 20:5 > +%rs1 15:5 > +%rd 7:5 > +%vm 25:1 > + > +# Argument sets: > +&rmrr vm rd rs1 rs2 !extern > + > +# Formats: > +@r_vm_1 ...... . ..... ..... ... ..... ....... &rmrr vm=1 %rs2 %rs1 %rd > + > +# *** Xsfvqmaccqoq: SiFive custom int8 matrix-multiply (4x8x4 tile) *** > +sf_vqmaccu_4x8x4 111100 1 ..... ..... 010 ..... 1011011 @r_vm_1 > +sf_vqmacc_4x8x4 111101 1 ..... ..... 010 ..... 1011011 @r_vm_1 > +sf_vqmaccus_4x8x4 111110 1 ..... ..... 010 ..... 1011011 @r_vm_1 > +sf_vqmaccsu_4x8x4 111111 1 ..... ..... 010 ..... 1011011 @r_vm_1 > + > +# *** Xsfvqmaccdod: SiFive custom int8 matrix-multiply (2x8x2 tile) *** > +sf_vqmaccu_2x8x2 101100 1 ..... ..... 010 ..... 1011011 @r_vm_1 > +sf_vqmacc_2x8x2 101101 1 ..... ..... 010 ..... 1011011 @r_vm_1 > +sf_vqmaccus_2x8x2 101110 1 ..... ..... 010 ..... 1011011 @r_vm_1 > +sf_vqmaccsu_2x8x2 101111 1 ..... ..... 010 ..... 1011011 @r_vm_1