From 0f3b7e924594ce653bbe0f618fe3d6332c7a029c Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 6 Aug 2026 13:49:24 +0000 Subject: [PATCH] Improve SVE2 Gemm32fNN kernels without macros Rewrite SimdSve2Gemm32fNN microkernels in explicit NEON/AVX-512BW style: remove SIMD_SVE2_GEMM_* macros, use unpredicated svmla_f32_x on full vector panels, add 1/2/3/4-panel N kernels, B-first FMLA order for the 6-row kernels, and L1/L2/L3 cache blocking. Document under release 7.2.165. Co-authored-by: Ihar Yermalayeu --- docs/2026.html | 1 + src/Simd/SimdSve2Gemm32fNN.cpp | 1033 ++++++++++++++++++++++++++++++-- 2 files changed, 972 insertions(+), 62 deletions(-) diff --git a/docs/2026.html b/docs/2026.html index 80e4326551..af49f117a8 100644 --- a/docs/2026.html +++ b/docs/2026.html @@ -55,6 +55,7 @@
New features
Improving
Renaming
diff --git a/src/Simd/SimdSve2Gemm32fNN.cpp b/src/Simd/SimdSve2Gemm32fNN.cpp index 679630b38e..decb6a168e 100644 --- a/src/Simd/SimdSve2Gemm32fNN.cpp +++ b/src/Simd/SimdSve2Gemm32fNN.cpp @@ -22,6 +22,7 @@ * SOFTWARE. */ #include "Simd/SimdGemm.h" +#include "Simd/SimdCpu.h" namespace Simd { @@ -30,67 +31,969 @@ namespace Simd { SIMD_INLINE void AddProduct(float* ptr, const svfloat32_t& value, const svfloat32_t& alpha, const svbool_t& mask) { - svst1_f32(mask, ptr, svmla_f32_m(mask, svld1_f32(mask, ptr), value, alpha)); + svst1_f32(mask, ptr, svmla_f32_x(mask, svld1_f32(mask, ptr), value, alpha)); } -#define SIMD_SVE2_GEMM_INIT(row) \ - svfloat32_t c##row##0, c##row##1, c##row##2, c##row##3; \ - if (M > row) c##row##0 = zero, c##row##1 = zero, c##row##2 = zero, c##row##3 = zero; + SIMD_INLINE void AddProduct(float* ptr, const svfloat32_t& value, const svfloat32_t& alpha) + { + const svbool_t body = svptrue_b32(); + svst1_f32(body, ptr, svmla_f32_x(body, svld1_f32(body, ptr), value, alpha)); + } + + static void Kernel1x1nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc, size_t n) + { + const size_t F = svcntw(); + const svbool_t mask = svwhilelt_b32((uint64_t)0, (uint64_t)n); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(mask, B + 0 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_m(mask, c00, b0, a0); + A += 1; + B += ldb; + } + AddProduct(C + 0 * ldc + 0 * F, c00, svdup_n_f32(alpha), mask); + } + + static void Kernel1x2nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + } + + static void Kernel1x3nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + svfloat32_t c02 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t b2 = svld1_f32(body, B + 2 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + c02 = svmla_f32_x(body, c02, b2, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + AddProduct(C + 0 * ldc + 2 * F, c02, _alpha); + } + + static void Kernel1x4nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + svfloat32_t c02 = zero; + svfloat32_t c03 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t b2 = svld1_f32(body, B + 2 * F); + svfloat32_t b3 = svld1_f32(body, B + 3 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + c02 = svmla_f32_x(body, c02, b2, a0); + c03 = svmla_f32_x(body, c03, b3, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + AddProduct(C + 0 * ldc + 2 * F, c02, _alpha); + AddProduct(C + 0 * ldc + 3 * F, c03, _alpha); + } + + static void Kernel2x1nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc, size_t n) + { + const size_t F = svcntw(); + const svbool_t mask = svwhilelt_b32((uint64_t)0, (uint64_t)n); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c10 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(mask, B + 0 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_m(mask, c00, b0, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_m(mask, c10, b0, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha, mask); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha, mask); + } + + static void Kernel2x2nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + svfloat32_t c10 = zero; + svfloat32_t c11 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_x(body, c10, b0, a0); + c11 = svmla_f32_x(body, c11, b1, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha); + AddProduct(C + 1 * ldc + 1 * F, c11, _alpha); + } + + static void Kernel2x3nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + svfloat32_t c02 = zero; + svfloat32_t c10 = zero; + svfloat32_t c11 = zero; + svfloat32_t c12 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t b2 = svld1_f32(body, B + 2 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + c02 = svmla_f32_x(body, c02, b2, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_x(body, c10, b0, a0); + c11 = svmla_f32_x(body, c11, b1, a0); + c12 = svmla_f32_x(body, c12, b2, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + AddProduct(C + 0 * ldc + 2 * F, c02, _alpha); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha); + AddProduct(C + 1 * ldc + 1 * F, c11, _alpha); + AddProduct(C + 1 * ldc + 2 * F, c12, _alpha); + } + + static void Kernel2x4nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + svfloat32_t c02 = zero; + svfloat32_t c03 = zero; + svfloat32_t c10 = zero; + svfloat32_t c11 = zero; + svfloat32_t c12 = zero; + svfloat32_t c13 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t b2 = svld1_f32(body, B + 2 * F); + svfloat32_t b3 = svld1_f32(body, B + 3 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + c02 = svmla_f32_x(body, c02, b2, a0); + c03 = svmla_f32_x(body, c03, b3, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_x(body, c10, b0, a0); + c11 = svmla_f32_x(body, c11, b1, a0); + c12 = svmla_f32_x(body, c12, b2, a0); + c13 = svmla_f32_x(body, c13, b3, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + AddProduct(C + 0 * ldc + 2 * F, c02, _alpha); + AddProduct(C + 0 * ldc + 3 * F, c03, _alpha); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha); + AddProduct(C + 1 * ldc + 1 * F, c11, _alpha); + AddProduct(C + 1 * ldc + 2 * F, c12, _alpha); + AddProduct(C + 1 * ldc + 3 * F, c13, _alpha); + } + + static void Kernel3x1nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc, size_t n) + { + const size_t F = svcntw(); + const svbool_t mask = svwhilelt_b32((uint64_t)0, (uint64_t)n); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c10 = zero; + svfloat32_t c20 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(mask, B + 0 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_m(mask, c00, b0, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_m(mask, c10, b0, a0); + a0 = svdup_n_f32(A[2 * lda]); + c20 = svmla_f32_m(mask, c20, b0, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha, mask); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha, mask); + AddProduct(C + 2 * ldc + 0 * F, c20, _alpha, mask); + } + + static void Kernel3x2nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + svfloat32_t c10 = zero; + svfloat32_t c11 = zero; + svfloat32_t c20 = zero; + svfloat32_t c21 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_x(body, c10, b0, a0); + c11 = svmla_f32_x(body, c11, b1, a0); + a0 = svdup_n_f32(A[2 * lda]); + c20 = svmla_f32_x(body, c20, b0, a0); + c21 = svmla_f32_x(body, c21, b1, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha); + AddProduct(C + 1 * ldc + 1 * F, c11, _alpha); + AddProduct(C + 2 * ldc + 0 * F, c20, _alpha); + AddProduct(C + 2 * ldc + 1 * F, c21, _alpha); + } + + static void Kernel3x3nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + svfloat32_t c02 = zero; + svfloat32_t c10 = zero; + svfloat32_t c11 = zero; + svfloat32_t c12 = zero; + svfloat32_t c20 = zero; + svfloat32_t c21 = zero; + svfloat32_t c22 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t b2 = svld1_f32(body, B + 2 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + c02 = svmla_f32_x(body, c02, b2, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_x(body, c10, b0, a0); + c11 = svmla_f32_x(body, c11, b1, a0); + c12 = svmla_f32_x(body, c12, b2, a0); + a0 = svdup_n_f32(A[2 * lda]); + c20 = svmla_f32_x(body, c20, b0, a0); + c21 = svmla_f32_x(body, c21, b1, a0); + c22 = svmla_f32_x(body, c22, b2, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + AddProduct(C + 0 * ldc + 2 * F, c02, _alpha); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha); + AddProduct(C + 1 * ldc + 1 * F, c11, _alpha); + AddProduct(C + 1 * ldc + 2 * F, c12, _alpha); + AddProduct(C + 2 * ldc + 0 * F, c20, _alpha); + AddProduct(C + 2 * ldc + 1 * F, c21, _alpha); + AddProduct(C + 2 * ldc + 2 * F, c22, _alpha); + } -#define SIMD_SVE2_GEMM_ROW(row) \ - if (M > row) \ - { \ - svfloat32_t a = svdup_n_f32(A[(row) * lda]); \ - c##row##0 = svmla_f32_m(mask0, c##row##0, b0, a); \ - c##row##1 = svmla_f32_m(mask1, c##row##1, b1, a); \ - c##row##2 = svmla_f32_m(mask2, c##row##2, b2, a); \ - c##row##3 = svmla_f32_m(mask3, c##row##3, b3, a); \ + static void Kernel3x4nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + svfloat32_t c02 = zero; + svfloat32_t c03 = zero; + svfloat32_t c10 = zero; + svfloat32_t c11 = zero; + svfloat32_t c12 = zero; + svfloat32_t c13 = zero; + svfloat32_t c20 = zero; + svfloat32_t c21 = zero; + svfloat32_t c22 = zero; + svfloat32_t c23 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t b2 = svld1_f32(body, B + 2 * F); + svfloat32_t b3 = svld1_f32(body, B + 3 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + c02 = svmla_f32_x(body, c02, b2, a0); + c03 = svmla_f32_x(body, c03, b3, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_x(body, c10, b0, a0); + c11 = svmla_f32_x(body, c11, b1, a0); + c12 = svmla_f32_x(body, c12, b2, a0); + c13 = svmla_f32_x(body, c13, b3, a0); + a0 = svdup_n_f32(A[2 * lda]); + c20 = svmla_f32_x(body, c20, b0, a0); + c21 = svmla_f32_x(body, c21, b1, a0); + c22 = svmla_f32_x(body, c22, b2, a0); + c23 = svmla_f32_x(body, c23, b3, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + AddProduct(C + 0 * ldc + 2 * F, c02, _alpha); + AddProduct(C + 0 * ldc + 3 * F, c03, _alpha); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha); + AddProduct(C + 1 * ldc + 1 * F, c11, _alpha); + AddProduct(C + 1 * ldc + 2 * F, c12, _alpha); + AddProduct(C + 1 * ldc + 3 * F, c13, _alpha); + AddProduct(C + 2 * ldc + 0 * F, c20, _alpha); + AddProduct(C + 2 * ldc + 1 * F, c21, _alpha); + AddProduct(C + 2 * ldc + 2 * F, c22, _alpha); + AddProduct(C + 2 * ldc + 3 * F, c23, _alpha); } -#define SIMD_SVE2_GEMM_SAVE(row) \ - if (M > row) \ - { \ - AddProduct(C + (row) * ldc + 0 * F, c##row##0, _alpha, mask0); \ - AddProduct(C + (row) * ldc + 1 * F, c##row##1, _alpha, mask1); \ - AddProduct(C + (row) * ldc + 2 * F, c##row##2, _alpha, mask2); \ - AddProduct(C + (row) * ldc + 3 * F, c##row##3, _alpha, mask3); \ + static void Kernel4x1nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc, size_t n) + { + const size_t F = svcntw(); + const svbool_t mask = svwhilelt_b32((uint64_t)0, (uint64_t)n); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c10 = zero; + svfloat32_t c20 = zero; + svfloat32_t c30 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(mask, B + 0 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_m(mask, c00, b0, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_m(mask, c10, b0, a0); + a0 = svdup_n_f32(A[2 * lda]); + c20 = svmla_f32_m(mask, c20, b0, a0); + a0 = svdup_n_f32(A[3 * lda]); + c30 = svmla_f32_m(mask, c30, b0, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha, mask); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha, mask); + AddProduct(C + 2 * ldc + 0 * F, c20, _alpha, mask); + AddProduct(C + 3 * ldc + 0 * F, c30, _alpha, mask); } - template void GemmKernelMx4nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, size_t F, float* C, size_t ldc, size_t tail) + static void Kernel4x4nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) { - const svbool_t mask0 = svwhilelt_b32(0 * F, tail); - const svbool_t mask1 = svwhilelt_b32(1 * F, tail); - const svbool_t mask2 = svwhilelt_b32(2 * F, tail); - const svbool_t mask3 = svwhilelt_b32(3 * F, tail); + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + svfloat32_t c02 = zero; + svfloat32_t c03 = zero; + svfloat32_t c10 = zero; + svfloat32_t c11 = zero; + svfloat32_t c12 = zero; + svfloat32_t c13 = zero; + svfloat32_t c20 = zero; + svfloat32_t c21 = zero; + svfloat32_t c22 = zero; + svfloat32_t c23 = zero; + svfloat32_t c30 = zero; + svfloat32_t c31 = zero; + svfloat32_t c32 = zero; + svfloat32_t c33 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t b2 = svld1_f32(body, B + 2 * F); + svfloat32_t b3 = svld1_f32(body, B + 3 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + c02 = svmla_f32_x(body, c02, b2, a0); + c03 = svmla_f32_x(body, c03, b3, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_x(body, c10, b0, a0); + c11 = svmla_f32_x(body, c11, b1, a0); + c12 = svmla_f32_x(body, c12, b2, a0); + c13 = svmla_f32_x(body, c13, b3, a0); + a0 = svdup_n_f32(A[2 * lda]); + c20 = svmla_f32_x(body, c20, b0, a0); + c21 = svmla_f32_x(body, c21, b1, a0); + c22 = svmla_f32_x(body, c22, b2, a0); + c23 = svmla_f32_x(body, c23, b3, a0); + a0 = svdup_n_f32(A[3 * lda]); + c30 = svmla_f32_x(body, c30, b0, a0); + c31 = svmla_f32_x(body, c31, b1, a0); + c32 = svmla_f32_x(body, c32, b2, a0); + c33 = svmla_f32_x(body, c33, b3, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + AddProduct(C + 0 * ldc + 2 * F, c02, _alpha); + AddProduct(C + 0 * ldc + 3 * F, c03, _alpha); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha); + AddProduct(C + 1 * ldc + 1 * F, c11, _alpha); + AddProduct(C + 1 * ldc + 2 * F, c12, _alpha); + AddProduct(C + 1 * ldc + 3 * F, c13, _alpha); + AddProduct(C + 2 * ldc + 0 * F, c20, _alpha); + AddProduct(C + 2 * ldc + 1 * F, c21, _alpha); + AddProduct(C + 2 * ldc + 2 * F, c22, _alpha); + AddProduct(C + 2 * ldc + 3 * F, c23, _alpha); + AddProduct(C + 3 * ldc + 0 * F, c30, _alpha); + AddProduct(C + 3 * ldc + 1 * F, c31, _alpha); + AddProduct(C + 3 * ldc + 2 * F, c32, _alpha); + AddProduct(C + 3 * ldc + 3 * F, c33, _alpha); + } + + static void Kernel5x1nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc, size_t n) + { + const size_t F = svcntw(); + const svbool_t mask = svwhilelt_b32((uint64_t)0, (uint64_t)n); const svfloat32_t zero = svdup_n_f32(0.0f); - SIMD_SVE2_GEMM_INIT(0); - SIMD_SVE2_GEMM_INIT(1); - SIMD_SVE2_GEMM_INIT(2); - SIMD_SVE2_GEMM_INIT(3); - SIMD_SVE2_GEMM_INIT(4); - SIMD_SVE2_GEMM_INIT(5); + svfloat32_t c00 = zero; + svfloat32_t c10 = zero; + svfloat32_t c20 = zero; + svfloat32_t c30 = zero; + svfloat32_t c40 = zero; for (size_t k = 0; k < K; ++k) { - svfloat32_t b0 = svld1_f32(mask0, B + 0 * F); - svfloat32_t b1 = svld1_f32(mask1, B + 1 * F); - svfloat32_t b2 = svld1_f32(mask2, B + 2 * F); - svfloat32_t b3 = svld1_f32(mask3, B + 3 * F); - SIMD_SVE2_GEMM_ROW(0); - SIMD_SVE2_GEMM_ROW(1); - SIMD_SVE2_GEMM_ROW(2); - SIMD_SVE2_GEMM_ROW(3); - SIMD_SVE2_GEMM_ROW(4); - SIMD_SVE2_GEMM_ROW(5); + svfloat32_t b0 = svld1_f32(mask, B + 0 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_m(mask, c00, b0, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_m(mask, c10, b0, a0); + a0 = svdup_n_f32(A[2 * lda]); + c20 = svmla_f32_m(mask, c20, b0, a0); + a0 = svdup_n_f32(A[3 * lda]); + c30 = svmla_f32_m(mask, c30, b0, a0); + a0 = svdup_n_f32(A[4 * lda]); + c40 = svmla_f32_m(mask, c40, b0, a0); A += 1; B += ldb; } svfloat32_t _alpha = svdup_n_f32(alpha); - SIMD_SVE2_GEMM_SAVE(0); - SIMD_SVE2_GEMM_SAVE(1); - SIMD_SVE2_GEMM_SAVE(2); - SIMD_SVE2_GEMM_SAVE(3); - SIMD_SVE2_GEMM_SAVE(4); - SIMD_SVE2_GEMM_SAVE(5); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha, mask); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha, mask); + AddProduct(C + 2 * ldc + 0 * F, c20, _alpha, mask); + AddProduct(C + 3 * ldc + 0 * F, c30, _alpha, mask); + AddProduct(C + 4 * ldc + 0 * F, c40, _alpha, mask); + } + + static void Kernel5x4nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + svfloat32_t c02 = zero; + svfloat32_t c03 = zero; + svfloat32_t c10 = zero; + svfloat32_t c11 = zero; + svfloat32_t c12 = zero; + svfloat32_t c13 = zero; + svfloat32_t c20 = zero; + svfloat32_t c21 = zero; + svfloat32_t c22 = zero; + svfloat32_t c23 = zero; + svfloat32_t c30 = zero; + svfloat32_t c31 = zero; + svfloat32_t c32 = zero; + svfloat32_t c33 = zero; + svfloat32_t c40 = zero; + svfloat32_t c41 = zero; + svfloat32_t c42 = zero; + svfloat32_t c43 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t b2 = svld1_f32(body, B + 2 * F); + svfloat32_t b3 = svld1_f32(body, B + 3 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + c02 = svmla_f32_x(body, c02, b2, a0); + c03 = svmla_f32_x(body, c03, b3, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_x(body, c10, b0, a0); + c11 = svmla_f32_x(body, c11, b1, a0); + c12 = svmla_f32_x(body, c12, b2, a0); + c13 = svmla_f32_x(body, c13, b3, a0); + a0 = svdup_n_f32(A[2 * lda]); + c20 = svmla_f32_x(body, c20, b0, a0); + c21 = svmla_f32_x(body, c21, b1, a0); + c22 = svmla_f32_x(body, c22, b2, a0); + c23 = svmla_f32_x(body, c23, b3, a0); + a0 = svdup_n_f32(A[3 * lda]); + c30 = svmla_f32_x(body, c30, b0, a0); + c31 = svmla_f32_x(body, c31, b1, a0); + c32 = svmla_f32_x(body, c32, b2, a0); + c33 = svmla_f32_x(body, c33, b3, a0); + a0 = svdup_n_f32(A[4 * lda]); + c40 = svmla_f32_x(body, c40, b0, a0); + c41 = svmla_f32_x(body, c41, b1, a0); + c42 = svmla_f32_x(body, c42, b2, a0); + c43 = svmla_f32_x(body, c43, b3, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + AddProduct(C + 0 * ldc + 2 * F, c02, _alpha); + AddProduct(C + 0 * ldc + 3 * F, c03, _alpha); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha); + AddProduct(C + 1 * ldc + 1 * F, c11, _alpha); + AddProduct(C + 1 * ldc + 2 * F, c12, _alpha); + AddProduct(C + 1 * ldc + 3 * F, c13, _alpha); + AddProduct(C + 2 * ldc + 0 * F, c20, _alpha); + AddProduct(C + 2 * ldc + 1 * F, c21, _alpha); + AddProduct(C + 2 * ldc + 2 * F, c22, _alpha); + AddProduct(C + 2 * ldc + 3 * F, c23, _alpha); + AddProduct(C + 3 * ldc + 0 * F, c30, _alpha); + AddProduct(C + 3 * ldc + 1 * F, c31, _alpha); + AddProduct(C + 3 * ldc + 2 * F, c32, _alpha); + AddProduct(C + 3 * ldc + 3 * F, c33, _alpha); + AddProduct(C + 4 * ldc + 0 * F, c40, _alpha); + AddProduct(C + 4 * ldc + 1 * F, c41, _alpha); + AddProduct(C + 4 * ldc + 2 * F, c42, _alpha); + AddProduct(C + 4 * ldc + 3 * F, c43, _alpha); + } + + static void Kernel6x1nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc, size_t n) + { + const size_t F = svcntw(); + const svbool_t mask = svwhilelt_b32((uint64_t)0, (uint64_t)n); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c10 = zero; + svfloat32_t c20 = zero; + svfloat32_t c30 = zero; + svfloat32_t c40 = zero; + svfloat32_t c50 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(mask, B + 0 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_m(mask, c00, b0, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_m(mask, c10, b0, a0); + a0 = svdup_n_f32(A[2 * lda]); + c20 = svmla_f32_m(mask, c20, b0, a0); + a0 = svdup_n_f32(A[3 * lda]); + c30 = svmla_f32_m(mask, c30, b0, a0); + a0 = svdup_n_f32(A[4 * lda]); + c40 = svmla_f32_m(mask, c40, b0, a0); + a0 = svdup_n_f32(A[5 * lda]); + c50 = svmla_f32_m(mask, c50, b0, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha, mask); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha, mask); + AddProduct(C + 2 * ldc + 0 * F, c20, _alpha, mask); + AddProduct(C + 3 * ldc + 0 * F, c30, _alpha, mask); + AddProduct(C + 4 * ldc + 0 * F, c40, _alpha, mask); + AddProduct(C + 5 * ldc + 0 * F, c50, _alpha, mask); + } + + static void Kernel6x2nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + svfloat32_t c10 = zero; + svfloat32_t c11 = zero; + svfloat32_t c20 = zero; + svfloat32_t c21 = zero; + svfloat32_t c30 = zero; + svfloat32_t c31 = zero; + svfloat32_t c40 = zero; + svfloat32_t c41 = zero; + svfloat32_t c50 = zero; + svfloat32_t c51 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_x(body, c10, b0, a0); + c11 = svmla_f32_x(body, c11, b1, a0); + a0 = svdup_n_f32(A[2 * lda]); + c20 = svmla_f32_x(body, c20, b0, a0); + c21 = svmla_f32_x(body, c21, b1, a0); + a0 = svdup_n_f32(A[3 * lda]); + c30 = svmla_f32_x(body, c30, b0, a0); + c31 = svmla_f32_x(body, c31, b1, a0); + a0 = svdup_n_f32(A[4 * lda]); + c40 = svmla_f32_x(body, c40, b0, a0); + c41 = svmla_f32_x(body, c41, b1, a0); + a0 = svdup_n_f32(A[5 * lda]); + c50 = svmla_f32_x(body, c50, b0, a0); + c51 = svmla_f32_x(body, c51, b1, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha); + AddProduct(C + 1 * ldc + 1 * F, c11, _alpha); + AddProduct(C + 2 * ldc + 0 * F, c20, _alpha); + AddProduct(C + 2 * ldc + 1 * F, c21, _alpha); + AddProduct(C + 3 * ldc + 0 * F, c30, _alpha); + AddProduct(C + 3 * ldc + 1 * F, c31, _alpha); + AddProduct(C + 4 * ldc + 0 * F, c40, _alpha); + AddProduct(C + 4 * ldc + 1 * F, c41, _alpha); + AddProduct(C + 5 * ldc + 0 * F, c50, _alpha); + AddProduct(C + 5 * ldc + 1 * F, c51, _alpha); + } + + static void Kernel6x3nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + svfloat32_t c02 = zero; + svfloat32_t c10 = zero; + svfloat32_t c11 = zero; + svfloat32_t c12 = zero; + svfloat32_t c20 = zero; + svfloat32_t c21 = zero; + svfloat32_t c22 = zero; + svfloat32_t c30 = zero; + svfloat32_t c31 = zero; + svfloat32_t c32 = zero; + svfloat32_t c40 = zero; + svfloat32_t c41 = zero; + svfloat32_t c42 = zero; + svfloat32_t c50 = zero; + svfloat32_t c51 = zero; + svfloat32_t c52 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t b2 = svld1_f32(body, B + 2 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + c02 = svmla_f32_x(body, c02, b2, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_x(body, c10, b0, a0); + c11 = svmla_f32_x(body, c11, b1, a0); + c12 = svmla_f32_x(body, c12, b2, a0); + a0 = svdup_n_f32(A[2 * lda]); + c20 = svmla_f32_x(body, c20, b0, a0); + c21 = svmla_f32_x(body, c21, b1, a0); + c22 = svmla_f32_x(body, c22, b2, a0); + a0 = svdup_n_f32(A[3 * lda]); + c30 = svmla_f32_x(body, c30, b0, a0); + c31 = svmla_f32_x(body, c31, b1, a0); + c32 = svmla_f32_x(body, c32, b2, a0); + a0 = svdup_n_f32(A[4 * lda]); + c40 = svmla_f32_x(body, c40, b0, a0); + c41 = svmla_f32_x(body, c41, b1, a0); + c42 = svmla_f32_x(body, c42, b2, a0); + a0 = svdup_n_f32(A[5 * lda]); + c50 = svmla_f32_x(body, c50, b0, a0); + c51 = svmla_f32_x(body, c51, b1, a0); + c52 = svmla_f32_x(body, c52, b2, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + AddProduct(C + 0 * ldc + 2 * F, c02, _alpha); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha); + AddProduct(C + 1 * ldc + 1 * F, c11, _alpha); + AddProduct(C + 1 * ldc + 2 * F, c12, _alpha); + AddProduct(C + 2 * ldc + 0 * F, c20, _alpha); + AddProduct(C + 2 * ldc + 1 * F, c21, _alpha); + AddProduct(C + 2 * ldc + 2 * F, c22, _alpha); + AddProduct(C + 3 * ldc + 0 * F, c30, _alpha); + AddProduct(C + 3 * ldc + 1 * F, c31, _alpha); + AddProduct(C + 3 * ldc + 2 * F, c32, _alpha); + AddProduct(C + 4 * ldc + 0 * F, c40, _alpha); + AddProduct(C + 4 * ldc + 1 * F, c41, _alpha); + AddProduct(C + 4 * ldc + 2 * F, c42, _alpha); + AddProduct(C + 5 * ldc + 0 * F, c50, _alpha); + AddProduct(C + 5 * ldc + 1 * F, c51, _alpha); + AddProduct(C + 5 * ldc + 2 * F, c52, _alpha); + } + + static void Kernel6x4nn(size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const svbool_t body = svptrue_b32(); + const svfloat32_t zero = svdup_n_f32(0.0f); + svfloat32_t c00 = zero; + svfloat32_t c01 = zero; + svfloat32_t c02 = zero; + svfloat32_t c03 = zero; + svfloat32_t c10 = zero; + svfloat32_t c11 = zero; + svfloat32_t c12 = zero; + svfloat32_t c13 = zero; + svfloat32_t c20 = zero; + svfloat32_t c21 = zero; + svfloat32_t c22 = zero; + svfloat32_t c23 = zero; + svfloat32_t c30 = zero; + svfloat32_t c31 = zero; + svfloat32_t c32 = zero; + svfloat32_t c33 = zero; + svfloat32_t c40 = zero; + svfloat32_t c41 = zero; + svfloat32_t c42 = zero; + svfloat32_t c43 = zero; + svfloat32_t c50 = zero; + svfloat32_t c51 = zero; + svfloat32_t c52 = zero; + svfloat32_t c53 = zero; + for (size_t k = 0; k < K; ++k) + { + svfloat32_t b0 = svld1_f32(body, B + 0 * F); + svfloat32_t b1 = svld1_f32(body, B + 1 * F); + svfloat32_t b2 = svld1_f32(body, B + 2 * F); + svfloat32_t b3 = svld1_f32(body, B + 3 * F); + svfloat32_t a0 = svdup_n_f32(A[0 * lda]); + c00 = svmla_f32_x(body, c00, b0, a0); + c01 = svmla_f32_x(body, c01, b1, a0); + c02 = svmla_f32_x(body, c02, b2, a0); + c03 = svmla_f32_x(body, c03, b3, a0); + a0 = svdup_n_f32(A[1 * lda]); + c10 = svmla_f32_x(body, c10, b0, a0); + c11 = svmla_f32_x(body, c11, b1, a0); + c12 = svmla_f32_x(body, c12, b2, a0); + c13 = svmla_f32_x(body, c13, b3, a0); + a0 = svdup_n_f32(A[2 * lda]); + c20 = svmla_f32_x(body, c20, b0, a0); + c21 = svmla_f32_x(body, c21, b1, a0); + c22 = svmla_f32_x(body, c22, b2, a0); + c23 = svmla_f32_x(body, c23, b3, a0); + a0 = svdup_n_f32(A[3 * lda]); + c30 = svmla_f32_x(body, c30, b0, a0); + c31 = svmla_f32_x(body, c31, b1, a0); + c32 = svmla_f32_x(body, c32, b2, a0); + c33 = svmla_f32_x(body, c33, b3, a0); + a0 = svdup_n_f32(A[4 * lda]); + c40 = svmla_f32_x(body, c40, b0, a0); + c41 = svmla_f32_x(body, c41, b1, a0); + c42 = svmla_f32_x(body, c42, b2, a0); + c43 = svmla_f32_x(body, c43, b3, a0); + a0 = svdup_n_f32(A[5 * lda]); + c50 = svmla_f32_x(body, c50, b0, a0); + c51 = svmla_f32_x(body, c51, b1, a0); + c52 = svmla_f32_x(body, c52, b2, a0); + c53 = svmla_f32_x(body, c53, b3, a0); + A += 1; + B += ldb; + } + svfloat32_t _alpha = svdup_n_f32(alpha); + AddProduct(C + 0 * ldc + 0 * F, c00, _alpha); + AddProduct(C + 0 * ldc + 1 * F, c01, _alpha); + AddProduct(C + 0 * ldc + 2 * F, c02, _alpha); + AddProduct(C + 0 * ldc + 3 * F, c03, _alpha); + AddProduct(C + 1 * ldc + 0 * F, c10, _alpha); + AddProduct(C + 1 * ldc + 1 * F, c11, _alpha); + AddProduct(C + 1 * ldc + 2 * F, c12, _alpha); + AddProduct(C + 1 * ldc + 3 * F, c13, _alpha); + AddProduct(C + 2 * ldc + 0 * F, c20, _alpha); + AddProduct(C + 2 * ldc + 1 * F, c21, _alpha); + AddProduct(C + 2 * ldc + 2 * F, c22, _alpha); + AddProduct(C + 2 * ldc + 3 * F, c23, _alpha); + AddProduct(C + 3 * ldc + 0 * F, c30, _alpha); + AddProduct(C + 3 * ldc + 1 * F, c31, _alpha); + AddProduct(C + 3 * ldc + 2 * F, c32, _alpha); + AddProduct(C + 3 * ldc + 3 * F, c33, _alpha); + AddProduct(C + 4 * ldc + 0 * F, c40, _alpha); + AddProduct(C + 4 * ldc + 1 * F, c41, _alpha); + AddProduct(C + 4 * ldc + 2 * F, c42, _alpha); + AddProduct(C + 4 * ldc + 3 * F, c43, _alpha); + AddProduct(C + 5 * ldc + 0 * F, c50, _alpha); + AddProduct(C + 5 * ldc + 1 * F, c51, _alpha); + AddProduct(C + 5 * ldc + 2 * F, c52, _alpha); + AddProduct(C + 5 * ldc + 3 * F, c53, _alpha); + } + + SIMD_INLINE void KernelMx4nn(size_t M, size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + switch (M) + { + case 1: Kernel1x4nn(K, alpha, A, lda, B, ldb, C, ldc); break; + case 2: Kernel2x4nn(K, alpha, A, lda, B, ldb, C, ldc); break; + case 3: Kernel3x4nn(K, alpha, A, lda, B, ldb, C, ldc); break; + case 4: Kernel4x4nn(K, alpha, A, lda, B, ldb, C, ldc); break; + case 5: Kernel5x4nn(K, alpha, A, lda, B, ldb, C, ldc); break; + case 6: Kernel6x4nn(K, alpha, A, lda, B, ldb, C, ldc); break; + } + } + + SIMD_INLINE void KernelMx3nn(size_t M, size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + switch (M) + { + case 1: Kernel1x3nn(K, alpha, A, lda, B, ldb, C, ldc); break; + case 2: Kernel2x3nn(K, alpha, A, lda, B, ldb, C, ldc); break; + case 3: Kernel3x3nn(K, alpha, A, lda, B, ldb, C, ldc); break; + case 4: Kernel4x1nn(K, alpha, A, lda, B + 0 * F, ldb, C + 0 * F, ldc, F); + Kernel4x1nn(K, alpha, A, lda, B + 1 * F, ldb, C + 1 * F, ldc, F); + Kernel4x1nn(K, alpha, A, lda, B + 2 * F, ldb, C + 2 * F, ldc, F); break; + case 5: Kernel5x1nn(K, alpha, A, lda, B + 0 * F, ldb, C + 0 * F, ldc, F); + Kernel5x1nn(K, alpha, A, lda, B + 1 * F, ldb, C + 1 * F, ldc, F); + Kernel5x1nn(K, alpha, A, lda, B + 2 * F, ldb, C + 2 * F, ldc, F); break; + case 6: Kernel6x3nn(K, alpha, A, lda, B, ldb, C, ldc); break; + } + } + + SIMD_INLINE void KernelMx2nn(size_t M, size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + switch (M) + { + case 1: Kernel1x2nn(K, alpha, A, lda, B, ldb, C, ldc); break; + case 2: Kernel2x2nn(K, alpha, A, lda, B, ldb, C, ldc); break; + case 3: Kernel3x2nn(K, alpha, A, lda, B, ldb, C, ldc); break; + case 4: Kernel4x1nn(K, alpha, A, lda, B + 0 * F, ldb, C + 0 * F, ldc, F); + Kernel4x1nn(K, alpha, A, lda, B + 1 * F, ldb, C + 1 * F, ldc, F); break; + case 5: Kernel5x1nn(K, alpha, A, lda, B + 0 * F, ldb, C + 0 * F, ldc, F); + Kernel5x1nn(K, alpha, A, lda, B + 1 * F, ldb, C + 1 * F, ldc, F); break; + case 6: Kernel6x2nn(K, alpha, A, lda, B, ldb, C, ldc); break; + } + } + + SIMD_INLINE void KernelMx1nn(size_t M, size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc, size_t n) + { + switch (M) + { + case 1: Kernel1x1nn(K, alpha, A, lda, B, ldb, C, ldc, n); break; + case 2: Kernel2x1nn(K, alpha, A, lda, B, ldb, C, ldc, n); break; + case 3: Kernel3x1nn(K, alpha, A, lda, B, ldb, C, ldc, n); break; + case 4: Kernel4x1nn(K, alpha, A, lda, B, ldb, C, ldc, n); break; + case 5: Kernel5x1nn(K, alpha, A, lda, B, ldb, C, ldc, n); break; + case 6: Kernel6x1nn(K, alpha, A, lda, B, ldb, C, ldc, n); break; + } + } + + SIMD_INLINE void MicroKernel(size_t M, size_t N, size_t K, float alpha, const float* A, size_t lda, const float* B, size_t ldb, float* C, size_t ldc) + { + const size_t F = svcntw(); + const size_t microN = 4 * F; + size_t j = 0; + for (; j + microN <= N; j += microN) + KernelMx4nn(M, K, alpha, A, lda, B + j, ldb, C + j, ldc); + if (j + 3 * F <= N) + { + KernelMx3nn(M, K, alpha, A, lda, B + j, ldb, C + j, ldc); + j += 3 * F; + } + if (j + 2 * F <= N) + { + KernelMx2nn(M, K, alpha, A, lda, B + j, ldb, C + j, ldc); + j += 2 * F; + } + if (j + F <= N) + { + KernelMx1nn(M, K, alpha, A, lda, B + j, ldb, C + j, ldc, F); + j += F; + } + if (j < N) + KernelMx1nn(M, K, alpha, A, lda, B + j, ldb, C + j, ldc, N - j); } void Gemm32fNN(size_t M, size_t N, size_t K, const float* alpha, const float* A, size_t lda, const float* B, size_t ldb, const float* beta, float* C, size_t ldc) @@ -98,29 +1001,35 @@ namespace Simd const size_t F = svcntw(); const size_t microM = 6; const size_t microN = 4 * F; - GemmScaleC(M, N, beta[0], C, ldc); - for (size_t i = 0; i < M; i += microM) + const size_t L1 = Base::AlgCacheL1(); + const size_t L2 = Base::AlgCacheL2(); + const size_t L3 = Base::AlgCacheL3(); + size_t macroK = Simd::Min(L1 / sizeof(float) / microN, K); + if (macroK == 0) + macroK = K; + size_t macroM = Simd::RestrictRange(AlignLoAny(L2 / sizeof(float) / macroK, microM), microM, AlignHiAny(M, microM)); + size_t macroN = Simd::RestrictRange(AlignLoAny(L3 / sizeof(float) / macroK, microN), microN, AlignHiAny(N, microN)); + + for (size_t j = 0; j < N; j += macroN) { - size_t m = Simd::Min(microM, M - i); - for (size_t j = 0; j < N; j += microN) + size_t currentN = Simd::Min(N, j + macroN) - j; + for (size_t k = 0; k < K; k += macroK) { - size_t tail = Simd::Min(microN, N - j); - switch (m) + size_t currentK = Simd::Min(K, k + macroK) - k; + for (size_t i = 0; i < M; i += macroM) { - case 1: GemmKernelMx4nn<1>(K, alpha[0], A + i * lda, lda, B + j, ldb, F, C + i * ldc + j, ldc, tail); break; - case 2: GemmKernelMx4nn<2>(K, alpha[0], A + i * lda, lda, B + j, ldb, F, C + i * ldc + j, ldc, tail); break; - case 3: GemmKernelMx4nn<3>(K, alpha[0], A + i * lda, lda, B + j, ldb, F, C + i * ldc + j, ldc, tail); break; - case 4: GemmKernelMx4nn<4>(K, alpha[0], A + i * lda, lda, B + j, ldb, F, C + i * ldc + j, ldc, tail); break; - case 5: GemmKernelMx4nn<5>(K, alpha[0], A + i * lda, lda, B + j, ldb, F, C + i * ldc + j, ldc, tail); break; - case 6: GemmKernelMx4nn<6>(K, alpha[0], A + i * lda, lda, B + j, ldb, F, C + i * ldc + j, ldc, tail); break; + size_t currentM = Simd::Min(M, i + macroM) - i; + if (k == 0) + GemmScaleC(currentM, currentN, beta[0], C + i * ldc + j, ldc); + for (size_t ii = 0; ii < currentM; ii += microM) + { + size_t m = Simd::Min(microM, currentM - ii); + MicroKernel(m, currentN, currentK, alpha[0], A + (i + ii) * lda + k, lda, B + k * ldb + j, ldb, C + (i + ii) * ldc + j, ldc); + } } } } } - -#undef SIMD_SVE2_GEMM_INIT -#undef SIMD_SVE2_GEMM_ROW -#undef SIMD_SVE2_GEMM_SAVE } #endif }