← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
gemm_kernels_q6k_q8k.c File Reference

Q6_K (weights) x Q8_K (activations) kernels for inference. More...

#include <assert.h>
#include <math.h>
#include <string.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include "ckernel_engine.h"
#include "ckernel_quant.h"

Go to the source code of this file.

Functions

static float ck_dot_q6_k_q8_k_fast_or_ref (const block_q6_K *w, const block_q8_K *x, int K)
 
void ck_q6_k_prepare_weight (const void *src, void *dst, int N, int K)
 
size_t ck_q6_k_prepared_block_size (void)
 
const char * ck_q6_k_prepared_provider_name (void)
 
const char * ck_q6_k_q8_k_provider_name (void)
 
static int ck_q6k_q8k_force_ref (void)
 
static float dot_q6_k_q8_k_ref (const block_q6_K *w, const block_q8_K *x, int K)
 Scalar dot product for Q6_K x Q8_K.
 
void gemm_nt_q6_k_q8_k (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K)
 NT GEMM: C = A @ B^T where A is Q8_K and B is Q6_K.
 
void gemm_nt_q6_k_q8_k_m4_tile (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K, int m0, int m1, int n0, int n1)
 
void gemm_nt_q6_k_q8_k_prepared (const void *A_q8, const void *B_prepared, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q6_k_q8_k_prepared_avx512_vnni (const void *A_q8, const void *B_prepared, const float *bias, float *C, int M, int N, int K)
 
void gemm_nt_q6_k_q8_k_prepared_tile (const void *A_q8, const void *B_prepared, const float *bias, float *C, int M, int N, int K, int m0, int m1, int n0, int n1)
 
static void gemm_nt_q6_k_q8_k_prepared_tile_impl (const void *A_q8, const void *B_prepared, const float *bias, float *C, int M, int N, int K, int m0, int m1, int n0, int n1, int use_avx512_vnni)
 
void gemm_nt_q6_k_q8_k_tile (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K, int m0, int m1, int n0, int n1)
 Compute one C[m0:m1, n0:n1] tile for Q8_K activations x Q6_K weights.
 
void gemm_nt_q6_k_q8_k_tiled (const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K)
 Experimental single-thread tiled NT GEMM wrapper.
 
void gemm_q6_k_q8_k (float *Y, const void *W, const void *X_q8, int M, int N, int K)
 GEMM: Y = W @ X^T where W is Q6_K and X is Q8_K.
 
void gemv_q6_k_q8_k (float *y, const void *W, const void *x_q8, int M, int K)
 GEMV: y = W @ x where W is Q6_K and x is Q8_K.
 
void gemv_q6_k_q8_k_avx (float *y, const void *W, const void *x_q8, int M, int K)
 
void gemv_q6_k_q8_k_avx2 (float *y, const void *W, const void *x_q8, int M, int K)
 
void gemv_q6_k_q8_k_avx512 (float *y, const void *W, const void *x_q8, int M, int K)
 
void gemv_q6_k_q8_k_avx512_vbmi (float *y, const void *W, const void *x_q8, int M, int K)
 
void gemv_q6_k_q8_k_parallel (float *y, const void *W, const void *x_q8, int M, int K, int ith, int nth)
 Parallel reference GEMV for Q6_K × Q8_K.
 
void gemv_q6_k_q8_k_parallel_simd (float *y, const void *W, const void *x_q8, int M, int K, int ith, int nth)
 Parallel SIMD GEMV for Q6_K × Q8_K.
 
void gemv_q6_k_q8_k_ref (float *y, const void *W, const void *x_q8, int M, int K)
 
void gemv_q6_k_q8_k_sse (float *y, const void *W, const void *x_q8, int M, int K)
 
void vec_dot_q6_k_q8_k (int n, float *s, const void *vx, const void *vy)
 Q6_K x Q8_K dot product (single row)
 

Detailed Description

Q6_K (weights) x Q8_K (activations) kernels for inference.

CK-ENGINE KERNEL RULES:

  1. NO malloc/free - memory via bump allocator, pointers passed in
  2. NO OpenMP - parallelization at orchestrator/codegen layer
  3. API must define: inputs, outputs, workspace, and memory layouts
  4. Pure computation - deterministic, no side effects

After changes: make test && make llamacpp-parity-full

Implements decode-style matvec/matmul where weights are Q6_K and the activations are quantized on-the-fly to Q8_K. This is inference-only; no backward pass is provided here.

Q6_K Format (256 weights per block):

  • d: FP16 super-block scale
  • ql: 128 bytes (low 4 bits of each weight)
  • qh: 64 bytes (high 2 bits of each weight)
  • scales: 16 int8 sub-block scales

Q8_K Format (256 weights per block):

  • d: FP32 scale
  • qs: 256 int8 values
  • bsums: 16 int16 block sums

Definition in file gemm_kernels_q6k_q8k.c.

Function Documentation

◆ ck_dot_q6_k_q8_k_fast_or_ref()

static float ck_dot_q6_k_q8_k_fast_or_ref ( const block_q6_K w,
const block_q8_K x,
int  K 
)
inlinestatic

Definition at line 1641 of file gemm_kernels_q6k_q8k.c.

1644{
1646 return dot_q6_k_q8_k_ref(w, x, K);
1647 }
1648#if defined(__AVX2__)
1649 return dot_q6_k_q8_k_avx2(w, x, K);
1650#elif defined(__AVX__)
1651 return dot_q6_k_q8_k_avx(w, x, K);
1652#elif defined(__SSE4_1__)
1653 return dot_q6_k_q8_k_sse(w, x, K);
1654#else
1655 return dot_q6_k_q8_k_ref(w, x, K);
1656#endif
1657}
int ck_strict_parity_enabled(void)
static int ck_q6k_q8k_force_ref(void)
static float dot_q6_k_q8_k_ref(const block_q6_K *w, const block_q8_K *x, int K)
Scalar dot product for Q6_K x Q8_K.

References ck_q6k_q8k_force_ref(), ck_strict_parity_enabled(), and dot_q6_k_q8_k_ref().

Referenced by gemm_nt_q6_k_q8_k(), and gemm_nt_q6_k_q8_k_tile().

◆ ck_q6_k_prepare_weight()

void ck_q6_k_prepare_weight ( const void *  src,
void *  dst,
int  N,
int  K 
)

Definition at line 74 of file gemm_kernels_q6k_q8k.c.

75{
76 if (!src || !dst || N <= 0 || K <= 0 || (K % QK_K) != 0) return;
77 const block_q6_K *input = (const block_q6_K *)src;
78 block_q6_K_prepared *output = (block_q6_K_prepared *)dst;
79 const size_t blocks = (size_t)N * (size_t)(K / QK_K);
80
81 for (size_t b = 0; b < blocks; ++b) {
82 output[b].d = input[b].d;
83 memcpy(output[b].scales, input[b].scales, sizeof(output[b].scales));
84 for (int n = 0; n < QK_K; n += 128) {
85 const uint8_t *ql = input[b].ql + n / 2;
86 const uint8_t *qh = input[b].qh + n / 4;
87 for (int l = 0; l < 32; ++l) {
88 output[b].qs[n + l + 0] =
89 (uint8_t)((ql[l] & 0x0f) | (((qh[l] >> 0) & 3) << 4));
90 output[b].qs[n + l + 32] =
91 (uint8_t)((ql[l + 32] & 0x0f) | (((qh[l] >> 2) & 3) << 4));
92 output[b].qs[n + l + 64] =
93 (uint8_t)((ql[l] >> 4) | (((qh[l] >> 4) & 3) << 4));
94 output[b].qs[n + l + 96] =
95 (uint8_t)((ql[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4));
96 }
97 }
98 }
99}
#define QK_K
uint8_t ql[256/2]
uint8_t qh[256/4]

References block_q6_K::d, block_q6_K::qh, QK_K, and block_q6_K::ql.

◆ ck_q6_k_prepared_block_size()

size_t ck_q6_k_prepared_block_size ( void  )

Definition at line 57 of file gemm_kernels_q6k_q8k.c.

58{
59 return sizeof(block_q6_K_prepared);
60}

◆ ck_q6_k_prepared_provider_name()

const char * ck_q6_k_prepared_provider_name ( void  )

Definition at line 62 of file gemm_kernels_q6k_q8k.c.

63{
64#if defined(__AVX512F__) && defined(__AVX512BW__) && \
65 defined(__AVX512VNNI__)
66 return "q6_k_prepared_avx512_vnni_exact";
67#elif defined(__AVX2__)
68 return "q6_k_prepared_avx2_exact";
69#else
70 return "q6_k_prepared_unavailable";
71#endif
72}

◆ ck_q6_k_q8_k_provider_name()

const char * ck_q6_k_q8_k_provider_name ( void  )

Definition at line 1367 of file gemm_kernels_q6k_q8k.c.

1368{
1370 return "q6_k_q8_k_ref";
1371 }
1372#if defined(__AVX2__)
1373 return "q6_k_q8_k_avx2";
1374#elif defined(__AVX__)
1375 return "q6_k_q8_k_avx";
1376#elif defined(__SSE4_1__)
1377 return "q6_k_q8_k_sse";
1378#else
1379 return "q6_k_q8_k_ref";
1380#endif
1381}

References ck_q6k_q8k_force_ref(), and ck_strict_parity_enabled().

◆ ck_q6k_q8k_force_ref()

static int ck_q6k_q8k_force_ref ( void  )
static

Definition at line 108 of file gemm_kernels_q6k_q8k.c.

109{
110 static int cached = -1;
111 if (cached < 0) {
112 const char *env = getenv("CK_DEBUG_Q6K_Q8K_REF");
113 cached = (env && env[0] && env[0] != '0') ? 1 : 0;
114 }
115 return cached;
116}

Referenced by ck_dot_q6_k_q8_k_fast_or_ref(), ck_q6_k_q8_k_provider_name(), gemm_nt_q6_k_q8_k_m4_tile(), gemv_q6_k_q8_k(), and gemv_q6_k_q8_k_parallel_simd().

◆ dot_q6_k_q8_k_ref()

static float dot_q6_k_q8_k_ref ( const block_q6_K w,
const block_q8_K x,
int  K 
)
static

Scalar dot product for Q6_K x Q8_K.

Q6_K layout: 256 weights per block

  • ql[0..127]: low 4 bits for all 256 weights (packed 2 per byte)
  • qh[0..63]: high 2 bits for all 256 weights (packed 4 per byte)
  • scales[0..15]: int8 scale for each 16-weight sub-block
  • d: FP16 super-block scale

The dequantization formula for each weight is: weight = d * scale[sub] * (q6_value - 32) where q6_value is the 6-bit unsigned value (0..63).

Definition at line 135 of file gemm_kernels_q6k_q8k.c.

138{
139 const int nb = K / QK_K;
140 float sumf = 0.0f;
141 float sums[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
142
143 for (int i = 0; i < nb; ++i) {
144 const float d = GGML_FP16_TO_FP32(w[i].d) * x[i].d;
145
146 const uint8_t *ql = w[i].ql;
147 const uint8_t *qh = w[i].qh;
148 const int8_t *sc = w[i].scales;
149 const int8_t *q8 = x[i].qs;
150 int32_t aux32[8] = {0, 0, 0, 0, 0, 0, 0, 0};
151
152 /* Process 256 weights in 2 iterations of 128 */
153 for (int n = 0; n < QK_K; n += 128) {
154 /* Each iteration processes 128 weights:
155 * - ql[0..63] contains low 4 bits
156 * - qh[0..31] contains high 2 bits
157 * - Interleaved pattern: weights 0-31, 32-63, 64-95, 96-127
158 */
159 for (int l = 0; l < 32; ++l) {
160 /* Sub-block index: each scale covers 16 weights */
161 const int is = l / 16;
162
163 /* Extract 6-bit values from packed format */
164 /* q1: weights l+0 (low nibble of ql[l], bits 0-1 of qh[l]) */
165 const int8_t q1 = (int8_t)((ql[l + 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32;
166 /* q2: weights l+32 (low nibble of ql[l+32], bits 2-3 of qh[l]) */
167 const int8_t q2 = (int8_t)((ql[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32;
168 /* q3: weights l+64 (high nibble of ql[l], bits 4-5 of qh[l]) */
169 const int8_t q3 = (int8_t)((ql[l + 0] >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32;
170 /* q4: weights l+96 (high nibble of ql[l+32], bits 6-7 of qh[l]) */
171 const int8_t q4 = (int8_t)((ql[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32;
172
173 aux32[l & 7] += (int)sc[is + 0] * (int)q1 * (int)q8[l + 0];
174 aux32[l & 7] += (int)sc[is + 2] * (int)q2 * (int)q8[l + 32];
175 aux32[l & 7] += (int)sc[is + 4] * (int)q3 * (int)q8[l + 64];
176 aux32[l & 7] += (int)sc[is + 6] * (int)q4 * (int)q8[l + 96];
177 }
178 q8 += 128;
179 ql += 64;
180 qh += 32;
181 sc += 8;
182 }
183
184 for (int l = 0; l < 8; ++l) {
185 sums[l] += d * (float)aux32[l];
186 }
187 }
188
189 for (int l = 0; l < 8; ++l) {
190 sumf += sums[l];
191 }
192 return sumf;
193}
#define GGML_FP16_TO_FP32
int8_t scales[256/16]
int8_t qs[256]

References block_q8_K::d, GGML_FP16_TO_FP32, block_q6_K::qh, QK_K, block_q6_K::ql, block_q8_K::qs, and block_q6_K::scales.

Referenced by ck_dot_q6_k_q8_k_fast_or_ref(), gemv_q6_k_q8_k_parallel(), gemv_q6_k_q8_k_parallel_simd(), gemv_q6_k_q8_k_ref(), and vec_dot_q6_k_q8_k().

◆ gemm_nt_q6_k_q8_k()

void gemm_nt_q6_k_q8_k ( const void *  A_q8,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

NT GEMM: C = A @ B^T where A is Q8_K and B is Q6_K.

This is the typical inference pattern:

  • A: Activations in Q8_K format [M x K]
  • B: Weights in Q6_K format [N x K]
  • C: Output [M x N]
Parameters
A_q8Input activations in Q8_K format
BWeight matrix in Q6_K format
biasOptional bias vector [N]
COutput matrix
MBatch size (number of tokens)
NOutput dimension
KInput dimension

Definition at line 1515 of file gemm_kernels_q6k_q8k.c.

1520{
1521 if (!A_q8 || !B || !C) {
1522 return;
1523 }
1524 if (M <= 0 || N <= 0 || K <= 0) {
1525 return;
1526 }
1527
1528 /* Prefill GEMM is the hot Qwen2/Qwen3.5 MLP-down path. Keep decode
1529 * gemv_q6_k_q8_k() conservative, but allow GEMM/prefill to use the
1530 * parity-gated SIMD dot helper by default. CK strict parity and
1531 * CK_DEBUG_Q6K_Q8K_REF=1 still force the scalar reference reduction. */
1532 const block_q8_K *A = (const block_q8_K *)A_q8;
1533 const block_q6_K *W = (const block_q6_K *)B;
1534 const int blocks_per_vec = K / QK_K;
1535 const int blocks_per_row = K / QK_K;
1536
1537 for (int m = 0; m < M; ++m) {
1538 const block_q8_K *a_row = A + (size_t)m * (size_t)blocks_per_vec;
1539 float *c_row = C + (size_t)m * (size_t)N;
1540 for (int n = 0; n < N; ++n) {
1541 const block_q6_K *w_row = W + (size_t)n * (size_t)blocks_per_row;
1542 const float b = bias ? bias[n] : 0.0f;
1543 c_row[n] = ck_dot_q6_k_q8_k_fast_or_ref(w_row, a_row, K) + b;
1544 }
1545 }
1546}
static float ck_dot_q6_k_q8_k_fast_or_ref(const block_q6_K *w, const block_q8_K *x, int K)
#define C(color)
Definition show_config.c:39

References C, ck_dot_q6_k_q8_k_fast_or_ref(), and QK_K.

Referenced by ck_test_gemm_q6_k(), gemm_nt_q8_k_mlp_dispatch(), and gemm_nt_q8_k_qkv_dispatch().

◆ gemm_nt_q6_k_q8_k_m4_tile()

void gemm_nt_q6_k_q8_k_m4_tile ( const void *  A_q8,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K,
int  m0,
int  m1,
int  n0,
int  n1 
)

Definition at line 1702 of file gemm_kernels_q6k_q8k.c.

1709{
1710 if (!A_q8 || !B || !C || M <= 0 || N <= 0 || K <= 0 ||
1711 K % QK_K != 0) {
1712 return;
1713 }
1714 if (m0 < 0) m0 = 0;
1715 if (n0 < 0) n0 = 0;
1716 if (m1 > M) m1 = M;
1717 if (n1 > N) n1 = N;
1718 if (m0 >= m1 || n0 >= n1) return;
1719
1720#if defined(__AVX2__)
1722 const block_q8_K *A = (const block_q8_K *)A_q8;
1723 const block_q6_K *W = (const block_q6_K *)B;
1724 const int blocks_per_vec = K / QK_K;
1725 for (int n = n0; n < n1; ++n) {
1726 const block_q6_K *w_row =
1727 W + (size_t)n * (size_t)blocks_per_vec;
1728 const float b = bias ? bias[n] : 0.0f;
1729 int m = m0;
1730 for (; m + 4 <= m1; m += 4) {
1731 float values[4];
1732 dot_q6_k_q8_k_avx2_m4(
1733 w_row, A + (size_t)m * (size_t)blocks_per_vec,
1734 blocks_per_vec, 4, K, values);
1735 for (int r = 0; r < 4; ++r) {
1736 C[(size_t)(m + r) * (size_t)N + (size_t)n] = values[r] + b;
1737 }
1738 }
1739 if (m < m1) {
1740 float values[4];
1741 const int rows = m1 - m;
1742 dot_q6_k_q8_k_avx2_m4(
1743 w_row, A + (size_t)m * (size_t)blocks_per_vec,
1744 blocks_per_vec, rows, K, values);
1745 for (int r = 0; r < rows; ++r) {
1746 C[(size_t)(m + r) * (size_t)N + (size_t)n] = values[r] + b;
1747 }
1748 }
1749 }
1750 return;
1751 }
1752#endif
1754 A_q8, B, bias, C, M, N, K, m0, m1, n0, n1);
1755}
void gemm_nt_q6_k_q8_k_tile(const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K, int m0, int m1, int n0, int n1)
Compute one C[m0:m1, n0:n1] tile for Q8_K activations x Q6_K weights.

References C, ck_q6k_q8k_force_ref(), ck_strict_parity_enabled(), gemm_nt_q6_k_q8_k_tile(), and QK_K.

◆ gemm_nt_q6_k_q8_k_prepared()

void gemm_nt_q6_k_q8_k_prepared ( const void *  A_q8,
const void *  B_prepared,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 1631 of file gemm_kernels_q6k_q8k.c.

1636{
1638 A_q8, B_prepared, bias, C, M, N, K, 0, M, 0, N);
1639}
void gemm_nt_q6_k_q8_k_prepared_tile(const void *A_q8, const void *B_prepared, const float *bias, float *C, int M, int N, int K, int m0, int m1, int n0, int n1)

References C, and gemm_nt_q6_k_q8_k_prepared_tile().

◆ gemm_nt_q6_k_q8_k_prepared_avx512_vnni()

void gemm_nt_q6_k_q8_k_prepared_avx512_vnni ( const void *  A_q8,
const void *  B_prepared,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 1619 of file gemm_kernels_q6k_q8k.c.

1625{
1627 A_q8, B_prepared, bias, C, M, N, K,
1628 0, M, 0, N, 1);
1629}
static void gemm_nt_q6_k_q8_k_prepared_tile_impl(const void *A_q8, const void *B_prepared, const float *bias, float *C, int M, int N, int K, int m0, int m1, int n0, int n1, int use_avx512_vnni)

References C, and gemm_nt_q6_k_q8_k_prepared_tile_impl().

◆ gemm_nt_q6_k_q8_k_prepared_tile()

void gemm_nt_q6_k_q8_k_prepared_tile ( const void *  A_q8,
const void *  B_prepared,
const float *  bias,
float *  C,
int  M,
int  N,
int  K,
int  m0,
int  m1,
int  n0,
int  n1 
)

Definition at line 1601 of file gemm_kernels_q6k_q8k.c.

1608{
1609 int use_avx512_vnni = 0;
1610#if defined(__AVX512F__) && defined(__AVX512BW__) && \
1611 defined(__AVX512VNNI__)
1612 use_avx512_vnni = 1;
1613#endif
1615 A_q8, B_prepared, bias, C, M, N, K,
1616 m0, m1, n0, n1, use_avx512_vnni);
1617}

References C, and gemm_nt_q6_k_q8_k_prepared_tile_impl().

Referenced by gemm_nt_q6_k_q8_k_prepared().

◆ gemm_nt_q6_k_q8_k_prepared_tile_impl()

static void gemm_nt_q6_k_q8_k_prepared_tile_impl ( const void *  A_q8,
const void *  B_prepared,
const float *  bias,
float *  C,
int  M,
int  N,
int  K,
int  m0,
int  m1,
int  n0,
int  n1,
int  use_avx512_vnni 
)
static

Definition at line 1548 of file gemm_kernels_q6k_q8k.c.

1557{
1558#if !defined(__AVX2__)
1559 (void)A_q8; (void)B_prepared; (void)bias; (void)C;
1560 (void)M; (void)N; (void)K; (void)m0; (void)m1; (void)n0; (void)n1;
1561 (void)use_avx512_vnni;
1562#else
1563#if !defined(__AVX512F__) || !defined(__AVX512BW__) || \
1564 !defined(__AVX512VNNI__)
1565 (void)use_avx512_vnni;
1566#endif
1567 if (!A_q8 || !B_prepared || !C || M <= 0 || N <= 0 || K <= 0 ||
1568 (K % QK_K) != 0) return;
1569 if (m0 < 0) m0 = 0;
1570 if (n0 < 0) n0 = 0;
1571 if (m1 > M) m1 = M;
1572 if (n1 > N) n1 = N;
1573 if (m0 >= m1 || n0 >= n1) return;
1574
1575 const block_q8_K *A = (const block_q8_K *)A_q8;
1576 const block_q6_K_prepared *W =
1577 (const block_q6_K_prepared *)B_prepared;
1578 const int blocks_per_row = K / QK_K;
1579 for (int n = n0; n < n1; ++n) {
1580 const block_q6_K_prepared *w_row =
1581 W + (size_t)n * (size_t)blocks_per_row;
1582 const float b = bias ? bias[n] : 0.0f;
1583 for (int m = m0; m < m1; ++m) {
1584 const block_q8_K *a_row =
1585 A + (size_t)m * (size_t)blocks_per_row;
1586#if defined(__AVX512F__) && defined(__AVX512BW__) && \
1587 defined(__AVX512VNNI__)
1588 const float dot = use_avx512_vnni
1589 ? dot_q6_k_prepared_q8_k_avx512_vnni(w_row, a_row, K)
1590 : dot_q6_k_prepared_q8_k_avx2(w_row, a_row, K);
1591#else
1592 const float dot = dot_q6_k_prepared_q8_k_avx2(w_row, a_row, K);
1593#endif
1594 C[(size_t)m * (size_t)N + (size_t)n] =
1595 dot + b;
1596 }
1597 }
1598#endif
1599}

References C, and QK_K.

Referenced by gemm_nt_q6_k_q8_k_prepared_avx512_vnni(), and gemm_nt_q6_k_q8_k_prepared_tile().

◆ gemm_nt_q6_k_q8_k_tile()

void gemm_nt_q6_k_q8_k_tile ( const void *  A_q8,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K,
int  m0,
int  m1,
int  n0,
int  n1 
)

Compute one C[m0:m1, n0:n1] tile for Q8_K activations x Q6_K weights.

Pure tile math only: no threadpool, no global scheduling, no allocation. The orchestrator decides how to split tile jobs across cores.

Definition at line 1665 of file gemm_kernels_q6k_q8k.c.

1672{
1673 if (!A_q8 || !B || !C) {
1674 return;
1675 }
1676 if (M <= 0 || N <= 0 || K <= 0 || K % QK_K != 0) {
1677 return;
1678 }
1679 if (m0 < 0) m0 = 0;
1680 if (n0 < 0) n0 = 0;
1681 if (m1 > M) m1 = M;
1682 if (n1 > N) n1 = N;
1683 if (m0 >= m1 || n0 >= n1) {
1684 return;
1685 }
1686
1687 const block_q8_K *A = (const block_q8_K *)A_q8;
1688 const block_q6_K *W = (const block_q6_K *)B;
1689 const int blocks_per_vec = K / QK_K;
1690 const int blocks_per_row = K / QK_K;
1691
1692 for (int n = n0; n < n1; ++n) {
1693 const block_q6_K *w_row = W + (size_t)n * (size_t)blocks_per_row;
1694 const float b = bias ? bias[n] : 0.0f;
1695 for (int m = m0; m < m1; ++m) {
1696 const block_q8_K *a_row = A + (size_t)m * (size_t)blocks_per_vec;
1697 C[(size_t)m * (size_t)N + (size_t)n] = ck_dot_q6_k_q8_k_fast_or_ref(w_row, a_row, K) + b;
1698 }
1699 }
1700}

References C, ck_dot_q6_k_q8_k_fast_or_ref(), and QK_K.

Referenced by gemm_nt_q6_k_q8_k_m4_tile(), and gemm_nt_q6_k_q8_k_tiled().

◆ gemm_nt_q6_k_q8_k_tiled()

void gemm_nt_q6_k_q8_k_tiled ( const void *  A_q8,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Experimental single-thread tiled NT GEMM wrapper.

Kept as a separate symbol from gemm_nt_q6_k_q8_k for benchmarks and parity. Production prefill should prefer the v8 2D tile scheduler when enabled.

Definition at line 1763 of file gemm_kernels_q6k_q8k.c.

1768{
1769 enum { TILE_M = 8, TILE_N = 16 };
1770 for (int n0 = 0; n0 < N; n0 += TILE_N) {
1771 const int n1 = (n0 + TILE_N < N) ? (n0 + TILE_N) : N;
1772 for (int m0 = 0; m0 < M; m0 += TILE_M) {
1773 const int m1 = (m0 + TILE_M < M) ? (m0 + TILE_M) : M;
1774 gemm_nt_q6_k_q8_k_tile(A_q8, B, bias, C, M, N, K, m0, m1, n0, n1);
1775 }
1776 }
1777}

References C, and gemm_nt_q6_k_q8_k_tile().

◆ gemm_q6_k_q8_k()

void gemm_q6_k_q8_k ( float *  Y,
const void *  W,
const void *  X_q8,
int  M,
int  N,
int  K 
)

GEMM: Y = W @ X^T where W is Q6_K and X is Q8_K.

Parameters
YOutput matrix [N x M] in row-major
WWeight matrix in Q6_K format [M x K]
X_q8Input matrix in Q8_K format [N x K]
MNumber of output rows (output dim)
NNumber of input vectors (batch size)
KInput dimension

Definition at line 1481 of file gemm_kernels_q6k_q8k.c.

1485{
1486 if (!Y || !W || !X_q8 || M <= 0 || N <= 0 || K <= 0) {
1487 return;
1488 }
1489
1490 const block_q8_K *X = (const block_q8_K *)X_q8;
1491 const int blocks_per_vec = K / QK_K;
1492
1493 for (int n = 0; n < N; ++n) {
1494 const block_q8_K *x_row = X + (size_t)n * (size_t)blocks_per_vec;
1495 gemv_q6_k_q8_k(&Y[n * M], W, x_row, M, K);
1496 }
1497}
void gemv_q6_k_q8_k(float *y, const void *W, const void *x_q8, int M, int K)
GEMV: y = W @ x where W is Q6_K and x is Q8_K.

References gemv_q6_k_q8_k(), and QK_K.

◆ gemv_q6_k_q8_k()

void gemv_q6_k_q8_k ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

GEMV: y = W @ x where W is Q6_K and x is Q8_K.

Definition at line 1341 of file gemm_kernels_q6k_q8k.c.

1345{
1347 gemv_q6_k_q8_k_ref(y, W, x_q8, M, K);
1348 return;
1349 }
1350
1351#if defined(__AVX2__)
1352 /* llama.cpp's x86 Q6_K production graph keeps the AVX2 reduction order
1353 * even when AVX-512 is available. Wider ISA availability is not a license
1354 * to change this numerical contract. */
1355 gemv_q6_k_q8_k_avx2(y, W, x_q8, M, K);
1356 return;
1357#elif defined(__AVX__)
1358 gemv_q6_k_q8_k_avx(y, W, x_q8, M, K);
1359 return;
1360#elif defined(__SSE4_1__)
1361 gemv_q6_k_q8_k_sse(y, W, x_q8, M, K);
1362 return;
1363#endif
1364 gemv_q6_k_q8_k_ref(y, W, x_q8, M, K);
1365}
void gemv_q6_k_q8_k_ref(float *y, const void *W, const void *x_q8, int M, int K)
void gemv_q6_k_q8_k_sse(float *y, const void *W, const void *x_q8, int M, int K)
void gemv_q6_k_q8_k_avx(float *y, const void *W, const void *x_q8, int M, int K)
void gemv_q6_k_q8_k_avx2(float *y, const void *W, const void *x_q8, int M, int K)

References ck_q6k_q8k_force_ref(), ck_strict_parity_enabled(), gemv_q6_k_q8_k_avx(), gemv_q6_k_q8_k_avx2(), gemv_q6_k_q8_k_ref(), and gemv_q6_k_q8_k_sse().

Referenced by ck_moe_q4k_mixed_route_work(), ck_test_gemv_q6_k(), ck_test_vec_dot_q6_k_q8_k(), gemm_q6_k_q8_k(), moe_swiglu_expert_forward_q4k_q6k_workspace(), and moe_swiglu_shared_forward_q4k_q6k_workspace().

◆ gemv_q6_k_q8_k_avx()

void gemv_q6_k_q8_k_avx ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

Referenced by gemv_q6_k_q8_k().

◆ gemv_q6_k_q8_k_avx2()

void gemv_q6_k_q8_k_avx2 ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

Referenced by gemv_q6_k_q8_k().

◆ gemv_q6_k_q8_k_avx512()

void gemv_q6_k_q8_k_avx512 ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

◆ gemv_q6_k_q8_k_avx512_vbmi()

void gemv_q6_k_q8_k_avx512_vbmi ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

◆ gemv_q6_k_q8_k_parallel()

void gemv_q6_k_q8_k_parallel ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K,
int  ith,
int  nth 
)

Parallel reference GEMV for Q6_K × Q8_K.

Caller provides ith (thread index) and nth (total threads). Each thread processes rows [r0, r1).

Definition at line 1398 of file gemm_kernels_q6k_q8k.c.

1403{
1404 if (!y || !W || !x_q8 || M <= 0 || K <= 0) return;
1405 if (ith < 0 || nth <= 0 || ith >= nth) return;
1406
1407 /* Compute row range for this thread */
1408 const int dr = (M + nth - 1) / nth;
1409 const int r0 = dr * ith;
1410 const int r1 = (r0 + dr < M) ? (r0 + dr) : M;
1411
1412 if (r0 >= M) return;
1413
1414 const block_q6_K *blocks = (const block_q6_K *)W;
1415 const block_q8_K *x = (const block_q8_K *)x_q8;
1416 const int blocks_per_row = K / QK_K;
1417
1418 for (int row = r0; row < r1; ++row) {
1419 const block_q6_K *w_row = blocks + (size_t)row * (size_t)blocks_per_row;
1420 y[row] = dot_q6_k_q8_k_ref(w_row, x, K);
1421 }
1422}

References dot_q6_k_q8_k_ref(), and QK_K.

◆ gemv_q6_k_q8_k_parallel_simd()

void gemv_q6_k_q8_k_parallel_simd ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K,
int  ith,
int  nth 
)

Parallel SIMD GEMV for Q6_K × Q8_K.

Uses best available SIMD (AVX/SSE) with row prefetching. Caller provides ith/nth from OpenMP region.

Definition at line 1430 of file gemm_kernels_q6k_q8k.c.

1435{
1436 if (!y || !W || !x_q8 || M <= 0 || K <= 0) return;
1437 if (ith < 0 || nth <= 0 || ith >= nth) return;
1438
1439 const int dr = (M + nth - 1) / nth;
1440 const int r0 = dr * ith;
1441 const int r1 = (r0 + dr < M) ? (r0 + dr) : M;
1442
1443 if (r0 >= M) return;
1444
1445 const block_q6_K *blocks = (const block_q6_K *)W;
1446 const block_q8_K *x = (const block_q8_K *)x_q8;
1447 const int blocks_per_row = K / QK_K;
1448 const int strict = ck_strict_parity_enabled() || ck_q6k_q8k_force_ref();
1449
1450 for (int row = r0; row < r1; ++row) {
1451 const block_q6_K *w_row = blocks + (size_t)row * (size_t)blocks_per_row;
1452#if defined(__AVX2__)
1453 y[row] = strict ? dot_q6_k_q8_k_ref(w_row, x, K)
1454 : dot_q6_k_q8_k_avx2(w_row, x, K);
1455#elif defined(__AVX__)
1456 y[row] = strict ? dot_q6_k_q8_k_ref(w_row, x, K)
1457 : dot_q6_k_q8_k_avx(w_row, x, K);
1458#elif defined(__SSE4_1__)
1459 y[row] = strict ? dot_q6_k_q8_k_ref(w_row, x, K)
1460 : dot_q6_k_q8_k_sse(w_row, x, K);
1461#else
1462 y[row] = dot_q6_k_q8_k_ref(w_row, x, K);
1463#endif
1464 }
1465}

References ck_q6k_q8k_force_ref(), ck_strict_parity_enabled(), dot_q6_k_q8_k_ref(), and QK_K.

◆ gemv_q6_k_q8_k_ref()

void gemv_q6_k_q8_k_ref ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

Definition at line 270 of file gemm_kernels_q6k_q8k.c.

274{
275 if (!y || !W || !x_q8 || M <= 0 || K <= 0) {
276 return;
277 }
278
279 const block_q6_K *blocks = (const block_q6_K *)W;
280 const block_q8_K *x = (const block_q8_K *)x_q8;
281 const int blocks_per_row = K / QK_K;
282
283 for (int row = 0; row < M; ++row) {
284 const block_q6_K *w_row = blocks + (size_t)row * (size_t)blocks_per_row;
285 y[row] = dot_q6_k_q8_k_ref(w_row, x, K);
286 }
287}

References dot_q6_k_q8_k_ref(), and QK_K.

Referenced by gemv_q6_k_q8_k().

◆ gemv_q6_k_q8_k_sse()

void gemv_q6_k_q8_k_sse ( float *  y,
const void *  W,
const void *  x_q8,
int  M,
int  K 
)

Referenced by gemv_q6_k_q8_k().

◆ vec_dot_q6_k_q8_k()

void vec_dot_q6_k_q8_k ( int  n,
float *  s,
const void *  vx,
const void *  vy 
)

Q6_K x Q8_K dot product (single row)

Definition at line 1324 of file gemm_kernels_q6k_q8k.c.

1325{
1326 if (!s || !vx || !vy || n <= 0) {
1327 return;
1328 }
1329
1330 const block_q6_K *x = (const block_q6_K *)vx;
1331 const block_q8_K *y = (const block_q8_K *)vy;
1332
1333 /* This is the architecture-neutral scalar oracle. Production x86 dispatch
1334 * uses the separately parity-tested SIMD reduction tree. */
1335 *s = dot_q6_k_q8_k_ref(x, y, n);
1336}

References dot_q6_k_q8_k_ref().