Re: [PATCH 3/5] target/riscv: rvv: Add SiFive custom int8 matmul instructions
Max Chou <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <[email protected]> |
On 2026-08-06 18:13, Daniel Henrique Barboza wrote: > > > 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. > > Hi Daniel, I believe we can move the vendor helper to the new helper file at v2. Additionally, we can extract the common part into vector_helper.c or vector_internal.h for related ISA extensions in the future. In fact, I’m preparing the upstream patchset for Zvdota/Zvbdota extensions and will send it after a release tag is added to the riscv-isa-manual repository. Thanks, rnax > 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 >