Files
llama.cpp-mtp-turboquant/ggml/src/ggml-cpu/spacemit/ime2_kernels.cpp
T

5769 lines
285 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "ggml-impl.h"
#include "ggml.h"
#include "ime_kernels.h"
#include "rvv_kernels.h"
#include "string.h"
#include <algorithm>
#include <cmath>
#include <stdexcept>
#if !defined(__riscv_v) || !defined(__riscv_v_intrinsic)
# error "riscv v extension or v_intrinsic not enabled"
#else
# include <riscv_vector.h>
#endif
#if !defined(__riscv_zfh)
# error "riscv zfh extension not enabled"
#endif
#if defined(RISCV64_SPACEMIT_IME2)
#else
# error "RISCV64_SPACEMIT_IME2 not defined"
#endif
#if defined(__GNUC__)
# pragma GCC diagnostic ignored "-Woverlength-strings"
# pragma GCC diagnostic ignored "-Wcast-qual"
# pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
namespace spacemit_kernels {
namespace ime2 {
template <size_t MB_ROWS, size_t NB_COLS>
void gemm_kernel_i8i2k_mrow_ref(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
using blk_type = nrow_block_q2_k<NB_COLS>;
constexpr float refactor_scale = 16.0f;
constexpr float factor_scale = 1.0f / refactor_scale;
int64_t a_blk_stride = q8k_blk_size(256);
int64_t a_nrow_block_stride = a_blk_stride * MB_ROWS;
int64_t b_ncol_block_stride = sizeof(blk_type);
float output[MB_ROWS * NB_COLS] = { 0 };
_Float16 output_f16[MB_ROWS * NB_COLS] = { 0 };
blk_type * quant_b_blk_data = (blk_type *) (quant_b_data);
for (size_t ni = 0; ni < count_n; ni += NB_COLS, c_ptr += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
int8_t * a_data = (int8_t *) quant_a_ptr + sizeof(float) * MB_ROWS + sizeof(int16_t) * MB_ROWS * 16;
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
output[ci + mi * NB_COLS] = 0;
}
}
for (size_t ki = 0; ki < k_blks; ki++, quant_b_blk_data++, a_data += a_nrow_block_stride) {
uint8_t * b_data = quant_b_blk_data->qs;
uint8_t * scales = quant_b_blk_data->scales;
uint8_t * scales16 = (uint8_t *) (quant_b_blk_data->scales16);
uint8_t * zeros16 = (uint8_t *) (quant_b_blk_data->zeros16);
_Float16 * scales_fp16 = (_Float16 *) scales16;
_Float16 * zeros_fp16 = (_Float16 *) zeros16;
float * a_scale_row = (float *) (a_data - sizeof(float) * MB_ROWS - sizeof(int16_t) * MB_ROWS * 16);
int16_t * a_sum_row = (int16_t *) (a_data - sizeof(int16_t) * MB_ROWS * 16);
memset(output_f16, 0, sizeof(output_f16));
uint8_t * scales_temp = scales;
uint8_t * zps_temp = scales;
for (size_t kii = 0; kii < 16; kii++, scales_temp += NB_COLS, zps_temp++) {
size_t b_shift = (kii % 4) * 2;
uint8_t * b_data_col = b_data + (kii / 4) * NB_COLS * 16;
for (size_t mi = 0; mi < MB_ROWS; mi++) {
int16_t a_sum = a_sum_row[mi * 16 + kii];
for (size_t ci = 0; ci < NB_COLS; ci++) {
_Float16 acc_0 = 0.0;
uint8_t b_zp = zps_temp[ci * 16] >> 4;
uint8_t b_scale = scales_temp[ci] & 0x0F;
for (size_t bi = 0; bi < 16; bi++) {
int8_t a0 = a_data[mi * 256 + bi + kii * 16];
uint8_t b0 = b_data_col[ci * 16 + bi];
acc_0 += static_cast<int16_t>(a0) * static_cast<int16_t>((b0 >> b_shift) & 0x03);
}
_Float16 scale_item =
static_cast<_Float16>(b_scale) * static_cast<_Float16>(factor_scale) * scales_fp16[ci];
output_f16[ci + mi * NB_COLS] += acc_0 * scale_item;
output[ci + mi * NB_COLS] += b_zp * a_sum * a_scale_row[mi] * zeros_fp16[ci];
}
}
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
auto a_scale = a_scale_row[mi] * refactor_scale;
for (size_t ci = 0; ci < NB_COLS; ci++) {
output[ci + mi * NB_COLS] += output_f16[ci + mi * NB_COLS] * a_scale;
}
}
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < nb_real; ci++) {
c_ptr[mi * ldc + ci] = output[mi * NB_COLS + ci];
}
}
}
}
template <size_t MB_ROWS, size_t NB_COLS>
void gemm_kernel_i8i3k_mrow_ref(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
using blk_type = nrow_block_q2_k<NB_COLS>;
constexpr float refactor_scale = 16.0f;
constexpr float factor_scale = 1.0f / refactor_scale;
int64_t a_blk_stride = q8k_blk_size(256);
int64_t a_nrow_block_stride = a_blk_stride * MB_ROWS;
int64_t b_ncol_block_stride = sizeof(blk_type);
float output[MB_ROWS * NB_COLS] = { 0 };
_Float16 output_f16[MB_ROWS * NB_COLS] = { 0 };
blk_type * quant_b_blk_data = (blk_type *) (quant_b_data);
for (size_t ni = 0; ni < count_n; ni += NB_COLS, c_ptr += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
int8_t * a_data = (int8_t *) quant_a_ptr + sizeof(float) * MB_ROWS + sizeof(int16_t) * MB_ROWS * 16;
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
output[ci + mi * NB_COLS] = 0;
}
}
for (size_t ki = 0; ki < k_blks; ki++, quant_b_blk_data++, a_data += a_nrow_block_stride) {
uint8_t * b_data = quant_b_blk_data->qs;
uint8_t * b_hmask = quant_b_blk_data->hmask;
int8_t * scales = quant_b_blk_data->scales;
uint8_t * scales16 = (uint8_t *) (quant_b_blk_data->scales16);
_Float16 * scales_fp16 = (_Float16 *) scales16;
float * a_scale_row = (float *) (a_data - sizeof(float) * MB_ROWS - sizeof(int16_t) * MB_ROWS * 16);
int16_t * a_sum_row = (int16_t *) (a_data - sizeof(int16_t) * MB_ROWS * 16);
memset(output_f16, 0, sizeof(output_f16));
int8_t * scales_temp = scales;
uint16_t * b_mask_col = (uint16_t *) b_hmask;
float acc_0_max = 0.0f;
for (size_t kii = 0; kii < 16; kii++, scales_temp += NB_COLS, b_mask_col += NB_COLS) {
size_t b_shift = (kii % 4) * 2;
uint8_t * b_data_col = b_data + (kii / 4) * NB_COLS * 16;
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
_Float16 acc_0 = 0;
// blk 2 * kii + 0
uint16_t b_shift_mask = 1;
for (size_t bi = 0; bi < 16; bi++, b_shift_mask <<= 1) {
int8_t a0 = a_data[mi * 256 + bi + kii * 16];
int8_t b0 = static_cast<int8_t>((b_data_col[ci * 16 + bi] >> b_shift) & 0x03);
b0 -= b_mask_col[ci] & b_shift_mask ? 0 : 4;
acc_0 += static_cast<int16_t>(a0) * static_cast<int16_t>(b0);
}
_Float16 scale_item = static_cast<_Float16>(scales_temp[ci]) * scales_fp16[ci] *
static_cast<_Float16>(factor_scale);
output_f16[ci + mi * NB_COLS] += acc_0 * scale_item;
}
}
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
auto a_scale = a_scale_row[mi] * refactor_scale;
for (size_t ci = 0; ci < NB_COLS; ci++) {
output[ci + mi * NB_COLS] += output_f16[ci + mi * NB_COLS] * a_scale;
}
}
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < nb_real; ci++) {
c_ptr[mi * ldc + ci] = output[mi * NB_COLS + ci];
}
}
}
}
template <size_t MB_ROWS, size_t NB_COLS>
void gemm_kernel_i8i4_mrow_ref(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
constexpr size_t kblks_per_blk = 16;
GGML_ASSERT(k_blks % kblks_per_blk == 0);
int64_t b_blk_stride = (sizeof(_Float16) + (blk_len / 2) + (quant_b_zp ? sizeof(uint8_t) : 0));
int64_t b_stride = k_blks * b_blk_stride;
int64_t a_blk_stride = q8_blk_size(blk_len, true);
int64_t a_nrow_block_stride = a_blk_stride * MB_ROWS;
int64_t b_ncol_block_stride = b_blk_stride * NB_COLS;
float output[MB_ROWS * NB_COLS] = { 0 };
_Float16 output_f16[MB_ROWS * NB_COLS] = { 0 };
for (size_t ni = 0; ni < count_n; ni += NB_COLS, c_ptr += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
uint8_t * b_data = (uint8_t *) quant_b_data + ni * b_stride + NB_COLS * sizeof(_Float16);
if (quant_b_zp) {
b_data += NB_COLS * sizeof(uint8_t);
}
int8_t * a_data = (int8_t *) quant_a_ptr + sizeof(float) * MB_ROWS + sizeof(int16_t) * MB_ROWS;
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
output[ci + mi * NB_COLS] = 0.0f;
output_f16[ci + mi * NB_COLS] = static_cast<_Float16>(0.0f);
}
}
size_t kii = 0;
for (size_t ki = 0; ki < k_blks; ki++, a_data += a_nrow_block_stride, b_data += b_ncol_block_stride) {
_Float16 * b_scale_fp16 = (_Float16 *) (b_data - NB_COLS * sizeof(_Float16));
uint8_t * b_zp = nullptr;
if (quant_b_zp) {
b_scale_fp16 = (_Float16 *) (b_data - NB_COLS * sizeof(_Float16) - NB_COLS * sizeof(uint8_t));
b_zp = (uint8_t *) (b_data - NB_COLS * sizeof(uint8_t));
}
float * a_scale_row = (float *) (a_data - sizeof(float) * MB_ROWS - sizeof(int16_t) * MB_ROWS);
int16_t * a_sum_row = (int16_t *) (a_data - sizeof(int16_t) * MB_ROWS);
for (size_t mi = 0; mi < MB_ROWS; mi++) {
_Float16 a_scale = a_scale_row[mi];
int16_t a_sum = a_sum_row[mi];
for (size_t ci = 0; ci < NB_COLS; ci++) {
_Float16 b_scale = b_scale_fp16[ci];
int32_t acc = 0;
if (b_zp) {
acc += a_sum * b_zp[ci];
} else {
acc += a_sum * 8;
}
for (size_t bi = 0; bi < blk_len / 2; bi++) {
int8_t a0 = a_data[mi * blk_len + 2 * bi];
int8_t a1 = a_data[mi * blk_len + 2 * bi + 1];
uint8_t b = b_data[ci * blk_len / 2 + bi];
int8_t b0 = static_cast<int8_t>(b & 0x0F);
int8_t b1 = static_cast<int8_t>((b & 0xF0) >> 4);
acc += static_cast<int32_t>(a0) * static_cast<int32_t>(b0) +
static_cast<int32_t>(a1) * static_cast<int32_t>(b1);
}
output_f16[ci + mi * NB_COLS] +=
static_cast<float>(acc) * static_cast<float>(a_scale) * static_cast<float>(b_scale);
}
}
if (kii == kblks_per_blk - 1) {
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
output[ci + mi * NB_COLS] += static_cast<float>(output_f16[ci + mi * NB_COLS]);
output_f16[ci + mi * NB_COLS] = 0.0f;
}
}
kii = 0;
} else {
kii++;
}
}
if (kii == kblks_per_blk - 1) {
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
output[ci + mi * NB_COLS] += static_cast<float>(output_f16[ci + mi * NB_COLS]);
output_f16[ci + mi * NB_COLS] = 0.0f;
}
}
kii = 0;
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < nb_real; ci++) {
c_ptr[mi * ldc + ci] = output[mi * NB_COLS + ci];
}
}
}
}
template <size_t MB_ROWS, size_t NB_COLS>
void gemm_kernel_i8i4_hp_mrow_ref(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
constexpr size_t k_subblks_per_superblk = 8;
struct block_q4_0x32_layout {
_Float16 d[NB_COLS];
uint8_t qs[16 * NB_COLS];
};
GGML_ASSERT(blk_len == 256);
const size_t b_superblk_stride = sizeof(block_q4_0x32_layout) * k_subblks_per_superblk +
(quant_b_zp ? NB_COLS * k_subblks_per_superblk * sizeof(uint8_t) : 0);
const size_t b_tile_stride = k_blks * b_superblk_stride;
const size_t a_nrow_block_stride = q8_hp_blk_size(blk_len, true, true) * MB_ROWS;
const size_t a_subblk_stride = q8_hp_blk_size(32, false, false) * MB_ROWS;
float output[MB_ROWS * NB_COLS] = { 0 };
for (size_t ni = 0; ni < count_n; ni += NB_COLS, c_ptr += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
const uint8_t * b_tile_base = quant_b_data + (ni / NB_COLS) * b_tile_stride;
int8_t * a_data = (int8_t *) quant_a_ptr;
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
output[ci + mi * NB_COLS] = 0.0f;
}
}
for (size_t ki = 0; ki < k_blks; ki++, a_data += a_nrow_block_stride) {
_Float16 output_f16[MB_ROWS * NB_COLS] = { 0 };
const uint8_t * b_superblk_ptr = b_tile_base + ki * b_superblk_stride;
const block_q4_0x32_layout * b_blocks = reinterpret_cast<const block_q4_0x32_layout *>(b_superblk_ptr);
const uint8_t * b_zps =
quant_b_zp ? b_superblk_ptr + sizeof(block_q4_0x32_layout) * k_subblks_per_superblk : nullptr;
_Float16 * a_sum_row = (_Float16 *) (a_data + a_subblk_stride * k_subblks_per_superblk);
_Float16 * a_scale_avg_row = (_Float16 *) (a_data + a_nrow_block_stride - sizeof(_Float16) * MB_ROWS);
_Float16 scale_factor = a_scale_avg_row[0];
for (size_t ksi = 0; ksi < k_subblks_per_superblk; ++ksi) {
const _Float16 * a_scale_row = reinterpret_cast<const _Float16 *>(a_data + a_subblk_stride * ksi);
int8_t * a_subblk = a_data + a_subblk_stride * ksi + MB_ROWS * sizeof(_Float16);
const _Float16 a_scale = a_scale_row[0];
const block_q4_0x32_layout & b_block = b_blocks[ksi];
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
const uint8_t * b_qs = b_block.qs + ci * 16;
_Float16 b_scale = b_block.d[ci] * a_scale;
int16_t acc = 0;
for (size_t bi = 0; bi < 16; bi++) {
uint8_t b = b_qs[bi];
int8_t b0 = static_cast<int8_t>(b & 0x0F);
int8_t b1 = static_cast<int8_t>((b & 0xF0) >> 4);
acc += static_cast<int16_t>(a_subblk[mi * 32 + 2 * bi]) * static_cast<int16_t>(b0) +
static_cast<int16_t>(a_subblk[mi * 32 + 2 * bi + 1]) * static_cast<int16_t>(b1);
}
const _Float16 scaled_acc = static_cast<_Float16>(acc) * b_scale;
output_f16[ci + mi * NB_COLS] += scaled_acc;
}
}
}
for (size_t ksi = 0; ksi < k_subblks_per_superblk; ++ksi) {
const _Float16 * a_scale_row = reinterpret_cast<const _Float16 *>(a_data + a_subblk_stride * ksi);
const block_q4_0x32_layout & b_block = b_blocks[ksi];
const uint8_t * b_zp_row = b_zps ? b_zps + ksi * NB_COLS : nullptr;
const _Float16 a_scale = a_scale_row[0];
for (size_t mi = 0; mi < MB_ROWS; mi++) {
const _Float16 a_sum = a_sum_row[mi * k_subblks_per_superblk + ksi];
for (size_t ci = 0; ci < NB_COLS; ci++) {
_Float16 b_scale = b_block.d[ci] * a_scale;
_Float16 a_sum_bzp = a_sum;
if (b_zp_row) {
a_sum_bzp = a_sum * static_cast<_Float16>(0.125f) * static_cast<_Float16>(b_zp_row[ci]);
}
const _Float16 scaled_acc = a_sum_bzp * b_scale;
output[ci + mi * NB_COLS] += scaled_acc * scale_factor;
}
}
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
auto val = static_cast<float>(output_f16[ci + mi * NB_COLS]) * static_cast<float>(scale_factor);
output[ci + mi * NB_COLS] += val;
}
}
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < nb_real; ci++) {
c_ptr[mi * ldc + ci] = output[mi * NB_COLS + ci];
}
}
}
}
template <size_t MB_ROWS, size_t NB_COLS>
void moe_gemm_kernel_i8i4_mrow_ref(size_t blk_len,
const uint8_t ** quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float ** c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
int64_t b_blk_stride = (sizeof(ggml_fp16_t) + (blk_len / 2) + (quant_b_zp ? sizeof(uint8_t) : 0));
int64_t b_stride = k_blks * b_blk_stride;
int64_t a_blk_stride = q8_blk_size(blk_len, true);
int64_t b_ncol_block_stride = b_blk_stride * NB_COLS;
float output[MB_ROWS * NB_COLS] = { 0 };
std::array<int8_t *, MB_ROWS> a_data;
std::array<float *, MB_ROWS> c_data;
for (size_t mi = 0; mi < MB_ROWS; mi++) {
c_data[mi] = c_ptr[mi];
}
for (size_t ni = 0; ni < count_n; ni += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
uint8_t * b_data = (uint8_t *) quant_b_data + ni * b_stride + NB_COLS * sizeof(ggml_fp16_t);
if (quant_b_zp) {
b_data += NB_COLS * sizeof(uint8_t);
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
a_data[mi] = (int8_t *) quant_a_ptr[mi] + sizeof(float) + sizeof(int16_t);
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
output[ci + mi * NB_COLS] = 0;
}
}
for (size_t ki = 0; ki < k_blks; ki++, b_data += b_ncol_block_stride) {
ggml_fp16_t * b_scale_fp16 = (ggml_fp16_t *) (b_data - NB_COLS * sizeof(ggml_fp16_t));
uint8_t * b_zp = nullptr;
if (quant_b_zp) {
b_scale_fp16 = (ggml_fp16_t *) (b_data - NB_COLS * sizeof(ggml_fp16_t) - NB_COLS * sizeof(uint8_t));
b_zp = (uint8_t *) (b_data - NB_COLS * sizeof(uint8_t));
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
float * a_scale_row = (float *) (a_data[mi] - sizeof(float) - sizeof(int16_t));
int16_t * a_sum_row = (int16_t *) (a_data[mi] - sizeof(int16_t));
float a_scale = *a_scale_row;
int16_t a_sum = *a_sum_row;
for (size_t ci = 0; ci < NB_COLS; ci++) {
float b_scale = ggml_fp16_to_fp32(b_scale_fp16[ci]);
int32_t acc = 0;
if (b_zp) {
acc += a_sum * b_zp[ci];
} else {
acc += a_sum * 8;
}
for (size_t bi = 0; bi < blk_len / 2; bi++) {
int8_t a0 = (a_data[mi])[2 * bi];
int8_t a1 = (a_data[mi])[2 * bi + 1];
uint8_t b = b_data[ci * blk_len / 2 + bi];
int8_t b0 = static_cast<int8_t>(b & 0x0F);
int8_t b1 = static_cast<int8_t>((b & 0xF0) >> 4);
acc += static_cast<int32_t>(a0) * static_cast<int32_t>(b0) +
static_cast<int32_t>(a1) * static_cast<int32_t>(b1);
}
output[ci + mi * NB_COLS] += static_cast<float>(acc) * a_scale * b_scale;
}
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
a_data[mi] += a_blk_stride;
}
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < nb_real; ci++) {
(c_data[mi])[ci] = output[mi * NB_COLS + ci];
}
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
c_data[mi] += NB_COLS;
}
}
}
template <size_t MB_ROWS, size_t NB_COLS>
void moe_gemm_kernel_i8i5_mrow_ref(size_t blk_len,
const uint8_t ** quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float ** c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
GGML_UNUSED(count_m);
GGML_UNUSED(ldc);
// blk_len is expected to be 32 for Q5 types.
int64_t a_blk_stride = q8_blk_size(blk_len, true);
float output[MB_ROWS * NB_COLS] = { 0 };
std::array<int8_t *, MB_ROWS> a_data;
std::array<float *, MB_ROWS> c_data;
for (size_t mi = 0; mi < MB_ROWS; ++mi) {
c_data[mi] = c_ptr[mi];
}
if (quant_b_zp) {
using blk_type = nrow_block_q5_1<NB_COLS>;
for (size_t ni = 0; ni < count_n; ni += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
blk_type * quant_b_blk_data = (blk_type *) quant_b_data + (ni / NB_COLS) * k_blks;
for (size_t mi = 0; mi < MB_ROWS; ++mi) {
a_data[mi] = (int8_t *) quant_a_ptr[mi] + sizeof(float) + sizeof(int16_t);
}
for (size_t mi = 0; mi < MB_ROWS; ++mi) {
for (size_t ci = 0; ci < NB_COLS; ++ci) {
output[ci + mi * NB_COLS] = 0;
}
}
for (size_t ki = 0; ki < k_blks; ++ki, ++quant_b_blk_data) {
for (size_t mi = 0; mi < MB_ROWS; ++mi) {
float * a_scale_row = (float *) (a_data[mi] - sizeof(float) - sizeof(int16_t));
int16_t * a_sum_row = (int16_t *) (a_data[mi] - sizeof(int16_t));
float a_scale = *a_scale_row;
int16_t a_sum = *a_sum_row;
for (size_t ci = 0; ci < NB_COLS; ++ci) {
float b_scale = ggml_fp16_to_fp32(quant_b_blk_data->scales16[ci]);
uint8_t b_zp_val = quant_b_blk_data->zp[ci];
int32_t acc = a_sum * static_cast<int32_t>(b_zp_val);
for (size_t bi = 0; bi < blk_len / 2; ++bi) {
int8_t a0 = a_data[mi][2 * bi];
int8_t a1 = a_data[mi][2 * bi + 1];
uint8_t qs_byte = quant_b_blk_data->qs[ci * (blk_len / 2) + bi];
int8_t b0 = static_cast<int8_t>(qs_byte & 0x0F);
int8_t b1 = static_cast<int8_t>((qs_byte >> 4) & 0x0F);
uint8_t qh_byte0 = quant_b_blk_data->qh[ci * 4 + (2 * bi) / 8];
uint8_t qh_byte1 = quant_b_blk_data->qh[ci * 4 + (2 * bi + 1) / 8];
uint8_t h0 = (qh_byte0 >> ((2 * bi) % 8)) & 1;
uint8_t h1 = (qh_byte1 >> ((2 * bi + 1) % 8)) & 1;
b0 |= (h0 << 4);
b1 |= (h1 << 4);
acc += static_cast<int32_t>(a0) * static_cast<int32_t>(b0) +
static_cast<int32_t>(a1) * static_cast<int32_t>(b1);
}
output[ci + mi * NB_COLS] += static_cast<float>(acc) * a_scale * b_scale;
}
a_data[mi] += a_blk_stride;
}
}
for (size_t mi = 0; mi < MB_ROWS; ++mi) {
for (size_t ci = 0; ci < nb_real; ++ci) {
c_data[mi][ci] = output[mi * NB_COLS + ci];
}
c_data[mi] += NB_COLS;
}
}
} else {
using blk_type = nrow_block_q5_0<NB_COLS>;
for (size_t ni = 0; ni < count_n; ni += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
blk_type * quant_b_blk_data = (blk_type *) quant_b_data + (ni / NB_COLS) * k_blks;
for (size_t mi = 0; mi < MB_ROWS; ++mi) {
a_data[mi] = (int8_t *) quant_a_ptr[mi] + sizeof(float) + sizeof(int16_t);
}
for (size_t mi = 0; mi < MB_ROWS; ++mi) {
for (size_t ci = 0; ci < NB_COLS; ++ci) {
output[ci + mi * NB_COLS] = 0;
}
}
for (size_t ki = 0; ki < k_blks; ++ki, ++quant_b_blk_data) {
for (size_t mi = 0; mi < MB_ROWS; ++mi) {
float * a_scale_row = (float *) (a_data[mi] - sizeof(float) - sizeof(int16_t));
int16_t * a_sum_row = (int16_t *) (a_data[mi] - sizeof(int16_t));
float a_scale = *a_scale_row;
int16_t a_sum = *a_sum_row;
for (size_t ci = 0; ci < NB_COLS; ++ci) {
float b_scale = ggml_fp16_to_fp32(quant_b_blk_data->scales16[ci]);
int32_t acc = a_sum * 16;
for (size_t bi = 0; bi < blk_len / 2; ++bi) {
int8_t a0 = a_data[mi][2 * bi];
int8_t a1 = a_data[mi][2 * bi + 1];
uint8_t qs_byte = quant_b_blk_data->qs[ci * (blk_len / 2) + bi];
int8_t b0 = static_cast<int8_t>(qs_byte & 0x0F);
int8_t b1 = static_cast<int8_t>((qs_byte >> 4) & 0x0F);
uint8_t qh_byte0 = quant_b_blk_data->qh[ci * 4 + (2 * bi) / 8];
uint8_t qh_byte1 = quant_b_blk_data->qh[ci * 4 + (2 * bi + 1) / 8];
uint8_t h0 = (qh_byte0 >> ((2 * bi) % 8)) & 1;
uint8_t h1 = (qh_byte1 >> ((2 * bi + 1) % 8)) & 1;
b0 |= (h0 << 4);
b1 |= (h1 << 4);
acc += static_cast<int32_t>(a0) * static_cast<int32_t>(b0) +
static_cast<int32_t>(a1) * static_cast<int32_t>(b1);
}
output[ci + mi * NB_COLS] += static_cast<float>(acc) * a_scale * b_scale;
}
a_data[mi] += a_blk_stride;
}
}
for (size_t mi = 0; mi < MB_ROWS; ++mi) {
for (size_t ci = 0; ci < nb_real; ++ci) {
c_data[mi][ci] = output[mi * NB_COLS + ci];
}
c_data[mi] += NB_COLS;
}
}
}
}
template <size_t MB_ROWS, size_t NB_COLS>
void gemm_kernel_i8i8_mrow_ref(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
int64_t b_blk_stride = (sizeof(ggml_fp16_t) + blk_len);
int64_t b_stride = k_blks * b_blk_stride;
int64_t a_blk_stride = q8_blk_size(blk_len, true);
int64_t a_nrow_block_stride = a_blk_stride * MB_ROWS;
int64_t b_ncol_block_stride = b_blk_stride * NB_COLS;
float output[MB_ROWS * NB_COLS] = { 0 };
for (size_t ni = 0; ni < count_n; ni += NB_COLS, c_ptr += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
int8_t * b_data = (int8_t *) quant_b_data + ni * b_stride + NB_COLS * sizeof(ggml_fp16_t);
int8_t * a_data = (int8_t *) quant_a_ptr + sizeof(float) * MB_ROWS + sizeof(int16_t) * MB_ROWS;
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
output[ci + mi * NB_COLS] = 0;
}
}
for (size_t ki = 0; ki < k_blks; ki++, a_data += a_nrow_block_stride, b_data += b_ncol_block_stride) {
ggml_fp16_t * b_scale_fp16 = (ggml_fp16_t *) (b_data - NB_COLS * sizeof(ggml_fp16_t));
float * a_scale_row = (float *) (a_data - sizeof(float) * MB_ROWS - sizeof(int16_t) * MB_ROWS);
for (size_t mi = 0; mi < MB_ROWS; mi++) {
float a_scale = a_scale_row[mi];
for (size_t ci = 0; ci < NB_COLS; ci++) {
float b_scale = ggml_fp16_to_fp32(b_scale_fp16[ci]);
int32_t acc = 0;
for (size_t bi = 0; bi < blk_len; bi++) {
int8_t a0 = a_data[mi * blk_len + bi];
int8_t b0 = b_data[ci * blk_len + bi];
acc += static_cast<int32_t>(a0) * static_cast<int32_t>(b0);
}
output[ci + mi * NB_COLS] += static_cast<float>(acc) * a_scale * b_scale;
}
}
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < nb_real; ci++) {
c_ptr[mi * ldc + ci] = output[mi * NB_COLS + ci];
}
}
}
}
template <size_t MB_ROWS, size_t NB_COLS>
void gemm_kernel_i8i5_mrow_ref(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
// blk_len is expected to be 32 for Q5 types
// quant_b_zp != nullptr => nrow_block_q5_1<NB_COLS> (has zp)
// quant_b_zp == nullptr => nrow_block_q5_0<NB_COLS> (no zp)
int64_t a_blk_stride = q8_blk_size(blk_len, true);
int64_t a_nrow_block_stride = a_blk_stride * MB_ROWS;
float output[MB_ROWS * NB_COLS] = { 0 };
if (quant_b_zp) {
// nrow_block_q5_1<NB_COLS>: scales16[NB_COLS] + zp[NB_COLS] + qh[4*NB_COLS] + qs[16*NB_COLS]
using blk_type = nrow_block_q5_1<NB_COLS>;
int64_t b_ncol_block_stride = sizeof(blk_type);
blk_type * quant_b_blk_data = (blk_type *) quant_b_data;
for (size_t ni = 0; ni < count_n; ni += NB_COLS, c_ptr += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
int8_t * a_data = (int8_t *) quant_a_ptr + sizeof(float) * MB_ROWS + sizeof(int16_t) * MB_ROWS;
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
output[ci + mi * NB_COLS] = 0;
}
}
for (size_t ki = 0; ki < k_blks; ki++, quant_b_blk_data++, a_data += a_nrow_block_stride) {
float * a_scale_row = (float *) (a_data - sizeof(float) * MB_ROWS - sizeof(int16_t) * MB_ROWS);
int16_t * a_sum_row = (int16_t *) (a_data - sizeof(int16_t) * MB_ROWS);
for (size_t mi = 0; mi < MB_ROWS; mi++) {
float a_scale = a_scale_row[mi];
int16_t a_sum = a_sum_row[mi];
for (size_t ci = 0; ci < NB_COLS; ci++) {
float b_scale = ggml_fp16_to_fp32(quant_b_blk_data->scales16[ci]);
uint8_t b_zp_val = quant_b_blk_data->zp[ci];
int32_t acc = a_sum * static_cast<int32_t>(b_zp_val);
for (size_t bi = 0; bi < blk_len / 2; bi++) {
int8_t a0 = a_data[mi * blk_len + 2 * bi];
int8_t a1 = a_data[mi * blk_len + 2 * bi + 1];
uint8_t qs_byte = quant_b_blk_data->qs[ci * (blk_len / 2) + bi];
int8_t b0 = static_cast<int8_t>(qs_byte & 0x0F);
int8_t b1 = static_cast<int8_t>((qs_byte >> 4) & 0x0F);
// Extract high bits from qh
// qh is packed as 4 bytes per column (32 bits for 32 elements)
uint8_t qh_byte0 = quant_b_blk_data->qh[ci * 4 + (2 * bi) / 8];
uint8_t qh_byte1 = quant_b_blk_data->qh[ci * 4 + (2 * bi + 1) / 8];
uint8_t h0 = (qh_byte0 >> ((2 * bi) % 8)) & 1;
uint8_t h1 = (qh_byte1 >> ((2 * bi + 1) % 8)) & 1;
b0 |= (h0 << 4);
b1 |= (h1 << 4);
acc += static_cast<int32_t>(a0) * static_cast<int32_t>(b0) +
static_cast<int32_t>(a1) * static_cast<int32_t>(b1);
}
output[ci + mi * NB_COLS] += static_cast<float>(acc) * a_scale * b_scale;
}
}
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < nb_real; ci++) {
c_ptr[mi * ldc + ci] = output[mi * NB_COLS + ci];
}
}
}
} else {
// nrow_block_q5_0<NB_COLS>: scales16[NB_COLS] + qh[4*NB_COLS] + qs[16*NB_COLS]
using blk_type = nrow_block_q5_0<NB_COLS>;
int64_t b_ncol_block_stride = sizeof(blk_type);
blk_type * quant_b_blk_data = (blk_type *) quant_b_data;
for (size_t ni = 0; ni < count_n; ni += NB_COLS, c_ptr += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
int8_t * a_data = (int8_t *) quant_a_ptr + sizeof(float) * MB_ROWS + sizeof(int16_t) * MB_ROWS;
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
output[ci + mi * NB_COLS] = 0;
}
}
for (size_t ki = 0; ki < k_blks; ki++, quant_b_blk_data++, a_data += a_nrow_block_stride) {
float * a_scale_row = (float *) (a_data - sizeof(float) * MB_ROWS - sizeof(int16_t) * MB_ROWS);
int16_t * a_sum_row = (int16_t *) (a_data - sizeof(int16_t) * MB_ROWS);
for (size_t mi = 0; mi < MB_ROWS; mi++) {
float a_scale = a_scale_row[mi];
int16_t a_sum = a_sum_row[mi];
for (size_t ci = 0; ci < NB_COLS; ci++) {
float b_scale = ggml_fp16_to_fp32(quant_b_blk_data->scales16[ci]);
// Q5_0 has no zp, use default offset 16 (midpoint of 5-bit unsigned range)
int32_t acc = a_sum * 16;
for (size_t bi = 0; bi < blk_len / 2; bi++) {
int8_t a0 = a_data[mi * blk_len + 2 * bi];
int8_t a1 = a_data[mi * blk_len + 2 * bi + 1];
uint8_t qs_byte = quant_b_blk_data->qs[ci * (blk_len / 2) + bi];
int8_t b0 = static_cast<int8_t>(qs_byte & 0x0F);
int8_t b1 = static_cast<int8_t>((qs_byte >> 4) & 0x0F);
// Extract high bits from qh
uint8_t qh_byte0 = quant_b_blk_data->qh[ci * 4 + (2 * bi) / 8];
uint8_t qh_byte1 = quant_b_blk_data->qh[ci * 4 + (2 * bi + 1) / 8];
uint8_t h0 = (qh_byte0 >> ((2 * bi) % 8)) & 1;
uint8_t h1 = (qh_byte1 >> ((2 * bi + 1) % 8)) & 1;
b0 |= (h0 << 4);
b1 |= (h1 << 4);
acc += static_cast<int32_t>(a0) * static_cast<int32_t>(b0) +
static_cast<int32_t>(a1) * static_cast<int32_t>(b1);
}
output[ci + mi * NB_COLS] += static_cast<float>(acc) * a_scale * b_scale;
}
}
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < nb_real; ci++) {
c_ptr[mi * ldc + ci] = output[mi * NB_COLS + ci];
}
}
}
}
}
template <size_t MB_ROWS, size_t NB_COLS>
void gemm_kernel_i8mxfp4_mrow_ref(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
// blk_len is expected to be 32 (QK_MXFP4)
// quant_b_zp is unused for MXFP4 (symmetric quantization)
GGML_UNUSED(quant_b_zp);
int64_t a_blk_stride = q8_blk_size(blk_len, true);
int64_t a_nrow_block_stride = a_blk_stride * MB_ROWS;
float output[MB_ROWS * NB_COLS] = { 0 };
using blk_type = nrow_block_mxfp4<NB_COLS>;
blk_type * quant_b_blk_data = (blk_type *) quant_b_data;
for (size_t ni = 0; ni < count_n; ni += NB_COLS, c_ptr += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
int8_t * a_data = (int8_t *) quant_a_ptr + sizeof(float) * MB_ROWS + sizeof(int16_t) * MB_ROWS;
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < NB_COLS; ci++) {
output[ci + mi * NB_COLS] = 0;
}
}
for (size_t ki = 0; ki < k_blks; ki++, quant_b_blk_data++, a_data += a_nrow_block_stride) {
float * a_scale_row = (float *) (a_data - sizeof(float) * MB_ROWS - sizeof(int16_t) * MB_ROWS);
int16_t * a_sum_row = (int16_t *) (a_data - sizeof(int16_t) * MB_ROWS);
for (size_t mi = 0; mi < MB_ROWS; mi++) {
float a_scale = a_scale_row[mi];
for (size_t ci = 0; ci < NB_COLS; ci++) {
float b_scale = GGML_E8M0_TO_FP32_HALF(quant_b_blk_data->e[ci]);
// Read 32 sign bits for this column
uint32_t sign_bits;
memcpy(&sign_bits, &quant_b_blk_data->qh[ci * 4], 4);
int32_t acc = 0;
for (size_t bi = 0; bi < blk_len / 2; bi++) {
int8_t a0 = a_data[mi * blk_len + 2 * bi];
int8_t a1 = a_data[mi * blk_len + 2 * bi + 1];
// qs[ci*16 + bi] stores abs(vals[bi*2]) in low 4 bits
// and abs(vals[bi*2+1]) in high 4 bits
uint8_t qs_byte = quant_b_blk_data->qs[ci * 16 + bi];
int8_t b_abs0 = static_cast<int8_t>(qs_byte & 0x0F);
int8_t b_abs1 = static_cast<int8_t>((qs_byte >> 4) & 0x0F);
// Extract sign bits: bit (2*bi) for vals[2*bi], bit (2*bi+1) for vals[2*bi+1]
int8_t b0 = (sign_bits >> (2 * bi)) & 1 ? -b_abs0 : b_abs0;
int8_t b1 = (sign_bits >> (2 * bi + 1)) & 1 ? -b_abs1 : b_abs1;
acc += static_cast<int32_t>(a0) * static_cast<int32_t>(b0) +
static_cast<int32_t>(a1) * static_cast<int32_t>(b1);
}
output[ci + mi * NB_COLS] += static_cast<float>(acc) * a_scale * b_scale;
}
}
}
for (size_t mi = 0; mi < MB_ROWS; mi++) {
for (size_t ci = 0; ci < nb_real; ci++) {
c_ptr[mi * ldc + ci] = output[mi * NB_COLS + ci];
}
}
}
}
void gemm_kernel_i8i2k_m1(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
constexpr size_t NB_COLS = 32;
using blk_type = nrow_block_q2_k<NB_COLS>;
int64_t b_ncol_block_stride = sizeof(blk_type) * k_blks;
for (size_t ni = 0; ni < count_n; ni += NB_COLS) {
uint8_t * b_data = (uint8_t *) quant_b_data + (ni / NB_COLS) * b_ncol_block_stride;
int8_t * a_data = (int8_t *) quant_a_ptr;
float * dst_c = (float *) c_ptr + ni;
asm volatile(
"vsetvli t0, x0, e16, m1 \n\t"
"vxor.vv v31, v31, v31 \n\t"
"mv s1, %[BK] \n\t"
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
// load scale A
"flw fa0, (%[A]) \n\t"
"addi %[A], %[A], 4 \n\t"
"li t1, 4 \n\t"
"addi t2, %[B], 512 \n\t" // B data addr
"addi t3, %[A], 32 \n\t" // A data addr
"addi s3, %[B], 0 \n\t"
"vxor.vv v30, v29, v29 \n\t" // tmp result
"INNER_K_LOOP%=: \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vxor.vv v2, v2, v2 \n\t"
"vxor.vv v3, v3, v3 \n\t"
"vxor.vv v4, v4, v4 \n\t"
"vxor.vv v5, v5, v5 \n\t"
"vxor.vv v6, v6, v6 \n\t"
"vxor.vv v28, v28, v28 \n\t"
"vxor.vv v29, v29, v29 \n\t"
// load scale B
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v0, (%[B]) \n\t"
"addi %[B], %[B], 128 \n\t"
// A data, 1x64@i8
"vsetivli t0, 16, e8, mf4 \n\t"
"vle8.v v2, (t3) \n\t"
"addi t3, t3, 16 \n\t"
"vsetivli t0, 16, e8, mf4 \n\t"
"vle8.v v4, (t3) \n\t"
"addi t3, t3, 16 \n\t"
"vsetivli t0, 16, e8, mf4 \n\t"
"vle8.v v5, (t3) \n\t"
"addi t3, t3, 16 \n\t"
"vsetivli t0, 16, e8, mf4 \n\t"
"vle8.v v6, (t3) \n\t"
"addi t3, t3, 16 \n\t"
"vsetvli t0, x0, e64, mf2 \n\t"
"vslideup.vi v3, v4, 2 \n\t"
"vslideup.vi v28, v5, 4 \n\t"
"vslideup.vi v29, v6, 6 \n\t"
// init the accumu to zero
"vsetvli t0, x0, e16, m1 \n\t"
"vxor.vv v20, v18, v18 \n\t"
"vxor.vv v22, v18, v18 \n\t"
"vxor.vv v24, v18, v18 \n\t"
"vxor.vv v26, v18, v18 \n\t"
// B data, 32x64@i2
"vsetvli t0, x0, e8, m1 \n\t"
"vl4r.v v4, (t2) \n\t"
"addi t2, t2, 512 \n\t"
"vand.vi v8, v4, 0x3 \n\t" // 0-15
"vsrl.vi v9, v4, 2 \n\t"
"vsrl.vi v10, v4, 4 \n\t"
"vsrl.vi v11, v4, 6 \n\t" // 48-63
"vand.vi v9, v9, 0x3 \n\t" // 16-31
"vand.vi v10, v10, 0x3 \n\t" // 32-47
"vand.vi v12, v5, 0x3 \n\t" // 0-15
"vsrl.vi v13, v5, 2 \n\t"
"vsrl.vi v14, v5, 4 \n\t"
"vsrl.vi v15, v5, 6 \n\t" // 48-63
"vand.vi v13, v13, 0x3 \n\t" // 16-31
"vand.vi v14, v14, 0x3 \n\t" // 32-47
"vand.vi v16, v6, 0x3 \n\t" // 0-15
"vsrl.vi v17, v6, 2 \n\t"
"vsrl.vi v18, v6, 4 \n\t"
"vsrl.vi v19, v6, 6 \n\t" // 48-63
"vand.vi v17, v17, 0x3 \n\t" // 16-31
"vand.vi v18, v18, 0x3 \n\t" // 32-47
"vand.vi v4, v7, 0x3 \n\t" // 0-15
"vsrl.vi v5, v7, 2 \n\t"
"vsrl.vi v6, v7, 4 \n\t"
"vsrl.vi v7, v7, 6 \n\t" // 48-63
"vand.vi v5, v5, 0x3 \n\t" // 16-31
"vand.vi v6, v6, 0x3 \n\t" // 32-47
// i2 * i8 vmadot
"vsetvli t0, x0, e8, m1 \n\t"
"vmadotsu v20, v2, v8, i8 \n\t"
"vmadotsu v22, v2, v12, i8 \n\t"
"vmadotsu v24, v2, v16, i8 \n\t"
"vmadotsu v26, v2, v4, i8 \n\t"
"vmadotsu v20, v3, v9, i8 \n\t"
"vmadotsu v22, v3, v13, i8 \n\t"
"vmadotsu v24, v3, v17, i8 \n\t"
"vmadotsu v26, v3, v5, i8 \n\t"
"vmadotsu v20, v28, v10, i8 \n\t"
"vmadotsu v22, v28, v14, i8 \n\t"
"vmadotsu v24, v28, v18, i8 \n\t"
"vmadotsu v26, v28, v6, i8 \n\t"
"vmadotsu v20, v29, v11, i8 \n\t"
"vmadotsu v22, v29, v15, i8 \n\t"
"vmadotsu v24, v29, v19, i8 \n\t"
"vmadotsu v26, v29, v7, i8 \n\t"
"vand.vi v10, v0, 0xf \n\t" // scale
"vwadd.vx v12, v10, x0 \n\t"
"vsetvli t0, x0, e16, m2 \n\t"
"vwadd.vx v16, v12, x0 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vpack.vv v2, v20, v22, 2 \n\t"
"vpack.vv v4, v24, v26, 2 \n\t"
"vpack.vv v6, v2, v4, 3 \n\t" // 0,1
"vpack.vv v8, v3, v5, 3 \n\t" // 2,3
// mul scale
"vmacc.vv v30, v6, v16 \n\t"
"vmacc.vv v30, v7, v17 \n\t"
"vmacc.vv v30, v8, v18 \n\t"
"vmacc.vv v30, v9, v19 \n\t"
"addi t1, t1, -1 \n\t"
"bgtz t1, INNER_K_LOOP%= \n\t"
// load zp B
"vsetvli t0, x0, e8, m4 \n\t"
"vle8.v v4, (s3) \n\t"
"vsrl.vi v8, v4, 4 \n\t" // zp
// asum * zp
"vsetvli t0, x0, e16, m1 \n\t"
"vxor.vv v20, v20, v20 \n\t"
"vxor.vv v22, v22, v22 \n\t"
"vxor.vv v24, v24, v24 \n\t"
"vxor.vv v26, v26, v26 \n\t"
"vsetvli t0, x0, e16, mf4 \n\t"
"vle16.v v2, (%[A]) \n\t"
"vsetvli t0, x0, e8, mf4 \n\t"
"vnsrl.wi v12, v2, 0 \n\t" // low 8
"vnsra.wi v13, v2, 8 \n\t" // high 8
"vsetvli t0, x0, e32, m1 \n\t"
"vmadotsu v20, v13, v8, i8 \n\t"
"vmadotsu v22, v13, v9, i8 \n\t"
"vmadotsu v24, v13, v10, i8 \n\t"
"vmadotsu v26, v13, v11, i8 \n\t"
"vsll.vi v20, v20, 8 \n\t"
"vsll.vi v22, v22, 8 \n\t"
"vsll.vi v24, v24, 8 \n\t"
"vsll.vi v26, v26, 8 \n\t"
"vmadotu v20, v12, v8, i8 \n\t"
"vmadotu v22, v12, v9, i8 \n\t"
"vmadotu v24, v12, v10, i8 \n\t"
"vmadotu v26, v12, v11, i8 \n\t"
"vpack.vv v2, v20, v22, 2 \n\t"
"vpack.vv v4, v24, v26, 2 \n\t"
"vpack.vv v28, v2, v4, 3 \n\t"
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v0, (t2) \n\t" // scale16
"addi t2, t2, 64 \n\t"
"vle16.v v1, (t2) \n\t" // zero16
"vfwcvt.f.f.v v2, v0 \n\t"
"vfwcvt.f.f.v v4, v1 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vfcvt.f.x.v v30, v30 \n\t"
"vfcvt.f.x.v v28, v28 \n\t"
"addi %[B], t2, 64 \n\t"
"mv %[A], t3 \n\t"
"vfmul.vv v30, v30, v2 \n\t" // mul scale16
"vfmacc.vv v30, v28, v4 \n\t" // + mul zero16
"vfmacc.vf v31, fa0, v30 \n\t"
"addi s1, s1, -1 \n\t"
"bgtz s1, BLK_LOOP%= \n\t"
// save
"vsetvli t0, x0, e32, m1 \n\t"
"vse32.v v31, (%[DST]) \n\t"
: [A] "+r"(a_data), [B] "+r"(b_data)
: [DST] "r"(dst_c), [BK] "r"(k_blks)
: "t0", "t1", "t2", "t3", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12",
"v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27",
"v28", "v29", "v30", "v31", "fa0", "t4", "t5", "t6", "s1", "s2", "s3");
}
}
void gemm_kernel_i8i2k_m4(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
constexpr size_t NB_COLS = 32;
using blk_type = nrow_block_q2_k<NB_COLS>;
int64_t b_ncol_block_stride = sizeof(blk_type) * k_blks;
_Float16 scale = 0.0625f;
_Float16 scale_1 = 16.0f;
for (size_t ni = 0; ni < count_n; ni += NB_COLS) {
uint8_t * b_data = (uint8_t *) quant_b_data + (ni / NB_COLS) * b_ncol_block_stride;
int8_t * a_data = (int8_t *) quant_a_ptr;
float * dst_c = (float *) c_ptr + ni;
asm volatile(
"vsetvli t0, x0, e16, m1 \n\t"
"vxor.vv v28, v31, v31 \n\t" // init result
"vxor.vv v29, v31, v31 \n\t"
"vxor.vv v30, v31, v31 \n\t"
"vxor.vv v31, v31, v31 \n\t"
"mv s1, %[BK] \n\t"
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
// load scale A
"flw fa0, (%[A]) \n\t"
"flw fa1, 4(%[A]) \n\t"
"flw fa2, 8(%[A]) \n\t"
"flw fa3, 12(%[A]) \n\t"
"addi %[A], %[A], 16 \n\t"
"li t1, 4 \n\t"
"addi t2, %[B], 512 \n\t" // B data addr
"addi t3, %[A], 128 \n\t" // A data addr
"addi s4, t2, 1024 \n\t" // scale16 addr
"addi s4, s4, 1024 \n\t" // TODO
"addi s3, %[B], 0 \n\t"
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v1, (s4) \n\t" // load scale16
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v22, v1, v1, 3 \n\t"
"addi s4, t3, 256 \n\t" // addr 1
"addi s5, t3, 512 \n\t" // addr 2
"addi s6, t3, 768 \n\t" // addr 3
// init the accu to 0
"vxor.vv v24, v24, v24 \n\t"
"vxor.vv v25, v25, v25 \n\t"
"vxor.vv v26, v26, v26 \n\t"
"vxor.vv v27, v27, v27 \n\t"
"INNER_K_LOOP%=: \n\t"
// load scale B
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v1, (%[B]) \n\t"
"addi %[B], %[B], 128 \n\t"
"vand.vi v1, v1, 0xf \n\t"
"vfwcvt.f.x.v v20, v1 \n\t" // f16 scale B
"vsetvli t0, x0, e16, m1 \n\t"
"vfmul.vv v0, v20, v22 \n\t" // mul scale16
"vfmul.vv v1, v21, v22 \n\t" // mul scale16
"vfmul.vf v0, v0, %[SCALE] \n\t" // mul magic
"vfmul.vf v1, v1, %[SCALE] \n\t" // mul magic
// A data, 4x64@i8
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v2, (t3) \n\t"
"addi t3, t3, 64 \n\t"
"vle8.v v3, (s4) \n\t"
"addi s4, s4, 64 \n\t"
"vle8.v v4, (s5) \n\t"
"addi s5, s5, 64 \n\t"
"vle8.v v5, (s6) \n\t"
"addi s6, s6, 64 \n\t"
// 4x64 => 4x16x4
"vsetvli t0, x0, e8, m1 \n\t"
"vpack.vv v6, v2, v3, 1 \n\t"
"vpack.vv v8, v4, v5, 1 \n\t"
"vpack.vv v2, v6, v8, 2 \n\t" // 0, 2
"vpack.vv v20, v2, v2, 3 \n\t" // 1
"vor.vv v23, v21, v21 \n\t"
"vpack.vv v20, v3, v3, 3 \n\t" // 3
// B data, 32x64@i2
"vsetvli t0, x0, e8, m1 \n\t"
"vl4r.v v4, (t2) \n\t"
"addi t2, t2, 512 \n\t"
"vand.vi v8, v4, 0x3 \n\t" // 0-15
"vsrl.vi v9, v4, 2 \n\t"
"vsrl.vi v10, v4, 4 \n\t"
"vsrl.vi v11, v4, 6 \n\t" // 48-63
"vand.vi v9, v9, 0x3 \n\t" // 16-31
"vand.vi v10, v10, 0x3 \n\t" // 32-47
"vand.vi v12, v5, 0x3 \n\t" // 0-15
"vsrl.vi v13, v5, 2 \n\t"
"vsrl.vi v14, v5, 4 \n\t"
"vsrl.vi v15, v5, 6 \n\t" // 48-63
"vand.vi v13, v13, 0x3 \n\t" // 16-31
"vand.vi v14, v14, 0x3 \n\t" // 32-47
"vand.vi v16, v6, 0x3 \n\t" // 0-15
"vsrl.vi v17, v6, 2 \n\t"
"vsrl.vi v18, v6, 4 \n\t"
"vsrl.vi v19, v6, 6 \n\t" // 48-63
"vand.vi v17, v17, 0x3 \n\t" // 16-31
"vand.vi v18, v18, 0x3 \n\t" // 32-47
"vand.vi v4, v7, 0x3 \n\t" // 0-15
"vsrl.vi v5, v7, 2 \n\t"
"vsrl.vi v6, v7, 4 \n\t"
"vsrl.vi v7, v7, 6 \n\t" // 48-63
"vand.vi v5, v5, 0x3 \n\t" // 16-31
"vand.vi v6, v6, 0x3 \n\t" // 32-47
// i2 * i8 vmadot
"vsetvli t0, x0, e8, m1 \n\t"
"vmadotsu.hp v24, v2, v8, v0, 0, i8 \n\t"
"vmadotsu.hp v25, v2, v12, v0, 1, i8 \n\t"
"vmadotsu.hp v26, v2, v16, v0, 2, i8 \n\t"
"vmadotsu.hp v27, v2, v4, v0, 3, i8 \n\t"
"vmadotsu.hp v24, v23, v9, v0, 4, i8 \n\t"
"vmadotsu.hp v25, v23, v13, v0, 5, i8\n\t"
"vmadotsu.hp v26, v23, v17, v0, 6, i8\n\t"
"vmadotsu.hp v27, v23, v5, v0, 7, i8 \n\t"
"vmadotsu.hp v24, v3, v10, v1, 0, i8 \n\t"
"vmadotsu.hp v25, v3, v14, v1, 1, i8 \n\t"
"vmadotsu.hp v26, v3, v18, v1, 2, i8 \n\t"
"vmadotsu.hp v27, v3, v6, v1, 3, i8 \n\t"
"vmadotsu.hp v24, v21, v11, v1, 4, i8\n\t"
"vmadotsu.hp v25, v21, v15, v1, 5, i8\n\t"
"vmadotsu.hp v26, v21, v19, v1, 6, i8\n\t"
"vmadotsu.hp v27, v21, v7, v1, 7, i8 \n\t"
"addi t1, t1, -1 \n\t"
"bgtz t1, INNER_K_LOOP%= \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v2, v24, v25, 1 \n\t"
"vpack.vv v4, v26, v27, 1 \n\t"
"vpack.vv v6, v2, v4, 2 \n\t" // 0,1,2,3
"vxor.vv v18, v18, v18 \n\t"
"vxor.vv v20, v20, v20 \n\t"
"vxor.vv v22, v22, v22 \n\t"
"vxor.vv v24, v24, v24 \n\t"
// load zp B, 16x8x4@int4
"vsetvli t0, x0, e8, m4 \n\t"
"vle8.v v0, (s3) \n\t"
"vsrl.vi v0, v0, 4 \n\t" // zp
// 4x16@int16
"vsetvli t0, x0, e16, m1 \n\t" // a sum
"vle16.v v12, (%[A]) \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vnsrl.wi v10, v12, 0 \n\t" // low 8
"vnsra.wi v11, v12, 8 \n\t" // high 8
// asum * zp
"vsetvli t0, x0, e32, m1 \n\t"
"vmadotsu v18, v11, v0, i8 \n\t"
"vmadotsu v20, v11, v1, i8 \n\t"
"vmadotsu v22, v11, v2, i8 \n\t"
"vmadotsu v24, v11, v3, i8 \n\t"
"vsll.vi v18, v18, 8 \n\t"
"vsll.vi v20, v20, 8 \n\t"
"vsll.vi v22, v22, 8 \n\t"
"vsll.vi v24, v24, 8 \n\t"
"vmadotu v18, v10, v0, i8 \n\t"
"vmadotu v20, v10, v1, i8 \n\t"
"vmadotu v22, v10, v2, i8 \n\t"
"vmadotu v24, v10, v3, i8 \n\t"
"vpack.vv v10, v18, v20, 2 \n\t"
"vpack.vv v12, v22, v24, 2 \n\t"
"vpack.vv v14, v10, v12, 3 \n\t"
"vpack.vv v16, v11, v13, 3 \n\t"
"vsetvli t0, x0, e16, mf2 \n\t"
"addi t2, t2, 64 \n\t"
"vle16.v v20, (t2) \n\t" // zero16
"vfwcvt.f.f.v v22, v20 \n\t"
// mul 1/magic
"vsetvli t0, x0, e16, m1 \n\t"
"vfwmul.vf v0, v6, %[SCALE_1] \n\t"
"vfwmul.vf v2, v7, %[SCALE_1] \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vfcvt.f.x.v v14, v14 \n\t"
"vfcvt.f.x.v v15, v15 \n\t"
"vfcvt.f.x.v v16, v16 \n\t"
"vfcvt.f.x.v v17, v17 \n\t"
"addi %[B], t2, 64 \n\t"
"mv %[A], s6 \n\t"
"vfmacc.vv v0, v14, v22 \n\t" // + mul zero16
"vfmacc.vv v1, v15, v22 \n\t"
"vfmacc.vv v2, v16, v22 \n\t"
"vfmacc.vv v3, v17, v22 \n\t"
"vfmacc.vf v28, fa0, v0 \n\t" // mul a scale
"vfmacc.vf v29, fa1, v1 \n\t"
"vfmacc.vf v30, fa2, v2 \n\t"
"vfmacc.vf v31, fa3, v3 \n\t"
"addi s1, s1, -1 \n\t"
"bgtz s1, BLK_LOOP%= \n\t"
// save
"vsetvli t0, x0, e32, m1 \n\t"
"add t1, %[LDC], %[DST] \n\t"
"vse32.v v28, (%[DST]) \n\t"
"vse32.v v29, (t1) \n\t"
"add t1, t1, %[LDC] \n\t"
"vse32.v v30, (t1) \n\t"
"add t1, t1, %[LDC] \n\t"
"vse32.v v31, (t1) \n\t"
: [A] "+r"(a_data), [B] "+r"(b_data)
: [DST] "r"(dst_c), [BK] "r"(k_blks), [LDC] "r"(ldc * 4), [SCALE] "f"(scale), [SCALE_1] "f"(scale_1)
: "t0", "t1", "t2", "t3", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12",
"v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27",
"v28", "v29", "v30", "v31", "fa0", "t4", "t5", "t6", "s1", "s2", "s3", "s4", "s5", "s6");
}
}
void gemm_kernel_i8i3k_m1(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
constexpr size_t NB_COLS = 32; //only support 32 in ASM
using blk_type = nrow_block_q3_k<NB_COLS>;
const blk_type * b_base = reinterpret_cast<const blk_type *>(quant_b_data);
int64_t a_blk_stride = q8k_blk_size(256);
int64_t a_nrow_block_stride = a_blk_stride;
int64_t b_ncol_block_stride = sizeof(blk_type);
// Constants used by q3_k scaling in HP branch:
// - k_q3k_scale_step: per-nibble scale factor (1/16).
// - k_a_scale_post_mul: A_scale needs an extra *16 at the end (pairs with 1/16 above).
const _Float16 k_q3k_scale_step = (_Float16) 0.0625f; // 1 / 16
const float k_a_scale_post_mul = 16.0f;
for (size_t ni = 0; ni < count_n; ni += NB_COLS, c_ptr += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
const blk_type * quant_b_blk_data = b_base + (ni / NB_COLS) * k_blks;
#if 0
//------------------------------------------------------------------------------
// A format
// Ascale fp32 * 1 32bit
// Asum int16 * 16 256bit
// A M1K256 int8 2048bit
//------------------------------------------------------------------------------
// B format
// B_scl uint8*N32*16 4096bit
// B_Hmask N32K16*16 1bit 8192bit
// B_Qs N32K16*16 2bit 16384bit
// B scl16 fp16 * N32 512bit;
//------------------------------------------------------------------------------
//bias always be nullptr
__asm__ volatile(
// t2 = k_blks (each is K256 superblock)
"mv t2, %[KBLKS] \n\t"
// t3 = 256/64 = 4 (K64 iterations per superblock)
"li t3, 4 \n\t"
"mv s2, %[pA] \n\t" // s2 = pASCL
"addi s3, %[pA], 4+32 \n\t" // s3 = pAData, (pA+AScl+ASum)
// B block layout for nrow_block_q3_k<32>:
// scales: 512B, hmask: 1024B, qs: 2048B, scales16: 64B
"addi s5, %[pB], 32*16 \n\t" // s5 = pB_hmask
"mv s4, %[pB] \n\t" // s4 = pB_scales
"addi s6, s5, 1024 \n\t" // s6 = pB_qs
"mv s7, %[pB] \n\t" // s7 = pB_base
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v31, v0, v0 \n\t" // clear acc
"vxor.vv v30, v0, v0 \n\t" // clear acc of K256
// ordinary vmadot: vle*10 vecIns*78 vmadot*16
".align 4 \n\t"
"BLK_LPST%=: \n\t"
"K64_LPST%=: \n\t"
// K0-15
// load B scales (32 bytes per K16, 16 times => 512B)
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v2, (s4) \n\t"
"addi s4, s4, 128 \n\t"
// load B qs chunk (128B per K16, 16 times => 2048B)
"vle8.v v4, (s6) \n\t"
"addi s6, s6, 128 \n\t"
"vle8.v v5, (s6) \n\t"
"addi s6, s6, 128 \n\t"
"vle8.v v6, (s6) \n\t"
"addi s6, s6, 128 \n\t"
"vle8.v v7, (s6) \n\t"
"addi s6, s6, 128 \n\t"
// load B hmask chunk (64B per K16, 16 times => 1024B)
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s5) \n\t"
"addi s5, s5, 64 \n\t"
// load A data (16 bytes per K16, 16 times => 256B)
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v1, (s3) \n\t"
"addi s3, s3, 64 \n\t"
// unpack 2-bit qs + hmask -> signed values
"vsetvli t0, x0, e8, m1 \n\t"
"vnot.v v0, v0 \n\t"
"vand.vi v12, v4, 0x3 \n\t"
"vand.vi v13, v5, 0x3 \n\t"
"vand.vi v14, v6, 0x3 \n\t"
"vand.vi v15, v7, 0x3 \n\t"
"vsetvli t0, x0, e8, m4 \n\t"
"vadd.vi v12, v12, -4, v0.t \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
"vmadot v16, v1, v12, i8 \n\t"
"vmadot v18, v1, v13, i8 \n\t"
"vmadot v20, v1, v14, i8 \n\t"
"vmadot v22, v1, v15, i8 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v24, v16, v18, 2 \n\t"
"vpack.vv v26, v20, v22, 2 \n\t"
"vpack.vv v16, v24, v26, 3 \n\t" // N0-N31 in v16
// apply B int8 scales (-32 bias has been applyed)
"vsetvli t0, x0, e8, mf4 \n\t"
"vwadd.vx v18, v2, x0 \n\t" // int8 -> int16
"vsetvli t0, x0, e16, mf2 \n\t"
"vwadd.vx v19, v18, x0 \n\t" // int8 -> int16
// static_cast<int32_t>(qsum) * b_scale;
"vsetvli t0, x0, e32, m1 \n\t"
"vmacc.vv v30, v16, v19 \n\t"
//K16-31
// load B scales (32 bytes per K16, 16 times => 512B)
"vsetvli t0, x0, e64, m1 \n\t"
"vslidedown.vi v2, v2, 4 \n\t"
// load B hmask chunk (64B per K16, 16 times => 1024B)
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s5) \n\t"
"addi s5, s5, 64 \n\t"
// load A data (16 bytes per K16, 16 times => 256B)
"vsetvli t0, x0, e64, mf2 \n\t"
"vslidedown.vi v1, v1, 2 \n\t"
// unpack 2-bit qs + hmask -> signed values
"vsetvli t0, x0, e8, m1 \n\t"
"vsll.vi v8, v4, 4 \n\t"
"vsll.vi v9, v5, 4 \n\t"
"vsll.vi v10, v6, 4 \n\t"
"vsll.vi v11, v7, 4 \n\t"
"vnot.v v0, v0 \n\t"
"vsrl.vi v12, v8, 6 \n\t"
"vsrl.vi v13, v9, 6 \n\t"
"vsrl.vi v14, v10, 6 \n\t"
"vsrl.vi v15, v11, 6 \n\t"
"vsetvli t0, x0, e8, m4 \n\t"
"vadd.vi v12, v12, -4, v0.t \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
"vmadot v16, v1, v12, i8 \n\t"
"vmadot v18, v1, v13, i8 \n\t"
"vmadot v20, v1, v14, i8 \n\t"
"vmadot v22, v1, v15, i8 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v24, v16, v18, 2 \n\t"
"vpack.vv v26, v20, v22, 2 \n\t"
"vpack.vv v16, v24, v26, 3 \n\t" // N0-N31 in v16
// apply B int8 scales (-32 bias has been applyed)
"vsetvli t0, x0, e8, mf4 \n\t"
"vwadd.vx v18, v2, x0 \n\t" // int8 -> int16
"vsetvli t0, x0, e16, mf2 \n\t"
"vwadd.vx v19, v18, x0 \n\t" // int8 -> int16
// static_cast<int32_t>(qsum) * b_scale;
"vsetvli t0, x0, e32, m1 \n\t"
"vmacc.vv v30, v16, v19 \n\t"
//K32-47
// load B scales (32 bytes per K16, 16 times => 512B)
"vsetvli t0, x0, e64, m1 \n\t"
"vslidedown.vi v2, v2, 4 \n\t"
// load B hmask chunk (64B per K16, 16 times => 1024B)
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s5) \n\t"
"addi s5, s5, 64 \n\t"
// load A data (16 bytes per K16, 16 times => 256B)
"vsetvli t0, x0, e64, mf2 \n\t"
"vslidedown.vi v1, v1, 2 \n\t"
// unpack 2-bit qs + hmask -> signed values
"vsetvli t0, x0, e8, m1 \n\t"
"vsll.vi v8, v4, 2 \n\t"
"vsll.vi v9, v5, 2 \n\t"
"vsll.vi v10, v6, 2 \n\t"
"vsll.vi v11, v7, 2 \n\t"
"vnot.v v0, v0 \n\t"
"vsrl.vi v12, v8, 6 \n\t"
"vsrl.vi v13, v9, 6 \n\t"
"vsrl.vi v14, v10, 6 \n\t"
"vsrl.vi v15, v11, 6 \n\t"
"vsetvli t0, x0, e8, m4 \n\t"
"vadd.vi v12, v12, -4, v0.t \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
"vmadot v16, v1, v12, i8 \n\t"
"vmadot v18, v1, v13, i8 \n\t"
"vmadot v20, v1, v14, i8 \n\t"
"vmadot v22, v1, v15, i8 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v24, v16, v18, 2 \n\t"
"vpack.vv v26, v20, v22, 2 \n\t"
"vpack.vv v16, v24, v26, 3 \n\t"
// apply B int8 scales (-32 bias has been applyed)
"vsetvli t0, x0, e8, mf4 \n\t"
"vwadd.vx v18, v2, x0 \n\t" // int8 -> int16
"vsetvli t0, x0, e16, mf2 \n\t"
"vwadd.vx v19, v18, x0 \n\t" // int8 -> int16
// static_cast<int32_t>(qsum) * b_scale;
"vsetvli t0, x0, e32, m1 \n\t"
"vmacc.vv v30, v16, v19 \n\t"
// K48-63
// load B scales (32 bytes per K16, 16 times => 512B)
"vsetvli t0, x0, e64, m1 \n\t"
"vslidedown.vi v2, v2, 4 \n\t"
// load B hmask chunk (64B per K16, 16 times => 1024B)
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s5) \n\t"
"addi s5, s5, 64 \n\t"
// load A data (16 bytes per K16, 16 times => 256B)
"vsetvli t0, x0, e64, mf2 \n\t"
"vslidedown.vi v1, v1, 2 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vnot.v v0, v0 \n\t"
"vsrl.vi v12, v4, 6 \n\t"
"vsrl.vi v13, v5, 6 \n\t"
"vsrl.vi v14, v6, 6 \n\t"
"vsrl.vi v15, v7, 6 \n\t"
"vsetvli t0, x0, e8, m4 \n\t"
"vadd.vi v12, v12, -4, v0.t \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
"vmadot v16, v1, v12, i8 \n\t"
"vmadot v18, v1, v13, i8 \n\t"
"vmadot v20, v1, v14, i8 \n\t"
"vmadot v22, v1, v15, i8 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v24, v16, v18, 2 \n\t"
"vpack.vv v26, v20, v22, 2 \n\t"
"vpack.vv v16, v24, v26, 3 \n\t"
// apply B int8 scales (-32 bias has been applyed)
"vsetvli t0, x0, e8, mf4 \n\t"
"vwadd.vx v18, v2, x0 \n\t" // int8 -> int16
"vsetvli t0, x0, e16, mf2 \n\t"
"vwadd.vx v19, v18, x0 \n\t" // int8 -> int16
// static_cast<int32_t>(qsum) * b_scale;
"vsetvli t0, x0, e32, m1 \n\t"
"vmacc.vv v30, v16, v19 \n\t"
"addi t3, t3, -1 \n\t"
"bgtz t3, K64_LPST%= \n\t"
"K64_LPND%=: \n\t"
// load A scale (fp32) and advance A to next superblock
"flw f0, (s2) \n\t"
"addi s2, s2, 4+32+256 \n\t"
"add t4, s7, %[B_STR] \n\t" // t4 = next B blk base
"addi s3, s2, 4+32 \n\t"
// load B scales16[32] (fp16) at end of qs region
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v2, (s6) \n\t"
// pointer modify
"addi s5, t4, 32*16 \n\t"
"mv s4, t4 \n\t"
"addi s6, s5, 32*32 \n\t"
"addi s7, t4, 0 \n\t"
// b_scale fp16 -> fp32
"vsetvli t0, x0, e16, mf2 \n\t"
"vfwcvt.f.f.v v24, v2 \n\t"
// a_scale * b_scale;
"vsetvli t0, x0, e32, m1 \n\t"
"vfcvt.f.x.v v26, v30 \n\t"
"vfmul.vf v1, v24, f0 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
// static_cast<float>(qsum) * a_scale * b_scale;
"vfmacc.vv v31, v1, v26 \n\t"
// next K-superblock
"addi t2, t2, -1 \n\t"
"vxor.vv v30, v0, v0 \n\t" // clear acc of K256
"li t3, 4 \n\t"
"bgtz t2, BLK_LPST%= \n\t"
"BLK_LPND%=: \n\t"
"vsetvli t0, %[NBLKS], e32, m1 \n\t"
"vse32.v v31, (%[pC]) \n\t"
"FUNC_END%=: \n\t"
:
: [KBLKS] "r"(k_blks), [NBLKS] "r"(nb_real), [pA] "r"(quant_a_ptr), [pB] "r"(quant_b_blk_data),
[pC] "r"(c_ptr), [B_STR] "r"(b_ncol_block_stride)
: "cc", "memory", "t0", "t2", "t3", "t4", "t5", "f0", "s2", "s3", "s4", "s5", "s6", "s7");
#else
__asm__ volatile(
// =========================
// Kernel overview (M1 x N32)
// =========================
// Process one output row (M=1) and 32 columns (N=32) per call.
//
// Loop structure:
// - Outer loop: K superblocks of size K=256 (k_blks times)
// - Each K256 superblock is broken into 4 x K64
// - Each K64 is processed as 4 x K16 "sub-blocks" (via unpack+dot)
//
// Data layout (high level):
// A (q8k K=256, per superblock):
// [ fp32 a_scale ][ int16 a_sum[16] ][ int8 a_qs[256] ]
// B (nrow_block_q3_k<32>, per superblock):
// [ int8 scales[32*16] ][ hmask[1024] ][ qs[2048] ][ fp16 scales16[32] ]
//
// Registers/pointers:
// s2: pA (points at A superblock header; used to load fp32 a_scale)
// s3: pA_qs (points at A int8 data within the current superblock)
// s4: pB_scales (points at B int8 per-K16 scales)
// s5: pB_hmask (points at B sign mask area)
// s6: pB_qs (points at B 2-bit packed qs area)
// s8: pB_scales16 (points at B fp16 scales16[32] at the end of block)
// s7: pB_base (base pointer to current B block; used for block-to-block stride)
// t2 = number of K256 superblocks
"mv t2, %[KBLKS] \n\t"
// t3 = number of K64 chunks per K256 superblock (256 / 64)
"li t3, 4 \n\t"
// A pointers
"mv s2, %[pA] \n\t" // s2 = pA_superblock (a_scale at +0)
"addi s3, %[pA], 4+32 \n\t" // s3 = pA_qs (skip a_scale + a_sum[16])
// B pointers for nrow_block_q3_k<32>
"addi s5, %[pB], 32*16 \n\t" // s5 = pB_hmask (skip scales[32*16])
"mv s4, %[pB] \n\t" // s4 = pB_scales
"addi s6, s5, 1024 \n\t" // s6 = pB_qs (skip hmask)
// scales16 is at the end of the block: qs(2048) after hmask
"addi s8, s6, 1024 \n\t"
"addi s8, s8, 1024 \n\t" // s8 = pB_scales16 (fp16 scales16[32])
"mv s7, %[pB] \n\t" // s7 = pB_base (for next-block address calc)
// v31: final FP32 accumulator for N=32
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v31, v0, v0 \n\t"
// ---- Preload B scales16[32] and build FP16 scale vector used by vmadot.hp ----
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v1, (s8) \n\t" // load fp16 scales16[32]
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v26, v1, v1, 3 \n\t" // broadcast/pack to match lanes
"vmv.v.v v17, v26 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vfmul.vf v30, v17, %[q3_step] \n\t" // v30 = scales16 * (1/16)
// v24-v27: fp16 partial accumulators for a K64 chunk (vmadot.hp outputs)
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v24, v16, v16 \n\t"
"vxor.vv v25, v16, v16 \n\t"
"vxor.vv v26, v16, v16 \n\t"
"vxor.vv v27, v16, v16 \n\t"
// HP vmadot: vle*10 vecIns*38 vmadot.hp*16
".align 4 \n\t"
"BLK_LPST%=: \n\t" // loop over K256 superblocks
"K64_LPST%=: \n\t" // loop over 4 x K64 chunks
// ------------------------------------------------------------
// K0-15: load B scales + {hmask, qs} + A data; unpack and dot
// ------------------------------------------------------------
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v2, (s4) \n\t" // B int8 scales for this K16
"addi s4, s4, 128 \n\t"
"vle8.v v4, (s6) \n\t"
"addi s6, s6, 128 \n\t"
"vle8.v v5, (s6) \n\t"
"addi s6, s6, 128 \n\t"
"vle8.v v6, (s6) \n\t"
"addi s6, s6, 128 \n\t"
"vle8.v v7, (s6) \n\t"
"addi s6, s6, 128 \n\t"
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s5) \n\t" // B hmask for this K16
"addi s5, s5, 64 \n\t"
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v3, (s3) \n\t" // A int8 data for this K16
"addi s3, s3, 64 \n\t"
// Convert B int8 scales to FP16 and apply scales16*(1/16)
"vsetvli t0, x0, e8, m1 \n\t"
"vfwcvt.f.x.v v28, v2 \n\t" // int8 -> fp16
"vsetvli t0, x0, e16, m1 \n\t"
"vfmul.vv v1, v28, v30 \n\t" // v1: FP16 scale vector for vmadot.hp
"vfmul.vv v29, v29, v30 \n\t"
// Unpack B 2-bit qs + hmask -> signed int8 in v12..v15
"vsetvli t0, x0, e8, m1 \n\t"
"vnot.v v0, v0 \n\t"
"vand.vi v12, v4, 0x3 \n\t"
"vand.vi v13, v5, 0x3 \n\t"
"vand.vi v14, v6, 0x3 \n\t"
"vand.vi v15, v7, 0x3 \n\t"
"vsetvli t0, x0, e8, m4 \n\t"
"vadd.vi v12, v12, -4, v0.t \n\t"
// (Next K16 unpack path uses a fresh hmask load)
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s5) \n\t"
"addi s5, s5, 64 \n\t"
// Prepare another group from packed qs (bit shifts) + apply sign from hmask
"vsetvli t0, x0, e8, m1 \n\t"
"vsll.vi v8, v4, 4 \n\t"
"vsll.vi v9, v5, 4 \n\t"
"vsll.vi v10, v6, 4 \n\t"
"vsll.vi v11, v7, 4 \n\t"
"vsrl.vi v16, v8, 6 \n\t"
"vsrl.vi v17, v9, 6 \n\t"
"vnot.v v0, v0 \n\t"
"vsrl.vi v18, v10, 6 \n\t"
"vsrl.vi v19, v11, 6 \n\t"
"vsetvli t0, x0, e8, m4 \n\t"
"vadd.vi v16, v16, -4, v0.t \n\t"
// A shift for the second dot within this K64
"vsetvli t0, x0, e64, mf2 \n\t"
"vslidedown.vi v2, v3, 2 \n\t"
// Dot products with FP16 scaling (accumulate into v24..v27)
"vsetvli t0, x0, e32, m1 \n\t"
"vmadot.hp v24, v3, v12, v1, 0, i8 \n\t"
"vmadot.hp v25, v3, v13, v1, 1, i8 \n\t"
"vmadot.hp v26, v3, v14, v1, 2, i8 \n\t"
"vmadot.hp v27, v3, v15, v1, 3, i8 \n\t"
"vmadot.hp v24, v2, v16, v1, 4, i8 \n\t"
"vmadot.hp v25, v2, v17, v1, 5, i8 \n\t"
"vmadot.hp v26, v2, v18, v1, 6, i8 \n\t"
"vmadot.hp v27, v2, v19, v1, 7, i8 \n\t"
// (K32-47 / K48-63 blocks continue unchanged...)
// load B scales (32 bytes per K16, 16 times => 512B)
"vsetvli t0, x0, e64, m1 \n\t"
"vmv.v.v v1, v29 \n\t"
// load B hmask chunk (64B per K16, 16 times => 1024B)
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s5) \n\t"
"addi s5, s5, 64 \n\t"
// load A data (16 bytes per K16, 16 times => 256B)
"vsetvli t0, x0, e64, mf2 \n\t"
"vslidedown.vi v3, v3, 4 \n\t"
// unpack 2-bit qs + hmask -> signed values
"vsetvli t0, x0, e8, m1 \n\t"
"vsll.vi v8, v4, 2 \n\t"
"vsll.vi v9, v5, 2 \n\t"
"vsll.vi v10, v6, 2 \n\t"
"vsll.vi v11, v7, 2 \n\t"
"vsrl.vi v20, v8, 6 \n\t"
"vsrl.vi v21, v9, 6 \n\t"
"vnot.v v0, v0 \n\t"
"vsrl.vi v22, v10, 6 \n\t"
"vsrl.vi v23, v11, 6 \n\t"
"vsetvli t0, x0, e8, m4 \n\t"
"vadd.vi v20, v20, -4, v0.t \n\t"
// K48-63
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s5) \n\t"
"addi s5, s5, 64 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vsrl.vi v8, v4, 6 \n\t"
"vsrl.vi v9, v5, 6 \n\t"
"vnot.v v0, v0 \n\t"
"vsrl.vi v10, v6, 6 \n\t"
"vsrl.vi v11, v7, 6 \n\t"
"vsetvli t0, x0, e8, m4 \n\t"
"vadd.vi v8, v8, -4, v0.t \n\t"
// load A data (16 bytes per K16, 16 times => 256B)
"vsetvli t0, x0, e64, mf2 \n\t"
"vslidedown.vi v2, v3, 2 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vmadot.hp v24, v3, v20, v1, 0, i8 \n\t"
"vmadot.hp v25, v3, v21, v1, 1, i8 \n\t"
"vmadot.hp v26, v3, v22, v1, 2, i8 \n\t"
"vmadot.hp v27, v3, v23, v1, 3, i8 \n\t"
"vmadot.hp v24, v2, v8, v1, 4, i8 \n\t"
"vmadot.hp v25, v2, v9, v1, 5, i8 \n\t"
"vmadot.hp v26, v2, v10, v1, 6, i8 \n\t"
"vmadot.hp v27, v2, v11, v1, 7, i8 \n\t"
"addi t3, t3, -1 \n\t"
"bgtz t3, K64_LPST%= \n\t"
"K64_LPND%=: \n\t"
// ---- End of K64 chunk: reduce fp16 accumulators -> fp32 and scale by A ----
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v12, v24, v25, 1 \n\t"
"vpack.vv v14, v26, v27, 1 \n\t"
"vpack.vv v16, v12, v14, 2 \n\t"
"vsetvli t0, x0, e16, mf2 \n\t"
"vfwcvt.f.f.v v26, v16 \n\t" // fp16 -> fp32 vector (qsum * b_scales)
// Load A scale and advance A pointer to next K256 superblock
"flw f0, (s2) \n\t"
"addi s2, s2, 4+32+256 \n\t"
"add t4, s7, %[B_STR] \n\t" // next B block base
"addi s3, s2, 4+32 \n\t" // reset A data pointer for next block
// Advance B pointers to next K256 superblock
"addi s5, t4, 32*16 \n\t"
"mv s4, t4 \n\t"
"addi s6, s5, 32*32 \n\t"
"addi s8, s6, 1024 \n\t"
"addi s8, s8, 1024 \n\t"
"addi s7, t4, 0 \n\t"
"addi t2, t2, -1 \n\t"
// Final per-block scaling: a_scale * 16.0f
"fmul.s f0, f0, %[a_post_mul] \n\t"
// acc += (qsum * b_scales) * (a_scale*16)
"vsetvli t0, x0, e32, m1 \n\t"
"vfmacc.vf v31, f0, v26 \n\t"
"beqz t2, BLK_LPND%= \n\t"
// Preload next block's scales16 and rebuild v30 for vmadot.hp
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v1, (s8) \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v26, v1, v1, 3 \n\t"
"vmv.v.v v17, v26 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vfmul.vf v30, v17, %[q3_step] \n\t"
// Reset fp16 partial accumulators for next K64 loop(s)
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v24, v16, v16 \n\t"
"vxor.vv v25, v16, v16 \n\t"
"vxor.vv v26, v16, v16 \n\t"
"vxor.vv v27, v16, v16 \n\t"
"li t3, 4 \n\t"
"bgtz t2, BLK_LPST%= \n\t"
"BLK_LPND%=: \n\t"
"vsetvli t0, %[NBLKS], e32, m1 \n\t"
"vse32.v v31, (%[pC]) \n\t"
:
: [KBLKS] "r"(k_blks), [NBLKS] "r"(nb_real), [pA] "r"(quant_a_ptr), [pB] "r"(quant_b_blk_data),
[pC] "r"(c_ptr), [B_STR] "r"(b_ncol_block_stride), [q3_step] "f"(k_q3k_scale_step),
[a_post_mul] "f"(k_a_scale_post_mul)
: "cc", "memory", "t0", "t2", "t3", "t4", "t5", "f0", "f1", "s2", "s3", "s4", "s5", "s6", "s7", "s8");
#endif
}
}
void gemm_kernel_i8i3k_m4(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
using blk_type = nrow_block_q3_k<32>;
constexpr size_t NB_COLS = 32; //only support 32 in ASM
const blk_type * b_base = reinterpret_cast<const blk_type *>(quant_b_data);
int64_t a_blk_stride = q8k_blk_size(256);
int64_t a_nrow_block_stride = a_blk_stride * 4;
int64_t b_ncol_block_stride = sizeof(blk_type);
for (size_t ni = 0; ni < count_n; ni += NB_COLS, c_ptr += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
const blk_type * quant_b_blk_data = b_base + (ni / NB_COLS) * k_blks;
//------------------------------------------------------------------------------
// A format
// Ascale fp32 * 1* 4row 128bit
// Asum int16 * 16 4row 1024bit
// A M1K256 int8 4row 8192bit
//------------------------------------------------------------------------------
// B format
// B_scl uint8*N32*16 4096bit
// B_Hmask N32K16*16 1bit 8192bit
// B_Qs N32K16*16 2bit 16384bit
// B scl16 fp16 * N32 512bit;
//------------------------------------------------------------------------------
//bias always be nullptr
__asm__ volatile(
// t2 = k_blks (each is K256 superblock)
"mv t2, %[KBLKS] \n\t"
// t3 = 256/64 = 4 (K64 iterations per superblock)
"li t3, 4 \n\t"
"mv s2, %[pA] \n\t" // s2 = pASCL
"addi s3, %[pA], 16+128 \n\t" // s3 = pAData, (pA+AScl+ASum)
// B block layout for nrow_block_q3_k<32>:
// scales: 512B, hmask: 1024B, qs: 2048B, scales16: 64B
"addi s5, %[pB], 32*16 \n\t" // s5 = pB_hmask (skip scales)
"mv s4, %[pB] \n\t" // s4 = pB_scales
"addi s6, s5, 1024 \n\t" // s6 = pB_qs (skip hmask)
"mv s7, %[pB] \n\t" // s7 = pB_base
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v24, v0, v0 \n\t" // v24-v27: K256 temp accumulator
"vxor.vv v25, v0, v0 \n\t"
"vxor.vv v26, v0, v0 \n\t"
"vxor.vv v27, v0, v0 \n\t"
"vxor.vv v28, v0, v0 \n\t" // v28-v31: final accumulator
"vxor.vv v29, v0, v0 \n\t"
"vxor.vv v30, v0, v0 \n\t"
"vxor.vv v31, v0, v0 \n\t"
// ordinary vmadot: vle*13 vecIns*96 vmadot*16
".align 4 \n\t"
"BLK_LPST%=: \n\t"
"K64_LPST%=: \n\t"
// ========== K0-15: First K16 sub-block ==========
// Load B INT8 scale factors (32 cols × 16 K16 blocks)
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v8, (s4) \n\t"
"addi s4, s4, 128 \n\t"
// Load B quantized data (32 cols × 16 elements × 2bit, stored in 4 groups)
"vle8.v v4, (s6) \n\t"
"addi s6, s6, 128 \n\t"
"vle8.v v5, (s6) \n\t"
"addi s6, s6, 128 \n\t"
"vle8.v v6, (s6) \n\t"
"addi s6, s6, 128 \n\t"
"vle8.v v7, (s6) \n\t"
"addi s6, s6, 128 \n\t"
// Load B hmask (32 cols × 16bit sign mask)
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s5) \n\t"
"addi s5, s5, 64 \n\t"
// Load A data (4 rows × 16 elements × INT8)
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v12, (s3) \n\t"
"addi s3, s3, 256 \n\t" // Jump to next row
"vle8.v v13, (s3) \n\t"
"addi s3, s3, 256 \n\t"
"vle8.v v14, (s3) \n\t"
"addi s3, s3, 256 \n\t"
"vle8.v v15, (s3) \n\t"
"addi s3, s3, -768+64 \n\t" // Back to first row, advance 16 elements
// Pack A data: merge 4 rows into 2 vectors
"vsetvli t0, x0, e8, m1 \n\t"
"vpack.vv v16, v12, v13, 1 \n\t"
"vpack.vv v18, v14, v15, 1 \n\t"
"vpack.vv v2, v16, v18, 2 \n\t"
// unpack 2-bit qs + hmask -> signed values
"vsetvli t0, x0, e8, m1 \n\t"
"vnot.v v0, v0 \n\t"
"vand.vi v12, v4, 0x3 \n\t"
"vand.vi v13, v5, 0x3 \n\t"
"vand.vi v14, v6, 0x3 \n\t"
"vand.vi v15, v7, 0x3 \n\t"
"vsetvli t0, x0, e8, m4 \n\t"
"vadd.vi v12, v12, -4, v0.t \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
"vmadot v16, v2, v12, i8 \n\t" // 4 rows × cols 0-7
"vmadot v18, v2, v13, i8 \n\t" // 4 rows × cols 8-15
"vmadot v20, v2, v14, i8 \n\t" // 4 rows × cols 16-23
"vmadot v22, v2, v15, i8 \n\t" // 4 rows × cols 24-31
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v12, v16, v18, 2 \n\t" // Merge cols 0-15
"vpack.vv v14, v20, v22, 2 \n\t" // Merge cols 16-31
"vpack.vv v16, v12, v14, 3 \n\t" // Inter-row results (INT16)
"vpack.vv v18, v13, v15, 3 \n\t"
// apply B int8 scales (-32 bias has been applyed)
"vsetvli t0, x0, e8, mf4 \n\t"
"vwadd.vx v21, v8, x0 \n\t" // INT8 → INT16
"vsetvli t0, x0, e16, mf2 \n\t"
"vwadd.vx v23, v21, x0 \n\t" // INT16 → INT32
// Accumulate to K256 accumulator: qsum * b_scale
"vsetvli t0, x0, e32, m1 \n\t"
"vmacc.vv v24, v16, v23 \n\t" // Row 0
"vmacc.vv v25, v17, v23 \n\t" // Row 1
"vmacc.vv v26, v18, v23 \n\t" // Row 2
"vmacc.vv v27, v19, v23 \n\t"
// ========== K16-31, K32-47, K48-63: Similar processing ==========
// load B scales (32 bytes per K16, 16 times => 512B)
"vsetvli t0, x0, e64, m1 \n\t"
"vslidedown.vi v8, v8, 4 \n\t"
// load B hmask chunk (64B per K16, 16 times => 1024B)
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s5) \n\t"
"addi s5, s5, 64 \n\t"
// load A data (16 bytes per K16, 16 times => 256B)
"vsetvli t0, x0, e64, m1 \n\t"
"vslidedown.vi v2, v2, 8 \n\t"
// unpack 2-bit qs + hmask -> signed values
"vsetvli t0, x0, e8, m1 \n\t"
"vsll.vi v12, v4, 4 \n\t"
"vsll.vi v13, v5, 4 \n\t"
"vsll.vi v14, v6, 4 \n\t"
"vsll.vi v15, v7, 4 \n\t"
"vnot.v v0, v0 \n\t"
"vsrl.vi v12, v12, 6 \n\t"
"vsrl.vi v13, v13, 6 \n\t"
"vsrl.vi v14, v14, 6 \n\t"
"vsrl.vi v15, v15, 6 \n\t"
"vsetvli t0, x0, e8, m4 \n\t"
"vadd.vi v12, v12, -4, v0.t \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
"vmadot v16, v2, v12, i8 \n\t"
"vmadot v18, v2, v13, i8 \n\t"
"vmadot v20, v2, v14, i8 \n\t"
"vmadot v22, v2, v15, i8 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v12, v16, v18, 2 \n\t"
"vpack.vv v14, v20, v22, 2 \n\t"
"vpack.vv v16, v12, v14, 3 \n\t" // N0-N31 in v16
"vpack.vv v18, v13, v15, 3 \n\t"
// apply B int8 scales (-32 bias has been applyed)
"vsetvli t0, x0, e8, mf4 \n\t"
"vwadd.vx v21, v8, x0 \n\t" // int8 -> int16
"vsetvli t0, x0, e16, mf2 \n\t"
"vwadd.vx v23, v21, x0 \n\t" // int8 -> int16
// static_cast<int32_t>(qsum) * b_scale;
"vsetvli t0, x0, e32, m1 \n\t"
"vmacc.vv v24, v16, v23 \n\t"
"vmacc.vv v25, v17, v23 \n\t"
"vmacc.vv v26, v18, v23 \n\t"
"vmacc.vv v27, v19, v23 \n\t"
//K32-47
// load B scales (32 bytes per K16, 16 times => 512B)
"vsetvli t0, x0, e64, m1 \n\t"
"vslidedown.vi v8, v8, 4 \n\t"
// load B hmask chunk (64B per K16, 16 times => 1024B)
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s5) \n\t"
"addi s5, s5, 64 \n\t"
// load A data (16 bytes per K16, 16 times => 256B)
// unpack 2-bit qs + hmask -> signed values
"vsetvli t0, x0, e8, m1 \n\t"
"vsll.vi v12, v4, 2 \n\t"
"vsll.vi v13, v5, 2 \n\t"
"vsll.vi v14, v6, 2 \n\t"
"vsll.vi v15, v7, 2 \n\t"
"vnot.v v0, v0 \n\t"
"vsrl.vi v12, v12, 6 \n\t"
"vsrl.vi v13, v13, 6 \n\t"
"vsrl.vi v14, v14, 6 \n\t"
"vsrl.vi v15, v15, 6 \n\t"
"vsetvli t0, x0, e8, m4 \n\t"
"vadd.vi v12, v12, -4, v0.t \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
"vmadot v16, v3, v12, i8 \n\t"
"vmadot v18, v3, v13, i8 \n\t"
"vmadot v20, v3, v14, i8 \n\t"
"vmadot v22, v3, v15, i8 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v12, v16, v18, 2 \n\t"
"vpack.vv v14, v20, v22, 2 \n\t"
"vpack.vv v16, v12, v14, 3 \n\t" // N0-N31 in v16
"vpack.vv v18, v13, v15, 3 \n\t"
// apply B int8 scales (-32 bias has been applyed)
"vsetvli t0, x0, e8, mf4 \n\t"
"vwadd.vx v21, v8, x0 \n\t" // int8 -> int16
"vsetvli t0, x0, e16, mf2 \n\t"
"vwadd.vx v23, v21, x0 \n\t" // int8 -> int16
// static_cast<int32_t>(qsum) * b_scale;
"vsetvli t0, x0, e32, m1 \n\t"
"vmacc.vv v24, v16, v23 \n\t"
"vmacc.vv v25, v17, v23 \n\t"
"vmacc.vv v26, v18, v23 \n\t"
"vmacc.vv v27, v19, v23 \n\t"
// K48-63
// load B scales (32 bytes per K16, 16 times => 512B)
"vsetvli t0, x0, e64, m1 \n\t"
"vslidedown.vi v8, v8, 4 \n\t"
// load B hmask chunk (64B per K16, 16 times => 1024B)
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s5) \n\t"
"addi s5, s5, 64 \n\t"
// load A data (16 bytes per K16, 16 times => 256B)
"vsetvli t0, x0, e64, m1 \n\t"
"vslidedown.vi v3, v3, 8 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vnot.v v0, v0 \n\t"
"vsrl.vi v12, v4, 6 \n\t"
"vsrl.vi v13, v5, 6 \n\t"
"vsrl.vi v14, v6, 6 \n\t"
"vsrl.vi v15, v7, 6 \n\t"
"vsetvli t0, x0, e8, m4 \n\t"
"vadd.vi v12, v12, -4, v0.t \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
"vmadot v16, v3, v12, i8 \n\t"
"vmadot v18, v3, v13, i8 \n\t"
"vmadot v20, v3, v14, i8 \n\t"
"vmadot v22, v3, v15, i8 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v12, v16, v18, 2 \n\t"
"vpack.vv v14, v20, v22, 2 \n\t"
"vpack.vv v16, v12, v14, 3 \n\t" // N0-N31 in v16
"vpack.vv v18, v13, v15, 3 \n\t"
// apply B int8 scales (-32 bias has been applyed)
"vsetvli t0, x0, e8, mf4 \n\t"
"vwadd.vx v21, v8, x0 \n\t" // int8 -> int16
"vsetvli t0, x0, e16, mf2 \n\t"
"vwadd.vx v23, v21, x0 \n\t" // int8 -> int16
// static_cast<int32_t>(qsum) * b_scale;
"vsetvli t0, x0, e32, m1 \n\t"
"vmacc.vv v24, v16, v23 \n\t"
"vmacc.vv v25, v17, v23 \n\t"
"vmacc.vv v26, v18, v23 \n\t"
"vmacc.vv v27, v19, v23 \n\t"
"addi t3, t3, -1 \n\t"
"bgtz t3, K64_LPST%= \n\t"
"K64_LPND%=: \n\t"
// ========== K256 superblock complete, apply scale factors ==========
// Load A's 4 row scale factors (FP32)
"flw f0, (s2) \n\t"
"flw f1, 4(s2) \n\t"
"flw f2, 8(s2) \n\t"
"flw f3, 12(s2) \n\t"
"add s2, s2, %[A_STR] \n\t" // Advance to next superblock
"add t4, s7, %[B_STR] \n\t" // t4 = next B block address
"addi s3, s2, (4+32)*4 \n\t"
// Load B FP16 global scale factors (32 cols)
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v8, (s6) \n\t"
// Update B pointers to next block
"addi s5, t4, 32*16 \n\t"
"mv s4, t4 \n\t"
"addi s6, s5, 32*32 \n\t"
"addi s7, t4, 0 \n\t"
// ========== Type conversion and final scaling ==========
// FP16 → FP32
"vsetvli t0, x0, e16, mf2 \n\t"
"vfwcvt.f.f.v v9, v8 \n\t"
// INT32 → FP32
"vsetvli t0, x0, e32, m1 \n\t"
"vfcvt.f.x.v v24, v24 \n\t"
"vfcvt.f.x.v v25, v25 \n\t"
"vfcvt.f.x.v v26, v26 \n\t"
"vfcvt.f.x.v v27, v27 \n\t"
// Compute a_scale * b_scale (4 rows)
"vfmul.vf v12, v9, f0 \n\t"
"vfmul.vf v13, v9, f1 \n\t"
"vfmul.vf v14, v9, f2 \n\t"
"vfmul.vf v15, v9, f3 \n\t"
// Final accumulation: result += qsum * a_scale * b_scale
"vsetvli t0, x0, e32, m1 \n\t"
"vfmacc.vv v28, v12, v24 \n\t"
"vfmacc.vv v29, v13, v25 \n\t"
"vfmacc.vv v30, v14, v26 \n\t"
"vfmacc.vv v31, v15, v27 \n\t"
// Prepare for next K superblock
"addi t2, t2, -1 \n\t"
"vxor.vv v24, v0, v0 \n\t" // Clear K256 accumulator
"vxor.vv v25, v0, v0 \n\t"
"vxor.vv v26, v0, v0 \n\t"
"vxor.vv v27, v0, v0 \n\t"
"li t3, 4 \n\t"
"bgtz t2, BLK_LPST%= \n\t"
"BLK_LPND%=: \n\t"
// ========== Store results (4 rows × 32 cols) ==========
"mv t5, %[pC] \n\t"
"vsetvli t0, %[NBLKS], e32, m1 \n\t"
"vse32.v v28, (%[pC]) \n\t"
"add t5, t5, %[LDC] \n\t"
"vse32.v v29, (t5) \n\t"
"add t5, t5, %[LDC] \n\t"
"vse32.v v30, (t5) \n\t"
"add t5, t5, %[LDC] \n\t"
"vse32.v v31, (t5) \n\t"
"add t5, t5, %[LDC] \n\t"
"FUNC_END%=: \n\t"
:
: [KBLKS] "r"(k_blks), [NBLKS] "r"(nb_real), [pA] "r"(quant_a_ptr), [pB] "r"(quant_b_blk_data),
[pC] "r"(c_ptr), [B_STR] "r"(b_ncol_block_stride), [A_STR] "r"(a_nrow_block_stride), [LDC] "r"(ldc * 4)
: "cc", "memory", "t0", "t2", "t3", "t4", "t5", "f0", "f1", "f2", "f3", "s2", "s3", "s4", "s5", "s6", "s7");
}
}
void gemm_kernel_i8i4_m1(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
if (quant_b_zp == NULL) {
for (size_t n = 0; n < count_n; n += 32) {
size_t nblks = (count_n - n) > 32 ? 32 : count_n - n;
uint8_t * QuantBDataPtr = (uint8_t *) quant_b_data + //
n * k_blks * blk_len / 2 + // b data
n * k_blks * sizeof(_Float16); // scale
float * CPtr = c_ptr + n;
size_t cnt = k_blks;
// A format Version_1 (FP32 SCALE FOR Normal VMADOTins of IME2)
// A M1K32 int8 256bit
// Ascale fp32 * 1 32bit
// || scl*1(fp32) | Asum(int16) | blk0 || scl*1(fp32) | Asum(int16) | blk0 || ...
// || Element || Element || ...
// B format
// B N8K32 int4 1024bit
// 4VRF, N32K32, 4096bit
// Bscale fp16 * N32 512bit;
// || scl*32..(fp16) | blk0 blk1 ... blk31 || scl*32..(fp16) | blk0 blk1 ... blk31 || ...
// || Element || Element || ...
#if 0
//bias always be nullptr
__asm__ volatile(
// t3 = k/32
"mv t3, %[BCK] \n\t"
"mv t4, %[NBLKS] \n\t"
"mv s2, %[pA] \n\t" // s2 = pASCL
"addi s3, %[pA], 4+2 \n\t" // s3 = pAData, (pA+AScl+ASum)
"mv s4, %[pB] \n\t" // s4 = pBSCL
"addi s5, %[pB], 32*2 \n\t" // s5 = pBdata;
"mv s6, %[pC] \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v2, v0, v0 \n\t" // clear acc
// ordinary vmadot: vle*6 flw*1 vecIns*21 vmadot*8
".align 4 \n\t"
"_K_LPST%=: \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vl4r.v v4, (s5) \n\t" // B Data 4VRF * 8Row * 32
"addi s5, s5, 128*4+64 \n\t" // 1024bit
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s4) \n\t" // B Scale 4VRF*8Row*FP16 = 512bit
"addi s4, s4, 64+128*4 \n\t"
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v3, (s3) \n\t" // A Data M1*K32*int8 = 256bit
"addi s3, s3, 32+6 \n\t"
"flw f0, (s2) \n\t" // A Scale fp32
"lh t2, 4(s2) \n\t" // A sum of int16
"addi s2, s2, 6+32 \n\t"
"vsetvli t0, zero, e8, m1 \n\t"
"vsrl.vi v24, v3, 4 \n\t"
"vnpack4.vv v8, v3, v3, 3 \n\t" // lo4 of A
"vnpack4.vv v10, v24, v24, 3 \n\t" // hi4 of A
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
"vmadotsu v16, v10, v4, i4 \n\t" // M0 N0 - N7 INT32(256bit)
"vmadotsu v18, v10, v5, i4 \n\t" // M0 N8 - N15
"vmadotsu v20, v10, v6, i4 \n\t" // M0 N16 - N23
"vmadotsu v22, v10, v7, i4 \n\t" // M0 N24 - N31
"vsll.vi v16, v16, 4 \n\t"
"vsll.vi v18, v18, 4 \n\t"
"vsll.vi v20, v20, 4 \n\t"
"vsll.vi v22, v22, 4 \n\t"
"vmadotu v16, v8, v4, i4 \n\t"
"vmadotu v18, v8, v5, i4 \n\t"
"vmadotu v20, v8, v6, i4 \n\t"
"vmadotu v22, v8, v7, i4 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vmv.v.i v28, 8 \n\t"
"vpack.vv v24, v16, v18, 2 \n\t"
"vpack.vv v26, v20, v22, 2 \n\t"
"vpack.vv v16, v24, v26, 3 \n\t"
"vwmul.vx v24, v28, t2 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vadd.vv v16, v16, v24 \n\t"
// b_scale fp16 -> fp32
"vsetvli t0, x0, e16, mf2 \n\t"
"vfwcvt.f.f.v v24, v0 \n\t"
// mac result i32 -> fp32
"vsetvli t0, x0, e32, m1 \n\t"
"vfcvt.f.x.v v26, v16 \n\t"
// a_scale * b_scale;
"vfmul.vf v1, v24, f0 \n\t"
// static_cast<float>(qsum) * a_scale * b_scale;
"vfmacc.vv v2, v1, v26 \n\t"
"addi t3, t3, -1 \n\t"
"bgtz t3, _K_LPST%= \n\t"
"_K_LPND%=: \n\t"
//-----------------------------------------
// STORE Equal 32N-------------------------
"_ST32%=: \n\t"
"vsetvli t0, t4, e32, m1 \n\t"
"vse32.v v2, (s6) \n\t" // M0 [N0 : N32]; FP32(1024bit)
"_FUNC_END%=: \n\t"
:
: [BCK] "r"(cnt), [NBLKS] "r"(nblks), [pA] "r"(quant_a_ptr), [pB] "r"(QuantBDataPtr), [pC] "r"(CPtr)
: "cc", "t0", "t2", "t3", "t4", "f0", "s2", "s3", "s4", "s5", "s6");
#else
__asm__ volatile(
// t3 = k/32
"mv t3, %[BCK] \n\t"
"mv t4, %[NBLKS] \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vmv.v.i v0, 1 \n\t" // init the scale
"mv s2, %[pA] \n\t" // s2 = pASCL
"addi s3, %[pA], 4+2 \n\t" // s3 = pAData, (pA+AScl+ASum)
"mv s4, %[pB] \n\t" // s4 = pBSCL
"addi s5, %[pB], 32*2 \n\t" // s5 = pBdata;
"mv s6, %[pC] \n\t"
"vsll.vi v1, v0, 4 \n\t"
"vxor.vv v2, v0, v0 \n\t" // clear acc
"vfcvt.f.x.v v0, v0 \n\t"
"vfcvt.f.x.v v1, v1 \n\t"
// vmadot hp: vle*7 flw*1 vecIns*14 vmadot*8
".align 4 \n\t"
"_K_LPST%=: \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vl4r.v v4, (s5) \n\t" // B Data 4VRF * 8Row * 32
"addi s5, s5, 128*4+64 \n\t" // 1024bit
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v30, (s4) \n\t" // B Scale 4VRF*8Row*FP16 = 512bit
"addi s4, s4, 64+128*4 \n\t"
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v3, (s3) \n\t" // A Data M1*K32*int8 = 256bit
"addi s3, s3, 32+6 \n\t"
"flw f0, (s2) \n\t" // A Scale fp32
"lh t2, 4(s2) \n\t" // A sum of int16
"addi s2, s2, 6+32 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vmv.v.i v28, 8 \n\t" // Bzp u8 -> u16
"vsetvli t0, x0, e8, m1 \n\t"
"vsrl.vi v24, v3, 4 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vmul.vx v26, v28, t2 \n\t" // asum*zp i16*i16
"vnpack4.vv v8, v3, v3, 3 \n\t" // lo4 of A
"vnpack4.vv v10, v24, v24, 3 \n\t" // hi4 of A
"vfcvt.f.x.v v16, v26 \n\t" // zp i16 -> fp16
"vadd.vi v18, v16, 0 \n\t"
"vadd.vi v20, v16, 0 \n\t"
"vadd.vi v22, v16, 0 \n\t"
"vmadotsu.hp v16, v10, v4, v1, 0, i4 \n\t" // high 4
"vmadotsu.hp v18, v10, v5, v1, 0, i4 \n\t"
"vmadotsu.hp v20, v10, v6, v1, 0, i4 \n\t"
"vmadotsu.hp v22, v10, v7, v1, 0, i4 \n\t"
"vmadotu.hp v16, v8, v4, v0, 0, i4 \n\t" // low 4
"vmadotu.hp v18, v8, v5, v0, 0, i4 \n\t"
"vmadotu.hp v20, v8, v6, v0, 0, i4 \n\t"
"vmadotu.hp v22, v8, v7, v0, 0, i4 \n\t"
"vpack.vv v24, v16, v18, 1 \n\t"
"vpack.vv v26, v20, v22, 1 \n\t"
"vpack.vv v16, v24, v26, 2 \n\t"
"vsetvli t0, x0, e16, mf2 \n\t"
// mac result * b_scale; f16*f16->f32
"vfwmul.vv v31, v30, v16 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
// static_cast<float>(qsum * b_scale) * a_scale;
"vfmacc.vf v2, f0, v31 \n\t"
"addi t3, t3, -1 \n\t"
"bgtz t3, _K_LPST%= \n\t"
"_K_LPND%=: \n\t"
//-----------------------------------------
// STORE Equal 32N-------------------------
"_ST32%=: \n\t"
"vsetvli t0, t4, e32, m1 \n\t"
"vse32.v v2, (s6) \n\t" // M0 [N0 : N32]; FP32(1024bit)
"_FUNC_END%=: \n\t"
:
: [BCK] "r"(cnt), [NBLKS] "r"(nblks), [pA] "r"(quant_a_ptr), [pB] "r"(QuantBDataPtr), [pC] "r"(CPtr)
: "cc", "t0", "t2", "t3", "t4", "f0", "s2", "s3", "s4", "s5", "s6");
#endif
}
} else {
for (size_t n = 0; n < count_n; n += 32) {
size_t nblks = (count_n - n) > 32 ? 32 : count_n - n;
uint8_t * QuantBDataPtr = (uint8_t *) quant_b_data + //
n * k_blks * blk_len / 2 + // b data
n * k_blks * sizeof(uint8_t) + // b zp
n * k_blks * sizeof(_Float16); // scale
float * CPtr = c_ptr + n;
size_t cnt = k_blks;
// A format Version_1 (FP32 SCALE FOR Normal VMADOTins of IME2)
// A M1K32 int8 256bit
// Ascale fp32 * 1 32bit
// || scl*1(fp32) | Asum(int16) | blk0 || scl*1(fp32) | Asum(int16) | blk0 || ...
// || Element || Element || ...
// B format
// B N8K32 int4 1024bit
// 4VRF, N32K32, 4096bit
// Bscale fp16 * N32 512bit;
// Bzp uint8_t * N32 256bit;
// || scl*32..(fp16) | zp*32(uint8) | blk0 blk1 ... blk31 || scl*32..(fp16) ...
// || Element || Element ...
//bias always be nullptr
#if 0
__asm__ volatile(
// t3 = k/32
"mv t3, %[BCK] \n\t"
"mv t4, %[NBLKS] \n\t"
"mv s2, %[pA] \n\t" // s2 = pASCL
"addi s3, %[pA], 4+2 \n\t" // s3 = pAData, (pA+AScl+ASum)
"mv s4, %[pB] \n\t" // s4 = pBSCL
"addi s5, %[pB], 32*3 \n\t" // s5 = pBdata, (pB+BScl+Bzp)
"mv s6, %[pC] \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v2, v0, v0 \n\t" // clear acc
// ordinary vmadot: vle*6 flw*1 vecIns*21 vmadot*8
".align 4 \n\t"
"_K_LPST%=: \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vl4r.v v4, (s5) \n\t" // B Data 4VRF * 8Row * 32
"addi s5, s5, 128*4+96 \n\t" // 1024bit
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s4) \n\t" // B Scale 4VRF*8Row*FP16 = 512bit
"addi s4, s4, 64 \n\t"
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v3, (s3) \n\t" // A Data M1*K32*int8 = 256bit
"addi s3, s3, 32+6 \n\t"
"flw f0, (s2) \n\t" // A Scale fp32
"lh t2, 4(s2) \n\t" // A sum of int16
"addi s2, s2, 6+32 \n\t"
"vsetvli t0, zero, e8, m1 \n\t"
"vsrl.vi v24, v3, 4 \n\t"
"vnpack4.vv v8, v3, v3, 3 \n\t" // lo4 of A
"vnpack4.vv v10, v24, v24, 3 \n\t" // hi4 of A
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
"vmadotsu v16, v10, v4, i4 \n\t" // M0 N0 - N7 INT32(256bit)
"vmadotsu v18, v10, v5, i4 \n\t" // M0 N8 - N15
"vmadotsu v20, v10, v6, i4 \n\t" // M0 N16 - N23
"vmadotsu v22, v10, v7, i4 \n\t" // M0 N24 - N31
"vsll.vi v16, v16, 4 \n\t"
"vsll.vi v18, v18, 4 \n\t"
"vsll.vi v20, v20, 4 \n\t"
"vsll.vi v22, v22, 4 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v1, (s4) \n\t" // Bzp
"addi s4, s4, 32+128*4 \n\t"
"vmadotu v16, v8, v4, i4 \n\t"
"vmadotu v18, v8, v5, i4 \n\t"
"vmadotu v20, v8, v6, i4 \n\t"
"vmadotu v22, v8, v7, i4 \n\t"
"vwaddu.vx v28, v1, x0 \n\t" // uint8 -> uint16
"vpack.vv v24, v16, v18, 2 \n\t"
"vpack.vv v26, v20, v22, 2 \n\t"
"vpack.vv v16, v24, v26, 3 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vwmul.vx v24, v28, t2 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vadd.vv v16, v16, v24 \n\t"
// b_scale fp16 -> fp32
"vsetvli t0, x0, e16, mf2 \n\t"
"vfwcvt.f.f.v v24, v0 \n\t"
// mac result i32 -> fp32
"vsetvli t0, x0, e32, m1 \n\t"
"vfcvt.f.x.v v26, v16 \n\t"
// a_scale * b_scale;
"vfmul.vf v1, v24, f0 \n\t"
// static_cast<float>(qsum) * a_scale * b_scale;
"vfmacc.vv v2, v1, v26 \n\t"
"addi t3, t3, -1 \n\t"
"bgtz t3, _K_LPST%= \n\t"
"_K_LPND%=: \n\t"
//-----------------------------------------
// STORE Equal 32N-------------------------
"_ST32%=: \n\t"
"vsetvli t0, t4, e32, m1 \n\t"
"vse32.v v2, (s6) \n\t" // M0 [N0 : N32]; FP32(1024bit)
"_FUNC_END%=: \n\t"
:
: [BCK] "r"(cnt), [NBLKS] "r"(nblks), [pA] "r"(quant_a_ptr), [pB] "r"(QuantBDataPtr), [pC] "r"(CPtr)
: "cc", "t0", "t2", "t3", "t4", "f0", "s2", "s3", "s4", "s5", "s6");
#else
__asm__ volatile(
// t3 = k/32
"mv t3, %[BCK] \n\t"
"mv t4, %[NBLKS] \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vmv.v.i v0, 1 \n\t" // init the scale
"mv s2, %[pA] \n\t" // s2 = pASCL
"addi s3, %[pA], 4+2 \n\t" // s3 = pAData, (pA+AScl+ASum)
"mv s4, %[pB] \n\t" // s4 = pBSCL
"addi s5, %[pB], 32*3 \n\t" // s5 = pBdata, (pB+BScl+Bzp)
"mv s6, %[pC] \n\t"
"vsll.vi v1, v0, 4 \n\t"
"vxor.vv v2, v0, v0 \n\t" // clear acc
"vfcvt.f.x.v v0, v0 \n\t"
"vfcvt.f.x.v v1, v1 \n\t"
// vmadot hp: vle*6 flw*1 vecIns*14 vmadot*8
".align 4 \n\t"
"_K_LPST%=: \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vl4r.v v4, (s5) \n\t" // B Data 4VRF * 8Row * 32
"addi s5, s5, 128*4+96 \n\t" // 1024bit
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v30, (s4) \n\t" // B Scale 4VRF*8Row*FP16 = 512bit
"addi s4, s4, 64 \n\t"
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v31, (s4) \n\t" // B zp 32Row*uint8 = 256bit
"addi s4, s4, 32+128*4 \n\t"
"vle8.v v3, (s3) \n\t" // A Data M1*K32*int8 = 256bit
"addi s3, s3, 32+6 \n\t"
"flw f0, (s2) \n\t" // A Scale fp32
"lh t2, 4(s2) \n\t" // A sum of int16
"addi s2, s2, 6+32 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vsrl.vi v24, v3, 4 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vnpack4.vv v8, v3, v3, 3 \n\t" // lo4 of A
"vnpack4.vv v10, v24, v24, 3 \n\t" // hi4 of A
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
"vmadotsu.hp v16, v10, v4, v1, 0, i4 \n\t" // high 4
"vmadotsu.hp v18, v10, v5, v1, 0, i4 \n\t"
"vmadotsu.hp v20, v10, v6, v1, 0, i4 \n\t"
"vmadotsu.hp v22, v10, v7, v1, 0, i4 \n\t"
"vmadotu.hp v16, v8, v4, v0, 0, i4 \n\t" // low 4
"vmadotu.hp v18, v8, v5, v0, 0, i4 \n\t"
"vmadotu.hp v20, v8, v6, v0, 0, i4 \n\t"
"vmadotu.hp v22, v8, v7, v0, 0, i4 \n\t"
"vsetvli t0, x0, e8, mf4 \n\t"
"vwaddu.vx v28, v31, x0 \n\t" // Bzp u8 -> u16
"vsetvli t0, x0, e8, m1 \n\t"
"vpack.vv v24, v16, v18, 1 \n\t"
"vpack.vv v26, v20, v22, 1 \n\t"
"vpack.vv v16, v24, v26, 2 \n\t"
"vsetvli t0, x0, e16, mf2 \n\t"
"vmul.vx v26, v28, t2 \n\t" // asum*zp i16*i16
"vfwcvt.f.f.v v22, v30 \n\t" // b_scale fp16 -> fp32
"vfcvt.f.x.v v18, v26 \n\t" // zp i16 -> fp16
"vsetvli t0, x0, e16, m1 \n\t"
"vfwadd.vv v20, v18, v16 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
// mac result * b_scale; f32*f32->f32
"vfmul.vv v31, v22, v20 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
// static_cast<float>(qsum * b_scale) * a_scale;
"vfmacc.vf v2, f0, v31 \n\t"
"addi t3, t3, -1 \n\t"
"bgtz t3, _K_LPST%= \n\t"
"_K_LPND%=: \n\t"
//-----------------------------------------
// STORE Equal 32N-------------------------
"_ST32%=: \n\t"
"vsetvli t0, t4, e32, m1 \n\t"
"vse32.v v2, (s6) \n\t" // M0 [N0 : N32]; FP32(1024bit)
"_FUNC_END%=: \n\t"
:
: [BCK] "r"(cnt), [NBLKS] "r"(nblks), [pA] "r"(quant_a_ptr), [pB] "r"(QuantBDataPtr), [pC] "r"(CPtr)
: "cc", "t0", "t2", "t3", "t4", "f0", "s2", "s3", "s4", "s5", "s6");
#endif
}
}
}
void gemm_kernel_i8i4_hp_m1(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
constexpr size_t NB_COLS = 32;
constexpr size_t k_subblks_per_superblk = 8;
struct block_q4_0x32_layout {
_Float16 d[NB_COLS];
uint8_t qs[16 * NB_COLS];
};
GGML_ASSERT(blk_len == 256);
const size_t b_superblk_stride = sizeof(block_q4_0x32_layout) * k_subblks_per_superblk +
(quant_b_zp ? NB_COLS * k_subblks_per_superblk * sizeof(uint8_t) : 0);
const size_t b_tile_stride = k_blks * b_superblk_stride;
if (quant_b_zp == NULL) {
for (size_t ni = 0; ni < count_n; ni += 32) {
uint8_t * b_data = (uint8_t *) quant_b_data + (ni / NB_COLS) * b_tile_stride;
int8_t * a_data = (int8_t *) quant_a_ptr;
float * dst_c = c_ptr + ni;
asm volatile(
"vsetvli t0, x0, e16, m1 \n\t"
"vxor.vv v31, v31, v31 \n\t" // init acc to zero
"mv t4, %[BK] \n\t"
"li t0, 0x4c00 \n\t" // 16 in fp16
"fmv.h.x fa0, t0 \n\t"
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
"li t5, 8 \n\t"
"addi t6, %[A], 288 \n\t" // point to blk scale
"flh ft1, (t6) \n\t"
"addi t6, %[A], 272 \n\t" // point to asum
// init the acc fp16
"vsetvli t0, x0, e16, m1 \n\t"
"vxor.vv v16, v18, v18 \n\t"
"vxor.vv v17, v18, v18 \n\t"
"vxor.vv v18, v18, v18 \n\t"
"vxor.vv v19, v18, v18 \n\t"
"INNER_BLK_LOOP%=: \n\t"
// load a sum and scale
"flh fa1, (t6) \n\t"
"addi t6, t6, 2 \n\t"
"flh ft0, (%[A]) \n\t"
"addi %[A], %[A], 2 \n\t"
// load A
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v3, (%[A]) \n\t" // 1x32@i8
"addi %[A], %[A], 32 \n\t"
// load scale B and B
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v8, (%[B]) \n\t" // b_scale fp16
"addi %[B], %[B], 64 \n\t"
"vl4r.v v4, (%[B]) \n\t" // 32*32@i4
"addi %[B], %[B], 512 \n\t"
"vfmul.vf v8, v8, ft0 \n\t" // scale b * scale a
"vfmul.vf v9, v8, fa0 \n\t"
"vfmul.vf v10, v8, fa1 \n\t" // scale b * scale a * asm
"vfwmacc.vf v31, ft1, v10 \n\t" // asum * scale a * scale b * blk scale
"vsetvli t0, x0, e8, m1 \n\t"
"vpack.vv v0, v8, v9, 3 \n\t"
"vsrl.vi v28, v3, 4 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vnpack4.vv v2, v3, v3, 3 \n\t" // lo4 of A
"vnpack4.vv v3, v28, v28, 3 \n\t" // hi4 of A
// i4 * i4 vmadot
"vsetvli t0, x0, e16, m1 \n\t"
"vmadotsu.hp v16, v3, v4, v0, 4, i4 \n\t" // high 4
"vmadotsu.hp v17, v3, v5, v0, 5, i4 \n\t"
"vmadotsu.hp v18, v3, v6, v0, 6, i4 \n\t"
"vmadotsu.hp v19, v3, v7, v0, 7, i4 \n\t"
"vmadotu.hp v16, v2, v4, v0, 0, i4 \n\t" // low 4
"vmadotu.hp v17, v2, v5, v0, 1, i4 \n\t"
"vmadotu.hp v18, v2, v6, v0, 2, i4 \n\t"
"vmadotu.hp v19, v2, v7, v0, 3, i4 \n\t"
"addi t5, t5, -1 \n\t"
"bgtz t5, INNER_BLK_LOOP%= \n\t"
"vpack.vv v8, v16, v17, 1 \n\t"
"vpack.vv v12, v18, v19, 1 \n\t"
"vpack.vv v20, v8, v12, 2 \n\t"
"vsetvli t0, x0, e16, mf2 \n\t"
"addi t4, t4, -1 \n\t"
"vfwmacc.vf v31, ft1, v20 \n\t"
//"vsetvli t0, x0, e32, m1 \n\t"
//"vfmul.vf v31, v31, ft1 \n\t" // blk scale
// update A ptr
"addi %[A], t6, 2 \n\t"
"bgtz t4, BLK_LOOP%= \n\t"
// save
"vsetvli t0, x0, e32, m1 \n\t"
"vse32.v v31, (%[DST]) \n\t"
: [A] "+r"(a_data), [B] "+r"(b_data)
: [DST] "r"(dst_c), [BK] "r"(k_blks)
: "t0", "t1", "t2", "t3", "t4", "t5", "t6", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9",
"v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "fa0", "fa1", "ft0", "ft1");
}
} else {
// TODO: support quant_b_zp for i8i4 hp kernel
GGML_ABORT("gemm_kernel_i8i4_hp_m1 with quant_b_zp is not supported yet");
}
}
void gemm_kernel_i8i4_m4(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
int64_t b_data_stride =
k_blks * (sizeof(ggml_fp16_t) + 16 * sizeof(int8_t) + (quant_b_zp != NULL ? sizeof(int8_t) : 0));
if (quant_b_zp == NULL) {
for (size_t ni = 0; ni < count_n; ni += 32) {
uint8_t * b_data = (uint8_t *) quant_b_data + ni * b_data_stride;
int8_t * a_data = (int8_t *) quant_a_ptr;
float * dst_c = c_ptr + ni;
#if 0
asm volatile(
"li t1, 8 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v28, v28, v28 \n\t"
"vxor.vv v29, v29, v29 \n\t"
"vxor.vv v30, v30, v30 \n\t"
"vxor.vv v31, v31, v31 \n\t"
"mv t4, %[BK] \n\t"
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
// load scale A
"flw fa0, (%[A]) \n\t"
"flw fa1, 4(%[A]) \n\t"
"flw fa2, 8(%[A]) \n\t"
"flw fa3, 12(%[A]) \n\t"
"addi %[A], %[A], 16 \n\t"
// load scale B
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v12, (%[B]) \n\t"
"addi %[B], %[B], 64 \n\t"
"vfwcvt.f.f.v v14, v12 \n\t"
"vsetivli t0, 4, e16, mf2 \n\t"
"vle16.v v8, (%[A]) \n\t" // asum
"addi %[A], %[A], 8 \n\t"
"vwmul.vx v10, v8, t1 \n\t" // 8*asum
"vsetvli t0, x0, e8, m1 \n\t"
"vl1r.v v0, (%[A]) \n\t"
"addi %[A], %[A], 128 \n\t" // 4*32@i8
"vl4r.v v4, (%[B]) \n\t" // 32*32@i4
"addi %[B], %[B], 512 \n\t"
"vsrl.vi v1, v0, 4 \n\t"
"vnpack4.vv v12, v0, v1, 3 \n\t" // A low u4
"vupack.vv v2, v12, v12, 2 \n\t"
// init the accumu to asum * zp
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
// i4 * i4 vmadot
"vsetvli t0, x0, e32, m1 \n\t"
"vmadotsu v16, v3, v4, i4 \n\t" // high 4
"vmadotsu v18, v3, v5, i4 \n\t"
"vmadotsu v20, v3, v6, i4 \n\t"
"vmadotsu v22, v3, v7, i4 \n\t"
"vsll.vi v16, v16, 4 \n\t"
"vsll.vi v18, v18, 4 \n\t"
"vsll.vi v20, v20, 4 \n\t"
"vsll.vi v22, v22, 4 \n\t"
"vmadotu v16, v2, v4, i4 \n\t" // low 4
"vmadotu v18, v2, v5, i4 \n\t"
"vmadotu v20, v2, v6, i4 \n\t"
"vmadotu v22, v2, v7, i4 \n\t"
"vpack.vv v0, v16, v18, 2 \n\t"
"vpack.vv v2, v20, v22, 2 \n\t"
"vpack.vv v16, v0, v2, 3 \n\t"
"vpack.vv v18, v1, v3, 3 \n\t"
"vrgather.vi v0, v10, 0 \n\t"
"vrgather.vi v1, v10, 1 \n\t"
"vrgather.vi v2, v10, 2 \n\t"
"vrgather.vi v3, v10, 3 \n\t"
"vadd.vv v16, v16, v0 \n\t"
"vadd.vv v17, v17, v1 \n\t"
"vadd.vv v18, v18, v2 \n\t"
"vadd.vv v19, v19, v3 \n\t"
"vfcvt.f.x.v v16, v16 \n\t"
"vfcvt.f.x.v v17, v17 \n\t"
"vfcvt.f.x.v v18, v18 \n\t"
"vfcvt.f.x.v v19, v19 \n\t"
// mul scale
"vfmul.vv v16, v16, v14 \n\t"
"vfmul.vv v17, v17, v14 \n\t"
"vfmul.vv v18, v18, v14 \n\t"
"vfmul.vv v19, v19, v14 \n\t"
"addi t4, t4, -1 \n\t"
"vfmacc.vf v28, fa0, v16 \n\t"
"vfmacc.vf v29, fa1, v17 \n\t"
"vfmacc.vf v30, fa2, v18 \n\t"
"vfmacc.vf v31, fa3, v19 \n\t"
"bgtz t4, BLK_LOOP%= \n\t"
// save
"vsetvli t0, x0, e32, m1 \n\t"
"add t2, %[LDC], %[DST] \n\t"
"vse32.v v28, (%[DST]) \n\t"
"add t3, %[LDC], t2 \n\t"
"vse32.v v29, (t2) \n\t"
"add t2, %[LDC], t3 \n\t"
"vse32.v v30, (t3) \n\t"
"vse32.v v31, (t2) \n\t"
: [A] "+r"(a_data), [B] "+r"(b_data)
: [DST] "r"(dst_c), [LDC] "r"(ldc*4), [BK] "r"(k_blks)
: "t0", "t1", "t2", "t3", "t4", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11",
"v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25",
"v26", "v27", "v28", "v29", "v30", "v31", "fa0", "fa1", "fa2", "fa3");
#else
asm volatile(
"vsetvli t0, x0, e16, m1 \n\t"
"vxor.vv v28, v28, v28 \n\t"
"vxor.vv v29, v29, v29 \n\t"
"vxor.vv v30, v30, v30 \n\t"
"vxor.vv v31, v31, v31 \n\t"
"vmv.v.i v0, 1 \n\t" // init the scale
"vsll.vi v1, v0, 4 \n\t"
"vfcvt.f.x.v v0, v0 \n\t"
"vfcvt.f.x.v v1, v1 \n\t"
"mv t4, %[BK] \n\t"
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
// load scale A
"flw fa0, (%[A]) \n\t"
"flw fa1, 4(%[A]) \n\t"
"flw fa2, 8(%[A]) \n\t"
"flw fa3, 12(%[A]) \n\t"
"addi %[A], %[A], 16 \n\t"
// load scale B
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v12, (%[B]) \n\t"
"addi %[B], %[B], 64 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v14, v12, v12, 3 \n\t"
"vsetivli t0, 4, e16, mf2 \n\t"
"vle16.v v8, (%[A]) \n\t" // asum
"addi %[A], %[A], 8 \n\t"
"vsll.vi v8, v8, 3 \n\t" // asum * 8
"vfcvt.f.x.v v9, v8 \n\t"
"vsetvli t0, x0, e64, m1 \n\t"
"vrgather.vi v10, v9, 0 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vl1r.v v16, (%[A]) \n\t"
"addi %[A], %[A], 128 \n\t" // 4*32@i8
"vl4r.v v4, (%[B]) \n\t" // 32*32@i4
"addi %[B], %[B], 512 \n\t"
"vsrl.vi v17, v16, 4 \n\t"
"vnpack4.vv v12, v16, v17, 3 \n\t" // A low u4
"vupack.vv v2, v12, v12, 2 \n\t"
// init the accumu to asum * zp
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v16, v10, v10,0 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vpack.vv v20, v16, v16,0 \n\t"
"vsetvli t0, x0, e64, m1 \n\t"
"vpack.vv v18, v20, v20, 0 \n\t"
"vor.vv v20, v18, v18 \n\t"
"vor.vv v21, v18, v18 \n\t"
// i4 * i4 vmadot
"vsetvli t0, x0, e16, m1 \n\t"
"vmadotsu.hp v18, v3, v4, v1, 0, i4 \n\t" // high 4
"vmadotsu.hp v19, v3, v5, v1, 0, i4 \n\t"
"vmadotsu.hp v20, v3, v6, v1, 0, i4 \n\t"
"vmadotsu.hp v21, v3, v7, v1, 0, i4 \n\t"
"vmadotu.hp v18, v2, v4, v0, 0, i4 \n\t" // low 4
"vmadotu.hp v19, v2, v5, v0, 0, i4 \n\t"
"vmadotu.hp v20, v2, v6, v0, 0, i4 \n\t"
"vmadotu.hp v21, v2, v7, v0, 0, i4 \n\t"
"vpack.vv v8, v18, v19, 1 \n\t"
"vpack.vv v12, v20, v21, 1 \n\t"
"vpack.vv v20, v8, v12, 2 \n\t"
"vfwmul.vv v16, v20, v14 \n\t"
"vfwmul.vv v18, v21, v14 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"addi t4, t4, -1 \n\t"
"vfmacc.vf v28, fa0, v16 \n\t"
"vfmacc.vf v29, fa1, v17 \n\t"
"vfmacc.vf v30, fa2, v18 \n\t"
"vfmacc.vf v31, fa3, v19 \n\t"
"bgtz t4, BLK_LOOP%= \n\t"
// save
"vsetvli t0, x0, e32, m1 \n\t"
"add t2, %[LDC], %[DST] \n\t"
"vse32.v v28, (%[DST]) \n\t"
"add t3, %[LDC], t2 \n\t"
"vse32.v v29, (t2) \n\t"
"add t2, %[LDC], t3 \n\t"
"vse32.v v30, (t3) \n\t"
"vse32.v v31, (t2) \n\t"
: [A] "+r"(a_data), [B] "+r"(b_data)
: [DST] "r"(dst_c), [LDC] "r"(ldc * 4), [BK] "r"(k_blks)
: "t0", "t1", "t2", "t3", "t4", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10",
"v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24",
"v25", "v26", "v27", "v28", "v29", "v30", "v31", "fa0", "fa1", "fa2", "fa3");
#endif
}
} else {
for (size_t ni = 0; ni < count_n; ni += 32) {
uint8_t * b_data = (uint8_t *) quant_b_data + ni * b_data_stride;
int8_t * a_data = (int8_t *) quant_a_ptr;
float * dst_c = c_ptr + ni;
asm volatile(
"li t1, 8 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v28, v28, v28 \n\t"
"vxor.vv v29, v29, v29 \n\t"
"vxor.vv v30, v30, v30 \n\t"
"vxor.vv v31, v31, v31 \n\t"
"mv t4, %[BK] \n\t"
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
// load scale A
"flw fa0, (%[A]) \n\t"
"flw fa1, 4(%[A]) \n\t"
"flw fa2, 8(%[A]) \n\t"
"flw fa3, 12(%[A]) \n\t"
"addi %[A], %[A], 16 \n\t"
// load scale B
"vsetvli t0, x0, e16, mf2\n\t"
"vle16.v v12, (%[B]) \n\t"
"addi %[B], %[B], 64 \n\t"
"vfwcvt.f.f.v v14, v12 \n\t"
// load zp
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v8, (%[B]) \n\t"
"addi %[B], %[B], 32 \n\t"
"vwaddu.vx v10, v8, x0 \n\t"
// load a sum
"lh s1, (%[A]) \n\t"
"lh s2, 2(%[A]) \n\t"
"lh s3, 4(%[A]) \n\t"
"lh s4, 6(%[A]) \n\t"
"addi %[A], %[A], 8 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vl1r.v v0, (%[A]) \n\t"
"addi %[A], %[A], 128 \n\t" // 4*32@i8
"vl4r.v v4, (%[B]) \n\t" // 32*32@i4
"addi %[B], %[B], 512 \n\t"
"vsrl.vi v1, v0, 4 \n\t"
"vnpack4.vv v12, v0, v1, 3 \n\t" // A low u4
"vupack.vv v2, v12, v12, 2 \n\t"
// init the accumu to asum * zp
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
// i4 * i4 vmadot
"vsetvli t0, x0, e32, m1 \n\t"
"vmadotsu v16, v3, v4, i4 \n\t" // high 4
"vmadotsu v18, v3, v5, i4 \n\t"
"vmadotsu v20, v3, v6, i4 \n\t"
"vmadotsu v22, v3, v7, i4 \n\t"
"vsll.vi v16, v16, 4 \n\t"
"vsll.vi v18, v18, 4 \n\t"
"vsll.vi v20, v20, 4 \n\t"
"vsll.vi v22, v22, 4 \n\t"
"vmadotu v16, v2, v4, i4 \n\t" // low 4
"vmadotu v18, v2, v5, i4 \n\t"
"vmadotu v20, v2, v6, i4 \n\t"
"vmadotu v22, v2, v7, i4 \n\t"
"vpack.vv v0, v16, v18, 2 \n\t"
"vpack.vv v2, v20, v22, 2 \n\t"
"vpack.vv v16, v0, v2, 3 \n\t"
"vpack.vv v18, v1, v3, 3 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vwmul.vx v0, v10, s1 \n\t"
"vwmul.vx v2, v10, s2 \n\t"
"vwmul.vx v4, v10, s3 \n\t"
"vwmul.vx v6, v10, s4 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vadd.vv v16, v16, v0 \n\t"
"vadd.vv v17, v17, v2 \n\t"
"vadd.vv v18, v18, v4 \n\t"
"vadd.vv v19, v19, v6 \n\t"
"vfcvt.f.x.v v16, v16 \n\t"
"vfcvt.f.x.v v17, v17 \n\t"
"vfcvt.f.x.v v18, v18 \n\t"
"vfcvt.f.x.v v19, v19 \n\t"
// mul scale
"vfmul.vv v16, v16, v14 \n\t"
"vfmul.vv v17, v17, v14 \n\t"
"vfmul.vv v18, v18, v14 \n\t"
"vfmul.vv v19, v19, v14 \n\t"
"addi t4, t4, -1 \n\t"
"vfmacc.vf v28, fa0, v16 \n\t"
"vfmacc.vf v29, fa1, v17 \n\t"
"vfmacc.vf v30, fa2, v18 \n\t"
"vfmacc.vf v31, fa3, v19 \n\t"
"bgtz t4, BLK_LOOP%= \n\t"
// save
"vsetvli t0, x0, e32, m1 \n\t"
"add t2, %[LDC], %[DST]\n\t"
"vse32.v v28, (%[DST]) \n\t"
"add t3, %[LDC], t2 \n\t"
"vse32.v v29, (t2) \n\t"
"add t2, %[LDC], t3 \n\t"
"vse32.v v30, (t3) \n\t"
"vse32.v v31, (t2) \n\t"
: [A] "+r"(a_data), [B] "+r"(b_data)
: [DST] "r"(dst_c), [LDC] "r"(ldc * 4), [BK] "r"(k_blks)
: "t0", "t1", "t2", "t3", "t4", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10",
"v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24",
"v25", "v26", "v27", "v28", "v29", "v30", "v31", "fa0", "fa1", "fa2", "fa3", "s1", "s2", "s3", "s4");
}
}
}
void gemm_kernel_i8i4_hp_m4(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
constexpr size_t NB_COLS = 32;
constexpr size_t K_SUBBLKS_PER_SUPERBLK = 8;
constexpr size_t K_SUBBLK_LEN = 32;
struct block_q4_0x32_layout {
_Float16 d[NB_COLS];
uint8_t qs[16 * NB_COLS];
};
GGML_ASSERT(blk_len == 256);
GGML_ASSERT(count_m >= 4);
// Contract:
// - computes a 4-row x 32-col tile per inner invocation
// - A is q8 HP packed in m4 layout, one logical K256 block at a time
// - B is q4 HP packed in N32 tiles, optionally with a separate zp area
// - tail-N is currently not handled here; the caller must provide full N32 tiles
const size_t b_superblk_stride = sizeof(block_q4_0x32_layout) * K_SUBBLKS_PER_SUPERBLK +
(quant_b_zp ? NB_COLS * K_SUBBLKS_PER_SUPERBLK * sizeof(uint8_t) : 0);
const size_t b_tile_stride = k_blks * b_superblk_stride;
const size_t a_nrow_block_stride = q8_hp_blk_size(blk_len, true, true) * 4;
const size_t a_subblk_stride = q8_hp_blk_size(K_SUBBLK_LEN, false, false) * 4;
if (quant_b_zp != nullptr) {
for (size_t ni = 0; ni < count_n; ni += NB_COLS) {
const size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
if (nb_real != NB_COLS) {
break;
}
uint8_t * b_tile_base = (uint8_t *) quant_b_data + (ni / NB_COLS) * b_tile_stride;
uint8_t * a_block = (uint8_t *) quant_a_ptr;
float * dst_c = c_ptr + ni;
// Data layout summary for the with-zp path.
//
// A: M4 x K256 q8 HP block
// - split into 8 x K32 subblocks
// - each K32 subblock is 136B:
// 8B = 4 x fp16 row scales
// 128B = 4 x int8[32] row payloads
// - trailer after 8 subblocks is 72B:
// 4 rows x fp16[8] a_sum values, indexed as [row][ksi]
// 4 rows x fp16 scale_avg tail
//
// B: N32 x K256 q4 HP block with explicit zp area
// - each K32 subblock is 576B:
// 64B = fp16 scale[32]
// 512B = packed q4 payload for 32 columns x 32 k-elements
// - zp is stored separately, not interleaved with the 576B payload block
// - one K256 superblock is laid out as:
// 8 x (scale + qs) blocks = 4608B
// 8 x zp[32] = 256B
//
// C: 4 rows x 32 fp32 outputs
//
// ASM pointer convention:
// - t6: current A K32 subblock base
// - t2: current A a_sum base for this ksi
// row1/row2/row3 are at +16/+32/+48 bytes
// - s5: current B (scale + qs) K32 subblock base
// - s6: current B zp[32] base for this ksi
//
// Loop progression:
// - per ksi: A += 136, a_sum += 2, B_data += 576, B_zp += 32
// - per ki : skip the 72B A trailer and advance B to the next 4864B superblock
const _Float16 hp_scale_16 = (_Float16) 16.0f;
const _Float16 hp_scale_1 = (_Float16) 1.0f;
const _Float16 hp_scale_0125 = (_Float16) 0.125f;
// VPR grouping used below:
// - v4-v7 : B q4 payload for N32 split as 4 x N8 groups
// - v8/v10 : zp u8 / widened fp16
// - v12 : B fp16 scale[32]
// - v14-v15 : packed (Bscale * Ascale) for rows [0,1] / [2,3]
// - v16-v19 : temporary per-row scaled B scales
// - v28-v31 : final fp32 accumulators for rows 0..3
asm volatile(
"mv t5, %[BK] \n\t"
"mv t6, %[A] \n\t"
"mv s5, %[B] \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v28, v28, v28 \n\t"
"vxor.vv v29, v29, v29 \n\t"
"vxor.vv v30, v30, v30 \n\t"
"vxor.vv v31, v31, v31 \n\t"
"li t4, 8 \n\t"
"li t1, 4608 \n\t"
"addi t2, t6, 1088 \n\t" // 8 * 136B A K32 subblocks, a_sum trailer starts here
"add s6, s5, t1 \n\t" // 8 * 576B B(scale+qs), zp area starts here
".align 4 \n\t"
"_BLK_LPST%=: \n\t"
"flh fa1, 64(t2) \n\t" // a_scale_avg_row[0]
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v18, v30, v30 \n\t"
"vxor.vv v19, v31, v31 \n\t"
"vxor.vv v20, v30, v30 \n\t"
"vxor.vv v21, v31, v31 \n\t"
"_KsubBLK_LPST%=: \n\t"
// load first subblock scales for 4 rows
"flh fa0, 0(t6) \n\t" // ascale_fp16
// load B fp16 scales[32]
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v12, (s5) \n\t"
// load Bzp[32] for the current ksi from the dedicated zp area
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v8, (s6) \n\t"
"fmul.h fa2, fa0, %[HP16] \n\t"
"vfwcvt.f.xu.v v10, v8 \n\t" // uint8 -> fp16
"vsetvli t0, x0, e16, mf2 \n\t"
"vfmul.vf v16, v12, fa0 \n\t" // row0: Bscale * Ascale
"vfmul.vf v17, v12, fa2 \n\t"
// load a_sum[row][ksi] from the trailer; t2 points to row0[ksi]
"flh ft1, 0(t2) \n\t"
"flh ft2, 16(t2) \n\t"
"flh ft3, 32(t2) \n\t"
"flh ft4, 48(t2) \n\t"
"fmul.h ft1, ft1, %[HP0125] \n\t"
"fmul.h ft2, ft2, %[HP0125] \n\t"
"fmul.h ft3, ft3, %[HP0125] \n\t"
"fmul.h ft4, ft4, %[HP0125] \n\t"
// load A payload from current K32 subblock and B q4 payload from current 576B block
"addi t3, t6, 8 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vl1r.v v0, (t3) \n\t" //A
"addi t3, s5, 64 \n\t"
"vl4r.v v4, (t3) \n\t" //B
"vsetvli t0, x0, e8, m1 \n\t"
"vsrl.vi v1, v0, 4 \n\t"
"vnpack4.vv v12, v0, v1, 3 \n\t"
"vpack.vv v0, v17, v16, 3 \n\t"
"vupack.vv v2, v12, v12, 2 \n\t"
"vsetvli t0, x0, e16, mf2 \n\t" // mf2 -> mf2
"vfmul.vv v10, v10, v16 \n\t" // zp * ascale * bscale; fp16*fp16
"vsetvli t0, x0, e16, mf2 \n\t" // mf2 -> m1
"vfmul.vf v12, v10, ft1 \n\t" // zp(1:n)* abscale * asum_m0; fp16*fp16
"vfmul.vf v13, v10, ft2 \n\t" // zp(1:n)* abscale * asum_m1; fp16*fp16
"vfmul.vf v24, v10, ft3 \n\t" // zp(1:n)* abscale * asum_m2; fp16*fp16
"vfmul.vf v25, v10, ft4 \n\t" // zp(1:n)* abscale * asum_m3; fp16*fp16
"vsetvli t0, x0, e16, mf2 \n\t"
"vfwmacc.vf v28, fa1, v12 \n\t" // row0/1 accum += dot * packed scale
"vfwmacc.vf v29, fa1, v13 \n\t"
"vfwmacc.vf v30, fa1, v24 \n\t"
"vfwmacc.vf v31, fa1, v25 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vmadotsu.hp v18, v3, v4, v0, 0, i4 \n\t" //lo4;n0n7
"vmadotsu.hp v19, v3, v5, v0, 1, i4 \n\t" //lo4;n8n15
"vmadotsu.hp v20, v3, v6, v0, 2, i4 \n\t" //lo4;n16n23
"vmadotsu.hp v21, v3, v7, v0, 3, i4 \n\t" //lo4;n24n31
"vmadotu.hp v18, v2, v4, v0, 4, i4 \n\t" //hi4;n0n7
"vmadotu.hp v19, v2, v5, v0, 5, i4 \n\t" //hi4;n8n15
"vmadotu.hp v20, v2, v6, v0, 6, i4 \n\t" //hi4;n16n23
"vmadotu.hp v21, v2, v7, v0, 7, i4 \n\t" //hi4;n24n31
"addi t4, t4, -1 \n\t"
"addi t6, t6, 8+128 \n\t" // next A K32 subblock
"addi t2, t2, 2 \n\t" // next ksi entry in each a_sum row
"addi s5, s5, 64+512 \n\t" // next B (scale + qs) K32 block
"addi s6, s6, 32 \n\t" // next zp[32]
"bgtz t4, _KsubBLK_LPST%= \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v8, v18, v19, 1 \n\t" // 128(16*8)->256(16*16)
"vpack.vv v12, v20, v21, 1 \n\t"
"vpack.vv v26, v8, v12, 2 \n\t" // 256(16*16)->512(16*32)
"vsetvli t0, x0, e16, m1 \n\t"
"vfwmacc.vf v28, fa1, v26 \n\t" // row0/1 accum += dot * packed scale
"vfwmacc.vf v30, fa1, v27 \n\t"
"li t4, 8 \n\t"
"addi t5, t5, -1 \n\t"
"addi t6, t6, 72 \n\t" // skip A trailer after 8 subblocks and scale_avg tail
"mv s5, s6 \n\t" // s6 already points to next B superblock base
"addi t2, t6, 1088 \n\t" // 8 * 136B A K32 subblocks, a_sum trailer starts here
"add s6, s5, t1 \n\t" // 8 * 576B B(scale+qs), zp area starts here
"bgtz t5, _BLK_LPST%= \n\t"
"_BLK_LPND%=: \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"add t2, %[LDC], %[DST] \n\t"
"vse32.v v28, (%[DST]) \n\t"
"add t3, %[LDC], t2 \n\t"
"vse32.v v29, (t2) \n\t"
"add t2, %[LDC], t3 \n\t"
"vse32.v v30, (t3) \n\t"
"vse32.v v31, (t2) \n\t"
: [A] "+r"(a_block), [B] "+r"(b_tile_base)
: [DST] "r"(dst_c), [LDC] "r"(ldc * 4), [BK] "r"(k_blks), [HP16] "f"(hp_scale_16),
[HP1] "f"(hp_scale_1), [HP0125] "f"(hp_scale_0125)
: "t0", "t1", "t2", "t3", "t4", "t5", "t6", "s5", "s6", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
"v8", "v10", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v24",
"v25", "v26", "v27", "v28", "v29", "v30", "v31", "fa0", "fa1", "fa2", "ft1", "ft2", "ft3", "ft4",
"memory");
}
return;
} else {
for (size_t ni = 0; ni < count_n; ni += NB_COLS) {
const size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
if (nb_real != NB_COLS) {
break;
}
uint8_t * b_tile_base = (uint8_t *) quant_b_data + (ni / NB_COLS) * b_tile_stride;
uint8_t * a_block = (uint8_t *) quant_a_ptr;
float * dst_c = c_ptr + ni;
// Data layout summary for the no-zp path.
//
// A layout is identical to the with-zp branch.
//
// B: N32 x K256 q4 HP block without explicit zp storage
// - each K32 subblock is still 576B:
// 64B = fp16 scale[32]
// 512B = packed q4 payload
// - zp is implicit and treated as a constant value 8 in the kernel
// - one K256 superblock therefore contains only:
// 8 x (scale + qs) blocks = 4608B
//
// C: 4 rows x 32 fp32 outputs
//
// ASM pointer convention:
// - t6: current A K32 subblock base
// - t2: current A a_sum base for this ksi
// - s5: current B (scale + qs) K32 subblock base
//
// Loop progression:
// - per ksi: A += 136, a_sum += 2, B_data += 576
// - per ki : skip the 72B A trailer and advance B to the next 4608B superblock
const _Float16 hp_scale_16 = (_Float16) 16.0f;
const _Float16 hp_scale_1 = (_Float16) 1.0f;
// VPR grouping used below matches the with-zp path:
// - v4-v7 : B q4 payload for N32 split as 4 x N8 groups
// - v8/v10 : implicit zp lane / widened fp16
// - v12 : B fp16 scale[32]
// - v14-v15 : packed (Bscale * Ascale) for rows [0,1] / [2,3]
// - v16-v19 : temporary per-row scaled B scales
// - v28-v31 : final fp32 accumulators for rows 0..3
asm volatile(
"mv t5, %[BK] \n\t"
"mv t6, %[A] \n\t"
"mv s5, %[B] \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v28, v28, v28 \n\t"
"vxor.vv v29, v29, v29 \n\t"
"vxor.vv v30, v30, v30 \n\t"
"vxor.vv v31, v31, v31 \n\t"
"li t4, 8 \n\t"
"addi t2, t6, 1088 \n\t" // 8 * 136B A K32 subblocks, a_sum trailer starts here
".align 4 \n\t"
"_BLK_LPST%=: \n\t"
"flh fa1, 64(t2) \n\t" // a_scale_avg_row[0]
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v18, v30, v30 \n\t"
"vxor.vv v19, v31, v31 \n\t"
"vxor.vv v20, v30, v30 \n\t"
"vxor.vv v21, v31, v31 \n\t"
"_KsubBLK_LPST%=: \n\t"
// load first subblock scales for 4 rows
"flh fa0, 0(t6) \n\t" // ascale_fp16
// load B fp16 scales[32]
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v12, (s5) \n\t"
"fmul.h fa2, fa0, %[HP16] \n\t"
"vsetvli t0, x0, e16, mf2 \n\t"
"vfmul.vf v16, v12, fa0 \n\t" // row0: Bscale * Ascale
"vfmul.vf v17, v12, fa2 \n\t"
// load a_sum[row][ksi] from the trailer; t2 points to row0[ksi]
"flh ft1, 0(t2) \n\t"
"flh ft2, 16(t2) \n\t"
"flh ft3, 32(t2) \n\t"
"flh ft4, 48(t2) \n\t"
// load A payload from current K32 subblock and B q4 payload from current 576B block
"addi t3, t6, 8 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vl1r.v v0, (t3) \n\t" //A
"addi t3, s5, 64 \n\t"
"vl4r.v v4, (t3) \n\t" //B
"vsetvli t0, x0, e8, m1 \n\t"
"vsrl.vi v1, v0, 4 \n\t"
"vnpack4.vv v12, v0, v1, 3 \n\t"
"vpack.vv v0, v17, v16, 3 \n\t"
"vupack.vv v2, v12, v12, 2 \n\t"
"vsetvli t0, x0, e16, mf2 \n\t" // mf2 -> m1
"vfmul.vf v12, v16, ft1 \n\t" // zp(1:n)* abscale * asum_m0; fp16*fp16
"vfmul.vf v13, v16, ft2 \n\t" // zp(1:n)* abscale * asum_m1; fp16*fp16
"vfmul.vf v24, v16, ft3 \n\t" // zp(1:n)* abscale * asum_m2; fp16*fp16
"vfmul.vf v25, v16, ft4 \n\t" // zp(1:n)* abscale * asum_m3; fp16*fp16
"vsetvli t0, x0, e16, mf2 \n\t"
"vfwmacc.vf v28, fa1, v12 \n\t"
"vfwmacc.vf v29, fa1, v13 \n\t"
"vfwmacc.vf v30, fa1, v24 \n\t"
"vfwmacc.vf v31, fa1, v25 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vmadotsu.hp v18, v3, v4, v0, 0, i4 \n\t" //lo4;n0n7
"vmadotsu.hp v19, v3, v5, v0, 1, i4 \n\t" //lo4;n8n15
"vmadotsu.hp v20, v3, v6, v0, 2, i4 \n\t" //lo4;n16n23
"vmadotsu.hp v21, v3, v7, v0, 3, i4 \n\t" //lo4;n24n31
"vmadotu.hp v18, v2, v4, v0, 4, i4 \n\t" //hi4;n0n7
"vmadotu.hp v19, v2, v5, v0, 5, i4 \n\t" //hi4;n8n15
"vmadotu.hp v20, v2, v6, v0, 6, i4 \n\t" //hi4;n16n23
"vmadotu.hp v21, v2, v7, v0, 7, i4 \n\t" //hi4;n24n31
"addi t4, t4, -1 \n\t"
"addi t6, t6, 8+128 \n\t" // next A K32 subblock
"addi t2, t2, 2 \n\t" // next ksi entry in each a_sum row
"addi s5, s5, 64+512 \n\t" // next B (scale + qs) K32 block
"bgtz t4, _KsubBLK_LPST%= \n\t"
"vsetvli t0, x0, e16, m1 \n\t" //N32in1register
"vpack.vv v8, v18, v19, 1 \n\t" // 128(16*8)->256(16*16)
"vpack.vv v12, v20, v21, 1 \n\t"
"vpack.vv v26, v8, v12, 2 \n\t" // 256(16*16)->512(16*32)
"vsetvli t0, x0, e16, m1 \n\t"
"vfwmacc.vf v28, fa1, v26 \n\t" // row0/1 accum += dot * packed scale
"vfwmacc.vf v30, fa1, v27 \n\t"
"li t4, 8 \n\t"
"addi t5, t5, -1 \n\t"
"addi t6, t6, 72 \n\t" // skip A trailer after 8 subblocks and scale_avg tail
// s5 already points to next B superblock base
"addi t2, t6, 1088 \n\t" // 8 * 136B A K32 subblocks, a_sum trailer starts here
"bgtz t5, _BLK_LPST%= \n\t"
"_BLK_LPND%=: \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"add t2, %[LDC], %[DST] \n\t"
"vse32.v v28, (%[DST]) \n\t"
"add t3, %[LDC], t2 \n\t"
"vse32.v v29, (t2) \n\t"
"add t2, %[LDC], t3 \n\t"
"vse32.v v30, (t3) \n\t"
"vse32.v v31, (t2) \n\t"
: [A] "+r"(a_block), [B] "+r"(b_tile_base)
: [DST] "r"(dst_c), [LDC] "r"(ldc * 4), [BK] "r"(k_blks), [HP16] "f"(hp_scale_16), [HP1] "f"(hp_scale_1)
: "t0", "t2", "t3", "t4", "t5", "t6", "s5", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v10",
"v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v24", "v25", "v26",
"v27", "v28", "v29", "v30", "v31", "fa0", "fa1", "fa2", "ft1", "ft2", "ft3", "ft4", "memory");
}
return;
}
}
void gemm_kernel_i8mxfp4_m1(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
constexpr size_t NB_COLS = 32;
constexpr size_t K_TILE = 32;
using blk_type = nrow_block_mxfp4<NB_COLS>;
GGML_ASSERT(blk_len == K_TILE);
GGML_ASSERT(count_m == 1);
GGML_UNUSED(quant_b_zp);
const size_t a_blk_stride = q8_blk_size(blk_len, true);
const size_t b_blk_stride = sizeof(blk_type);
const size_t b_tile_stride = k_blks * b_blk_stride;
if (quant_b_zp == NULL) {
for (size_t n = 0; n < count_n; n += 32) {
size_t nblks = (count_n - n) > 32 ? 32 : count_n - n;
// MXFP4 no-zp: per column per k-block stride = scale_e8m0(1B) + qs(16B) + qh(4B) = 21B
uint8_t * QuantBDataPtr = (uint8_t *) quant_b_data + //
n * k_blks * (blk_len / 8) + // qh sign/high-bit mask: n×k_blks×4
n * k_blks * blk_len / 2 + // qs packed 4-bit magnitudes: n×k_blks×16
n * k_blks * sizeof(uint8_t); // scale: n×k_blks×1
float * CPtr = c_ptr + n;
size_t cnt = k_blks;
// A format (q8 block with per-block scale and stored sum field):
// || scl(fp32,4B) | asum(int16,2B) | data(int8,32B) || × k_blks
//
// Register map:
// t3 = k_blks loop counter t4 = nblks (tail)
// f0 = A scale (fp32)
// s2 = pA (scale/asum) s3 = pA data
// s4 = pB scales (u8×32)
// s5 = pB qh (sign/high-bit mask, 128B)
// s6 = pB qs (packed 4-bit magnitudes, 512B)
// s7 = pC
// v3 = fp32 accumulator (N32)
// v2 = B scales u8 (loaded as bytes; later widened)
// v0 = qh mask bytes (also used as v0.t mask after load)
// v1 = A int8 (K32)
// v8..v15 / v16..v23 = qs unpack/pack temporaries (build signed vmadot lanes)
// v24/v26/v28/v30 = int32 dot accumulators & packing temps
__asm__ volatile(
"mv t3, %[BCK] \n\t" // t3 = k_blks
"mv t4, %[NBLKS] \n\t" // t4 = nblks (tail guard)
// ---- pre-loop: init fp16 constants in e16 m1 context ----
"vsetvli t0, x0, e16, m1 \n\t"
"vmv.v.i v0, 1 \n\t" // v0 = int16(1)
"vfcvt.f.x.v v0, v0 \n\t" // v0 = 1.0_fp16
"vxor.vv v3, v16, v16 \n\t"
// ---- pointer setup ----
"mv s2, %[pA] \n\t" // s2 = pA (scale, fp32)
"addi s3, %[pA], 4+2 \n\t" // s3 = pA data (skip scale+asum)
"mv s4, %[pB] \n\t" // s4 = pBSCL
"addi s5, %[pB], 32 \n\t" // s5 = pBh (pB + 32B scale)
"addi s6, %[pB], 32+128 \n\t" // s6 = pBs (pB + 32 + 128 = pB+192)
"mv s7, %[pC] \n\t" // s7 = pC
// =====================================================================
// K-block loop: each iteration processes one N32×K32 block
// Stride per k-block = 672B = 32(scl) + 512(Bs) + 128(Bh)
// =====================================================================
".align 4 \n\t"
"BLK_LPST%=: \n\t"
// ---- load qs (512B = 4 VRF) from s6, advance s6 by 672 ----
"vsetvli t0, x0, e8, m1 \n\t"
"vl4r.v v8, (s6) \n\t" // v8..v11 = qs N32K32 packed 4-bit magnitudes
"addi s6, s6, 128*4+128+32 \n\t" // s6 += 672 (512+128+32)
// ---- load B scale (32B = 32×u8) from s4, advance s4 by 672 ----
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v2, (s4) \n\t" // v2 = scale_u8 × 32
"addi s4, s4, 32+128*4+128 \n\t" // s4 += 672 (32+512+128)
// ---- load qh (128B = 1 VRF) from s5, advance s5 by 672 ----
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v0, (s5) \n\t" // v0 = qh N32K32 sign/high-bit packed
"addi s5, s5, 128+32+128*4 \n\t" // s5 += 672 (128+32+512)
// ---- load A data (32B = K32 int8) from s3 ----
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v1, (s3) \n\t" // v1 = A M1K32 int8
"addi s3, s3, 32+6 \n\t" // s3 += 38 (data + scl + asum)
// ---- load A scale (fp32) and asum (int16) from s2 ----
"flw f0, (s2) \n\t" // f0 = A scale (fp32)
"addi s2, s2, 6+32 \n\t" // s2 += 38
// ---- Decode packed MXFP4 payload into a vmadot-friendly signed-lane layout ----
"vsetvli t0, x0, e8, m1 \n\t"
"vand.vi v12, v8, 0xF \n\t" //8bit(lo4) //[8*32]
"vand.vi v13, v9, 0xF \n\t"
"vand.vi v14, v10, 0xF \n\t"
"vand.vi v15, v11, 0xF \n\t"
"vsrl.vi v8, v8, 4 \n\t" //8bit(hi4)
"vsrl.vi v9, v9, 4 \n\t"
"vsrl.vi v10, v10, 4 \n\t"
"vsrl.vi v11, v11, 4 \n\t"
// [4*32]*2
"vsetvli t0, x0, e8, m1 \n\t"
"vpack.vv v16, v12, v8, 0 \n\t"
"vpack.vv v18, v13, v9, 0 \n\t"
"vpack.vv v20, v14, v10, 0 \n\t"
"vpack.vv v22, v15, v11, 0 \n\t"
"vsetvli t0, x0, e8, m8 \n\t"
"vrsub.vi v16, v16, 0, v0.t \n\t"
// [4*32]*2 -> [8*16]
"vsetvli t0, x0, e8, m1 \n\t"
"vupack.vv v8, v16, v17, 1 \n\t"
"vupack.vv v10, v18, v19, 1 \n\t"
"vupack.vv v12, v20, v21, 1 \n\t"
"vupack.vv v14, v22, v23, 1 \n\t"
"vsetvli t0, x0, e64, m1 \n\t"
"vslidedown.vi v16, v1, 2 \n\t"
// init the accumu to 0
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v24, v16, v16 \n\t"
"vxor.vv v26, v16, v16 \n\t"
"vxor.vv v28, v16, v16 \n\t"
"vxor.vv v30, v16, v16 \n\t"
// ---- int8 dot products over the decoded MXFP4 lane groups ----
"vmadot v24, v1, v8, i8 \n\t" // N0..7
"vmadot v26, v1, v10, i8 \n\t" // N8..15
"vmadot v28, v1, v12, i8 \n\t" // N16..23
"vmadot v30, v1, v14, i8 \n\t" // N24..31
"vmadot v24, v16, v9, i8 \n\t" // N0..7
"vmadot v26, v16, v11, i8 \n\t" // N8..15
"vmadot v28, v16, v13, i8 \n\t" // N16..23
"vmadot v30, v16, v15, i8 \n\t" // N24..31
"vsetvli t0, x0, e32, m1 \n\t"
"vpack.vv v16, v24, v26, 2 \n\t" // v16 = N0..15
"vpack.vv v18, v28, v30, 2 \n\t" // v18 = N16..31
"vpack.vv v24, v16, v18, 3 \n\t" // v24 = N0..31
"lui t1, 0x00200 \n\t"
"vmv.v.x v30, t1 \n\t"
// b_scale e8m0 -> fp32
"vsetvli t0, x0, e8, mf4 \n\t"
"vwaddu.vx v28, v2, x0 \n\t"
"vsetvli t0, x0, e16, mf2 \n\t"
"vwadd.vx v2, v28, x0 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vmsle.vi v0, v2, 1 \n\t"
"vadd.vi v28, v2, -1 \n\t"
"vsll.vi v28, v28, 23 \n\t"
"vsll.vv v28, v30, v2, v0.t \n\t"
// a_scale * b_scale;
"vsetvli t0, x0, e32, m1 \n\t"
"vfcvt.f.x.v v26, v24 \n\t"
"vfmul.vf v30, v28, f0 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
// static_cast<float>(qsum) * a_scale * b_scale;
"vfmacc.vv v3, v30, v26 \n\t"
"addi t3, t3, -1 \n\t"
"bgtz t3, BLK_LPST%= \n\t"
"BLK_LPND%=: \n\t"
"vsetvli t0, %[NBLKS], e32, m1 \n\t"
"vse32.v v3, (%[pC]) \n\t"
"FUNC_END%=: \n\t"
:
: [BCK] "r"(cnt), [NBLKS] "r"(nblks), [pA] "r"(quant_a_ptr), [pB] "r"(QuantBDataPtr), [pC] "r"(CPtr)
: "cc", "memory", "t0", "t1", "t2", "t3", "t4", "f0", "s2", "s3", "s4", "s5", "s6", "s7", "v0", "v1",
"v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v16", "v17", "v18", "v19",
"v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31");
}
}
}
void gemm_kernel_i8mxfp4_m4(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
constexpr size_t NB_COLS = 32;
constexpr size_t K_TILE = 32;
using blk_type = nrow_block_mxfp4<NB_COLS>;
GGML_ASSERT(blk_len == K_TILE);
GGML_ASSERT(count_m == 4);
GGML_UNUSED(quant_b_zp);
const size_t a_blk_stride = q8_blk_size(blk_len, true);
const size_t b_blk_stride = sizeof(blk_type);
const size_t b_tile_stride = k_blks * b_blk_stride;
if (quant_b_zp == NULL) {
// MXFP4 block layout per K32/N32 tile:
// [scale_e8m0 x 32][qh sign/high-bit mask x 128B][qs packed 4-bit magnitudes x 512B]
// There is no explicit zp stream; qh is combined with qs to reconstruct signed MXFP4 values.
for (size_t ni = 0; ni < count_n; ni += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
uint8_t * b_data = (uint8_t *) quant_b_data + (ni / NB_COLS) * b_tile_stride;
uint8_t * a_data = (uint8_t *) quant_a_ptr;
float * dst_c = c_ptr + ni;
size_t cnt = k_blks;
asm volatile(
// v4-v7 are the fp32 accumulators for rows 0..3 of the current N32 tile.
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v4, v4, v4 \n\t"
"vxor.vv v5, v5, v5 \n\t"
"vxor.vv v6, v6, v6 \n\t"
"vxor.vv v7, v7, v7 \n\t"
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
// Load the 4 A-row scales for this K32 block and build row data pointers.
"flw fa0, 0(%[A]) \n\t"
"flw fa1, 4(%[A]) \n\t"
"flw fa2, 8(%[A]) \n\t"
"flw fa3, 12(%[A]) \n\t"
"addi t3, %[A], 24 \n\t"
"addi t4, t3, 32 \n\t"
"addi t5, t3, 64 \n\t"
"addi t6, t3, 96 \n\t"
"addi %[A], %[A], 152 \n\t"
// B-side pointers:
// t1 -> qh bitmask stream, t2 -> qs low-nibble stream.
"addi t1, %[B], 32 \n\t"
"addi t2, %[B], 160 \n\t"
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v2, (%[B]) \n\t"
"addi %[B], %[B], 672 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v0, (t1) \n\t"
"vl4r.v v8, (t2) \n\t"
// Decode the packed MXFP4 payload once for the whole tile and expand it
// into a vmadot-friendly layout.
"vand.vi v12, v8, 0xF \n\t"
"vand.vi v13, v9, 0xF \n\t"
"vand.vi v14, v10, 0xF \n\t"
"vand.vi v15, v11, 0xF \n\t"
"vsrl.vi v8, v8, 4 \n\t"
"vsrl.vi v9, v9, 4 \n\t"
"vsrl.vi v10, v10, 4 \n\t"
"vsrl.vi v11, v11, 4 \n\t"
"vpack.vv v16, v12, v8, 0 \n\t"
"vpack.vv v18, v13, v9, 0 \n\t"
"vpack.vv v20, v14, v10, 0 \n\t"
"vpack.vv v22, v15, v11, 0 \n\t"
"vsetvli t0, x0, e8, m8 \n\t"
"vrsub.vi v16, v16, 0, v0.t \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vupack.vv v8, v16, v17, 1 \n\t"
"vupack.vv v10, v18, v19, 1 \n\t"
"vupack.vv v12, v20, v21, 1 \n\t"
"vupack.vv v14, v22, v23, 1 \n\t"
"lui t1, 0x00200 \n\t"
"vmv.v.x v30, t1 \n\t"
// b_scale e8m0 -> fp32
"vsetvli t0, x0, e8, mf4 \n\t"
"vwaddu.vx v28, v2, x0 \n\t"
"vsetvli t0, x0, e16, mf2 \n\t"
"vwadd.vx v26, v28, x0 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vmsle.vi v0, v26, 1 \n\t"
"vadd.vi v24, v26, -1 \n\t"
"vsll.vi v18, v24, 23 \n\t"
"vsll.vv v18, v30, v26, v0.t \n\t"
// Row 0: dot(A0, decoded MXFP4 lane groups), accumulate in int32 and
// then apply A/B scaling.
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v1, (t3) \n\t"
"vsetvli t0, x0, e64, m1 \n\t"
"vupack.vv v16, v1, v2, 1 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v24, v24, v24 \n\t"
"vxor.vv v26, v26, v26 \n\t"
"vxor.vv v28, v28, v28 \n\t"
"vxor.vv v30, v30, v30 \n\t"
"vmadot v24, v16, v8, i8 \n\t"
"vmadot v26, v16, v10, i8 \n\t"
"vmadot v28, v16, v12, i8 \n\t"
"vmadot v30, v16, v14, i8 \n\t"
"vmadot v24, v17, v9, i8 \n\t"
"vmadot v26, v17, v11, i8 \n\t"
"vmadot v28, v17, v13, i8 \n\t"
"vmadot v30, v17, v15, i8 \n\t"
"vpack.vv v16, v24, v26, 2 \n\t"
"vpack.vv v20, v28, v30, 2 \n\t"
"vpack.vv v24, v16, v20, 3 \n\t"
"vpack.vv v26, v17, v21, 3 \n\t"
"vfcvt.f.x.v v24, v24 \n\t"
"vfcvt.f.x.v v25, v25 \n\t"
"vfcvt.f.x.v v26, v26 \n\t"
"vfcvt.f.x.v v27, v27 \n\t"
"vfmul.vv v24, v24, v18 \n\t"
"vfmul.vv v25, v25, v18 \n\t"
"vfmul.vv v26, v26, v18 \n\t"
"vfmul.vv v27, v27, v18 \n\t"
"vfmacc.vf v4, fa0, v24 \n\t"
"vfmacc.vf v5, fa1, v25 \n\t"
"vfmacc.vf v6, fa2, v26 \n\t"
"vfmacc.vf v7, fa3, v27 \n\t"
"addi %[BK], %[BK], -1 \n\t"
"bgtz %[BK], BLK_LOOP%= \n\t"
// Tail-aware store for the final N tile (`nb_real` may be < 32).
"vsetvli t0, %[NBLKS], e32, m1 \n\t"
"add t1, %[LDC], %[DST] \n\t"
"vse32.v v4, (%[DST]) \n\t"
"vse32.v v5, (t1) \n\t"
"add t2, t1, %[LDC] \n\t"
"vse32.v v6, (t2) \n\t"
"add t3, t2, %[LDC] \n\t"
"vse32.v v7, (t3) \n\t"
: [A] "+r"(a_data), [B] "+r"(b_data), [BK] "+r"(cnt)
: [DST] "r"(dst_c), [LDC] "r"(ldc * 4), [NBLKS] "r"(nb_real)
: "cc", "memory", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "s1", "s2", "s3", "s4", "v0", "v1", "v2",
"v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17",
"v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
"fa0", "fa1", "fa2", "fa3");
}
}
}
void gemm_kernel_i8i5_m1(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
// =========================================================================
// i8i5: 8-bit activation × 5-bit weight (4-bit low + 1-bit high mask)
//
// B layout per N32K32 k-block (no-zp):
// [0 .. 63 ] : scale_fp16 × 32 (64B)
// [64 .. 191] : Bh i1-high-bit × 32N × 32K (128B = 1 VRF)
// [192.. 703] : Bs i4-low-nibble × 32N × 32K (512B = 4 VRF)
// Total: 704B per k-block stride
//
// B layout per N32K32 k-block (with-zp):
// [0 .. 63 ] : scale_fp16 × 32 (64B)
// [64 .. 95 ] : zp_uint8 × 32 (32B)
// [96 .. 223] : Bh i1-high-bit × 32N × 32K (128B = 1 VRF)
// [224.. 735] : Bs i4-low-nibble × 32N × 32K (512B = 4 VRF)
// Total: 736B per k-block stride
//
// Bh format per N8K32 sub-block (32B):
// K rows × N cols × 1bit packed as bytes (8 cols per byte, K groups of 4B)
// Byte k gives 8 mask bits for columns N7..N0 at k-th K-element.
//
// Computation:
// B5bit_signed = (Bs | (Bh << 4)) - zp
// dot(A, B5) = dot(A, Bs_u4) + 16*dot(A, Bh_u1) - zp*asum
// No-zp: implicit zp = 16 (unsigned [0..31] centered at 16)
// With-zp: explicit zp from data
//
// =========================================================================
if (quant_b_zp == NULL) {
for (size_t n = 0; n < count_n; n += 32) {
size_t nblks = (count_n - n) > 32 ? 32 : count_n - n;
// i8i5 no-zp: per column per k-block stride = fp16(2B) + i4(16B) + i1(4B) = 22B
uint8_t * QuantBDataPtr = (uint8_t *) quant_b_data + //
n * k_blks * (blk_len / 8) + // Bh i1 mask: n×k_blks×4
n * k_blks * blk_len / 2 + // Bs i4 data: n×k_blks×16
n * k_blks * sizeof(_Float16); // scale: n×k_blks×2
float * CPtr = c_ptr + n;
size_t cnt = k_blks;
// A format (same as i8i4):
// || scl(fp32,4B) | asum(int16,2B) | data(int8,32B) || × k_blks
//
// Register map:
// t3 = k_blks loop counter t4 = nblks (tail)
// t2 = A asum (int16) << 4 f0 = A scale (fp32)
// s2 = pA (scale/asum) s3 = pA data
// s4 = pB scales (fp16×32)
// s5 = pB Bh (i1 mask, 128B)
// s6 = pB Bs (i4 packed, 512B)
// s7 = pC
// v3 = fp32 accumulator (N32)
// v2 = B scales fp16 (loaded as bytes; later widened)
// v0 = Bh mask bytes (also used as v0.t mask after load)
// v1 = A int8 (K32)
// v8..v15 / v16..v23 = Bs unpack/pack temporaries (build b5bit bytes)
// v24/v26/v28/v30 = int32 dot accumulators & packing temps
__asm__ volatile(
"mv t3, %[BCK] \n\t" // t3 = k_blks
"mv t4, %[NBLKS] \n\t" // t4 = nblks (tail guard)
// ---- pre-loop: init fp16 constants in e16 m1 context ----
"vsetvli t0, x0, e16, m1 \n\t"
"vmv.v.i v0, 1 \n\t" // v0 = int16(1)
"vfcvt.f.x.v v0, v0 \n\t" // v0 = 1.0_fp16
"vxor.vv v3, v16, v16 \n\t"
// ---- pointer setup ----
"mv s2, %[pA] \n\t" // s2 = pA (scale, fp32)
"addi s3, %[pA], 4+2 \n\t" // s3 = pA data (skip scale+asum)
"mv s4, %[pB] \n\t" // s4 = pBSCL
"addi s5, %[pB], 32*2 \n\t" // s5 = pBh (pB + 64B scale)
"addi s6, %[pB], 32*2+128 \n\t" // s6 = pBs (pB + 64 + 128 = pB+192)
"mv s7, %[pC] \n\t" // s7 = pC
// =====================================================================
// K-block loop: each iteration processes one N32×K32 block
// Stride per k-block = 704B = 64(scl) + 512(Bs) + 128(Bh)
// =====================================================================
".align 4 \n\t"
"BLK_LPST%=: \n\t"
// ---- load Bs (512B = 4 VRF) from s6, advance s6 by 704 ----
"vsetvli t0, x0, e8, m1 \n\t"
"vl4r.v v8, (s6) \n\t" // v8..v11 = Bs N32K32 i4
"addi s6, s6, 128*4+128+64 \n\t" // s6 += 704 (512+128+64)
// ---- load B scale (64B = 32×fp16) from s4, advance s4 by 704 ----
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v2, (s4) \n\t" // v2 = scale_fp16 × 32
"addi s4, s4, 64+128*4+128 \n\t" // s4 += 704 (64+512+128)
// ---- load Bh (128B = 1 VRF) from s5, advance s5 by 704 ----
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v0, (s5) \n\t" // v0 = Bh N32K32 1-bit packed
"addi s5, s5, 128+64+128*4 \n\t" // s5 += 704 (128+64+512)
// ---- load A data (32B = K32 int8) from s3 ----
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v1, (s3) \n\t" // v1 = A M1K32 int8
"addi s3, s3, 32+6 \n\t" // s3 += 38 (data + scl + asum)
// ---- load A scale (fp32) and asum (int16) from s2 ----
"flw f0, (s2) \n\t" // f0 = A scale (fp32)
"lh t2, 4(s2) \n\t" // t2 = A asum (int16)
"addi s2, s2, 6+32 \n\t" // s2 += 38
//// ---- A nibble unpacking ----
"vsetvli t0, x0, e8, m1 \n\t"
"vand.vi v12, v8, 0xF \n\t" //8bit(lo4) //[8*32]
"vand.vi v13, v9, 0xF \n\t"
"vand.vi v14, v10, 0xF \n\t"
"vand.vi v15, v11, 0xF \n\t"
"vsrl.vi v8, v8, 4 \n\t" //8bit(hi4)
"vsrl.vi v9, v9, 4 \n\t"
"vsrl.vi v10, v10, 4 \n\t"
"vsrl.vi v11, v11, 4 \n\t"
"slli t2, t2, 4 \n\t" // a_sum * 16;
// [4*32]*2
"vsetvli t0, x0, e8, m1 \n\t"
"vpack.vv v16, v12, v8, 0 \n\t"
"vpack.vv v18, v13, v9, 0 \n\t"
"vpack.vv v20, v14, v10, 0 \n\t"
"vpack.vv v22, v15, v11, 0 \n\t"
"li t1, 16 \n\t"
"vsetvli t0, x0, e8, m8 \n\t"
"vadd.vx v16, v16, t1, v0.t \n\t"
// [4*32]*2 -> [8*16]
"vsetvli t0, x0, e8, m1 \n\t"
"vupack.vv v8, v16, v17, 1 \n\t"
"vupack.vv v10, v18, v19, 1 \n\t"
"vupack.vv v12, v20, v21, 1 \n\t"
"vupack.vv v14, v22, v23, 1 \n\t"
"vsetvli t0, x0, e64, m1 \n\t"
"vslidedown.vi v16, v1, 2 \n\t"
// init the accumu to asum * zp
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v24, v16, v16 \n\t"
"vxor.vv v26, v16, v16 \n\t"
"vxor.vv v28, v16, v16 \n\t"
"vxor.vv v30, v16, v16 \n\t"
// ---- i8 main dot products ----
// vmadot: A × unsigned Bh × 16 → fp16 accumulate
"vmadot v24, v1, v8, i8 \n\t" // N0..7
"vmadot v26, v1, v10, i8 \n\t" // N8..15
"vmadot v28, v1, v12, i8 \n\t" // N16..23
"vmadot v30, v1, v14, i8 \n\t" // N24..31
//// vmadot: A × unsigned Bh × 1 → fp16 accumulate
"vmadot v24, v16, v9, i8 \n\t" // N0..7
"vmadot v26, v16, v11, i8 \n\t" // N8..15
"vmadot v28, v16, v13, i8 \n\t" // N16..23
"vmadot v30, v16, v15, i8 \n\t" // N24..31
"vsetvli t0, x0, e32, m1 \n\t"
"vpack.vv v16, v24, v26, 2 \n\t" // v16 = N0..15
"vpack.vv v18, v28, v30, 2 \n\t" // v18 = N16..31
"vpack.vv v24, v16, v18, 3 \n\t" // v24 = N0..31
"vadd.vx v24, v24, t2 \n\t"
// b_scale fp16 -> fp32
"vsetvli t0, x0, e16, mf2 \n\t"
"vfwcvt.f.f.v v28, v2 \n\t"
// a_scale * b_scale;
"vsetvli t0, x0, e32, m1 \n\t"
"vfcvt.f.x.v v26, v24 \n\t"
"vfmul.vf v30, v28, f0 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
// static_cast<float>(qsum) * a_scale * b_scale;
"vfmacc.vv v3, v30, v26 \n\t"
"addi t3, t3, -1 \n\t"
"bgtz t3, BLK_LPST%= \n\t"
"BLK_LPND%=: \n\t"
"vsetvli t0, %[NBLKS], e32, m1 \n\t"
"vse32.v v3, (%[pC]) \n\t"
"FUNC_END%=: \n\t"
:
: [BCK] "r"(cnt), [NBLKS] "r"(nblks), [pA] "r"(quant_a_ptr), [pB] "r"(QuantBDataPtr), [pC] "r"(CPtr)
: "cc", "memory", "t0", "t1", "t2", "t3", "t4", "f0", "s2", "s3", "s4", "s5", "s6", "s7", "v0", "v1",
"v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v16", "v17", "v18", "v19",
"v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31");
}
} else {
for (size_t n = 0; n < count_n; n += 32) {
size_t nblks = (count_n - n) > 32 ? 32 : count_n - n;
// i8i5 with-zp: per column per k-block stride = fp16(2B)+zp(1B)+i4(16B)+i1(4B)=23B
uint8_t * QuantBDataPtr = (uint8_t *) quant_b_data + //
n * k_blks * blk_len / 2 + // Bs i4: n×k_blks×16
n * k_blks * (blk_len / 8) + // Bh i1: n×k_blks×4
n * k_blks * sizeof(uint8_t) + // zp: n×k_blks×1
n * k_blks * sizeof(_Float16); // scale: n×k_blks×2
float * CPtr = c_ptr + n;
size_t cnt = k_blks;
// A format (same as i8i4):
// || scl(fp32,4B) | asum(int16,2B) | data(int8,32B) || × k_blks
//
// Register map:
// t3 = k_blks loop counter t4 = nblks (tail)
// t2 = A asum (int16) << 4 f0 = A scale (fp32)
// s2 = pA (scale/asum) s3 = pA data
// s4 = pB scales (fp16×32); 每个 k-block 先 +64 指向 zp,再 +672 到下一个 block
// s5 = pB Bh (i1 mask, 128B) (offset +96)
// s6 = pB Bs (i4 packed, 512B) (offset +224)
// s7 = pC
// v3 = fp32 accumulator (N32)
// v2 = B scales fp16 (loaded as bytes; later widened)
// v0 = Bh mask bytes (also used as v0.t mask after load)
// v1 = A int8 (K32) / later reused to hold Bzp bytes
// v8..v15 / v16..v23 = Bs unpack/pack temporaries (build b5bit bytes)
// v24/v26/v28/v30 = int32 dot accumulators & packing temps
__asm__ volatile(
"mv t3, %[BCK] \n\t" // t3 = k_blks
"mv t4, %[NBLKS] \n\t" // t4 = nblks (tail guard)
// ---- pre-loop: init fp16 constants in e16 m1 context ----
"vsetvli t0, x0, e16, m1 \n\t"
"vmv.v.i v0, 1 \n\t" // v0 = int16(1)
"vfcvt.f.x.v v0, v0 \n\t" // v0 = 1.0_fp16
"vxor.vv v3, v16, v16 \n\t"
// ---- pointer setup ----
"mv s2, %[pA] \n\t" // s2 = pA (scale, fp32)
"addi s3, %[pA], 4+2 \n\t" // s3 = pA data (skip scale+asum)
"mv s4, %[pB] \n\t" // s4 = pBSCL
"addi s5, %[pB], 32*3 \n\t" // s5 = pBh (pB + 64B scale + 32B zp = pB+96)
"addi s6, %[pB], 32*3+128 \n\t" // s6 = pBs (pB + 96 + 128 = pB+224)
"mv s7, %[pC] \n\t" // s7 = pC
// =====================================================================
// K-block loop: each iteration processes one N32×K32 block
// Stride per k-block = 736B = 64(scale) + 32(zp) + 128(Bh) + 512(Bs)
// =====================================================================
".align 4 \n\t"
"BLK_LPST%=: \n\t"
// ---- load Bs (512B = 4 VRF) from s6, advance s6 by 736 ----
"vsetvli t0, x0, e8, m1 \n\t"
"vl4r.v v8, (s6) \n\t" // v8..v11 = Bs N32K32 i4
"addi s6, s6, 128*4+128+96 \n\t" // s6 += 736 (512+128+96)
// ---- load B scale (64B = 32×fp16) from s4; then s4 points to zp[32] ----
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v2, (s4) \n\t" // v2 = scale_fp16 × 32
"addi s4, s4, 64 \n\t" // s4 += 64 (now points to zp)
// ---- load Bh (128B = 1 VRF) from s5, advance s5 by 736 ----
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v0, (s5) \n\t" // v0 = Bh N32K32 1-bit packed
"addi s5, s5, 128+96+128*4 \n\t" // s5 += 736 (128+96+512)
// ---- load A data (32B = K32 int8) from s3 ----
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v1, (s3) \n\t" // v1 = A M1K32 int8
"addi s3, s3, 32+6 \n\t" // s3 += 38 (data + scl + asum)
// ---- load A scale (fp32) and asum (int16) from s2 ----
"flw f0, (s2) \n\t" // f0 = A scale (fp32)
"lh t2, 4(s2) \n\t" // t2 = A asum (int16)
"addi s2, s2, 6+32 \n\t" // s2 += 38
//// ---- A nibble unpacking ----
"vsetvli t0, x0, e8, m1 \n\t"
"vand.vi v12, v8, 0xF \n\t" //8bit(lo4) //[8*32]
"vand.vi v13, v9, 0xF \n\t"
"vand.vi v14, v10, 0xF \n\t"
"vand.vi v15, v11, 0xF \n\t"
"vsrl.vi v8, v8, 4 \n\t" //8bit(hi4)
"vsrl.vi v9, v9, 4 \n\t"
"vsrl.vi v10, v10, 4 \n\t"
"vsrl.vi v11, v11, 4 \n\t"
// [4*32]*2
"vsetvli t0, x0, e8, m1 \n\t"
"vpack.vv v16, v12, v8, 0 \n\t"
"vpack.vv v18, v13, v9, 0 \n\t"
"vpack.vv v20, v14, v10, 0 \n\t"
"vpack.vv v22, v15, v11, 0 \n\t"
"li t1, 16 \n\t"
"vsetvli t0, x0, e8, m8 \n\t"
"vadd.vx v16, v16, t1, v0.t \n\t"
// [4*32]*2 -> [8*16]
"vsetvli t0, x0, e8, m1 \n\t"
"vupack.vv v8, v16, v17, 1 \n\t"
"vupack.vv v10, v18, v19, 1 \n\t"
"vupack.vv v12, v20, v21, 1 \n\t"
"vupack.vv v14, v22, v23, 1 \n\t"
"vsetvli t0, x0, e64, m1 \n\t"
"vslidedown.vi v16, v1, 2 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v24, v16, v16 \n\t"
"vxor.vv v26, v16, v16 \n\t"
"vxor.vv v28, v16, v16 \n\t"
"vxor.vv v30, v16, v16 \n\t"
// ---- i8 main dot products ----
// vmadot: A × unsigned Bh × 16 → fp16 accumulate
"vmadot v24, v1, v8, i8 \n\t" // N0..7
"vmadot v26, v1, v10, i8 \n\t" // N8..15
"vmadot v28, v1, v12, i8 \n\t" // N16..23
"vmadot v30, v1, v14, i8 \n\t" // N24..31
// vmadot: A × unsigned Bh × 1 → fp16 accumulate
"vmadot v24, v16, v9, i8 \n\t" // N0..7
"vmadot v26, v16, v11, i8 \n\t" // N8..15
"vmadot v28, v16, v13, i8 \n\t" // N16..23
"vmadot v30, v16, v15, i8 \n\t" // N24..31
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v1, (s4) \n\t" // Bzp
"addi s4, s4, 32+128*4+128 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vpack.vv v16, v24, v26, 2 \n\t" // v16 = N0..15
"vpack.vv v18, v28, v30, 2 \n\t" // v18 = N16..31
"vpack.vv v24, v16, v18, 3 \n\t" // v24 = N0..31
"vwaddu.vx v28, v1, x0 \n\t" // uint8 -> uint16
"vsetvli t0, x0, e16, m1 \n\t"
"vwmul.vx v30, v28, t2 \n\t"
// b_scale fp16 -> fp32
"vsetvli t0, x0, e16, mf2 \n\t"
"vfwcvt.f.f.v v28, v2 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vadd.vv v24, v24, v30 \n\t"
// a_scale * b_scale;
"vsetvli t0, x0, e32, m1 \n\t"
"vfmul.vf v30, v28, f0 \n\t"
"vfcvt.f.x.v v26, v24 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
// static_cast<float>(qsum) * a_scale * b_scale;
"vfmacc.vv v3, v30, v26 \n\t"
"addi t3, t3, -1 \n\t"
"bgtz t3, BLK_LPST%= \n\t"
"BLK_LPND%=: \n\t"
"vsetvli t0, %[NBLKS], e32, m1 \n\t"
"vse32.v v3, (%[pC]) \n\t"
"FUNC_END%=: \n\t"
:
: [BCK] "r"(cnt), [NBLKS] "r"(nblks), [pA] "r"(quant_a_ptr), [pB] "r"(QuantBDataPtr), [pC] "r"(CPtr)
: "cc", "memory", "t0", "t1", "t2", "t3", "t4", "f0", "s2", "s3", "s4", "s5", "s6", "s7", "v0", "v1",
"v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v16", "v17", "v18", "v19",
"v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31");
}
}
}
void gemm_kernel_i8i5_m4(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
constexpr size_t NB_COLS = 32;
GGML_UNUSED(count_m);
GGML_UNUSED(blk_len);
// This kernel computes a 4x32 output tile. For each K32 block we decode the
// packed Q5 weights once and reuse the decoded vectors across the 4 A rows.
constexpr size_t B_Q50_BLK_STRIDE = sizeof(nrow_block_q5_0<NB_COLS>);
constexpr size_t B_Q51_BLK_STRIDE = sizeof(nrow_block_q5_1<NB_COLS>);
if (quant_b_zp) {
// Q5_1 block layout per K32/N32 tile:
// [scale_fp16 x 32][zp_u8 x 32][qh high-bit mask x 128B][qs low nibbles x 512B]
for (size_t ni = 0; ni < count_n; ni += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
uint8_t * b_data = (uint8_t *) quant_b_data + (ni / NB_COLS) * k_blks * B_Q51_BLK_STRIDE;
uint8_t * a_data = (uint8_t *) quant_a_ptr;
float * dst_c = c_ptr + ni;
size_t cnt = k_blks;
asm volatile(
// v4-v7 are the fp32 accumulators for rows 0..3 of the current N32 tile.
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v4, v4, v4 \n\t"
"vxor.vv v5, v5, v5 \n\t"
"vxor.vv v6, v6, v6 \n\t"
"vxor.vv v7, v7, v7 \n\t"
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
// Load the 4 A-row scales/sums for this K32 block and build row data pointers.
"flw fa0, 0(%[A]) \n\t"
"flw fa1, 4(%[A]) \n\t"
"flw fa2, 8(%[A]) \n\t"
"flw fa3, 12(%[A]) \n\t"
"lh s1, 16(%[A]) \n\t"
"lh s2, 18(%[A]) \n\t"
"lh s3, 20(%[A]) \n\t"
"lh s4, 22(%[A]) \n\t"
"addi t3, %[A], 24 \n\t"
"addi t4, t3, 32 \n\t"
"addi t5, t3, 64 \n\t"
"addi t6, t3, 96 \n\t"
"addi %[A], %[A], 152 \n\t"
// B-side pointers:
// t1 -> zp stream, t2 -> qh bitmask stream, s5 -> qs low-nibble stream.
"addi t1, %[B], 64 \n\t"
"addi t2, %[B], 96 \n\t"
"addi s5, %[B], 224 \n\t"
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v2, (%[B]) \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v0, (t2) \n\t"
"vl4r.v v8, (s5) \n\t"
"addi %[B], %[B], 736 \n\t"
// Decode Q5 payload once for the whole tile:
// 1) split `qs` low/high nibbles,
// 2) repack into bytes,
// 3) use the `qh` mask to inject bit4 (+16) where needed,
// 4) expand into the vmadot-friendly layout reused by all 4 rows.
"vand.vi v12, v8, 0xF \n\t"
"vand.vi v13, v9, 0xF \n\t"
"vand.vi v14, v10, 0xF \n\t"
"vand.vi v15, v11, 0xF \n\t"
"vsrl.vi v8, v8, 4 \n\t"
"vsrl.vi v9, v9, 4 \n\t"
"vsrl.vi v10, v10, 4 \n\t"
"vsrl.vi v11, v11, 4 \n\t"
"vpack.vv v16, v12, v8, 0 \n\t"
"vpack.vv v18, v13, v9, 0 \n\t"
"li t2, 16 \n\t"
"vpack.vv v20, v14, v10, 0 \n\t"
"vpack.vv v22, v15, v11, 0 \n\t"
"vsetvli t0, x0, e8, m8 \n\t"
"vadd.vx v16, v16, t2, v0.t \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vupack.vv v8, v16, v17, 1 \n\t"
"vupack.vv v10, v18, v19, 1 \n\t"
"vupack.vv v12, v20, v21, 1 \n\t"
"vupack.vv v14, v22, v23, 1 \n\t"
// Convert per-column fp16 scales once; the same scale vector is shared by all 4 rows.
"vsetvli t0, x0, e16, mf2 \n\t"
"vfwcvt.f.f.v v18, v2 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v3, (t1) \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
// Row 0: dot(A0, decoded_q5) + a_sum0 * zp, then scale by A/B scales.
// The widen/mul correction sequence intentionally matches the proven m1 Q5_1 path.
"vle8.v v1, (t3) \n\t"
"vsetvli t0, x0, e64, m1 \n\t"
"vupack.vv v16, v1, v2, 1 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v24, v24, v24 \n\t"
"vxor.vv v26, v26, v26 \n\t"
"vxor.vv v28, v28, v28 \n\t"
"vxor.vv v30, v30, v30 \n\t"
"vmadot v24, v16, v8, i8 \n\t"
"vmadot v26, v16, v10, i8 \n\t"
"vmadot v28, v16, v12, i8 \n\t"
"vmadot v30, v16, v14, i8 \n\t"
"vmadot v24, v17, v9, i8 \n\t"
"vmadot v26, v17, v11, i8 \n\t"
"vmadot v28, v17, v13, i8 \n\t"
"vmadot v30, v17, v15, i8 \n\t"
"vpack.vv v16, v24, v26, 2 \n\t"
"vpack.vv v20, v28, v30, 2 \n\t"
"vpack.vv v24, v16, v20, 3 \n\t"
"vpack.vv v26, v17, v21, 3 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vwaddu.vx v28, v3, x0 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vwmul.vx v12, v28, s1 \n\t"
"vwmul.vx v14, v28, s2 \n\t"
"vwmul.vx v20, v28, s3 \n\t"
"vwmul.vx v22, v28, s4 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vadd.vv v24, v24, v12 \n\t"
"vadd.vv v25, v25, v14 \n\t"
"vadd.vv v26, v26, v20 \n\t"
"vadd.vv v27, v27, v22 \n\t"
"vfcvt.f.x.v v12, v24 \n\t"
"vfcvt.f.x.v v14, v25 \n\t"
"vfcvt.f.x.v v20, v26 \n\t"
"vfcvt.f.x.v v22, v27 \n\t"
"vfmul.vv v12, v12, v18 \n\t"
"vfmul.vv v14, v14, v18 \n\t"
"vfmul.vv v20, v20, v18 \n\t"
"vfmul.vv v22, v22, v18 \n\t"
"vfmacc.vf v4, fa0, v12 \n\t"
"vfmacc.vf v5, fa1, v14 \n\t"
"vfmacc.vf v6, fa2, v20 \n\t"
"vfmacc.vf v7, fa3, v22 \n\t"
"addi %[BK], %[BK], -1 \n\t"
"bgtz %[BK], BLK_LOOP%= \n\t"
// Tail-aware store for the final N tile (`nb_real` may be < 32).
"vsetvli t0, %[NBLKS], e32, m1 \n\t"
"add t1, %[LDC], %[DST] \n\t"
"vse32.v v4, (%[DST]) \n\t"
"vse32.v v5, (t1) \n\t"
"add t2, t1, %[LDC] \n\t"
"vse32.v v6, (t2) \n\t"
"add t3, t2, %[LDC] \n\t"
"vse32.v v7, (t3) \n\t"
: [A] "+r"(a_data), [B] "+r"(b_data), [BK] "+r"(cnt)
: [DST] "r"(dst_c), [LDC] "r"(ldc * 4), [NBLKS] "r"(nb_real)
: "cc", "memory", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "s1", "s2", "s3", "s4", "s5", "v0", "v1",
"v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16",
"v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30",
"v31", "fa0", "fa1", "fa2", "fa3");
}
} else {
// Q5_0 block layout per K32/N32 tile:
// [scale_fp16 x 32][qh high-bit mask x 128B][qs low nibbles x 512B]
// There is no explicit zp stream; the implicit midpoint correction is +16.
for (size_t ni = 0; ni < count_n; ni += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
uint8_t * b_data = (uint8_t *) quant_b_data + (ni / NB_COLS) * k_blks * B_Q50_BLK_STRIDE;
uint8_t * a_data = (uint8_t *) quant_a_ptr;
float * dst_c = c_ptr + ni;
size_t cnt = k_blks;
asm volatile(
// v4-v7 are the fp32 accumulators for rows 0..3 of the current N32 tile.
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v4, v4, v4 \n\t"
"vxor.vv v5, v5, v5 \n\t"
"vxor.vv v6, v6, v6 \n\t"
"vxor.vv v7, v7, v7 \n\t"
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
// Load the 4 A-row scales/sums for this K32 block and build row data pointers.
"flw fa0, 0(%[A]) \n\t"
"flw fa1, 4(%[A]) \n\t"
"flw fa2, 8(%[A]) \n\t"
"flw fa3, 12(%[A]) \n\t"
"lh s1, 16(%[A]) \n\t"
"lh s2, 18(%[A]) \n\t"
"lh s3, 20(%[A]) \n\t"
"lh s4, 22(%[A]) \n\t"
"addi t3, %[A], 24 \n\t"
"addi t4, t3, 32 \n\t"
"addi t5, t3, 64 \n\t"
"addi t6, t3, 96 \n\t"
"addi %[A], %[A], 152 \n\t"
// B-side pointers:
// t1 -> qh bitmask stream, t2 -> qs low-nibble stream.
"addi t1, %[B], 64 \n\t"
"addi t2, %[B], 192 \n\t"
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v2, (%[B]) \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v0, (t1) \n\t"
"vl4r.v v8, (t2) \n\t"
"addi %[B], %[B], 704 \n\t"
// Decode Q5 payload once for the whole tile and expand it into the vmadot layout.
"vand.vi v12, v8, 0xF \n\t"
"vand.vi v13, v9, 0xF \n\t"
"vand.vi v14, v10, 0xF \n\t"
"vand.vi v15, v11, 0xF \n\t"
"vsrl.vi v8, v8, 4 \n\t"
"vsrl.vi v9, v9, 4 \n\t"
"vsrl.vi v10, v10, 4 \n\t"
"vsrl.vi v11, v11, 4 \n\t"
"vpack.vv v16, v12, v8, 0 \n\t"
"vpack.vv v18, v13, v9, 0 \n\t"
"li t2, 16 \n\t"
"vpack.vv v20, v14, v10, 0 \n\t"
"vpack.vv v22, v15, v11, 0 \n\t"
"vsetvli t0, x0, e8, m8 \n\t"
"vadd.vx v16, v16, t2, v0.t \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vupack.vv v8, v16, v17, 1 \n\t"
"vupack.vv v10, v18, v19, 1 \n\t"
"vupack.vv v12, v20, v21, 1 \n\t"
"vupack.vv v14, v22, v23, 1 \n\t"
// Convert per-column fp16 scales once; the same scale vector is shared by all 4 rows.
"vsetvli t0, x0, e16, mf2 \n\t"
"vfwcvt.f.f.v v18, v2 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
// Row 0: dot(A0, decoded_q5) + a_sum0 * 16 (implicit Q5_0 midpoint correction).
"vle8.v v1, (t3) \n\t"
"vsetvli t0, x0, e64, m1 \n\t"
"vupack.vv v16, v1, v2, 1 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v24, v24, v24 \n\t"
"vxor.vv v26, v26, v26 \n\t"
"vxor.vv v28, v28, v28 \n\t"
"vxor.vv v30, v30, v30 \n\t"
"vmadot v24, v16, v8, i8 \n\t"
"vmadot v26, v16, v10, i8 \n\t"
"vmadot v28, v16, v12, i8 \n\t"
"vmadot v30, v16, v14, i8 \n\t"
"vmadot v24, v17, v9, i8 \n\t"
"vmadot v26, v17, v11, i8 \n\t"
"vmadot v28, v17, v13, i8 \n\t"
"vmadot v30, v17, v15, i8 \n\t"
"vpack.vv v16, v24, v26, 2 \n\t"
"slli s1, s1, 4 \n\t"
"vpack.vv v20, v28, v30, 2 \n\t"
"slli s2, s2, 4 \n\t"
"vpack.vv v24, v16, v20, 3 \n\t"
"slli s3, s3, 4 \n\t"
"vpack.vv v26, v17, v21, 3 \n\t"
"slli s4, s4, 4 \n\t"
"vadd.vx v24, v24, s1 \n\t"
"vadd.vx v25, v25, s2 \n\t"
"vadd.vx v26, v26, s3 \n\t"
"vadd.vx v27, v27, s4 \n\t"
"vfcvt.f.x.v v24, v24 \n\t"
"vfcvt.f.x.v v25, v25 \n\t"
"vfcvt.f.x.v v26, v26 \n\t"
"vfcvt.f.x.v v27, v27 \n\t"
"vfmul.vv v24, v24, v18 \n\t"
"vfmul.vv v25, v25, v18 \n\t"
"vfmul.vv v26, v26, v18 \n\t"
"vfmul.vv v27, v27, v18 \n\t"
"vfmacc.vf v4, fa0, v24 \n\t"
"vfmacc.vf v5, fa1, v25 \n\t"
"vfmacc.vf v6, fa2, v26 \n\t"
"vfmacc.vf v7, fa3, v27 \n\t"
"addi %[BK], %[BK], -1 \n\t"
"bgtz %[BK], BLK_LOOP%= \n\t"
// Tail-aware store for the final N tile (`nb_real` may be < 32).
"vsetvli t0, %[NBLKS], e32, m1 \n\t"
"add t1, %[LDC], %[DST] \n\t"
"vse32.v v4, (%[DST]) \n\t"
"vse32.v v5, (t1) \n\t"
"add t2, t1, %[LDC] \n\t"
"vse32.v v6, (t2) \n\t"
"add t3, t2, %[LDC] \n\t"
"vse32.v v7, (t3) \n\t"
: [A] "+r"(a_data), [B] "+r"(b_data), [BK] "+r"(cnt)
: [DST] "r"(dst_c), [LDC] "r"(ldc * 4), [NBLKS] "r"(nb_real)
: "cc", "memory", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "s1", "s2", "s3", "s4", "v0", "v1", "v2",
"v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17",
"v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
"fa0", "fa1", "fa2", "fa3");
}
}
}
void gemm_kernel_i8i8_m1(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
for (size_t n = 0; n < count_n; n += 32) {
size_t nblks = (count_n - n) > 32 ? 32 : count_n - n;
uint8_t * QuantBDataPtr = (uint8_t *) quant_b_data + //
n * k_blks * blk_len + // b data
n * k_blks * sizeof(_Float16); // scale
float * CPtr = c_ptr + n;
size_t cnt = k_blks;
// A format Version_1 (FP32 SCALE FOR Normal VMADOTins of IME2)
// A M1K32 int8 256bit
// Ascale fp32 * 1 32bit
// || scl*1(fp32) | Asum(int16) | blk0 || scl*1(fp32) | Asum(int16) | blk0 || ...
// || Element || Element || ...
// B format
// B N8K32 int4 2048bit
// 4VRF, N32K32, 8192bit
// Bscale fp16 * N32 512bit;
// || scl*32..(fp16) | blk0 blk1 ... blk31 || scl*32..(fp16) | blk0 blk1 ... blk31 || ...
// || Element || Element || ...
//bias always be nullptr
__asm__ volatile(
// t3 = k/32
"mv t3, %[BCK] \n\t"
"mv t4, %[NBLKS] \n\t"
"mv s2, %[pA] \n\t" // s2 = pASCL
"addi s3, %[pA], 4+2 \n\t" // s3 = pAData, (pA+AScl+ASum)
"mv s4, %[pB] \n\t" // s4 = pBSCL
"addi s5, %[pB], 32*2 \n\t" // s5 = pBdata;
"mv s6, %[pC] \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v2, v0, v0 \n\t" // clear acc
// ordinary vmadot: vle*6 flw*1 vecIns*64 vmadot*8
".align 4 \n\t"
"_K_LPST%=: \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vl4r.v v4, (s5) \n\t" // B Data 4VRF * 8Row * 32
"addi s5, s5, 128*4 \n\t"
"vl4r.v v8, (s5) \n\t" // B Data 4VRF * 8Row * 32
"addi s5, s5, 128*4+64 \n\t"
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v0, (s4) \n\t" // B Scale 4VRF*8Row*FP16 = 512bit
"addi s4, s4, 64+128*8 \n\t"
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v3, (s3) \n\t" // A Data M1*K32*int8 = 256bit
"addi s3, s3, 32+6 \n\t"
"flw f0, (s2) \n\t" // A Scale fp32
"addi s2, s2, 6+32 \n\t" // AScale + Asum(FP32+i16)
"vsetvli t0, zero, e32, m1 \n\t"
"vupack.vv v24, v4, v5, 1 \n\t"
"vupack.vv v26, v6, v7, 1 \n\t"
"vupack.vv v28, v8, v9, 1 \n\t"
"vupack.vv v30, v10, v11, 1 \n\t"
"vslidedown.vi v4, v3, 4 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
"vmadot v16, v3, v24, i8 \n\t" // M0 N0 - N7 INT32(256bit)
"vmadot v18, v3, v26, i8 \n\t" // M0 N8 - N15
"vmadot v20, v3, v28, i8 \n\t" // M0 N16 - N23
"vmadot v22, v3, v30, i8 \n\t" // M0 N24 - N31
"vmadot v16, v4, v25, i8 \n\t"
"vmadot v18, v4, v27, i8 \n\t"
"vmadot v20, v4, v29, i8 \n\t"
"vmadot v22, v4, v31, i8 \n\t"
"vpack.vv v24, v16, v18, 2 \n\t"
"vpack.vv v26, v20, v22, 2 \n\t"
"vpack.vv v16, v24, v26, 3 \n\t"
// b_scale fp16 -> fp32
"vsetvli t0, x0, e16, mf2 \n\t"
"vfwcvt.f.f.v v24, v0 \n\t"
// mac result i32 -> fp32
"vsetvli t0, x0, e32, m1 \n\t"
"vfcvt.f.x.v v26, v16 \n\t"
// a_scale * b_scale;
"vfmul.vf v1, v24, f0 \n\t"
// static_cast<float>(qsum) * a_scale * b_scale;
"vfmacc.vv v2, v1, v26 \n\t"
"addi t3, t3, -1 \n\t"
"bgtz t3, _K_LPST%= \n\t"
"_K_LPND%=: \n\t"
//-----------------------------------------
// STORE Equal 32N-------------------------
"_ST32%=: \n\t"
"vsetvli t0, t4, e32, m1 \n\t"
"vse32.v v2, (s6) \n\t" // M0 [N0 : N32]; FP32(1024bit)
"_FUNC_END%=: \n\t"
:
: [BCK] "r"(cnt), [NBLKS] "r"(nblks), [pA] "r"(quant_a_ptr), [pB] "r"(QuantBDataPtr), [pC] "r"(CPtr)
: "cc", "t0", "t3", "t4", "f0", "s2", "s3", "s4", "s5", "s6");
}
}
void gemm_kernel_i8i8_m4(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
int64_t b_data_stride = k_blks * sizeof(ggml_fp16_t) + k_blks * blk_len;
for (size_t ni = 0; ni < count_n; ni += 32) {
uint8_t * b_data = (uint8_t *) quant_b_data + ni * b_data_stride;
int8_t * a_data = (int8_t *) quant_a_ptr;
float * dst_c = c_ptr + ni;
asm volatile(
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v28, v28, v28 \n\t"
"vxor.vv v29, v29, v29 \n\t"
"vxor.vv v30, v30, v30 \n\t"
"vxor.vv v31, v31, v31 \n\t"
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
// load scale A
"flw fa0, (%[A]) \n\t"
"flw fa1, 4(%[A]) \n\t"
"flw fa2, 8(%[A]) \n\t"
"flw fa3, 12(%[A]) \n\t"
"addi %[A], %[A], 16+8 \n\t" // Ascl+Asum; FP32*4+i16*4
// load scale B
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v12, (%[B]) \n\t"
"addi %[B], %[B], 64 \n\t"
"vfwcvt.f.f.v v14, v12 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vl1r.v v0, (%[A]) \n\t"
"addi %[A], %[A], 128 \n\t" // 4*32@i8
"vl4r.v v4, (%[B]) \n\t" // 32*32@i8
"addi %[B], %[B], 512 \n\t"
"vl4r.v v8, (%[B]) \n\t" // 32*32@i8
"addi %[B], %[B], 512 \n\t"
"vsetvli t0, zero, e32, m1 \n\t"
"vupack.vv v2, v0, v0, 1 \n\t"
"vupack.vv v24, v4, v5, 1 \n\t"
"vupack.vv v26, v6, v7, 1 \n\t"
"vupack.vv v4, v8, v9, 1 \n\t"
"vupack.vv v6, v10, v11, 1 \n\t"
// init the accumu to asum * zp
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v16, v16, v16 \n\t"
"vxor.vv v18, v16, v16 \n\t"
"vxor.vv v20, v16, v16 \n\t"
"vxor.vv v22, v16, v16 \n\t"
// i4 * i4 vmadot
"vsetvli t0, x0, e32, m1 \n\t"
"vmadot v16, v2, v24, i8 \n\t"
"vmadot v18, v2, v26, i8 \n\t"
"vmadot v20, v2, v4, i8 \n\t"
"vmadot v22, v2, v6, i8 \n\t"
"vmadot v16, v3, v25, i8 \n\t"
"vmadot v18, v3, v27, i8 \n\t"
"vmadot v20, v3, v5, i8 \n\t"
"vmadot v22, v3, v7, i8 \n\t"
"vpack.vv v0, v16, v18, 2 \n\t"
"vpack.vv v2, v20, v22, 2 \n\t"
"vpack.vv v16, v0, v2, 3 \n\t"
"vpack.vv v18, v1, v3, 3 \n\t"
"vfcvt.f.x.v v16, v16 \n\t"
"vfcvt.f.x.v v17, v17 \n\t"
"vfcvt.f.x.v v18, v18 \n\t"
"vfcvt.f.x.v v19, v19 \n\t"
// mul scale
"vfmul.vv v16, v16, v14 \n\t"
"vfmul.vv v17, v17, v14 \n\t"
"vfmul.vv v18, v18, v14 \n\t"
"vfmul.vv v19, v19, v14 \n\t"
"addi %[BK], %[BK], -1 \n\t"
"vfmacc.vf v28, fa0, v16 \n\t"
"vfmacc.vf v29, fa1, v17 \n\t"
"vfmacc.vf v30, fa2, v18 \n\t"
"vfmacc.vf v31, fa3, v19 \n\t"
"bgtz %[BK], BLK_LOOP%= \n\t"
// save
"vsetvli t0, x0, e32, m1 \n\t"
"add t2, %[LDC], %[DST] \n\t"
"vse32.v v28, (%[DST]) \n\t"
"add t3, %[LDC], t2 \n\t"
"vse32.v v29, (t2) \n\t"
"add t2, %[LDC], t3 \n\t"
"vse32.v v30, (t3) \n\t"
"vse32.v v31, (t2) \n\t"
: [A] "+r"(a_data), [B] "+r"(b_data)
: [DST] "r"(dst_c), [LDC] "r"(ldc * 4), [BK] "r"(k_blks)
: "t0", "t1", "t2", "t3", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12",
"v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27",
"v28", "v29", "v30", "v31", "fa0", "fa1", "fa2", "fa3");
}
}
void moe_m2_gemm_kernel_i8i4_impl(size_t blk_len,
const uint8_t ** quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float ** c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
#if 0
moe_gemm_kernel_i8i4_mrow_ref<2, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks,
ldc);
#else
int64_t b_data_stride =
k_blks * (sizeof(ggml_fp16_t) + 16 * sizeof(int8_t) + (quant_b_zp != NULL ? sizeof(int8_t) : 0));
if (quant_b_zp == NULL) {
for (size_t ni = 0; ni < count_n; ni += 32) {
uint8_t * b_data = (uint8_t *) quant_b_data + ni * b_data_stride;
int8_t * a_data0 = (int8_t *) quant_a_ptr[0];
int8_t * a_data1 = (int8_t *) quant_a_ptr[1];
float * dst_c0 = (float *) c_ptr[0] + ni;
float * dst_c1 = (float *) c_ptr[1] + ni;
asm volatile(
"vsetvli t0, x0, e16, m1 \n\t"
"vxor.vv v28, v28, v28 \n\t"
"vxor.vv v29, v29, v29 \n\t"
"vmv.v.i v0, 1 \n\t" // init the scale
"vsll.vi v1, v0, 4 \n\t"
"vfcvt.f.x.v v0, v0 \n\t"
"vfcvt.f.x.v v1, v1 \n\t"
"mv t3, %[BK] \n\t"
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
// load scale A0
"flw fa0, (%[A0]) \n\t" // A0 scale
"lh t1, 4(%[A0]) \n\t" // A0 asum
"addi %[A0], %[A0], 6 \n\t"
// load scale B
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v12, (%[B]) \n\t"
"addi %[B], %[B], 64 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v14, v12, v12, 3 \n\t"
// load scale A1
"flw fa1, (%[A1]) \n\t" // A1 scale
"lh t2, 4(%[A1]) \n\t" // A1 asum
"addi %[A1], %[A1], 6 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vmv.v.x v10, t1 \n\t"
"vmv.v.x v11, t2 \n\t"
"vpack.vv v18, v10, v11, 1 \n\t"
"vsll.vi v18, v18, 3 \n\t" // mul 8
"vfcvt.f.x.v v18, v18 \n\t"
"vsetvli t0, x0, e8, mf4 \n\t" // A0 data
"vle8.v v16, (%[A0]) \n\t"
"addi %[A0], %[A0], 32 \n\t" // 1*32@i8
"vle8.v v20, (%[A1]) \n\t"
"addi %[A1], %[A1], 32 \n\t" // 1*32@i8
"vl4r.v v4, (%[B]) \n\t" // 32*32@i4
"addi %[B], %[B], 512 \n\t"
"vsrl.vi v17, v16, 4 \n\t"
"vsrl.vi v21, v20, 4 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vnpack4.vv v2, v16, v20, 2 \n\t" // low u4
"vnpack4.vv v3, v17, v21, 2 \n\t" // high s4
// init the accumu to asum * zp
"vsetvli t0, x0, e16, m1 \n\t"
"vor.vv v19, v18, v18 \n\t"
"vor.vv v20, v18, v18 \n\t"
"vor.vv v21, v18, v18 \n\t"
// i4 * i4 vmadot
"vsetvli t0, x0, e16, m1 \n\t"
"vmadotsu.hp v18, v3, v4, v1, 0, i4 \n\t" // high 4
"vmadotsu.hp v19, v3, v5, v1, 0, i4 \n\t"
"vmadotsu.hp v20, v3, v6, v1, 0, i4 \n\t"
"vmadotsu.hp v21, v3, v7, v1, 0, i4 \n\t"
"vmadotu.hp v18, v2, v4, v0, 0, i4 \n\t" // low 4
"vmadotu.hp v19, v2, v5, v0, 0, i4 \n\t"
"vmadotu.hp v20, v2, v6, v0, 0, i4 \n\t"
"vmadotu.hp v21, v2, v7, v0, 0, i4 \n\t"
"vpack.vv v8, v18, v19, 1 \n\t"
"vpack.vv v12, v20, v21, 1 \n\t"
"vpack.vv v20, v8, v12, 2 \n\t"
"vfwmul.vv v16, v20, v14 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"addi t3, t3, -1 \n\t"
"vfmacc.vf v28, fa0, v16 \n\t"
"vfmacc.vf v29, fa1, v17 \n\t"
"bgtz t3, BLK_LOOP%= \n\t"
// save
"vsetvli t0, x0, e32, m1 \n\t"
"vse32.v v28, (%[DST0]) \n\t"
"vse32.v v29, (%[DST1]) \n\t"
: [A0] "+r"(a_data0), [A1] "+r"(a_data1), [B] "+r"(b_data)
: [DST0] "r"(dst_c0), [DST1] "r"(dst_c1), [BK] "r"(k_blks)
: "t0", "t1", "t2", "t3", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11",
"v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25",
"v26", "v27", "v28", "v29", "v30", "v31", "fa0", "fa1", "fa2", "fa3");
}
} else {
# if 0
moe_gemm_kernel_i8i4_mrow_ref<2, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
k_blks, ldc);
# else
for (size_t ni = 0; ni < count_n; ni += 32) {
uint8_t * b_data = (uint8_t *) quant_b_data + ni * b_data_stride;
int8_t * a_data0 = (int8_t *) quant_a_ptr[0];
int8_t * a_data1 = (int8_t *) quant_a_ptr[1];
float * dst_c0 = (float *) c_ptr[0] + ni;
float * dst_c1 = (float *) c_ptr[1] + ni;
asm volatile(
"vsetvli t0, x0, e16, m1 \n\t"
"vxor.vv v28, v28, v28 \n\t"
"vxor.vv v29, v29, v29 \n\t"
"vmv.v.i v0, 1 \n\t" // init the scale
"vsll.vi v1, v0, 4 \n\t"
"vfcvt.f.x.v v0, v0 \n\t"
"vfcvt.f.x.v v1, v1 \n\t"
"mv t3, %[BK] \n\t"
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
// load scale A0
"flw fa0, (%[A0]) \n\t" // A0 scale
"lh t1, 4(%[A0]) \n\t" // A0 asum
"addi %[A0], %[A0], 6 \n\t"
// load scale B
"vsetvli t0, x0, e16, mf2 \n\t"
"vle16.v v12, (%[B]) \n\t"
"addi %[B], %[B], 64 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vpack.vv v14, v12, v12, 3 \n\t"
// load scale A1
"flw fa1, (%[A1]) \n\t" // A1 scale
"lh t2, 4(%[A1]) \n\t" // A1 asum
"addi %[A1], %[A1], 6 \n\t"
// load zp
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v8, (%[B]) \n\t"
"addi %[B], %[B], 32 \n\t"
"vwaddu.vx v10, v8, x0 \n\t"
"vsetvli t0, x0, e8, mf4 \n\t" // A0 data
"vle8.v v16, (%[A0]) \n\t"
"addi %[A0], %[A0], 32 \n\t" // 1*32@i8
"vle8.v v20, (%[A1]) \n\t"
"addi %[A1], %[A1], 32 \n\t" // 1*32@i8
"vl4r.v v4, (%[B]) \n\t" // 32*32@i4
"addi %[B], %[B], 512 \n\t"
"vsrl.vi v17, v16, 4 \n\t"
"vsrl.vi v21, v20, 4 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vnpack4.vv v2, v16, v20, 2 \n\t" // low u4
"vnpack4.vv v3, v17, v21, 2 \n\t" // high s4
// init the accumu to asum * zp
"vsetvli t0, x0, e16, m1 \n\t"
"vxor.vv v18, v18, v18 \n\t"
"vxor.vv v19, v19, v19 \n\t"
"vxor.vv v20, v20, v20 \n\t"
"vxor.vv v21, v21, v21 \n\t"
// i4 * i4 vmadot
"vsetvli t0, x0, e16, m1 \n\t"
"vmadotsu.hp v18, v3, v4, v1, 0, i4 \n\t" // high 4
"vmadotsu.hp v19, v3, v5, v1, 0, i4 \n\t"
"vmadotsu.hp v20, v3, v6, v1, 0, i4 \n\t"
"vmadotsu.hp v21, v3, v7, v1, 0, i4 \n\t"
"vmadotu.hp v18, v2, v4, v0, 0, i4 \n\t" // low 4
"vmadotu.hp v19, v2, v5, v0, 0, i4 \n\t"
"vmadotu.hp v20, v2, v6, v0, 0, i4 \n\t"
"vmadotu.hp v21, v2, v7, v0, 0, i4 \n\t"
"vpack.vv v8, v18, v19, 1 \n\t"
"vpack.vv v12, v20, v21, 1 \n\t"
"vpack.vv v20, v8, v12, 2 \n\t"
// asum*zp
"vsetvli t0, x0, e16, mf2 \n\t"
"vwmul.vx v2, v10, t1 \n\t"
"vwmul.vx v4, v10, t2 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vfcvt.f.x.v v2, v2 \n\t"
"vfcvt.f.x.v v4, v4 \n\t"
"vsetvli t0, x0, e16, m1 \n\t"
"vfwcvt.f.f.v v16, v20 \n\t"
"vfwcvt.f.f.v v18, v14 \n\t"
// +asum*zp
"vsetvli t0, x0, e32, m1 \n\t"
"vfadd.vv v16, v16, v2 \n\t"
"vfadd.vv v17, v17, v4 \n\t"
"vfmul.vv v16, v16, v18 \n\t"
"vfmul.vv v17, v17, v18 \n\t"
"addi t3, t3, -1 \n\t"
"vfmacc.vf v28, fa0, v16 \n\t"
"vfmacc.vf v29, fa1, v17 \n\t"
"bgtz t3, BLK_LOOP%= \n\t"
// save
"vsetvli t0, x0, e32, m1 \n\t"
"vse32.v v28, (%[DST0]) \n\t"
"vse32.v v29, (%[DST1]) \n\t"
: [A0] "+r"(a_data0), [A1] "+r"(a_data1), [B] "+r"(b_data)
: [DST0] "r"(dst_c0), [DST1] "r"(dst_c1), [BK] "r"(k_blks)
: "t0", "t1", "t2", "t3", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11",
"v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25",
"v26", "v27", "v28", "v29", "v30", "v31", "fa0", "fa1", "fa2", "fa3");
}
# endif
}
#endif
}
void moe_m2_gemm_kernel_i8i5_impl(size_t blk_len,
const uint8_t ** quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float ** c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
constexpr size_t NB_COLS = 32;
constexpr size_t B_Q50_BLK_STRIDE = sizeof(nrow_block_q5_0<NB_COLS>);
constexpr size_t B_Q51_BLK_STRIDE = sizeof(nrow_block_q5_1<NB_COLS>);
GGML_UNUSED(blk_len);
GGML_UNUSED(count_m);
GGML_UNUSED(ldc);
if (quant_b_zp == NULL) {
for (size_t ni = 0; ni < count_n; ni += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
uint8_t * b_data = (uint8_t *) quant_b_data + (ni / NB_COLS) * k_blks * B_Q50_BLK_STRIDE;
int8_t * a_data0 = (int8_t *) quant_a_ptr[0];
int8_t * a_data1 = (int8_t *) quant_a_ptr[1];
float * dst_c0 = (float *) c_ptr[0] + ni;
float * dst_c1 = (float *) c_ptr[1] + ni;
asm volatile(
"mv t4, %[BK] \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v2, v0, v0 \n\t"
"vxor.vv v3, v0, v0 \n\t"
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
// ---- load B scale/Bh/Bs and advance to the next q5_0 k-block ----
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v1, (%[B]) \n\t" // v1 = scale_fp16 × 32
"addi %[B], %[B], 64 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v0, (%[B]) \n\t" // v0 = Bh N32K32 1-bit packed
"addi %[B], %[B], 128 \n\t"
"vl4r.v v8, (%[B]) \n\t" // v8..v11 = Bs N32K32 i4
"addi %[B], %[B], 512 \n\t"
// ---- load A0/A1 header then payload, each block stride = 38B ----
"flw f0, (%[A0]) \n\t" // f0 = A0 scale (fp32)
"lh t2, 4(%[A0]) \n\t" // t2 = A0 asum (int16)
"addi %[A0], %[A0], 6 \n\t"
"flw f1, (%[A1]) \n\t" // f1 = A1 scale (fp32)
"lh t3, 4(%[A1]) \n\t" // t3 = A1 asum (int16)
"addi %[A1], %[A1], 6 \n\t"
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v4, (%[A0]) \n\t" // v4 = A0 M1K32 int8
"addi %[A0], %[A0], 32 \n\t"
"vle8.v v5, (%[A1]) \n\t" // v5 = A1 M1K32 int8
"addi %[A1], %[A1], 32 \n\t"
//// ---- A nibble unpacking ----
"vsetvli t0, x0, e8, m1 \n\t"
"vand.vi v12, v8, 0xF \n\t" //8bit(lo4) //[8*32]
"vand.vi v13, v9, 0xF \n\t"
"vand.vi v14, v10, 0xF \n\t"
"vand.vi v15, v11, 0xF \n\t"
"vsrl.vi v8, v8, 4 \n\t" //8bit(hi4)
"vsrl.vi v9, v9, 4 \n\t"
"vsrl.vi v10, v10, 4 \n\t"
"vsrl.vi v11, v11, 4 \n\t"
"slli t2, t2, 4 \n\t" // a_sum * 16;
"slli t3, t3, 4 \n\t"
// [4*32]*2
"vsetvli t0, x0, e8, m1 \n\t"
"vpack.vv v16, v12, v8, 0 \n\t"
"vpack.vv v18, v13, v9, 0 \n\t"
"vpack.vv v20, v14, v10, 0 \n\t"
"vpack.vv v22, v15, v11, 0 \n\t"
"li t1, 16 \n\t"
"vsetvli t0, x0, e8, m8 \n\t"
"vadd.vx v16, v16, t1, v0.t \n\t"
// [4*32]*2 -> [8*16]
"vsetvli t0, x0, e8, m1 \n\t"
"vupack.vv v8, v16, v17, 1 \n\t"
"vupack.vv v10, v18, v19, 1 \n\t"
"vupack.vv v12, v20, v21, 1 \n\t"
"vupack.vv v14, v22, v23, 1 \n\t"
"vpack.vv v6, v4, v5, 2 \n\t"
// init the accumu to asum * zp
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v24, v16, v16 \n\t"
"vxor.vv v26, v16, v16 \n\t"
"vupack.vv v4, v6, v7, 1 \n\t"
"vxor.vv v28, v16, v16 \n\t"
"vxor.vv v30, v16, v16 \n\t"
// ---- i8 main dot products ----
// vmadot: A × unsigned Bh × 16 → fp16 accumulate
"vmadot v24, v4, v8, i8 \n\t" // N0..7
"vmadot v26, v4, v10, i8 \n\t" // N8..15
"vmadot v28, v4, v12, i8 \n\t" // N16..23
"vmadot v30, v4, v14, i8 \n\t" // N24..31
// vmadot: A × unsigned Bh × 1 → fp16 accumulate
"vmadot v24, v5, v9, i8 \n\t" // N0..7
"vmadot v26, v5, v11, i8 \n\t" // N8..15
"vmadot v28, v5, v13, i8 \n\t" // N16..23
"vmadot v30, v5, v15, i8 \n\t" // N24..31
"vpack.vv v16, v24, v26, 2 \n\t" // v16 = N0..15
"vpack.vv v18, v28, v30, 2 \n\t" // v18 = N16..31
"vpack.vv v24, v16, v18, 3 \n\t" // v24 = N0..31
"vadd.vx v24, v24, t2 \n\t"
"vadd.vx v25, v25, t3 \n\t"
// b_scale fp16 -> fp32
"vsetvli t0, x0, e16, mf2 \n\t"
"vfwcvt.f.f.v v28, v1 \n\t"
// a_scale * b_scale;
"vsetvli t0, x0, e32, m1 \n\t"
"vfcvt.f.x.v v26, v24 \n\t"
"vfcvt.f.x.v v27, v25 \n\t"
"vfmul.vf v30, v28, f0 \n\t"
"vfmul.vf v31, v28, f1 \n\t"
// static_cast<float>(qsum) * a_scale * b_scale;
"vfmacc.vv v2, v30, v26 \n\t"
"vfmacc.vv v3, v31, v27 \n\t"
"addi t4, t4, -1 \n\t"
"bgtz t4, BLK_LOOP%= \n\t"
"vsetvli t0, %[NR], e32, m1 \n\t"
"vse32.v v2, (%[DST0]) \n\t"
"vse32.v v3, (%[DST1]) \n\t"
: [A0] "+r"(a_data0), [A1] "+r"(a_data1), [B] "+r"(b_data)
: [DST0] "r"(dst_c0), [DST1] "r"(dst_c1), [BK] "r"(k_blks), [NR] "r"(nb_real)
: "cc", "memory", "t0", "t1", "t2", "t3", "t4", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8",
"v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22",
"v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "f0", "f1");
}
} else {
for (size_t ni = 0; ni < count_n; ni += NB_COLS) {
size_t nb_real = std::min<size_t>(NB_COLS, count_n - ni);
uint8_t * b_data = (uint8_t *) quant_b_data + (ni / NB_COLS) * k_blks * B_Q51_BLK_STRIDE;
int8_t * a_data0 = (int8_t *) quant_a_ptr[0];
int8_t * a_data1 = (int8_t *) quant_a_ptr[1];
float * dst_c0 = (float *) c_ptr[0] + ni;
float * dst_c1 = (float *) c_ptr[1] + ni;
asm volatile(
"mv t4, %[BK] \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v2, v0, v0 \n\t"
"vxor.vv v3, v0, v0 \n\t"
"addi t5, %[B], 64 \n\t" // t5 = zp (32B)
"addi t6, %[B], 96 \n\t" // t6 = qh (128B)
"addi s1, %[B], 224 \n\t" // s1 = qs (512B)
".align 4 \n\t"
"BLK_LOOP%=: \n\t"
// ---- load B scale/zp/Bh/Bs and advance to the next q5_1 k-block ----
"vsetvli t0, x0, e8, mf2 \n\t"
"vle8.v v1, (%[B]) \n\t" // v1 = scale_fp16 × 32
"addi %[B], %[B], 736 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vle8.v v0, (t6) \n\t" // v0 = Bh N32K32 1-bit packed
"addi t6, t6, 736 \n\t"
"vl4r.v v8, (s1) \n\t" // v8..v11 = Bs N32K32 i4
"addi s1, s1, 736 \n\t"
// ---- load A0/A1 header then payload, each block stride = 38B ----
"flw f0, (%[A0]) \n\t" // f0 = A0 scale (fp32)
"lh t2, 4(%[A0]) \n\t" // t2 = A0 asum (int16)
"addi %[A0], %[A0], 6 \n\t"
"flw f1, (%[A1]) \n\t" // f1 = A1 scale (fp32)
"lh t3, 4(%[A1]) \n\t" // t3 = A1 asum (int16)
"addi %[A1], %[A1], 6 \n\t"
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v4, (%[A0]) \n\t" // v4 = A0 M1K32 int8
"addi %[A0], %[A0], 32 \n\t"
"vle8.v v5, (%[A1]) \n\t" // v5 = A1 M1K32 int8
"addi %[A1], %[A1], 32 \n\t"
//// ---- A nibble unpacking ----
"vsetvli t0, x0, e8, m1 \n\t"
"vand.vi v12, v8, 0xF \n\t" //8bit(lo4) //[8*32]
"vand.vi v13, v9, 0xF \n\t"
"vand.vi v14, v10, 0xF \n\t"
"vand.vi v15, v11, 0xF \n\t"
"vsrl.vi v8, v8, 4 \n\t" //8bit(hi4)
"vsrl.vi v9, v9, 4 \n\t"
"vsrl.vi v10, v10, 4 \n\t"
"vsrl.vi v11, v11, 4 \n\t"
// q5_1 uses explicit zp, so keep a_sum unshifted here.
// [4*32]*2
"vpack.vv v16, v12, v8, 0 \n\t"
"vpack.vv v18, v13, v9, 0 \n\t"
"vpack.vv v20, v14, v10, 0 \n\t"
"vpack.vv v22, v15, v11, 0 \n\t"
"li t1, 16 \n\t"
"vsetvli t0, x0, e8, m8 \n\t"
"vadd.vx v16, v16, t1, v0.t \n\t"
// [4*32]*2 -> [8*16]
"vsetvli t0, x0, e8, m1 \n\t"
"vupack.vv v8, v16, v17, 1 \n\t"
"vupack.vv v10, v18, v19, 1 \n\t"
"vupack.vv v12, v20, v21, 1 \n\t"
"vupack.vv v14, v22, v23, 1 \n\t"
"vpack.vv v6, v4, v5, 2 \n\t"
// init the accumu to asum * zp
"vsetvli t0, x0, e32, m1 \n\t"
"vxor.vv v24, v16, v16 \n\t"
"vxor.vv v26, v16, v16 \n\t"
"vupack.vv v4, v6, v7, 1 \n\t"
"vxor.vv v28, v16, v16 \n\t"
"vxor.vv v30, v16, v16 \n\t"
// ---- i8 main dot products ----
// vmadot: A × unsigned Bh × 16 → fp16 accumulate
"vmadot v24, v4, v8, i8 \n\t" // N0..7
"vmadot v26, v4, v10, i8 \n\t" // N8..15
"vmadot v28, v4, v12, i8 \n\t" // N16..23
"vmadot v30, v4, v14, i8 \n\t" // N24..31
// vmadot: A × unsigned Bh × 1 → fp16 accumulate
"vmadot v24, v5, v9, i8 \n\t" // N0..7
"vmadot v26, v5, v11, i8 \n\t" // N8..15
"vmadot v28, v5, v13, i8 \n\t" // N16..23
"vmadot v30, v5, v15, i8 \n\t" // N24..31
"vsetvli t0, x0, e8, mf4 \n\t"
"vle8.v v4, (t5) \n\t" // v4 = Bzp N32 uint8
"addi t5, t5, 736 \n\t"
"vsetvli t0, x0, e8, m1 \n\t"
"vpack.vv v16, v24, v26, 2 \n\t" // v16 = N0..15
"vpack.vv v18, v28, v30, 2 \n\t" // v18 = N16..31
"vpack.vv v24, v16, v18, 3 \n\t" // v24 = N0..31
"vsetvli t0, x0, e8, mf4 \n\t"
"vwaddu.vx v28, v4, x0 \n\t"
"vsetvli t0, x0, e16, mf2 \n\t"
"vwmul.vx v30, v28, t2 \n\t"
"vwmul.vx v31, v28, t3 \n\t"
// b_scale fp16 -> fp32
"vfwcvt.f.f.v v28, v1 \n\t"
"vsetvli t0, x0, e32, m1 \n\t"
"vadd.vv v24, v24, v30 \n\t"
"vadd.vv v25, v25, v31 \n\t"
// a_scale * b_scale;
"vfcvt.f.x.v v26, v24 \n\t"
"vfcvt.f.x.v v27, v25 \n\t"
"vfmul.vf v30, v28, f0 \n\t"
"vfmul.vf v31, v28, f1 \n\t"
// static_cast<float>(qsum) * a_scale * b_scale;
"vfmacc.vv v2, v30, v26 \n\t"
"vfmacc.vv v3, v31, v27 \n\t"
"addi t4, t4, -1 \n\t"
"bgtz t4, BLK_LOOP%= \n\t"
"vsetvli t0, %[NR], e32, m1 \n\t"
"vse32.v v2, (%[DST0]) \n\t"
"vse32.v v3, (%[DST1]) \n\t"
: [A0] "+r"(a_data0), [A1] "+r"(a_data1), [B] "+r"(b_data)
: [DST0] "r"(dst_c0), [DST1] "r"(dst_c1), [BK] "r"(k_blks), [NR] "r"(nb_real)
: "cc", "memory", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "s1", "v0", "v1", "v2", "v3", "v4", "v5",
"v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20",
"v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "f0", "f1");
}
}
}
size_t gemm_kernel_i8i2k(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
if (count_m >= 4) {
#if 0
gemm_kernel_i8i2k_mrow_ref<4, 32>(blk_len, quant_a_ptr, quant_b_data, c_ptr, count_m, count_n, k_blks, ldc);
#else
gemm_kernel_i8i2k_m4(blk_len, quant_a_ptr, quant_b_data, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 4;
} else {
#if 0
gemm_kernel_i8i2k_mrow_ref<1, 32>(blk_len, quant_a_ptr, quant_b_data, c_ptr, count_m, count_n, k_blks,
ldc);
#else
gemm_kernel_i8i2k_m1(blk_len, quant_a_ptr, quant_b_data, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 1;
}
}
size_t gemm_kernel_i8i3k(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
if (count_m >= 4) {
#if 0
gemm_kernel_i8i3k_mrow_ref<4, 32>(blk_len, quant_a_ptr, quant_b_data, c_ptr, count_m, count_n, k_blks, ldc);
#else
gemm_kernel_i8i3k_m4(blk_len, quant_a_ptr, quant_b_data, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 4;
} else {
#if 0
gemm_kernel_i8i3k_mrow_ref<1, 32>(blk_len, quant_a_ptr, quant_b_data, c_ptr, count_m, count_n, k_blks, ldc);
#else
gemm_kernel_i8i3k_m1(blk_len, quant_a_ptr, quant_b_data, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 1;
}
}
size_t gemm_kernel_i8i4(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
if (count_m >= 4) {
#if 0
gemm_kernel_i8i4_mrow_ref<4, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
k_blks, ldc);
#else
gemm_kernel_i8i4_m4(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 4;
} else {
#if 0
gemm_kernel_i8i4_mrow_ref<1, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
k_blks, ldc);
#else
gemm_kernel_i8i4_m1(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 1;
}
}
size_t gemm_kernel_i8i4_hp(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
if (count_m >= 4) {
#if 0
gemm_kernel_i8i4_hp_mrow_ref<4, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
k_blks, ldc);
#else
gemm_kernel_i8i4_hp_m4(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 4;
} else {
#if 0
gemm_kernel_i8i4_hp_mrow_ref<1, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
k_blks, ldc);
#else
gemm_kernel_i8i4_hp_m1(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 1;
}
}
size_t moe_m2_gemm_kernel_i8i4(size_t blk_len,
const uint8_t ** quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float ** c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
moe_m2_gemm_kernel_i8i4_impl(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
return 2;
}
size_t gemm_kernel_i8i8(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
if (count_m >= 4) {
#if 0
gemm_kernel_i8i8_mrow_ref<4, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
k_blks, ldc);
#else
gemm_kernel_i8i8_m4(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 4;
} else {
#if 0
gemm_kernel_i8i8_mrow_ref<1, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
k_blks, ldc);
#else
gemm_kernel_i8i8_m1(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 1;
}
}
size_t gemm_kernel_i8mxfp4(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
if (count_m >= 4) {
#if 1
gemm_kernel_i8mxfp4_mrow_ref<4, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
k_blks, ldc);
#else
gemm_kernel_i8mxfp4_m4(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 4;
} else {
#if 1
gemm_kernel_i8mxfp4_mrow_ref<1, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
k_blks, ldc);
#else
gemm_kernel_i8mxfp4_m1(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 1;
}
}
size_t moe_m2_gemm_kernel_i8mxfp4(size_t blk_len,
const uint8_t ** quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float ** c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
//moe_m2_gemm_kernel_i8mxfp4_impl(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
return 2;
}
size_t gemm_kernel_i8i5(size_t blk_len,
const uint8_t * quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float * c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
if (count_m >= 4) {
#if 0
gemm_kernel_i8i5_mrow_ref<4, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
k_blks, ldc);
#else
gemm_kernel_i8i5_m4(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 4;
} else {
#if 0
gemm_kernel_i8i5_mrow_ref<1, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
k_blks, ldc);
#else
gemm_kernel_i8i5_m1(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 1;
}
}
size_t moe_m2_gemm_kernel_i8i5(size_t blk_len,
const uint8_t ** quant_a_ptr,
const uint8_t * quant_b_data,
const uint8_t * quant_b_zp,
float ** c_ptr,
size_t count_m,
size_t count_n,
size_t k_blks,
size_t ldc) {
#if 0
moe_gemm_kernel_i8i5_mrow_ref<2, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
k_blks, ldc);
#else
moe_m2_gemm_kernel_i8i5_impl(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
#endif
return 2;
}
} // namespace ime2
} // namespace spacemit_kernels