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

Dequantization kernels for GGML-compatible formats. More...

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

Go to the source code of this file.

Functions

void dequant_q4_0_block (const block_q4_0 *block, float *output)
 Dequantize a single Q4_0 block to FP32.
 
void dequant_q4_0_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q4_0 row (multiple blocks)
 
void dequant_q4_1_block (const block_q4_1 *block, float *output)
 Dequantize a single Q4_1 block to FP32.
 
void dequant_q4_1_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q4_1 row (multiple blocks)
 
void dequant_q4_k_block (const block_q4_K *block, float *output)
 Dequantize a single Q4_K block to FP32.
 
void dequant_q4_k_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q4_K row (multiple blocks)
 
void dequant_q5_0_block (const block_q5_0 *block, float *output)
 Dequantize a single Q5_0 block to FP32.
 
void dequant_q5_0_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q5_0 row (multiple blocks)
 
void dequant_q5_1_block (const block_q5_1 *block, float *output)
 Dequantize a single Q5_1 block to FP32.
 
void dequant_q5_1_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q5_1 row (multiple blocks)
 
void dequant_q6_k_block (const block_q6_K *block, float *output)
 Dequantize a single Q6_K block to FP32.
 
void dequant_q6_k_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q6_K row (multiple blocks)
 
void dequant_q8_0_block (const block_q8_0 *block, float *output)
 Dequantize a single Q8_0 block to FP32.
 
void dequant_q8_0_row (const void *src, float *dst, size_t n_elements)
 Dequantize Q8_0 row (multiple blocks)
 
void dequant_row (CKDataType dtype, const void *src, float *dst, size_t n_elements)
 Dequantize a row of quantized data to FP32.
 

Detailed Description

Dequantization kernels for GGML-compatible formats.

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 dequantization from Q4_0, Q5_0, Q5_1, Q4_K, Q6_K, Q8_0 to FP32. These kernels are used as building blocks for quantized GEMM/GEMV.

Key optimization: Dequantize into registers, use immediately in FMA, never write intermediate FP32 values to memory.

Definition in file dequant_kernels.c.

Function Documentation

◆ dequant_q4_0_block()

void dequant_q4_0_block ( const block_q4_0 block,
float *  output 
)

Dequantize a single Q4_0 block to FP32.

Parameters
blockPointer to Q4_0 block (18 bytes)
outputOutput FP32 array (32 floats)

Definition at line 40 of file dequant_kernels.c.

41{
42 const float d = GGML_FP16_TO_FP32(block->d);
43
44 for (int i = 0; i < QK4_0 / 2; i++) {
45 const uint8_t packed = block->qs[i];
46
47 /* Lower nibble: elements 0..15 */
48 const int8_t q0 = (packed & 0x0F) - 8;
49 /* Upper nibble: elements 16..31 */
50 const int8_t q1 = (packed >> 4) - 8;
51
52 output[i] = d * (float)q0;
53 output[i + QK4_0 / 2] = d * (float)q1;
54 }
55}
#define GGML_FP16_TO_FP32
#define QK4_0
uint8_t qs[32/2]

References block_q4_0::d, GGML_FP16_TO_FP32, QK4_0, and block_q4_0::qs.

Referenced by dequant_q4_0_row().

◆ dequant_q4_0_row()

void dequant_q4_0_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q4_0 row (multiple blocks)

Parameters
srcQ4_0 data
dstFP32 output
n_elementsNumber of elements to dequantize

Definition at line 63 of file dequant_kernels.c.

64{
65 const block_q4_0 *blocks = (const block_q4_0 *)src;
66 const size_t n_blocks = n_elements / QK4_0;
67
68 for (size_t b = 0; b < n_blocks; b++) {
69 dequant_q4_0_block(&blocks[b], &dst[b * QK4_0]);
70 }
71}
void dequant_q4_0_block(const block_q4_0 *block, float *output)
Dequantize a single Q4_0 block to FP32.

References dequant_q4_0_block(), and QK4_0.

Referenced by ck_test_dequant_q4_0(), and dequant_row().

◆ dequant_q4_1_block()

void dequant_q4_1_block ( const block_q4_1 block,
float *  output 
)

Dequantize a single Q4_1 block to FP32.

Parameters
blockPointer to Q4_1 block (20 bytes)
outputOutput FP32 array (32 floats)

Definition at line 119 of file dequant_kernels.c.

120{
121 const float d = GGML_FP16_TO_FP32(block->d);
122 const float m = GGML_FP16_TO_FP32(block->m);
123
124 for (int i = 0; i < QK4_1 / 2; i++) {
125 const uint8_t packed = block->qs[i];
126
127 /* Lower nibble: unsigned 0-15 */
128 const int q0 = (packed & 0x0F);
129 /* Upper nibble: unsigned 0-15 */
130 const int q1 = (packed >> 4);
131
132 /* Dequantize: w = d * q + m */
133 output[i] = d * (float)q0 + m;
134 output[i + QK4_1 / 2] = d * (float)q1 + m;
135 }
136}
#define QK4_1
uint8_t qs[32/2]

References block_q4_1::d, GGML_FP16_TO_FP32, block_q4_1::m, QK4_1, and block_q4_1::qs.

Referenced by dequant_q4_1_row().

◆ dequant_q4_1_row()

void dequant_q4_1_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q4_1 row (multiple blocks)

Definition at line 141 of file dequant_kernels.c.

142{
143 const block_q4_1 *blocks = (const block_q4_1 *)src;
144 const size_t n_blocks = n_elements / QK4_1;
145
146 for (size_t b = 0; b < n_blocks; b++) {
147 dequant_q4_1_block(&blocks[b], &dst[b * QK4_1]);
148 }
149}
void dequant_q4_1_block(const block_q4_1 *block, float *output)
Dequantize a single Q4_1 block to FP32.

References dequant_q4_1_block(), and QK4_1.

Referenced by dequant_row().

◆ dequant_q4_k_block()

void dequant_q4_k_block ( const block_q4_K block,
float *  output 
)

Dequantize a single Q4_K block to FP32.

This matches llama.cpp's dequantize_row_q4_K exactly:

  • Formula: weight = d * scale * q - dmin * m
  • Layout: 4 iterations of 64 weights each
    • First 32: low nibbles of qs[0..31] with scale[2*iter], min[2*iter]
    • Next 32: high nibbles of qs[0..31] with scale[2*iter+1], min[2*iter+1]

Definition at line 336 of file dequant_kernels.c.

337{
338 const float d = GGML_FP16_TO_FP32(block->d);
339 const float dmin = GGML_FP16_TO_FP32(block->dmin);
340
341 /* Unpack the 6-bit sub-block scales and mins */
342 uint8_t sc[8], m[8];
343 unpack_q4_k_scales(block->scales, sc, m);
344
345 /* llama.cpp layout: 4 iterations of 64 weights each */
346 for (int iter = 0; iter < 4; iter++) {
347 const float d1 = d * (float)sc[2 * iter];
348 const float m1 = dmin * (float)m[2 * iter];
349 const float d2 = d * (float)sc[2 * iter + 1];
350 const float m2 = dmin * (float)m[2 * iter + 1];
351
352 const uint8_t *qs = &block->qs[iter * 32];
353 float *out = &output[iter * 64];
354
355 /* First 32 weights: low nibbles */
356 for (int l = 0; l < 32; l++) {
357 const int q = (qs[l] & 0x0F);
358 out[l] = d1 * (float)q - m1;
359 }
360
361 /* Next 32 weights: high nibbles */
362 for (int l = 0; l < 32; l++) {
363 const int q = (qs[l] >> 4);
364 out[32 + l] = d2 * (float)q - m2;
365 }
366 }
367}
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 block_q4_K::d, block_q4_K::dmin, GGML_FP16_TO_FP32, block_q4_K::qs, block_q4_K::scales, and unpack_q4_k_scales().

Referenced by dequant_q4_k_row().

◆ dequant_q4_k_row()

void dequant_q4_k_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q4_K row (multiple blocks)

Definition at line 372 of file dequant_kernels.c.

373{
374 const block_q4_K *blocks = (const block_q4_K *)src;
375 const size_t n_blocks = n_elements / QK_K;
376
377 for (size_t b = 0; b < n_blocks; b++) {
378 dequant_q4_k_block(&blocks[b], &dst[b * QK_K]);
379 }
380}
#define QK_K
void dequant_q4_k_block(const block_q4_K *block, float *output)
Dequantize a single Q4_K block to FP32.

References dequant_q4_k_block(), and QK_K.

Referenced by ck_test_dequant_q4_k(), dequant_row(), and embedding_forward_q4_k().

◆ dequant_q5_0_block()

void dequant_q5_0_block ( const block_q5_0 block,
float *  output 
)

Dequantize a single Q5_0 block to FP32.

Parameters
blockPointer to Q5_0 block (22 bytes)
outputOutput FP32 array (32 floats)

Definition at line 163 of file dequant_kernels.c.

164{
165 const float d = GGML_FP16_TO_FP32(block->d);
166
167 /* Get high bits as a 32-bit integer */
168 uint32_t qh;
169 memcpy(&qh, block->qh, sizeof(qh));
170
171 /* llama.cpp Q5_0 layout:
172 * - Weight j uses: low nibble of qs[j], high bit from qh bit j
173 * - Weight j+16 uses: high nibble of qs[j], high bit from qh bit (j+12)
174 */
175 for (int j = 0; j < QK5_0 / 2; j++) {
176 const uint8_t packed = block->qs[j];
177
178 /* Extract low 4 bits for two weights */
179 const int lo = (packed & 0x0F);
180 const int hi = (packed >> 4);
181
182 /* Extract high bits from qh - matches llama.cpp exactly */
183 const int xh_0 = ((qh >> (j + 0)) << 4) & 0x10;
184 const int xh_1 = ((qh >> (j + 12))) & 0x10;
185
186 /* Combine: 5-bit value, range 0-31, then subtract 16 */
187 const int q0 = (lo | xh_0) - 16;
188 const int q1 = (hi | xh_1) - 16;
189
190 output[j] = d * (float)q0;
191 output[j + 16] = d * (float)q1;
192 }
193}
#define QK5_0
uint8_t qh[4]
uint8_t qs[32/2]

References block_q5_0::d, GGML_FP16_TO_FP32, block_q5_0::qh, QK5_0, and block_q5_0::qs.

Referenced by dequant_q5_0_row().

◆ dequant_q5_0_row()

void dequant_q5_0_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q5_0 row (multiple blocks)

Definition at line 198 of file dequant_kernels.c.

199{
200 const block_q5_0 *blocks = (const block_q5_0 *)src;
201 const size_t n_blocks = n_elements / QK5_0;
202
203 for (size_t b = 0; b < n_blocks; b++) {
204 dequant_q5_0_block(&blocks[b], &dst[b * QK5_0]);
205 }
206}
void dequant_q5_0_block(const block_q5_0 *block, float *output)
Dequantize a single Q5_0 block to FP32.

References dequant_q5_0_block(), and QK5_0.

Referenced by dequant_row(), embedding_forward_q5_0(), moe_relu2_expert_forward_q5_0_q5_0(), moe_relu2_expert_forward_q5_0_q8_0(), and qwen4_ple_ngram_embed_impl().

◆ dequant_q5_1_block()

void dequant_q5_1_block ( const block_q5_1 block,
float *  output 
)

Dequantize a single Q5_1 block to FP32.

Parameters
blockPointer to Q5_1 block (24 bytes)
outputOutput FP32 array (32 floats)

Definition at line 220 of file dequant_kernels.c.

221{
222 const float d = GGML_FP16_TO_FP32(block->d);
223 const float m = GGML_FP16_TO_FP32(block->m);
224
225 /* Get high bits as a 32-bit integer */
226 uint32_t qh;
227 memcpy(&qh, block->qh, sizeof(qh));
228
229 /* llama.cpp Q5_1 layout (same as Q5_0):
230 * - Weight j uses: low nibble of qs[j], high bit from qh bit j
231 * - Weight j+16 uses: high nibble of qs[j], high bit from qh bit (j+12)
232 */
233 for (int j = 0; j < QK5_1 / 2; j++) {
234 const uint8_t packed = block->qs[j];
235
236 /* Extract low 4 bits for two weights */
237 const int lo = (packed & 0x0F);
238 const int hi = (packed >> 4);
239
240 /* Extract high bits from qh - matches llama.cpp exactly */
241 const int xh_0 = ((qh >> (j + 0)) << 4) & 0x10;
242 const int xh_1 = ((qh >> (j + 12))) & 0x10;
243
244 /* Combine: 5-bit unsigned value, range 0-31 */
245 const int q0 = (lo | xh_0);
246 const int q1 = (hi | xh_1);
247
248 /* Dequantize: w = d * q + m */
249 output[j] = d * (float)q0 + m;
250 output[j + 16] = d * (float)q1 + m;
251 }
252}
#define QK5_1
uint8_t qs[32/2]
uint8_t qh[4]

References block_q5_1::d, GGML_FP16_TO_FP32, block_q5_1::m, block_q5_1::qh, QK5_1, and block_q5_1::qs.

Referenced by dequant_q5_1_row().

◆ dequant_q5_1_row()

void dequant_q5_1_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q5_1 row (multiple blocks)

Definition at line 257 of file dequant_kernels.c.

258{
259 const block_q5_1 *blocks = (const block_q5_1 *)src;
260 const size_t n_blocks = n_elements / QK5_1;
261
262 for (size_t b = 0; b < n_blocks; b++) {
263 dequant_q5_1_block(&blocks[b], &dst[b * QK5_1]);
264 }
265}
void dequant_q5_1_block(const block_q5_1 *block, float *output)
Dequantize a single Q5_1 block to FP32.

References dequant_q5_1_block(), and QK5_1.

Referenced by dequant_row(), and moe_relu2_shared_forward_q5_1_q8_0().

◆ dequant_q6_k_block()

void dequant_q6_k_block ( const block_q6_K block,
float *  output 
)

Dequantize a single Q6_K block to FP32.

Definition at line 391 of file dequant_kernels.c.

392{
393 const float d = GGML_FP16_TO_FP32(block->d);
394 const uint8_t *ql = block->ql;
395 const uint8_t *qh = block->qh;
396 const int8_t *sc = block->scales;
397 float *y = output;
398
399 for (int n = 0; n < QK_K; n += 128) {
400 for (int l = 0; l < 32; ++l) {
401 const int is = l / 16;
402 const int8_t q1 = (int8_t)((ql[l + 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32;
403 const int8_t q2 = (int8_t)((ql[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32;
404 const int8_t q3 = (int8_t)((ql[l + 0] >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32;
405 const int8_t q4 = (int8_t)((ql[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32;
406
407 y[l + 0] = d * (float)sc[is + 0] * (float)q1;
408 y[l + 32] = d * (float)sc[is + 2] * (float)q2;
409 y[l + 64] = d * (float)sc[is + 4] * (float)q3;
410 y[l + 96] = d * (float)sc[is + 6] * (float)q4;
411 }
412 y += 128;
413 ql += 64;
414 qh += 32;
415 sc += 8;
416 }
417}
uint8_t ql[256/2]
int8_t scales[256/16]
uint8_t qh[256/4]

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

Referenced by dequant_q6_k_row().

◆ dequant_q6_k_row()

void dequant_q6_k_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q6_K row (multiple blocks)

Definition at line 422 of file dequant_kernels.c.

423{
424 const block_q6_K *blocks = (const block_q6_K *)src;
425 const size_t n_blocks = n_elements / QK_K;
426
427 for (size_t b = 0; b < n_blocks; b++) {
428 dequant_q6_k_block(&blocks[b], &dst[b * QK_K]);
429 }
430}
void dequant_q6_k_block(const block_q6_K *block, float *output)
Dequantize a single Q6_K block to FP32.

References dequant_q6_k_block(), and QK_K.

Referenced by ck_test_dequant_q6_k(), dequant_row(), and embedding_forward_q6_k().

◆ dequant_q8_0_block()

void dequant_q8_0_block ( const block_q8_0 block,
float *  output 
)

Dequantize a single Q8_0 block to FP32.

Definition at line 276 of file dequant_kernels.c.

277{
278 const float d = GGML_FP16_TO_FP32(block->d);
279
280 for (int i = 0; i < QK8_0; i++) {
281 output[i] = d * (float)block->qs[i];
282 }
283}
#define QK8_0
int8_t qs[32]

References block_q8_0::d, GGML_FP16_TO_FP32, QK8_0, and block_q8_0::qs.

Referenced by dequant_q8_0_row().

◆ dequant_q8_0_row()

void dequant_q8_0_row ( const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize Q8_0 row (multiple blocks)

Definition at line 288 of file dequant_kernels.c.

289{
290 const block_q8_0 *blocks = (const block_q8_0 *)src;
291 const size_t n_blocks = n_elements / QK8_0;
292
293 for (size_t b = 0; b < n_blocks; b++) {
294 dequant_q8_0_block(&blocks[b], &dst[b * QK8_0]);
295 }
296}
void dequant_q8_0_block(const block_q8_0 *block, float *output)
Dequantize a single Q8_0 block to FP32.

References dequant_q8_0_block(), and QK8_0.

Referenced by dequant_row(), embedding_forward_q8_0(), moe_relu2_expert_forward_q5_0_q8_0(), and moe_relu2_shared_forward_q5_1_q8_0().

◆ dequant_row()

void dequant_row ( CKDataType  dtype,
const void *  src,
float *  dst,
size_t  n_elements 
)

Dequantize a row of quantized data to FP32.

Parameters
dtypeData type (must be quantized type)
srcSource quantized data
dstDestination FP32 buffer
n_elementsNumber of elements

Definition at line 514 of file dequant_kernels.c.

515{
516 switch (dtype) {
517 case CK_DT_Q4_0:
518 dequant_q4_0_row(src, dst, n_elements);
519 break;
520 case CK_DT_Q4_1:
521 dequant_q4_1_row(src, dst, n_elements);
522 break;
523 case CK_DT_Q5_0:
524 dequant_q5_0_row(src, dst, n_elements);
525 break;
526 case CK_DT_Q5_1:
527 dequant_q5_1_row(src, dst, n_elements);
528 break;
529 case CK_DT_Q4_K:
530 dequant_q4_k_row(src, dst, n_elements);
531 break;
532 case CK_DT_Q6_K:
533 dequant_q6_k_row(src, dst, n_elements);
534 break;
535 case CK_DT_Q8_0:
536 dequant_q8_0_row(src, dst, n_elements);
537 break;
538 default:
539 /* Not a quantized type - no-op or error */
540 break;
541 }
542}
@ CK_DT_Q4_K
@ CK_DT_Q4_0
@ CK_DT_Q8_0
@ CK_DT_Q5_0
@ CK_DT_Q6_K
@ CK_DT_Q4_1
@ CK_DT_Q5_1
void dequant_q4_0_row(const void *src, float *dst, size_t n_elements)
Dequantize Q4_0 row (multiple blocks)
void dequant_q5_0_row(const void *src, float *dst, size_t n_elements)
Dequantize Q5_0 row (multiple blocks)
void dequant_q8_0_row(const void *src, float *dst, size_t n_elements)
Dequantize Q8_0 row (multiple blocks)
void dequant_q5_1_row(const void *src, float *dst, size_t n_elements)
Dequantize Q5_1 row (multiple blocks)
void dequant_q4_1_row(const void *src, float *dst, size_t n_elements)
Dequantize Q4_1 row (multiple blocks)
void dequant_q6_k_row(const void *src, float *dst, size_t n_elements)
Dequantize Q6_K row (multiple blocks)
void dequant_q4_k_row(const void *src, float *dst, size_t n_elements)
Dequantize Q4_K row (multiple blocks)

References CK_DT_Q4_0, CK_DT_Q4_1, CK_DT_Q4_K, CK_DT_Q5_0, CK_DT_Q5_1, CK_DT_Q6_K, CK_DT_Q8_0, dequant_q4_0_row(), dequant_q4_1_row(), dequant_q4_k_row(), dequant_q5_0_row(), dequant_q5_1_row(), dequant_q6_k_row(), and dequant_q8_0_row().