Skip to content

Enable RVV-optimized TRSM kernels for RISCV64_ZVL128B#5830

Draft
Felix-Gong wants to merge 1 commit into
OpenMathLib:developfrom
Felix-Gong:feature/rvv-trsm-zvl128b
Draft

Enable RVV-optimized TRSM kernels for RISCV64_ZVL128B#5830
Felix-Gong wants to merge 1 commit into
OpenMathLib:developfrom
Felix-Gong:feature/rvv-trsm-zvl128b

Conversation

@Felix-Gong

@Felix-Gong Felix-Gong commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Enable RVV-optimized TRSM kernels (trsm_kernel_{LN,LT,RN,RT}_rvv_v1.c) for RISCV64_ZVL128B target
  • These RVV kernel implementations already exist in the repository and are used by the x280 target, but were not enabled for ZVL128B configuration
  • Affects all four TRSM variants (S/D/C/Z) in both left/right and normal/transposed configurations

Note on ZVL256B

ZVL256B is intentionally excluded from this change. Testing revealed that the RVV TRSM kernel produces incorrect results with VLEN=256 (e.g., 3x3 lower triangular solve returns wrong values). This needs to be investigated separately.

Test plan

  • Built and tested on RISC-V hardware with RVV 1.0 (VLEN=128)
  • DTRSM correctness verified (n=2, n=100)
  • STRSM correctness verified
  • CI tests pass

Use existing RVV-optimized TRSM kernel implementations instead of the
generic C versions for the RISCV64_ZVL128B target. The RVV kernels
(trsm_kernel_{LN,LT,RN,RT}_rvv_v1.c) are already present in the
repository and used by the x280 target, but were not enabled for
ZVL128B.

Note: ZVL256B is not included because the RVV TRSM kernel has
correctness issues with VLEN=256.

Signed-off-by: Felix-Gong <gongxiaofei24@iscas.ac.cn>
@Felix-Gong
Felix-Gong force-pushed the feature/rvv-trsm-zvl128b branch from c50f0a6 to 4fb51e3 Compare June 7, 2026 03:43
@Felix-Gong Felix-Gong changed the title Enable RVV-optimized TRSM kernels for RISCV64_ZVL128B and ZVL256B Enable RVV-optimized TRSM kernels for RISCV64_ZVL128B Jun 7, 2026
@Felix-Gong Felix-Gong closed this Jun 7, 2026
@Felix-Gong Felix-Gong reopened this Jun 7, 2026
@Felix-Gong
Felix-Gong marked this pull request as draft June 7, 2026 08:13
@hmeiland

Copy link
Copy Markdown
Contributor

Root-cause analysis of the RISCV64_ZVL128B CI failure (cblas_ctrsm FAILED / TESTS ABANDONED)

I dug into why this PR fails the TEST (RISCV64_ZVL128B ...) job. Sharing the findings so we can pick the right fix.

TL;DR

The trsm_kernel_*_rvv_v1.c kernels are only correct when the whole GEMM path is the VLEN-adaptive _rvv_v1 family (as on x280). RISCV64_ZVL128B keeps fixed-unroll GEMM/TRMM microkernels and fixed-width rectangular packing, so switching only the TRSM kernel line creates a packing-width mismatch → wrong TRSM results.

The packing contract mismatch

trsm_kernel_*_rvv_v1.c uses LMUL m2 and blocks the M dimension by the runtime VSETVL_MAX (= VLEN·2 / SEW):

size_t vl = VSETVL_MAX;      // M-block width
i = vl;
while (i <= m) {
    GEMM_KERNEL(vl, GEMM_UNROLL_N, kk, ...);   // reads packed A in vl-row blocks
    solve(vl, GEMM_UNROLL_N, aa + kk*vl*COMPSIZE, ...);
    aa += vl * k * COMPSIZE; kk += vl; i += vl;
}

The paired trsm_*copy_rvv_v1.c packs the triangular block in the same VSETVL_MAX-wide strips, so the kernel + its trsm-copy are internally self-consistent at any VLEN. But the rectangular part of A is packed by GEMM_ITCOPY, which on ZVL128B is the fixed-width ../generic/gemm_tcopy_$(UNROLL_M).c (block width = compile-time GEMM_UNROLL_M). The solver reads it back stepping by VSETVL_MAX. When VSETVL_MAX != GEMM_UNROLL_M, the strides disagree → incorrect results.

Why it fails on the CI runner (VLEN = 256, SpaceMiT X60)

VSETVL_MAX for LMUL m2 at VLEN=256 vs the ZVL128B param.h GEMM_UNROLL_M:

type SEW VSETVL_MAX (solver M-block) GEMM_UNROLL_M (packer) match?
S 32 16 8
D 64 8 8
C 32 16 8 ✗ (→ cblas_ctrsm FAILED)
Z 64 8 4

This lines up exactly with the observed cblas_ctrsm failure, and it is the same effect as the "wrong results at VLEN=256" that motivated excluding ZVL256B — it's one root cause, not two. x280 is unaffected because its GEMM kernel and copies are all _rvv_v1, so the rectangular block width is also VSETVL_MAX and everything agrees.

Note the mismatch depends on the runtime VLEN, not the build target name: a ZVL128B binary run on a VLEN≥256 core still uses VSETVL_MAX≥16, so it breaks even though the target says 128.

Options

  1. Revert TRSM to generic for this target (safe, guaranteed green, drops the RVV TRSM speedup):
    [SDCZ]TRSMKERNEL_{LN,LT,RN,RT} = ../generic/trsm_kernel_{LN,LT,RN,RT}.c
  2. Keep the optimization by making the whole ZVL128B GEMM path adaptive _rvv_v1 (like x280), or by writing TRSM kernels that block by GEMM_UNROLL_M instead of VSETVL_MAX. This is a larger change and needs on-hardware verification that GEMM/TRMM don't regress.

I'm planning to verify both empirically on a SpaceMiT X60 (VLEN=256) — reproduce the ctrsm failure as-is, then confirm the chosen fix. Happy to push the fix once validated. Let me know which direction you'd prefer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants