diff --git a/modules/core/include/opencv2/core/hal/intrin_rvv_scalable.hpp b/modules/core/include/opencv2/core/hal/intrin_rvv_scalable.hpp index 67c9d12741..ca82d140f8 100644 --- a/modules/core/include/opencv2/core/hal/intrin_rvv_scalable.hpp +++ b/modules/core/include/opencv2/core/hal/intrin_rvv_scalable.hpp @@ -2145,28 +2145,29 @@ inline v_float64 v_dotprod_expand_fast(const v_int32& a, const v_int32& b, const { return v_add(v_dotprod_expand_fast(a, b) , c); } #endif -// TODO: only 128 bit now. inline v_float32 v_matmul(const v_float32& v, const v_float32& mat0, const v_float32& mat1, const v_float32& mat2, const v_float32& mat3) { - vfloat32m2_t res; - res = __riscv_vfmul_vf_f32m2(mat0, v_extract_n(v, 0), VTraits::vlanes()); - res = __riscv_vfmacc_vf_f32m2(res, v_extract_n(v, 1), mat1, VTraits::vlanes()); - res = __riscv_vfmacc_vf_f32m2(res, v_extract_n(v, 2), mat2, VTraits::vlanes()); - res = __riscv_vfmacc_vf_f32m2(res, v_extract_n(v, 3), mat3, VTraits::vlanes()); - return res; + const int vl = VTraits::vlanes(); + vuint32m2_t idx = __riscv_vand(__riscv_vid_v_u32m2(vl), 0xfffffffc, vl); + v_float32 v0 = __riscv_vrgather(v, idx, vl); + v_float32 v1 = __riscv_vrgather(v, __riscv_vadd(idx, 1, vl), vl); + v_float32 v2 = __riscv_vrgather(v, __riscv_vadd(idx, 2, vl), vl); + v_float32 v3 = __riscv_vrgather(v, __riscv_vadd(idx, 3, vl), vl); + return v_fma(v0, mat0, v_fma(v1, mat1, v_fma(v2, mat2, v_mul(v3, mat3)))); } -// TODO: only 128 bit now. inline v_float32 v_matmuladd(const v_float32& v, const v_float32& mat0, const v_float32& mat1, const v_float32& mat2, const v_float32& a) { - vfloat32m2_t res = __riscv_vfmul_vf_f32m2(mat0, v_extract_n(v,0), VTraits::vlanes()); - res = __riscv_vfmacc_vf_f32m2(res, v_extract_n(v,1), mat1, VTraits::vlanes()); - res = __riscv_vfmacc_vf_f32m2(res, v_extract_n(v,2), mat2, VTraits::vlanes()); - return __riscv_vfadd(res, a, VTraits::vlanes()); + const int vl = VTraits::vlanes(); + vuint32m2_t idx = __riscv_vand(__riscv_vid_v_u32m2(vl), 0xfffffffc, vl); + v_float32 v0 = __riscv_vrgather(v, idx, vl); + v_float32 v1 = __riscv_vrgather(v, __riscv_vadd(idx, 1, vl), vl); + v_float32 v2 = __riscv_vrgather(v, __riscv_vadd(idx, 2, vl), vl); + return v_fma(v0, mat0, v_fma(v1, mat1, v_fma(v2, mat2, a))); } inline void v_cleanup() {} diff --git a/modules/core/src/matmul.simd.hpp b/modules/core/src/matmul.simd.hpp index f089c90a01..5645617dd1 100644 --- a/modules/core/src/matmul.simd.hpp +++ b/modules/core/src/matmul.simd.hpp @@ -1596,8 +1596,7 @@ static void transform_32f( const float* src, float* dst, const float* m, int len, int scn, int dcn ) { // Disabled for RISC-V Vector (scalable), because of: -// 1. v_matmuladd for RVV is 128-bit only but not scalable, this will fail the test `Core_Transform.accuracy`. -// 2. Both gcc and clang can autovectorize this, with better performance than using Universal intrinsic. +// 1. Both gcc and clang can autovectorize this, with better performance than using Universal intrinsic. #if (CV_SIMD || CV_SIMD_SCALABLE) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(_M_ARM64EC) && !(CV_TRY_RVV && CV_RVV) int x = 0; if( scn == 3 && dcn == 3 ) diff --git a/modules/core/test/test_intrin_utils.hpp b/modules/core/test/test_intrin_utils.hpp index 8c2c69c79f..2a0ce37611 100644 --- a/modules/core/test/test_intrin_utils.hpp +++ b/modules/core/test/test_intrin_utils.hpp @@ -1519,9 +1519,8 @@ template struct TheTest R v = dataV, a = dataA, b = dataB, c = dataC, d = dataD; Data res = v_matmul(v, a, b, c, d); - // for (int i = 0; i < VTraits::vlanes(); i += 4) - // { - int i = 0; + for (int i = 0; i < VTraits::vlanes(); i += 4) + { for (int j = i; j < i + 4; ++j) { SCOPED_TRACE(cv::format("i=%d j=%d", i, j)); @@ -1531,12 +1530,11 @@ template struct TheTest + dataV[i + 3] * dataD[j]; EXPECT_COMPARE_EQ(val, res[j]); } - // } + } Data resAdd = v_matmuladd(v, a, b, c, d); - // for (int i = 0; i < VTraits::vlanes(); i += 4) - // { - i = 0; + for (int i = 0; i < VTraits::vlanes(); i += 4) + { for (int j = i; j < i + 4; ++j) { SCOPED_TRACE(cv::format("i=%d j=%d", i, j)); @@ -1546,7 +1544,7 @@ template struct TheTest + dataD[j]; EXPECT_COMPARE_EQ(val, resAdd[j]); } - // } + } return *this; }