← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
ckernel_dtype.h
Go to the documentation of this file.
1#ifndef CKERNEL_DTYPE_H
2#define CKERNEL_DTYPE_H
3
4#include <stdint.h>
5#include <stddef.h>
6
7/**
8 * @brief Supported data types in C-Kernel-Engine
9 *
10 * Standard types:
11 * - CK_DT_FP32: 32-bit float (baseline, full precision)
12 * - CK_DT_BF16: Brain Float 16 (1+8+7 bits)
13 * - CK_DT_FP16: IEEE Half Precision (1+5+10 bits)
14 *
15 * Simple quantization:
16 * - CK_DT_INT8: 8-bit signed integer
17 * - CK_DT_INT4: 4-bit signed integer (simple, no scales)
18 *
19 * GGML-compatible quantization (block-based with scales):
20 * - CK_DT_Q4_0: 4-bit, 32 weights/block, 1 FP16 scale
21 * - CK_DT_Q4_K: 4-bit k-quant, 256 weights/block, nested scales (Q4_K_M)
22 * - CK_DT_Q6_K: 6-bit k-quant, 256 weights/block, per-16 scales
23 * - CK_DT_Q8_0: 8-bit, 32 weights/block, 1 FP16 scale
24 * - CK_DT_Q8_K: 8-bit k-quant, 256 weights/block, FP32 scale + bsums
25 * - CK_DT_Q5_0: 5-bit, 32 weights/block, 1 FP16 scale
26 * - CK_DT_NVFP4: E2M1 weights, 16-value E4M3 block scales
27 */
28typedef enum {
29 /* Standard floating-point types */
30 CK_DT_FP32 = 0, /* 4 bytes per element */
31 CK_DT_BF16, /* 2 bytes per element */
32 CK_DT_FP16, /* 2 bytes per element */
33
34 /* Simple integer types (legacy) */
35 CK_DT_INT8, /* 1 byte per element */
36 CK_DT_INT4, /* 0.5 bytes per element (packed) */
37
38 /* GGML-compatible block quantization */
39 CK_DT_Q4_0, /* 4.5 bits/weight (18 bytes per 32 weights) */
40 CK_DT_Q4_1, /* 5.0 bits/weight (20 bytes per 32 weights) */
41 CK_DT_Q4_K, /* 4.5 bits/weight (144 bytes per 256 weights) - Q4_K_M */
42 CK_DT_Q6_K, /* 6.5 bits/weight (210 bytes per 256 weights) */
43 CK_DT_Q8_0, /* 8.5 bits/weight (34 bytes per 32 weights) */
44 CK_DT_Q8_K, /* 9.125 bits/weight (292 bytes per 256 weights) */
45 CK_DT_Q5_0, /* 5.5 bits/weight (22 bytes per 32 weights) */
46 CK_DT_Q5_1, /* 6.0 bits/weight (24 bytes per 32 weights) */
47 CK_DT_Q5_K, /* 5.5 bits/weight (176 bytes per 256 weights) - Q5_K super-block */
48 CK_DT_NVFP4, /* 4.5 bits/weight (36 bytes per 64 weights) */
49
52
53typedef uint32_t CKDataTypeMask;
54
55#define CK_DT_MASK(dt) (1u << (uint32_t)(dt))
56
57/**
58 * @brief Check if a data type is block-quantized (GGML-style)
59 */
60static inline int ck_dtype_is_quantized(CKDataType dt)
61{
62 return dt == CK_DT_Q4_0 || dt == CK_DT_Q4_1 || dt == CK_DT_Q5_0 || dt == CK_DT_Q5_1 ||
63 dt == CK_DT_Q5_K || dt == CK_DT_Q4_K || dt == CK_DT_Q6_K || dt == CK_DT_Q8_0 ||
64 dt == CK_DT_Q8_K || dt == CK_DT_NVFP4;
65}
66
67/**
68 * @brief Get bytes per element for non-quantized types
69 * @note For quantized types, use ck_dtype_block_bytes() and ck_dtype_block_size()
70 */
71static inline size_t ck_dtype_bytes(CKDataType dt)
72{
73 switch (dt) {
74 case CK_DT_BF16:
75 case CK_DT_FP16:
76 return 2;
77 case CK_DT_INT8:
78 return 1;
79 case CK_DT_INT4:
80 return 1; /* Note: actually 0.5, but stored as pairs */
81 case CK_DT_FP32:
82 default:
83 return 4;
84 }
85}
86
87/**
88 * @brief Get the number of elements per quantization block
89 */
90static inline size_t ck_dtype_block_size(CKDataType dt)
91{
92 switch (dt) {
93 case CK_DT_Q4_0:
94 case CK_DT_Q4_1:
95 case CK_DT_Q5_0:
96 case CK_DT_Q5_1:
97 case CK_DT_Q8_0:
98 return 32;
99 case CK_DT_Q4_K:
100 case CK_DT_Q5_K:
101 case CK_DT_Q6_K:
102 case CK_DT_Q8_K:
103 return 256;
104 case CK_DT_NVFP4:
105 return 64;
106 default:
107 return 1; /* Non-quantized types: 1 element per "block" */
108 }
109}
110
111/**
112 * @brief Get bytes per block for quantized types
113 */
114static inline size_t ck_dtype_block_bytes(CKDataType dt)
115{
116 switch (dt) {
117 case CK_DT_Q4_0:
118 return 18; /* 2 (scale) + 16 (32 x 4-bit) */
119 case CK_DT_Q4_1:
120 return 20; /* 2 (scale) + 2 (min) + 16 (32 x 4-bit) */
121 case CK_DT_Q5_0:
122 return 22; /* 2 (scale) + 4 (high bit) + 16 (low 4-bit) */
123 case CK_DT_Q5_1:
124 return 24; /* 2 (scale) + 2 (min) + 4 (high bit) + 16 (low 4-bit) */
125 case CK_DT_Q4_K:
126 return 144; /* 2 + 2 + 12 + 128 */
127 case CK_DT_Q5_K:
128 return 176; /* 2 + 2 + 12 + 32 + 128 */
129 case CK_DT_Q6_K:
130 return 210; /* 2 + 16 + 128 + 64 */
131 case CK_DT_Q8_0:
132 return 34; /* 2 (scale) + 32 (32 x 8-bit) */
133 case CK_DT_Q8_K:
134 return 292; /* 4 (scale) + 256 (int8) + 32 (bsums) */
135 case CK_DT_NVFP4:
136 return 36; /* 4 E4M3 scales + 32 packed E2M1 values */
137 default:
138 return ck_dtype_bytes(dt);
139 }
140}
141
142/**
143 * @brief Calculate total bytes for n_elements of given dtype
144 */
145static inline size_t ck_dtype_row_bytes(CKDataType dt, size_t n_elements)
146{
147 if (ck_dtype_is_quantized(dt)) {
148 size_t block_size = ck_dtype_block_size(dt);
149 size_t n_blocks = (n_elements + block_size - 1) / block_size;
150 return n_blocks * ck_dtype_block_bytes(dt);
151 }
152 return n_elements * ck_dtype_bytes(dt);
153}
154
156{
157 return (mask & CK_DT_MASK(dt)) != 0;
158}
159
160#endif /* CKERNEL_DTYPE_H */
static int ck_dtype_supported(CKDataTypeMask mask, CKDataType dt)
#define CK_DT_MASK(dt)
static size_t ck_dtype_block_size(CKDataType dt)
Get the number of elements per quantization block.
static size_t ck_dtype_block_bytes(CKDataType dt)
Get bytes per block for quantized types.
uint32_t CKDataTypeMask
CKDataType
Supported data types in C-Kernel-Engine.
@ CK_DT_Q4_K
@ CK_DT_COUNT
@ CK_DT_Q4_0
@ CK_DT_Q8_0
@ CK_DT_Q8_K
@ CK_DT_Q5_0
@ CK_DT_Q5_K
@ CK_DT_FP32
@ CK_DT_FP16
@ CK_DT_Q6_K
@ CK_DT_Q4_1
@ CK_DT_NVFP4
@ CK_DT_INT4
@ CK_DT_BF16
@ CK_DT_INT8
@ CK_DT_Q5_1
static int ck_dtype_is_quantized(CKDataType dt)
Check if a data type is block-quantized (GGML-style)
static size_t ck_dtype_bytes(CKDataType dt)
Get bytes per element for non-quantized types.
static size_t ck_dtype_row_bytes(CKDataType dt, size_t n_elements)
Calculate total bytes for n_elements of given dtype.
int32_t int32_t int32_t int32_t int32_t mask
Definition tokenizer.h:234