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

GEMM/GEMV kernels with Q4_K quantized weights. More...

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

Go to the source code of this file.

Macros

#define CK_Q4K_STACK_Q8_BLOCKS   128
 

Functions

static int ck_q4k_debug_q8_contract (void)
 
float dot_q4_k (const void *w_q4k, const float *x, int K)
 Compute dot product of Q4_K row with FP32 vector.
 
void gemm_nt_q4_k (const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
 
void gemm_q4_k (float *Y, const void *W, const float *X, int M, int N, int K)
 Auto-dispatch GEMM based on available SIMD.
 
void gemm_q4_k_backward (float *dX, const void *W, const float *dY, int M, int N, int K)
 Batched backward pass.
 
void gemm_q4_k_ref (float *Y, const void *W, const float *X, int M, int N, int K)
 Matrix-matrix multiply with Q4_K weights (scalar reference)
 
void gemv_q4_k (float *y, const void *W, const float *x, int M, int K)
 Auto-dispatch GEMV based on available SIMD.
 
void gemv_q4_k_backward (float *dX, const void *W, const float *dY, int M, int K)
 Auto-dispatch backward.
 
void gemv_q4_k_backward_ref (float *dX, const void *W, const float *dY, int M, int K)
 Backward pass: compute input gradient (scalar reference)
 
void gemv_q4_k_q8_k (float *y, const void *W, const void *x_q8, int M, int K)
 
void gemv_q4_k_ref (float *y, const void *W, const float *x, int M, int K)
 Matrix-vector multiply with Q4_K weights (scalar reference)
 
void quantize_row_q8_k (const float *x, void *vy, int k)
 

Detailed Description

GEMM/GEMV kernels with Q4_K quantized weights.

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 matrix multiplication where:

  • Activations (input): FP32
  • Weights: Q4_K (4.5 bits/weight, nested scales)
  • Output: FP32

Key optimization: Fused dequantization - weights are dequantized in registers and immediately used in FMA, never written to memory.

Operations:

  • gemv_q4_k: Matrix-vector multiply (batch=1, token generation)
  • gemm_q4_k: Matrix-matrix multiply (batch>1, prefill)

Definition in file gemm_kernels_q4k.c.

Macro Definition Documentation

◆ CK_Q4K_STACK_Q8_BLOCKS

#define CK_Q4K_STACK_Q8_BLOCKS   128

Definition at line 38 of file gemm_kernels_q4k.c.

Function Documentation

◆ ck_q4k_debug_q8_contract()

static int ck_q4k_debug_q8_contract ( void  )
static

Definition at line 43 of file gemm_kernels_q4k.c.

44{
45 static int cached = -1;
46 if (cached < 0) {
47 const char *env = getenv("CK_DEBUG_Q4K_Q8_CONTRACT");
48 cached = (env && env[0] && env[0] != '0') ? 1 : 0;
49 }
50 return cached;
51}

Referenced by gemv_q4_k().

◆ dot_q4_k()

float dot_q4_k ( const void *  w_q4k,
const float *  x,
int  K 
)

Compute dot product of Q4_K row with FP32 vector.

Parameters
w_q4kQ4_K blocks for one row
xFP32 input vector
KVector length (must be multiple of 256)
Returns
Dot product result

Definition at line 509 of file gemm_kernels_q4k.c.

510{
511 float result;
512 gemv_q4_k(&result, w_q4k, x, 1, K);
513 return result;
514}
void gemv_q4_k(float *y, const void *W, const float *x, int M, int K)
Auto-dispatch GEMV based on available SIMD.

References gemv_q4_k().

◆ gemm_nt_q4_k()

void gemm_nt_q4_k ( const float *  A,
const void *  B,
const float *  bias,
float *  C,
int  M,
int  N,
int  K 
)

Definition at line 708 of file gemm_kernels_q4k.c.

713{
714 if (!A || !B || !C) {
715 return;
716 }
717 if (M <= 0 || N <= 0 || K <= 0) {
718 return;
719 }
720
721 /* gemm_q4_k produces Y as [batch x M_out]. Here:
722 * batch = M (tokens)
723 * M_out = N (output channels) */
724 gemm_q4_k(C, B, A, /*M_out=*/N, /*N_batch=*/M, K);
725
726 if (!bias) {
727 return;
728 }
729
730 for (int i = 0; i < M; ++i) {
731 float *row = C + (size_t)i * (size_t)N;
732 for (int j = 0; j < N; ++j) {
733 row[j] += bias[j];
734 }
735 }
736}
void gemm_q4_k(float *Y, const void *W, const float *X, int M, int N, int K)
Auto-dispatch GEMM based on available SIMD.
#define C(color)
Definition show_config.c:39

References C, and gemm_q4_k().

Referenced by ck_attention_project_head_major_q4_k(), ck_gemm_nt_quant(), ck_layer_forward_rmsnorm_swiglu_decode_q4_k(), ck_mlp_swiglu_forward_q4_k(), ck_qkv_project_head_major_q4_k(), ck_qkv_project_head_major_token_q4_k(), model_decode_token(), model_decode_token(), model_layer_0_decode(), model_layer_0_decode(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_0_prefill(), model_layer_10_decode(), model_layer_10_decode(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_10_prefill(), model_layer_11_decode(), model_layer_11_decode(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_11_prefill(), model_layer_12_decode(), model_layer_12_decode(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_12_prefill(), model_layer_13_decode(), model_layer_13_decode(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_13_prefill(), model_layer_14_decode(), model_layer_14_decode(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_14_prefill(), model_layer_15_decode(), model_layer_15_decode(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_15_prefill(), model_layer_16_decode(), model_layer_16_decode(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_16_prefill(), model_layer_17_decode(), model_layer_17_decode(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_17_prefill(), model_layer_18_decode(), model_layer_18_decode(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_18_prefill(), model_layer_19_decode(), model_layer_19_decode(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_19_prefill(), model_layer_1_decode(), model_layer_1_decode(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_1_prefill(), model_layer_20_decode(), model_layer_20_decode(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_20_prefill(), model_layer_21_decode(), model_layer_21_decode(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_21_prefill(), model_layer_22_decode(), model_layer_22_decode(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_22_prefill(), model_layer_23_decode(), model_layer_23_decode(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_23_prefill(), model_layer_2_decode(), model_layer_2_decode(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_2_prefill(), model_layer_3_decode(), model_layer_3_decode(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_3_prefill(), model_layer_4_decode(), model_layer_4_decode(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_4_prefill(), model_layer_5_decode(), model_layer_5_decode(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_5_prefill(), model_layer_6_decode(), model_layer_6_decode(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_6_prefill(), model_layer_7_decode(), model_layer_7_decode(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_7_prefill(), model_layer_8_decode(), model_layer_8_decode(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_8_prefill(), model_layer_9_decode(), model_layer_9_decode(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), model_layer_9_prefill(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_decode_token(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_decode(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_0_prefill(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_decode(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_10_prefill(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_decode(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_11_prefill(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_decode(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_12_prefill(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_decode(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_13_prefill(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_decode(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_14_prefill(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_decode(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_15_prefill(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_decode(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_16_prefill(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_decode(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_17_prefill(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_decode(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_18_prefill(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_decode(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_19_prefill(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_decode(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_1_prefill(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_decode(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_20_prefill(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_decode(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_21_prefill(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_decode(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_22_prefill(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_decode(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_23_prefill(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_decode(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_2_prefill(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_decode(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_3_prefill(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_decode(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_4_prefill(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_decode(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_5_prefill(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_decode(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_6_prefill(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_decode(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_7_prefill(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_decode(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_8_prefill(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_decode(), qwen2_0_5b_decode_layer_9_prefill(), qwen2_0_5b_decode_layer_9_prefill(), qwen2_0_5b_decode_layer_9_prefill(), and qwen2_0_5b_decode_layer_9_prefill().

◆ gemm_q4_k()

void gemm_q4_k ( float *  Y,
const void *  W,
const float *  X,
int  M,
int  N,
int  K 
)

Auto-dispatch GEMM based on available SIMD.

Definition at line 486 of file gemm_kernels_q4k.c.

490{
491 /* Use reference implementation for correctness
492 * TODO: Fix AVX-512 version to match llama.cpp layout */
493 gemm_q4_k_ref(Y, W, X, M, N, K);
494}
void gemm_q4_k_ref(float *Y, const void *W, const float *X, int M, int N, int K)
Matrix-matrix multiply with Q4_K weights (scalar reference)

References gemm_q4_k_ref().

Referenced by gemm_nt_q4_k().

◆ gemm_q4_k_backward()

void gemm_q4_k_backward ( float *  dX,
const void *  W,
const float *  dY,
int  M,
int  N,
int  K 
)

Batched backward pass.

Definition at line 681 of file gemm_kernels_q4k.c.

685{
686 for (int n = 0; n < N; n++) {
687 gemv_q4_k_backward(&dX[n * K], W, &dY[n * M], M, K);
688 }
689}
void gemv_q4_k_backward(float *dX, const void *W, const float *dY, int M, int K)
Auto-dispatch backward.

References gemv_q4_k_backward().

◆ gemm_q4_k_ref()

void gemm_q4_k_ref ( float *  Y,
const void *  W,
const float *  X,
int  M,
int  N,
int  K 
)

Matrix-matrix multiply with Q4_K weights (scalar reference)

Parameters
YOutput matrix [M x N]
WWeight matrix in Q4_K format [M x K]
XInput matrix [K x N] (column-major for cache efficiency)
MNumber of output rows
NBatch size (number of columns)
KHidden dimension

Definition at line 341 of file gemm_kernels_q4k.c.

345{
346 /* For each column in batch, use the dispatching gemv_q4_k
347 * which automatically selects AVX/AVX-512/scalar based on CPU */
348 for (int n = 0; n < N; n++) {
349 gemv_q4_k(&Y[n * M], W, &X[n * K], M, K);
350 }
351}

References gemv_q4_k().

Referenced by gemm_q4_k().

◆ gemv_q4_k()

void gemv_q4_k ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Auto-dispatch GEMV based on available SIMD.

Definition at line 301 of file gemm_kernels_q4k.c.

305{
306 if (ck_q4k_debug_q8_contract() && K > 0 && (K % QK_K) == 0) {
307 const int nb = K / QK_K;
308 if (nb <= CK_Q4K_STACK_Q8_BLOCKS) {
310 quantize_row_q8_k(x, x_q8, K);
311 gemv_q4_k_q8_k(y, W, x_q8, M, K);
312 return;
313 }
314 }
315#ifdef __AVX512F__
316 gemv_q4_k_avx512(y, W, x, M, K);
317#elif defined(__AVX__)
318 gemv_q4_k_avx(y, W, x, M, K);
319#else
320 gemv_q4_k_ref(y, W, x, M, K);
321#endif
322}
#define QK_K
void gemv_q4_k_ref(float *y, const void *W, const float *x, int M, int K)
Matrix-vector multiply with Q4_K weights (scalar reference)
#define CK_Q4K_STACK_Q8_BLOCKS
void quantize_row_q8_k(const float *x, void *vy, int k)
void gemv_q4_k_q8_k(float *y, const void *W, const void *x_q8, int M, int K)
static int ck_q4k_debug_q8_contract(void)

References ck_q4k_debug_q8_contract(), CK_Q4K_STACK_Q8_BLOCKS, gemv_q4_k_q8_k(), gemv_q4_k_ref(), QK_K, and quantize_row_q8_k().

Referenced by attention_mlp_fused_q4k(), dot_q4_k(), gemm_q4_k_ref(), layer_fused_attn_mlp_qkv_q4k(), and rmsnorm_qkv_q4k_fused().

◆ gemv_q4_k_backward()

void gemv_q4_k_backward ( float *  dX,
const void *  W,
const float *  dY,
int  M,
int  K 
)

Auto-dispatch backward.

Definition at line 666 of file gemm_kernels_q4k.c.

670{
671#ifdef __AVX512F__
672 gemv_q4_k_backward_avx512(dX, W, dY, M, K);
673#else
674 gemv_q4_k_backward_ref(dX, W, dY, M, K);
675#endif
676}
void gemv_q4_k_backward_ref(float *dX, const void *W, const float *dY, int M, int K)
Backward pass: compute input gradient (scalar reference)

References gemv_q4_k_backward_ref().

Referenced by gemm_q4_k_backward().

◆ gemv_q4_k_backward_ref()

void gemv_q4_k_backward_ref ( float *  dX,
const void *  W,
const float *  dY,
int  M,
int  K 
)

Backward pass: compute input gradient (scalar reference)

Parameters
dXOutput gradient w.r.t. input [K]
WWeight matrix in Q4_K format [M x K]
dYGradient w.r.t. output [M]
MNumber of output rows
KNumber of columns (input dimension)

Definition at line 536 of file gemm_kernels_q4k.c.

540{
541 const block_q4_K *blocks = (const block_q4_K *)W;
542 const int blocks_per_row = K / QK_K;
543
544 /* Zero output gradient */
545 memset(dX, 0, K * sizeof(float));
546
547 /* Accumulate: dX += W^T @ dY
548 * Uses llama.cpp layout: 4 iterations of 64 weights each */
549 for (int row = 0; row < M; row++) {
550 const float dy = dY[row];
551
552 for (int b = 0; b < blocks_per_row; b++) {
553 const block_q4_K *block = &blocks[row * blocks_per_row + b];
554 const float d = CK_FP16_TO_FP32(block->d);
555 const float dmin = CK_FP16_TO_FP32(block->dmin);
556
557 uint8_t sc[8], m[8];
558 unpack_q4_k_scales(block->scales, sc, m);
559
560 /* llama.cpp layout: 4 iterations of 64 weights each */
561 for (int iter = 0; iter < 4; iter++) {
562 const float d1 = d * (float)sc[2 * iter];
563 const float m1 = dmin * (float)m[2 * iter];
564 const float d2 = d * (float)sc[2 * iter + 1];
565 const float m2 = dmin * (float)m[2 * iter + 1];
566
567 const uint8_t *qs = &block->qs[iter * 32];
568 float *dxp = &dX[b * QK_K + iter * 64];
569
570 /* First 32 weights: low nibbles */
571 for (int l = 0; l < 32; l++) {
572 const int q = (qs[l] & 0x0F);
573 const float w = d1 * (float)q - m1;
574 dxp[l] += w * dy;
575 }
576
577 /* Next 32 weights: high nibbles */
578 for (int l = 0; l < 32; l++) {
579 const int q = (qs[l] >> 4);
580 const float w = d2 * (float)q - m2;
581 dxp[32 + l] += w * dy;
582 }
583 }
584 }
585 }
586}
#define CK_FP16_TO_FP32(x)
static void unpack_q4_k_scales(const uint8_t *scales, uint8_t *sc, uint8_t *m)
Unpack Q4_K sub-block scales and mins.
uint8_t scales[12]
uint8_t qs[256/2]

References CK_FP16_TO_FP32, block_q4_K::d, block_q4_K::dmin, QK_K, block_q4_K::qs, block_q4_K::scales, and unpack_q4_k_scales().

Referenced by gemv_q4_k_backward().

◆ gemv_q4_k_q8_k()

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

Definition at line 273 of file gemm_kernels_q4k_q8k.c.

277{
278 if (ck_q4k_q8k_force_ref()) {
279 gemv_q4_k_q8_k_ref(y, W, x_q8, M, K);
280 return;
281 }
282#if defined(__AVX512VNNI__) && defined(__AVX512VL__) && !defined(CK_NO_AVX512_VNNI)
283 /* VNNI: Best for decode (single token) - INT8 dot product acceleration */
284 gemv_q4_k_q8_k_vnni(y, W, x_q8, M, K);
285#elif defined(__AVX2__)
286 gemv_q4_k_q8_k_avx2(y, W, x_q8, M, K);
287#elif defined(__AVX__)
288 /* AVX version uses maddubs_epi16 (more efficient than SSE) */
289 gemv_q4_k_q8_k_avx(y, W, x_q8, M, K);
290#elif defined(__SSE4_1__)
291 gemv_q4_k_q8_k_sse(y, W, x_q8, M, K);
292#else
293 gemv_q4_k_q8_k_ref(y, W, x_q8, M, K);
294#endif
295}
void gemv_q4_k_q8_k_avx2(float *y, const void *W, const void *x_q8, int M, int K)
void gemv_q4_k_q8_k_vnni(float *y, const void *W, const void *x_q8, int M, int K)
void gemv_q4_k_q8_k_ref(float *y, const void *W, const void *x_q8, int M, int K)
static int ck_q4k_q8k_force_ref(void)
void gemv_q4_k_q8_k_avx(float *y, const void *W, const void *x_q8, int M, int K)
void gemv_q4_k_q8_k_sse(float *y, const void *W, const void *x_q8, int M, int K)

Referenced by gemm_q4_k_q8_k(), gemm_q4_k_q8_k_thread_fn(), and gemv_q4_k().

◆ gemv_q4_k_ref()

void gemv_q4_k_ref ( float *  y,
const void *  W,
const float *  x,
int  M,
int  K 
)

Matrix-vector multiply with Q4_K weights (scalar reference)

Parameters
yOutput vector [M]
WWeight matrix in Q4_K format [M x K], stored row-major
xInput vector [K]
MNumber of output rows
KNumber of columns (must be multiple of 256)

Definition at line 69 of file gemm_kernels_q4k.c.

73{
74 const block_q4_K *blocks = (const block_q4_K *)W;
75 const int blocks_per_row = K / QK_K; /* QK_K = 256 */
76
77 for (int row = 0; row < M; row++) {
78 float sum = 0.0f;
79
80 for (int b = 0; b < blocks_per_row; b++) {
81 const block_q4_K *block = &blocks[row * blocks_per_row + b];
82 const float d = GGML_FP16_TO_FP32(block->d);
83 const float dmin = GGML_FP16_TO_FP32(block->dmin);
84
85 /* Unpack sub-block scales */
86 uint8_t sc[8], m[8];
87 unpack_q4_k_scales(block->scales, sc, m);
88
89 /* llama.cpp Q4_K layout: 4 iterations of 64 weights each
90 * Each iteration uses 32 bytes of qs and 2 scales:
91 * - First 32 weights (indices 0-31): low nibbles with scale[2*iter]
92 * - Next 32 weights (indices 32-63): high nibbles with scale[2*iter+1]
93 */
94 for (int iter = 0; iter < 4; iter++) {
95 const float d1 = d * (float)sc[2*iter];
96 const float m1 = dmin * (float)m[2*iter];
97 const float d2 = d * (float)sc[2*iter + 1];
98 const float m2 = dmin * (float)m[2*iter + 1];
99 const uint8_t *qs = &block->qs[iter * 32];
100 const float *xp = &x[b * QK_K + iter * 64];
101
102 /* First 32 weights: low nibbles of qs[0..31] */
103 for (int l = 0; l < 32; l++) {
104 const int8_t q = (qs[l] & 0x0F);
105 sum += (d1 * (float)q - m1) * xp[l];
106 }
107 /* Next 32 weights: high nibbles of qs[0..31] */
108 for (int l = 0; l < 32; l++) {
109 const int8_t q = (qs[l] >> 4);
110 sum += (d2 * (float)q - m2) * xp[l + 32];
111 }
112 }
113 }
114
115 y[row] = sum;
116 }
117}
#define GGML_FP16_TO_FP32

References block_q4_K::d, block_q4_K::dmin, GGML_FP16_TO_FP32, QK_K, block_q4_K::qs, block_q4_K::scales, and unpack_q4_k_scales().

Referenced by gemv_q4_k().

◆ quantize_row_q8_k()

void quantize_row_q8_k ( const float *  x,
void *  vy,
int  k 
)

Definition at line 121 of file gemm_kernels_q4k_q8k.c.

121 {
122 const char *ref_env = getenv("CK_DEBUG_Q8K_REF");
123 if (ref_env && atoi(ref_env) != 0) {
124 quantize_row_q8_k_ref(x, vy, k);
125 return;
126 }
127#if defined(__AVX512F__) && defined(__AVX512BW__)
128 quantize_row_q8_k_avx512(x, vy, k);
129#elif defined(__AVX2__)
130 quantize_row_q8_k_avx2(x, vy, k);
131#elif defined(__AVX__)
132 quantize_row_q8_k_avx(x, vy, k);
133#elif defined(__SSE4_1__)
134 quantize_row_q8_k_sse(x, vy, k);
135#else
136 quantize_row_q8_k_ref(x, vy, k);
137#endif
138}
void quantize_row_q8_k_avx512(const float *x, void *vy, int k)
void quantize_row_q8_k_avx2(const float *x, void *vy, int k)
void quantize_row_q8_k_avx(const float *x, void *vy, int k)
void quantize_row_q8_k_sse(const float *x, void *vy, int k)
void quantize_row_q8_k_ref(const float *x, void *vy, int k)

Referenced by gemv_q4_k().