Re: [PATCH 5/5] tests/tcg/riscv64: Add tests for SiFive int8 matmul extensions

Daniel Henrique Barboza <[email protected]>
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>

On 7/21/2026 9:20 AM, Max Chou wrote:
> Add a test that exercises all SiFive int8 matrix-multiply instructions
> from the Xsfvqmaccqoq and Xsfvqmaccdod extensions.
> 
> For each tile shape the test covers the four signedness variants
> (sf.vqmaccu / sf.vqmacc / sf.vqmaccus / sf.vqmaccsu) and the
> reserved-encoding path: with vl set to a value that is not a multiple
> of the tile size the helper raises an illegal-instruction exception.
> 
> Signed-off-by: Max Chou <[email protected]>
> ---


Reviewed-by: Daniel Henrique Barboza <[email protected]>

>   MAINTAINERS                               |   1 +
>   tests/tcg/riscv64/Makefile.softmmu-target |   7 +
>   tests/tcg/riscv64/test-xsfvqmacc.S        | 260 ++++++++++++++++++++++
>   3 files changed, 268 insertions(+)
>   create mode 100644 tests/tcg/riscv64/test-xsfvqmacc.S
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 1a40d86685..d7bfe19b1d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -396,6 +396,7 @@ S: Supported
>   F: target/riscv/xsf.decode
>   F: target/riscv/tcg/insn_trans/trans_xsf.c.inc
>   F: disas/riscv-xsf*
> +F: tests/tcg/riscv64/test-xsfvqmacc.S
>   
>   RENESAS RX CPUs
>   R: Yoshinori Sato <[email protected]>
> diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target
> index 82be8a2c91..0615dc83e8 100644
> --- a/tests/tcg/riscv64/Makefile.softmmu-target
> +++ b/tests/tcg/riscv64/Makefile.softmmu-target
> @@ -41,5 +41,12 @@ comma:= ,
>   run-test-crc32: test-crc32
>   	$(call run-test, $<, $(QEMU) -cpu rv64$(comma)xlrbr=true $(QEMU_OPTS)$<)
>   
> +# The SiFive int8 matmul instructions are reserved unless VLEN >= 256, so the
> +# runner selects vlen=256 along with both extensions.
> +EXTRA_RUNS += run-test-xsfvqmacc
> +XSFVQMACC_CPU = rv64$(comma)v=true$(comma)vlen=256$(comma)xsfvqmaccdod=true$(comma)xsfvqmaccqoq=true
> +run-test-xsfvqmacc: test-xsfvqmacc
> +	$(call run-test, $<, $(QEMU) -cpu $(XSFVQMACC_CPU) $(QEMU_OPTS)$<)
> +
>   # We don't currently support the multiarch system tests
>   undefine MULTIARCH_TESTS
> diff --git a/tests/tcg/riscv64/test-xsfvqmacc.S b/tests/tcg/riscv64/test-xsfvqmacc.S
> new file mode 100644
> index 0000000000..a116712e50
> --- /dev/null
> +++ b/tests/tcg/riscv64/test-xsfvqmacc.S
> @@ -0,0 +1,260 @@
> +/*
> + * Test the SiFive Xsfvqmaccqoq/Xsfvqmaccdod custom int8 matrix-multiply
> + * extensions.
> + *
> + * The eight instructions widen 8-bit integer inputs to 32 bits and perform
> + * a matrix-multiply-accumulate into a vector of int32 accumulators:
> + *
> + *   C[j] += A * B[j]
> + *
> + * Xsfvqmaccqoq (4x8x4): A is 4x8, B[j] is 8x4, C[j] is 4x4 int32. One matrix
> + * operation is performed per 32 elements of vl (TILE_SIZE = 32).
> + * Xsfvqmaccdod (2x8x2): A is 2x8, B[j] is 8x2, C[j] is 2x2 int32. One matrix
> + * operation is performed per 16 elements of vl (TILE_SIZE = 16).
> + *
> + * The input tiles below contain bytes >= 0x80 so that each signedness
> + * variant produces a distinct result; the expected int32 tiles were computed
> + * with an independent reference model of the specification. The accumulators
> + * are cleared before every operation, so the expected value is the pure
> + * matrix product.
> + *
> + * Test exits via semihosting with status 0 on success, or the 1-based index
> + * of the first failing operation.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +	.option arch, +v
> +	.option norvc
> +
> +	.text
> +
> +/*
> + * Run one 4x8x4 operation: load the 32-byte A and B tiles, clear the 4x4
> + * int32 accumulator (vd = v4:v5, EMUL = 2), execute the op, then compare the
> + * 16 int32 results against the expected tile.
> + */
> +.macro RUN_QOQ id, word, exp
> +	li	a2, 32
> +	vsetvli	t0, a2, e8, m1, ta, ma
> +	la	t1, a_qoq
> +	vle8.v	v1, (t1)
> +	la	t1, b_qoq
> +	vle8.v	v2, (t1)
> +	vsetvli	t0, x0, e32, m2, ta, ma
> +	vmv.v.i	v4, 0
> +	li	a2, 32
> +	vsetvli	t0, a2, e8, m1, ta, ma
> +	.word	\word
> +	vsetvli	t0, x0, e32, m2, ta, ma
> +	la	t1, result
> +	vse32.v	v4, (t1)
> +	la	a0, result
> +	la	a1, \exp
> +	li	a2, 16
> +	li	t6, \id
> +	call	check_words
> +.endm
> +
> +/*
> + * Run one 2x8x2 operation: load the 16-byte A and B tiles, clear the 2x2
> + * int32 accumulator (vd = v4, EMUL = 1), execute the op, then compare the
> + * 4 int32 results against the expected tile.
> + */
> +.macro RUN_DOD id, word, exp
> +	li	a2, 16
> +	vsetvli	t0, a2, e8, m1, ta, ma
> +	la	t1, a_dod
> +	vle8.v	v1, (t1)
> +	la	t1, b_dod
> +	vle8.v	v2, (t1)
> +	vsetvli	t0, x0, e32, m1, ta, ma
> +	vmv.v.i	v4, 0
> +	li	a2, 16
> +	vsetvli	t0, a2, e8, m1, ta, ma
> +	.word	\word
> +	vsetvli	t0, x0, e32, m1, ta, ma
> +	la	t1, result
> +	vse32.v	v4, (t1)
> +	la	a0, result
> +	la	a1, \exp
> +	li	a2, 4
> +	li	t6, \id
> +	call	check_words
> +.endm
> +
> +	.global _start
> +_start:
> +	/* Enable the vector unit (mstatus.VS = Initial). */
> +	li	t0, 1 << 9
> +	csrs	mstatus, t0
> +
> +	/* Route synchronous traps to trap_handler (mtvec direct mode). */
> +	la	t0, trap_handler
> +	csrw	mtvec, t0
> +
> +	RUN_QOQ	1, 0xF220A25B, exp_qoq_u	/* sf.vqmaccu.4x8x4  */
> +	RUN_QOQ	2, 0xF620A25B, exp_qoq_s	/* sf.vqmacc.4x8x4   */
> +	RUN_QOQ	3, 0xFA20A25B, exp_qoq_us	/* sf.vqmaccus.4x8x4 */
> +	RUN_QOQ	4, 0xFE20A25B, exp_qoq_su	/* sf.vqmaccsu.4x8x4 */
> +	RUN_DOD	5, 0xB220A25B, exp_dod_u	/* sf.vqmaccu.2x8x2  */
> +	RUN_DOD	6, 0xB620A25B, exp_dod_s	/* sf.vqmacc.2x8x2   */
> +	RUN_DOD	7, 0xBA20A25B, exp_dod_us	/* sf.vqmaccus.2x8x2 */
> +	RUN_DOD	8, 0xBE20A25B, exp_dod_su	/* sf.vqmaccsu.2x8x2 */
> +
> +	/*
> +	 * Illegal-instruction reporting test (op 9).
> +	 *
> +	 * When vl is not a multiple of the tile size the instruction is
> +	 * reserved and the helper raises an illegal-instruction exception at
> +	 * runtime.
> +	 */
> +	la	t1, trap_mtval
> +	sd	zero, 0(t1)
> +	la	t1, trap_mcause
> +	sd	zero, 0(t1)
> +	/* vl = 16 is not a multiple of the 4x8x4 tile size (32 elements). */
> +	li	a2, 16
> +	vsetvli	t0, a2, e8, m1, ta, ma
> +	.word	0xF220A25B		/* sf.vqmaccu.4x8x4, traps */
> +	/* The handler skips the faulting insn, so control resumes here. */
> +	li	a0, 9			/* fail code for this check */
> +	la	t1, trap_mcause
> +	ld	t2, 0(t1)
> +	li	t3, 2			/* RISCV_EXCP_ILLEGAL_INST */
> +	bne	t2, t3, _exit
> +	la	t1, trap_mtval
> +	ld	t2, 0(t1)
> +	li	t3, 0xF220A25B
> +	bne	t2, t3, _exit
> +
> +	li	a0, 0
> +	j	_exit
> +
> +/*
> + * Machine-mode trap handler: record mcause and mtval, then advance mepc
> + * past the 4-byte faulting instruction and return.
> + */
> +	.balign	4
> +trap_handler:
> +	csrr	t4, mcause
> +	la	t5, trap_mcause
> +	sd	t4, 0(t5)
> +	csrr	t4, mtval
> +	la	t5, trap_mtval
> +	sd	t4, 0(t5)
> +	csrr	t4, mepc
> +	addi	t4, t4, 4
> +	csrw	mepc, t4
> +	mret
> +
> +/*
> + * check_words(a0 = result, a1 = expected, a2 = word count).
> + * Returns to the caller if every word matches; otherwise exits with the
> + * operation index held in t6.
> + */
> +check_words:
> +1:	beqz	a2, 2f
> +	lw	t2, 0(a0)
> +	lw	t3, 0(a1)
> +	bne	t2, t3, 3f
> +	addi	a0, a0, 4
> +	addi	a1, a1, 4
> +	addi	a2, a2, -1
> +	j	1b
> +2:	ret
> +3:	mv	a0, t6
> +	j	_exit
> +
> +/* Exit through the semihosting SYS_EXIT_EXTENDED call with a0 as the code. */
> +_exit:
> +	la	a1, semiargs
> +	li	t0, 0x20026	/* ADP_Stopped_ApplicationExit */
> +	sd	t0, 0(a1)
> +	sd	a0, 8(a1)
> +	li	a0, 0x20	/* TARGET_SYS_EXIT_EXTENDED */
> +	.balign	16
> +	slli	zero, zero, 0x1f
> +	ebreak
> +	srai	zero, zero, 0x7
> +	j	.
> +
> +	.data
> +	.balign	8
> +semiargs:
> +	.space	16
> +result:
> +	.space	64
> +trap_mcause:
> +	.space	8
> +trap_mtval:
> +	.space	8
> +
> +/*
> + * A (4x8, row-major) in bytes [0, 32) of vs1.
> + */
> +a_qoq:
> +	.byte	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x80
> +	.byte	0xFF, 0x01, 0x00, 0x02, 0x7F, 0x03, 0x04, 0x05
> +	.byte	0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x08
> +	.byte	0x00, 0x00, 0x81, 0x00, 0x00, 0x02, 0x00, 0x03
> +/*
> + * B (8x4, row-major) in bytes [0, 32) of vs2.
> + */
> +b_qoq:
> +	.byte	0x01, 0x02, 0x03, 0x04
> +	.byte	0x05, 0x06, 0x07, 0x08
> +	.byte	0x80, 0x7F, 0xFF, 0x01
> +	.byte	0x00, 0x10, 0x20, 0x30
> +	.byte	0x02, 0x02, 0x02, 0x02
> +	.byte	0xFE, 0x01, 0x00, 0x7F
> +	.byte	0x03, 0x00, 0x81, 0x04
> +	.byte	0x40, 0x50, 0x60, 0x70
> +/*
> + * A (2x8, row-major) in bytes [0, 16) of vs1.
> + */
> +a_dod:
> +	.byte	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x80
> +	.byte	0xFF, 0x7F, 0x00, 0x02, 0x81, 0x03, 0x04, 0x05
> +/*
> + * B (8x2, row-major) in bytes [0, 16) of vs2.
> + */
> +b_dod:
> +	.byte	0x01, 0x02
> +	.byte	0x80, 0x7F
> +	.byte	0x03, 0xFF
> +	.byte	0x00, 0x10
> +	.byte	0x02, 0xFE
> +	.byte	0x7F, 0x01
> +	.byte	0x81, 0x04
> +	.byte	0x40, 0x50
> +
> +	.balign	4
> +exp_qoq_u:
> +	.word	0x0000279e, 0x000029db, 0x0000371f, 0x00003bf7
> +	.word	0x00000648, 0x000004b5, 0x00000826, 0x0000091f
> +	.word	0x00007be0, 0x00002030, 0x000074f0, 0x000042f0
> +	.word	0x0000433c, 0x000040f1, 0x0000819f, 0x000002cf
> +exp_qoq_s:
> +	.word	0xffffde9e, 0xffffd9db, 0xffffcd1f, 0xffffcbf7
> +	.word	0x00000248, 0x000002b5, 0x00000126, 0x0000051f
> +	.word	0xffffebe0, 0x00002030, 0xffffd4f0, 0x000042f0
> +	.word	0x0000403c, 0xffffc1f1, 0x0000019f, 0x000001cf
> +exp_qoq_us:
> +	.word	0x00001e9e, 0x000029db, 0x00002d1f, 0x00003bf7
> +	.word	0x00000348, 0x000004b5, 0x00000426, 0x0000091f
> +	.word	0xffffebe0, 0x00002030, 0xffffd4f0, 0x000042f0
> +	.word	0xffffc03c, 0x000040f1, 0x0000009f, 0x000002cf
> +exp_qoq_su:
> +	.word	0xffffe79e, 0xffffd9db, 0xffffd71f, 0xffffcbf7
> +	.word	0x00000548, 0x000002b5, 0x00000526, 0x0000051f
> +	.word	0x00007be0, 0x00002030, 0x000074f0, 0x000042f0
> +	.word	0xffffc33c, 0xffffc1f1, 0xffff829f, 0x000001cf
> +exp_dod_u:
> +	.word	0x00002795, 0x00003155, 0x00004642, 0x0000c2c0
> +exp_dod_s:
> +	.word	0xffffde95, 0xffffd955, 0xffffc042, 0x000041c0
> +exp_dod_us:
> +	.word	0x00001e95, 0x00002955, 0xffffc342, 0x000041c0
> +exp_dod_su:
> +	.word	0xffffe795, 0xffffe155, 0x00004342, 0xffffc2c0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.