← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
ckernel_quant.h
Go to the documentation of this file.
1/**
2 * @file ckernel_quant.h
3 * @brief Quantization block structures for weight-only quantization
4 *
5 * Defines block structures for various quantization formats used in LLM inference.
6 * Primary focus on Q4_K_M which is commonly used for LLM weight compression.
7 *
8 * Block structures are compatible with llama.cpp/GGML for model loading.
9 */
10
11#ifndef CKERNEL_QUANT_H
12#define CKERNEL_QUANT_H
13
14#include <stdint.h>
15#include <stddef.h>
16#include <math.h>
17#include "ckernel_dtype.h"
18
19#ifdef __cplusplus
20extern "C" {
21#endif
22
23/* ============================================================================
24 * Half-Precision Type (FP16 - IEEE 754)
25 * ============================================================================ */
26
27typedef uint16_t ck_half;
28
29/* ============================================================================
30 * Q4_0: Simple 4-bit Quantization
31 * - 32 weights per block
32 * - 1 FP16 scale per block
33 * - 18 bytes per 32 weights = 4.5 bits/weight
34 * ============================================================================ */
35
36#define QK4_0 32
37
38typedef struct {
39 ck_half d; /* 2 bytes: scale (delta) */
40 uint8_t qs[QK4_0 / 2]; /* 16 bytes: 32 x 4-bit weights (2 per byte) */
42/* Total: 18 bytes per 32 weights */
43
44/* ============================================================================
45 * Q4_1: Simple 4-bit Quantization with Min
46 * - 32 weights per block
47 * - 2 FP16 values: scale (d) and min (m)
48 * - 20 bytes per 32 weights = 5.0 bits/weight
49 * ============================================================================ */
50
51#define QK4_1 32
52
53typedef struct {
54 ck_half d; /* 2 bytes: scale (delta) */
55 ck_half m; /* 2 bytes: minimum */
56 uint8_t qs[QK4_1 / 2]; /* 16 bytes: 32 x 4-bit weights (2 per byte) */
58/* Total: 20 bytes per 32 weights */
59
60/* ============================================================================
61 * Q5_0: Simple 5-bit Quantization
62 * - 32 weights per block
63 * - 1 FP16 scale per block
64 * - Low 4 bits stored like Q4_0, high 1 bit packed separately
65 * - 22 bytes per 32 weights = 5.5 bits/weight
66 * ============================================================================ */
67
68#define QK5_0 32
69
70typedef struct {
71 ck_half d; /* 2 bytes: scale (delta) */
72 uint8_t qh[4]; /* 4 bytes: high 1-bit of each weight (32 bits total) */
73 uint8_t qs[QK5_0 / 2]; /* 16 bytes: low 4-bits of 32 weights (2 per byte) */
75/* Total: 22 bytes per 32 weights */
76
77/* ============================================================================
78 * Q5_1: Simple 5-bit Quantization with Min
79 * - 32 weights per block
80 * - 2 FP16 values: scale (d) and min (m)
81 * - Low 4 bits stored like Q4_1, high 1 bit packed separately
82 * - 24 bytes per 32 weights = 6.0 bits/weight
83 * ============================================================================ */
84
85#define QK5_1 32
86
87typedef struct {
88 ck_half d; /* 2 bytes: scale (delta) */
89 ck_half m; /* 2 bytes: minimum */
90 uint8_t qh[4]; /* 4 bytes: high 1-bit of each weight (32 bits total) */
91 uint8_t qs[QK5_1 / 2]; /* 16 bytes: low 4-bits of 32 weights (2 per byte) */
93/* Total: 24 bytes per 32 weights */
94
95/* ============================================================================
96 * Q8_0: Simple 8-bit Quantization
97 * - 32 weights per block
98 * - 1 FP16 scale per block
99 * - 34 bytes per 32 weights = 8.5 bits/weight
100 * ============================================================================ */
101
102#define QK8_0 32
103
104typedef struct {
105 ck_half d; /* 2 bytes: scale */
106 int8_t qs[QK8_0]; /* 32 bytes: 32 x 8-bit signed weights */
107} block_q8_0;
108/* Total: 34 bytes per 32 weights */
109
110#if defined(__cplusplus)
111static_assert(sizeof(block_q8_0) == 34, "block_q8_0 ABI size changed");
112#else
113_Static_assert(sizeof(block_q8_0) == 34, "block_q8_0 ABI size changed");
114#endif
115
116/* ============================================================================
117 * NVFP4: NVIDIA E2M1 weights with two-level scaling
118 * - 64 weights per canonical storage block
119 * - Four unsigned E4M3 scales, one per 16 weights
120 * - Two E2M1 values packed per byte
121 * - A tensor/expert global scale remains a separate runtime operand
122 * ============================================================================ */
123
124#define QK_NVFP4 64
125#define QK_NVFP4_SUB 16
126
127typedef struct {
128 uint8_t d[QK_NVFP4 / QK_NVFP4_SUB];
129 uint8_t qs[QK_NVFP4 / 2];
131
132#if defined(__cplusplus)
133static_assert(sizeof(block_nvfp4) == 36, "block_nvfp4 ABI size changed");
134#else
135_Static_assert(sizeof(block_nvfp4) == 36, "block_nvfp4 ABI size changed");
136#endif
137
138float ck_ue4m3_to_fp32(uint8_t value);
139void dequantize_row_nvfp4(const void *weights, float *output, int k,
140 float weight_scale);
141void vec_dot_nvfp4_q8_0_ref(int n, float *output, const void *weights,
142 const void *activations, float weight_scale);
143void vec_dot_nvfp4_q8_0(int n, float *output, const void *weights,
144 const void *activations, float weight_scale);
145void gemv_nvfp4_q8_0(float *output, const void *weights,
146 const float *weight_scales, const void *activations,
147 int rows, int cols);
148size_t moe_swiglu_nvfp4_workspace_bytes(int hidden_dim, int intermediate_dim);
150 const float *hidden, const int *indices, const float *routing_weights,
151 const void *expert_gate, const float *expert_gate_scales,
152 const void *expert_up, const float *expert_up_scales,
153 const void *expert_down, const float *expert_down_scales,
154 float *output, int rows, int hidden_dim, int intermediate_dim,
155 int n_experts, int top_k, void *workspace, size_t workspace_bytes);
157 const float *hidden, const float *routed,
158 const void *shared_gate, const float *shared_gate_scale,
159 const void *shared_up, const float *shared_up_scale,
160 const void *shared_down, const float *shared_down_scale,
161 float *output, int rows, int hidden_dim, int intermediate_dim,
162 float combination_scale, void *workspace, size_t workspace_bytes);
163
164/* ============================================================================
165 * Q4_K: K-Quant 4-bit with Nested Scales (Primary Target)
166 * - 256 weights per super-block
167 * - 8 sub-blocks of 32 weights each
168 * - Two-level scaling: super-block FP16 + sub-block 6-bit
169 * - 144 bytes per 256 weights = 4.5 bits/weight
170 *
171 * This is the format used by Q4_K_M, Q4_K_S, Q4_K_L variants.
172 * The M/S/L suffix indicates quantization aggressiveness, not structure.
173 * ============================================================================ */
174
175#define QK_K 256
176#define K_SCALE_SIZE 12
177
178typedef struct {
179 ck_half d; /* 2 bytes: super-block scale */
180 ck_half dmin; /* 2 bytes: super-block minimum */
181 uint8_t scales[K_SCALE_SIZE]; /* 12 bytes: 8 sub-block scales + 8 sub-block mins (6-bit packed) */
182 uint8_t qs[QK_K / 2]; /* 128 bytes: 256 x 4-bit weights */
183} block_q4_K;
184/* Total: 144 bytes per 256 weights */
185
186/* ============================================================================
187 * Q6_K: K-Quant 6-bit (per-16 scales)
188 * - 256 weights per block
189 * - 16 sub-blocks of 16 weights each
190 * - Stored as low 4 bits (ql) + high 2 bits (qh) + int8 scales
191 * ============================================================================ */
192
193typedef struct {
194 uint8_t ql[QK_K / 2]; /* 128 bytes: low 4 bits */
195 uint8_t qh[QK_K / 4]; /* 64 bytes: high 2 bits */
196 int8_t scales[QK_K / 16]; /* 16 bytes: 16 sub-block scales */
197 ck_half d; /* 2 bytes: super-block scale */
198} block_q6_K;
199/* Total: 210 bytes per 256 weights */
200
201/* ============================================================================
202 * Q8_K: K-Quant 8-bit (used for activations in some ops)
203 * - 256 weights per super-block
204 * - 1 FP32 scale per block (not FP16 like others!)
205 * ============================================================================ */
206
207typedef struct {
208 float d; /* 4 bytes: scale */
209 int8_t qs[QK_K]; /* 256 bytes: 256 x 8-bit signed weights */
210 int16_t bsums[QK_K / 16]; /* 32 bytes: block sums for optimization */
211} block_q8_K;
212/* Total: 292 bytes per 256 weights */
213
214#if defined(__cplusplus)
215static_assert(sizeof(block_q8_K) == 292, "block_q8_K ABI size changed");
216#else
217_Static_assert(sizeof(block_q8_K) == 292, "block_q8_K ABI size changed");
218#endif
219
220/* ============================================================================
221 * Size Calculation Utilities
222 * ============================================================================ */
223
224/**
225 * @brief Get the block size (number of weights per block) for a quant type
226 */
227static inline size_t ck_quant_block_size(int type) {
228 switch (type) {
229 case 0: return QK4_0; /* Q4_0 */
230 case 1: return QK8_0; /* Q8_0 */
231 case 2: return QK_K; /* Q4_K */
232 case 3: return QK_K; /* Q8_K */
233 case CK_DT_Q4_1: return QK4_1;
234 case CK_DT_Q5_0: return QK5_0;
235 case CK_DT_Q5_1: return QK5_1;
236 case CK_DT_Q6_K: return QK_K;
237 default: return 1;
238 }
239}
240
241/**
242 * @brief Get the byte size per block for a quant type
243 */
244static inline size_t ck_quant_type_size(int type) {
245 switch (type) {
246 case 0: return sizeof(block_q4_0);
247 case 1: return sizeof(block_q8_0);
248 case 2: return sizeof(block_q4_K);
249 case 3: return sizeof(block_q8_K);
250 case CK_DT_Q4_1: return sizeof(block_q4_1);
251 case CK_DT_Q5_0: return sizeof(block_q5_0);
252 case CK_DT_Q5_1: return sizeof(block_q5_1);
253 case CK_DT_Q6_K: return sizeof(block_q6_K);
254 default: return 4; /* FP32 */
255 }
256}
257
258/**
259 * @brief Calculate total bytes needed for n_elements with given quant type
260 */
261static inline size_t ck_quant_row_size(int type, int64_t n_elements) {
262 size_t block_size = ck_quant_block_size(type);
263 size_t type_size = ck_quant_type_size(type);
264 return (n_elements / block_size) * type_size;
265}
266
267/* ============================================================================
268 * Q4_K Scale Unpacking Utilities
269 *
270 * The scales[12] array packs 8 scales and 8 mins in 6-bit format.
271 * Unpacking is non-trivial due to the bit packing.
272 * ============================================================================ */
273
274/**
275 * @brief Unpack Q4_K sub-block scales and mins
276 *
277 * @param scales The packed scales[12] array from block_q4_K
278 * @param sc Output: 8 unpacked scale values (multiply by super-block d)
279 * @param m Output: 8 unpacked min values (multiply by super-block dmin)
280 *
281 * This matches llama.cpp's get_scale_min_k4() function exactly.
282 * The 12-byte scales array layout:
283 * - bytes 0-3: 6-bit scales[0-3] (high 2 bits used for scales[4-7])
284 * - bytes 4-7: 6-bit mins[0-3] (high 2 bits used for mins[4-7])
285 * - bytes 8-11: low 4 bits for scales[4-7], high 4 bits for mins[4-7]
286 */
287static inline void unpack_q4_k_scales(const uint8_t *scales,
288 uint8_t *sc, uint8_t *m) {
289 /* Direct 6-bit values for indices 0-3 */
290 sc[0] = scales[0] & 0x3F;
291 sc[1] = scales[1] & 0x3F;
292 sc[2] = scales[2] & 0x3F;
293 sc[3] = scales[3] & 0x3F;
294
295 m[0] = scales[4] & 0x3F;
296 m[1] = scales[5] & 0x3F;
297 m[2] = scales[6] & 0x3F;
298 m[3] = scales[7] & 0x3F;
299
300 /* 6-bit values for indices 4-7: low 4 bits from bytes 8-11,
301 * high 2 bits from upper bits of bytes 0-3 (scales) and 4-7 (mins) */
302 sc[4] = (scales[8] & 0x0F) | ((scales[0] >> 6) << 4);
303 sc[5] = (scales[9] & 0x0F) | ((scales[1] >> 6) << 4);
304 sc[6] = (scales[10] & 0x0F) | ((scales[2] >> 6) << 4);
305 sc[7] = (scales[11] & 0x0F) | ((scales[3] >> 6) << 4);
306
307 m[4] = (scales[8] >> 4) | ((scales[4] >> 6) << 4);
308 m[5] = (scales[9] >> 4) | ((scales[5] >> 6) << 4);
309 m[6] = (scales[10] >> 4) | ((scales[6] >> 6) << 4);
310 m[7] = (scales[11] >> 4) | ((scales[7] >> 6) << 4);
311}
312
313/* ============================================================================
314 * FP16 Conversion Utilities
315 *
316 * Three variants:
317 * _soft - Pure C bit manipulation (always available, portable)
318 * _simd - F16C hardware instruction (vcvtph2ps/vcvtps2ph, Ivy Bridge+)
319 * (default) - Auto-dispatches to best available at compile time
320 * ============================================================================ */
321
322/**
323 * @brief Convert FP16 (ck_half) to FP32 — software implementation
324 */
325static inline float ck_fp16_to_fp32_soft(ck_half h) {
326 uint32_t sign = (h & 0x8000) << 16;
327 uint32_t exp = (h >> 10) & 0x1F;
328 uint32_t mant = h & 0x3FF;
329
330 uint32_t result;
331
332 if (exp == 0) {
333 if (mant == 0) {
334 result = sign;
335 } else {
336 /* Denormalized - convert to normalized FP32 */
337 exp = 1;
338 while ((mant & 0x400) == 0) {
339 mant <<= 1;
340 exp--;
341 }
342 mant &= 0x3FF;
343 result = sign | ((exp + 127 - 15) << 23) | (mant << 13);
344 }
345 } else if (exp == 31) {
346 result = sign | 0x7F800000 | (mant << 13);
347 } else {
348 result = sign | ((exp + 127 - 15) << 23) | (mant << 13);
349 }
350
351 union { uint32_t u; float f; } u;
352 u.u = result;
353 return u.f;
354}
355
356static inline uint32_t ck_fp32_to_bits(float f) {
357 union { float f; uint32_t u; } u;
358 u.f = f;
359 return u.u;
360}
361
362static inline float ck_fp32_from_bits(uint32_t u32) {
363 union { uint32_t u; float f; } u;
364 u.u = u32;
365 return u.f;
366}
367
368/**
369 * @brief Convert FP32 to FP16 (ck_half) — software implementation
370 */
371static inline ck_half ck_fp32_to_fp16_soft(float f) {
372#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) || defined(__GNUC__) && !defined(__STRICT_ANSI__)) && (!defined(__cplusplus) || __cplusplus >= 201703L)
373 const float scale_to_inf = 0x1.0p+112f;
374 const float scale_to_zero = 0x1.0p-110f;
375#else
376 const float scale_to_inf = ck_fp32_from_bits(UINT32_C(0x77800000));
377 const float scale_to_zero = ck_fp32_from_bits(UINT32_C(0x08800000));
378#endif
379 float base = (fabsf(f) * scale_to_inf) * scale_to_zero;
380
381 const uint32_t w = ck_fp32_to_bits(f);
382 const uint32_t shl1_w = w + w;
383 const uint32_t sign = w & UINT32_C(0x80000000);
384 uint32_t bias = shl1_w & UINT32_C(0xFF000000);
385 if (bias < UINT32_C(0x71000000)) {
386 bias = UINT32_C(0x71000000);
387 }
388
389 base = ck_fp32_from_bits((bias >> 1) + UINT32_C(0x07800000)) + base;
390 const uint32_t bits = ck_fp32_to_bits(base);
391 const uint32_t exp_bits = (bits >> 13) & UINT32_C(0x00007C00);
392 const uint32_t mantissa_bits = bits & UINT32_C(0x00000FFF);
393 const uint32_t nonsign = exp_bits + mantissa_bits;
394
395 return (ck_half) ((sign >> 16) | (shl1_w > UINT32_C(0xFF000000) ? UINT16_C(0x7E00) : nonsign));
396}
397
398/* --------------------------------------------------------------------------
399 * F16C Hardware SIMD conversion (requires Intel Ivy Bridge+ or AMD Piledriver+)
400 * Uses vcvtsh2ss / vcvtss2sh single-element hardware instructions.
401 * -------------------------------------------------------------------------- */
402#if defined(__F16C__)
403#include <immintrin.h>
404
405/**
406 * @brief Convert FP16 to FP32 — F16C hardware (1 instruction: vcvtsh2ss)
407 */
408static inline float ck_fp16_to_fp32_simd(ck_half h) {
409 return _cvtsh_ss(h);
410}
411
412/**
413 * @brief Convert FP32 to FP16 — F16C hardware (1 instruction: vcvtss2sh)
414 */
415static inline ck_half ck_fp32_to_fp16_simd(float f) {
416 return (ck_half)_cvtss_sh(f, _MM_FROUND_TO_NEAREST_INT);
417}
418#endif /* __F16C__ */
419
420/* --------------------------------------------------------------------------
421 * Default dispatch: selects hardware SIMD when available, else software
422 * -------------------------------------------------------------------------- */
423static inline float ck_fp16_to_fp32(ck_half h) {
424#if defined(__F16C__)
425 return ck_fp16_to_fp32_simd(h);
426#else
427 return ck_fp16_to_fp32_soft(h);
428#endif
429}
430
431static inline ck_half ck_fp32_to_fp16(float f) {
432#if defined(__F16C__)
433 return ck_fp32_to_fp16_simd(f);
434#else
435 return ck_fp32_to_fp16_soft(f);
436#endif
437}
438
439/* Convenience macros */
440#define CK_FP16_TO_FP32(x) ck_fp16_to_fp32(x)
441#define CK_FP32_TO_FP16(x) ck_fp32_to_fp16(x)
442#define CK_FP16_TO_FP32_SIMD(x) ck_fp16_to_fp32_simd(x)
443#define CK_FP32_TO_FP16_SIMD(x) ck_fp32_to_fp16_simd(x)
444#define CK_FP16_TO_FP32_SOFT(x) ck_fp16_to_fp32_soft(x)
445#define CK_FP32_TO_FP16_SOFT(x) ck_fp32_to_fp16_soft(x)
446
447/* Legacy compatibility (for files that used the old names) */
449#define ggml_fp16_to_fp32 ck_fp16_to_fp32
450#define ggml_fp32_to_fp16 ck_fp32_to_fp16
451#define GGML_FP16_TO_FP32 CK_FP16_TO_FP32
452#define GGML_FP32_TO_FP16 CK_FP32_TO_FP16
453
454/* ============================================================================
455 * SSE Optimized Kernels
456 * ============================================================================ */
457
458void gemm_nt_q5_0_sse_v2(const float *A, const void *B, const float *bias, float *C, int M, int N, int K);
459void gemm_nt_q6_k_sse(const float *A, const void *B, const float *bias, float *C, int M, int N, int K);
460void gemm_nt_q6_k_ref(const float *A, const void *B, const float *bias, float *C, int M, int N, int K);
461void gemv_q4_k_q8_k_sse(float *y, const void *W, const void *x_q8, int M, int K);
462void quantize_row_q8_k_sse(const float *x, void *vy, int k);
463void rmsnorm_q8_k_fused(const float *input, const float *gamma, void *vy, int tokens, int d_model, int aligned_embed_dim, float eps);
464
465/* INT8 activation batch GEMM kernels (Q5_0 weights x Q8_0 activations) */
466void gemm_nt_q5_0_q8_0(const void *A_q8, const void *B_q5, const float *bias, float *C, int M, int N, int K);
467void gemm_nt_q5_0_q8_0_unroll_avx(const void *A_q8, const void *B_q5, const float *bias, float *C, int M, int N, int K);
468void vec_dot_q5_0_q8_0(int n, float *s, const void *vx, const void *vy);
469void vec_dot_q8_0_q8_0(int n, float *s, const void *vx, const void *vy);
470void quantize_row_q8_0(const float *x, void *vy, int k);
471
472#ifdef __cplusplus
473}
474#endif
475
476#endif /* CKERNEL_QUANT_H */
@ CK_DT_Q5_0
@ CK_DT_Q6_K
@ CK_DT_Q4_1
@ CK_DT_Q5_1
void gemm_nt_q5_0_sse_v2(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
int moe_swiglu_expert_forward_nvfp4_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const float *expert_gate_scales, const void *expert_up, const float *expert_up_scales, const void *expert_down, const float *expert_down_scales, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
#define QK5_0
static uint32_t ck_fp32_to_bits(float f)
static float ck_fp32_from_bits(uint32_t u32)
void gemv_nvfp4_q8_0(float *output, const void *weights, const float *weight_scales, const void *activations, int rows, int cols)
float ck_ue4m3_to_fp32(uint8_t value)
static float ck_fp16_to_fp32_soft(ck_half h)
Convert FP16 (ck_half) to FP32 — software implementation.
#define K_SCALE_SIZE
int moe_swiglu_shared_forward_nvfp4_workspace(const float *hidden, const float *routed, const void *shared_gate, const float *shared_gate_scale, const void *shared_up, const float *shared_up_scale, const void *shared_down, const float *shared_down_scale, float *output, int rows, int hidden_dim, int intermediate_dim, float combination_scale, void *workspace, size_t workspace_bytes)
#define QK_NVFP4_SUB
#define QK_NVFP4
uint16_t ck_half
void gemm_nt_q6_k_ref(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void vec_dot_nvfp4_q8_0_ref(int n, float *output, const void *weights, const void *activations, float weight_scale)
size_t moe_swiglu_nvfp4_workspace_bytes(int hidden_dim, int intermediate_dim)
#define QK5_1
void gemm_nt_q6_k_sse(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void vec_dot_q5_0_q8_0(int n, float *s, const void *vx, const void *vy)
Auto-dispatch quantized dot product Q5_0 x Q8_0.
static size_t ck_quant_type_size(int type)
Get the byte size per block for a quant type.
void rmsnorm_q8_k_fused(const float *input, const float *gamma, void *vy, int tokens, int d_model, int aligned_embed_dim, float eps)
#define QK4_0
static ck_half ck_fp32_to_fp16(float f)
#define QK4_1
void gemm_nt_q5_0_q8_0(const void *A_q8, const void *B_q5, const float *bias, float *C, int M, int N, int K)
Batch GEMM with Q5_0 weights and Q8_0 activations for prefill.
ck_half ggml_half
void gemm_nt_q5_0_q8_0_unroll_avx(const void *A_q8, const void *B_q5, const float *bias, float *C, int M, int N, int K)
static float ck_fp16_to_fp32(ck_half h)
void quantize_row_q8_k_sse(const float *x, void *vy, int k)
static size_t ck_quant_block_size(int type)
Get the block size (number of weights per block) for a quant type.
static void unpack_q4_k_scales(const uint8_t *scales, uint8_t *sc, uint8_t *m)
Unpack Q4_K sub-block scales and mins.
void quantize_row_q8_0(const float *x, void *vy, int k)
Quantize FP32 to Q8_0 format (scalar reference)
static size_t ck_quant_row_size(int type, int64_t n_elements)
Calculate total bytes needed for n_elements with given quant type.
void vec_dot_q8_0_q8_0(int n, float *s, const void *vx, const void *vy)
Auto-dispatch quantized dot product Q8_0 x Q8_0.
static ck_half ck_fp32_to_fp16_soft(float f)
Convert FP32 to FP16 (ck_half) — software implementation.
void vec_dot_nvfp4_q8_0(int n, float *output, const void *weights, const void *activations, float weight_scale)
#define QK8_0
void dequantize_row_nvfp4(const void *weights, float *output, int k, float weight_scale)
void gemv_q4_k_q8_k_sse(float *y, const void *W, const void *x_q8, int M, int K)
#define QK_K
#define C(color)
Definition show_config.c:39