From 1c179f79752962de55c6e2288c44e6958cef385a Mon Sep 17 00:00:00 2001 From: Zhang Jinhan Date: Wed, 9 Sep 2026 15:23:45 +0800 Subject: [PATCH] hal/riscv-rvv: localize VL in DFT odd-radix loop The generic odd-radix DFT path created the index vector with vsetvlmax_e32mf2() and kept it live across a subsequent setvl() call used for the current processing chunk. This code pattern can produce incorrect results with GCC 15.2 using the default optimized VSETVL strategy. Core_DFT.accuracy and Core_DCT.accuracy fail with the RVV HAL enabled, while disabling VSETVL global fusion makes the same tests pass. Generate the index vector after setting the vector length for each q-loop chunk instead. Keep all vector operations within the same local qvl and advance q explicitly by that value. This preserves the existing odd-radix DFT algorithm while avoiding vector values that span changes of VL. Tested on SpaceMIT K3 with GCC 15.2.0, RVV 1.0 and VLEN=256: RISCV_RVV_SCALABLE=ON WITH_HAL_RVV=ON CMAKE_BUILD_TYPE=Release Core_DFT and Core_DCT accuracy tests pass with GCC's default VSETVL optimization enabled. Co-authored-by: Yuansheng Co-authored-by: Yang Wang --- hal/riscv-rvv/src/core/dxt.cpp | 45 +++++++++++++++++----------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/hal/riscv-rvv/src/core/dxt.cpp b/hal/riscv-rvv/src/core/dxt.cpp index fa0c464e88..cf412702c5 100644 --- a/hal/riscv-rvv/src/core/dxt.cpp +++ b/hal/riscv-rvv/src/core/dxt.cpp @@ -466,38 +466,37 @@ inline int dft(const Complex* src, Complex* dst, int nf, int *factors, T s Complex s0 = v_0, s1 = v_0; dd = dw_f*p; - vl = __riscv_vsetvlmax_e32mf2(); - auto vec_dd = __riscv_vid_v_u32mf2(vl); - vec_dd = __riscv_vmul(vec_dd, dd, vl); - vec_dd = __riscv_vremu(vec_dd, tab_size, vl); - - for( q = 0; q < factor2; q += vl ) + for( q = 0; q < factor2; ) { - vl = rvv::setvl(factor2 - q); + const int qvl = rvv::setvl(factor2 - q); - auto vec_d = __riscv_vadd(vec_dd, (q + 1) * dd % tab_size, vl); - auto vmask = __riscv_vmsgeu(vec_d, tab_size, vl); - vec_d = __riscv_vsub_mu(vmask, vec_d, vec_d, tab_size, vl); - vec_d = __riscv_vmul(vec_d, sizeof(T) * 2, vl); + auto vec_d = __riscv_vid_v_u32mf2(qvl); + vec_d = __riscv_vmul(vec_d, dd, qvl); + vec_d = __riscv_vremu(vec_d, tab_size, qvl); + vec_d = __riscv_vadd(vec_d, (q + 1) * dd % tab_size, qvl); + auto vmask = __riscv_vmsgeu(vec_d, tab_size, qvl); + vec_d = __riscv_vsub_mu(vmask, vec_d, vec_d, tab_size, qvl); + vec_d = __riscv_vmul(vec_d, sizeof(T) * 2, qvl); - auto vec_w = __riscv_vloxei32(reinterpret_cast(wave), vec_d, vl); + auto vec_w = __riscv_vloxei32(reinterpret_cast(wave), vec_d, qvl); VT vec_a_re, vec_a_im, vec_b_re, vec_b_im; - rvv::vlsseg(reinterpret_cast(a + q), sizeof(T) * 2, vec_a_re, vec_a_im, vl); - rvv::vlsseg(reinterpret_cast(b + q), sizeof(T) * 2, vec_b_re, vec_b_im, vl); - auto vec_r0 = __riscv_vfmul(vec_w, vec_a_re, vl); - auto vec_r1 = __riscv_vfmul(vec_w, vec_b_im, vl); + rvv::vlsseg(reinterpret_cast(a + q), sizeof(T) * 2, vec_a_re, vec_a_im, qvl); + rvv::vlsseg(reinterpret_cast(b + q), sizeof(T) * 2, vec_b_re, vec_b_im, qvl); + auto vec_r0 = __riscv_vfmul(vec_w, vec_a_re, qvl); + auto vec_r1 = __riscv_vfmul(vec_w, vec_b_im, qvl); - vec_w = __riscv_vloxei32(reinterpret_cast(wave) + 1, vec_d, vl); - auto vec_i0 = __riscv_vfmul(vec_w, vec_a_im, vl); - auto vec_i1 = __riscv_vfmul(vec_w, vec_b_re, vl); + vec_w = __riscv_vloxei32(reinterpret_cast(wave) + 1, vec_d, qvl); + auto vec_i0 = __riscv_vfmul(vec_w, vec_a_im, qvl); + auto vec_i1 = __riscv_vfmul(vec_w, vec_b_re, qvl); - T r0 = __riscv_vfmv_f(__riscv_vfredosum(vec_r0, RVV::vmv_s(0, vl), vl)); - T i0 = __riscv_vfmv_f(__riscv_vfredosum(vec_i0, RVV::vmv_s(0, vl), vl)); - T r1 = __riscv_vfmv_f(__riscv_vfredosum(vec_r1, RVV::vmv_s(0, vl), vl)); - T i1 = __riscv_vfmv_f(__riscv_vfredosum(vec_i1, RVV::vmv_s(0, vl), vl)); + T r0 = __riscv_vfmv_f(__riscv_vfredosum(vec_r0, RVV::vmv_s(0, qvl), qvl)); + T i0 = __riscv_vfmv_f(__riscv_vfredosum(vec_i0, RVV::vmv_s(0, qvl), qvl)); + T r1 = __riscv_vfmv_f(__riscv_vfredosum(vec_r1, RVV::vmv_s(0, qvl), qvl)); + T i1 = __riscv_vfmv_f(__riscv_vfredosum(vec_i1, RVV::vmv_s(0, qvl), qvl)); s1.re += r0 + i0; s0.re += r0 - i0; s1.im += r1 - i1; s0.im += r1 + i1; + q += qvl; } v[k] = s0;