← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
ckernel_orchestration.c
Go to the documentation of this file.
1/**
2 * @file ckernel_orchestration.c
3 *
4 * ===========================================================================
5 * LEGACY CODE - NOT USED IN v6.6
6 * ===========================================================================
7 *
8 * This file contains v6.5 orchestration code that is NO LONGER USED.
9 * It is kept for reference and potential future use but is NOT compiled
10 * into the v6.6 engine.
11 *
12 * v6.6 Architecture:
13 * - IR Lower 3 handles all orchestration via dataflow graph
14 * - Kernel dispatch via ckernel_codegen.c (for dynamically loaded kernels)
15 * - Memory planning via memory_planner_v6_6.py
16 *
17 * Contents of this file (NOT used):
18 * - ck_attention_flash_decode_wrapper: Flash attention wrapper (use
19 * mega_fused_attention_prefill/avx instead)
20 * - ck_quantized_gemm: Dispatcher for Q4_K, Q5_0, Q5_1, Q6_K, Q8_0
21 * (use version/v6.6/kernel_maps/KERNEL_REGISTRY.json + codegen instead)
22 *
23 * To remove completely:
24 * 1. Delete this file
25 * 2. Remove from Makefile SRCS list
26 * 3. Remove ckernel_orchestration.h
27 *
28 * Last used: v6.5
29 * Deprecated: v6.6 (2026-02)
30 * ===========================================================================
31 */
32
34
35#include "ckernel_engine.h"
36#include "ckernel_dtype.h"
37#include "ckernel_quant.h"
38
39#include <stddef.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <math.h>
44
45#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__)
46#include <immintrin.h>
47#endif
48
49/* ============================================================================
50 * TRUE FLASH ATTENTION (O(1) for decode)
51 *
52 * New implementation based on Tri Dao's Flash Attention algorithm.
53 * Provides O(1) complexity for decode instead of O(n).
54 *
55 * Reference: attention_flash_decode() in src/kernels/attention_flash_true.c
56 * ============================================================================ */
57
58/**
59 * @brief Wrapper to call TRUE flash attention from orchestration layer
60 *
61 * @param q_token Query token [H, D_h]
62 * @param k_cache Cached keys [T_k, H, D_h]
63 * @param v_cache Cached values [T_k, H, D_h]
64 * @param out_token Output [H, D_h]
65 * @param num_heads Number of heads
66 * @param num_kv_heads Number of KV heads (for GQA)
67 * @param kv_tokens Number of tokens in KV cache
68 * @param cache_capacity Cache capacity
69 * @param head_dim Head dimension
70 * @param aligned_head_dim Aligned head dimension
71 */
73 const float *q_token,
74 const float *k_cache,
75 const float *v_cache,
76 float *out_token,
77 int num_heads,
78 int num_kv_heads,
79 int kv_tokens,
80 int cache_capacity,
81 int head_dim,
82 int aligned_head_dim)
83{
84 if (!q_token || !k_cache || !v_cache || !out_token) {
85 return;
86 }
87 if (num_heads <= 0 || num_kv_heads <= 0 || kv_tokens <= 0 || cache_capacity <= 0) {
88 return;
89 }
90 if (kv_tokens > cache_capacity || head_dim <= 0 || aligned_head_dim <= 0) {
91 return;
92 }
93
94 static int use_strict = -1;
95 if (use_strict < 0) {
96 const char *env = getenv("CK_FLASH_ATTN_STRICT");
97 use_strict = (env && env[0] && env[0] != '0') ? 1 : 0;
98 }
99
100 if (use_strict) {
102 k_cache,
103 v_cache,
104 out_token,
105 num_heads,
106 num_kv_heads,
107 kv_tokens,
108 cache_capacity,
109 head_dim,
110 aligned_head_dim);
111 return;
112 }
113
114 // Scale factor: 1/sqrt(head_dim)
115 const float scale = 1.0f / sqrtf((float)head_dim);
116 const size_t head_stride = (size_t)cache_capacity * (size_t)aligned_head_dim;
117
118#pragma omp parallel for schedule(static) if(num_heads > 1)
119 for (int h = 0; h < num_heads; ++h) {
120 const int kv_head = (int)((long long)h * (long long)num_kv_heads / (long long)num_heads);
121 const float *q_head = q_token + (size_t)h * (size_t)aligned_head_dim;
122 const float *k_head = k_cache + (size_t)kv_head * head_stride;
123 const float *v_head = v_cache + (size_t)kv_head * head_stride;
124 float *out_head = out_token + (size_t)h * (size_t)aligned_head_dim;
125
126 // Use aligned_head_dim as D_h so per-token stride matches the cache layout.
127 attention_flash_decode(out_head,
128 q_head,
129 k_head,
130 v_head,
131 1,
132 kv_tokens,
133 1,
134 aligned_head_dim,
135 scale);
136 }
137}
138
139void ck_residual_add_token_major(const float *a,
140 const float *b,
141 float *out,
142 int tokens,
143 int aligned_embed_dim)
144{
145 size_t total = (size_t)tokens * (size_t)aligned_embed_dim;
146 for (size_t i = 0; i < total; ++i) {
147 out[i] = a[i] + b[i];
148 }
149}
150
151void ck_residual_add_backward(const float *d_out,
152 float *d_a,
153 float *d_b,
154 int tokens,
155 int aligned_embed_dim)
156{
157 if (!d_out || !d_a || !d_b) {
158 return;
159 }
160 size_t total = (size_t)tokens * (size_t)aligned_embed_dim;
161 for (size_t i = 0; i < total; ++i) {
162 float v = d_out[i];
163 d_a[i] = v;
164 d_b[i] = v;
165 }
166}
167
168void ck_qkv_project_head_major(const float *input,
169 const float *wq, const float *bq,
170 const float *wk, const float *bk,
171 const float *wv, const float *bv,
172 float *q, float *k, float *v,
173 int tokens,
174 int kv_stride_tokens,
175 int aligned_embed_dim,
176 int num_heads,
177 int num_kv_heads,
178 int aligned_head_dim)
179{
180 if (!input || !wq || !wk || !wv || !q || !k || !v) {
181 return;
182 }
183 if (kv_stride_tokens < tokens) {
184 return;
185 }
186
187 size_t head_weight_stride = (size_t)aligned_head_dim * (size_t)aligned_embed_dim;
188 size_t q_head_stride = (size_t)tokens * (size_t)aligned_head_dim;
189 size_t kv_head_stride = (size_t)kv_stride_tokens * (size_t)aligned_head_dim;
190
191 for (int h = 0; h < num_heads; ++h) {
192 const float *wq_h = wq + (size_t)h * head_weight_stride;
193 const float *bq_h = bq ? (bq + (size_t)h * (size_t)aligned_head_dim) : NULL;
194 float *q_h = q + (size_t)h * q_head_stride;
195
196 gemm_blocked_serial(input, wq_h, bq_h, q_h,
197 tokens, aligned_head_dim, aligned_embed_dim);
198 }
199
200 for (int h = 0; h < num_kv_heads; ++h) {
201 const float *wk_h = wk + (size_t)h * head_weight_stride;
202 const float *wv_h = wv + (size_t)h * head_weight_stride;
203
204 const float *bk_h = bk ? (bk + (size_t)h * (size_t)aligned_head_dim) : NULL;
205 const float *bv_h = bv ? (bv + (size_t)h * (size_t)aligned_head_dim) : NULL;
206
207 float *k_h = k + (size_t)h * kv_head_stride;
208 float *v_h = v + (size_t)h * kv_head_stride;
209
210 gemm_blocked_serial(input, wk_h, bk_h, k_h,
211 tokens, aligned_head_dim, aligned_embed_dim);
212 gemm_blocked_serial(input, wv_h, bv_h, v_h,
213 tokens, aligned_head_dim, aligned_embed_dim);
214 }
215}
216
218{
219 static int cached = -2;
220 if (cached != -2) {
221 return cached;
222 }
223 const char *env = getenv("CK_LAYER_DEBUG");
224 if (env && (env[0] == '1' || env[0] == 'y' || env[0] == 'Y')) {
225 cached = 1;
226 } else {
227 cached = 0;
228 }
229 return cached;
230}
231
232static void ck_debug_check_buffer(const char *stage, const float *buf, int size)
233{
234 if (!ck_layer_debug_enabled() || !buf) {
235 return;
236 }
237 int nan_count = 0, inf_count = 0;
238 float min_val = 1e38f, max_val = -1e38f;
239 for (int i = 0; i < size; ++i) {
240 float v = buf[i];
241 if (isnan(v)) {
242 nan_count++;
243 } else if (isinf(v)) {
244 inf_count++;
245 } else {
246 if (v < min_val) min_val = v;
247 if (v > max_val) max_val = v;
248 }
249 }
250 if (nan_count > 0 || inf_count > 0) {
251 fprintf(stderr, "[LAYER_DEBUG] %-30s size=%5d nan=%d inf=%d\n",
252 stage, size, nan_count, inf_count);
253 } else {
254 fprintf(stderr, "[LAYER_DEBUG] %-30s size=%5d range=[%.3e, %.3e]\n",
255 stage, size, min_val, max_val);
256 }
257}
258
259static void ck_debug_check_q8k(const char *stage, const void *q8_buf, int num_blocks)
260{
261 if (!ck_layer_debug_enabled() || !q8_buf) {
262 return;
263 }
264 const block_q8_K *blocks = (const block_q8_K *)q8_buf;
265 int nan_scale = 0, inf_scale = 0;
266 float min_d = 1e38f, max_d = -1e38f;
267 for (int i = 0; i < num_blocks; ++i) {
268 float d = blocks[i].d;
269 if (isnan(d)) {
270 nan_scale++;
271 } else if (isinf(d)) {
272 inf_scale++;
273 } else {
274 if (d < min_d) min_d = d;
275 if (d > max_d) max_d = d;
276 }
277 }
278 if (nan_scale > 0 || inf_scale > 0) {
279 fprintf(stderr, "[LAYER_DEBUG] %-30s blocks=%d nan_scale=%d inf_scale=%d\n",
280 stage, num_blocks, nan_scale, inf_scale);
281 } else {
282 fprintf(stderr, "[LAYER_DEBUG] %-30s blocks=%d scale_range=[%.3e, %.3e]\n",
283 stage, num_blocks, min_d, max_d);
284 }
285}
286
287static void ck_debug_check_q4k_weights(const char *stage, const void *q4_buf, int num_blocks)
288{
289 if (!ck_layer_debug_enabled() || !q4_buf) {
290 return;
291 }
292 const block_q4_K *blocks = (const block_q4_K *)q4_buf;
293 int nan_d = 0, nan_dmin = 0;
294 float min_d = 1e38f, max_d = -1e38f;
295 for (int i = 0; i < num_blocks; ++i) {
296 float d = CK_FP16_TO_FP32(blocks[i].d);
297 float dm = CK_FP16_TO_FP32(blocks[i].dmin);
298 if (isnan(d)) nan_d++;
299 if (isnan(dm)) nan_dmin++;
300 if (!isnan(d) && !isinf(d)) {
301 if (d < min_d) min_d = d;
302 if (d > max_d) max_d = d;
303 }
304 }
305 if (nan_d > 0 || nan_dmin > 0) {
306 fprintf(stderr, "[LAYER_DEBUG] %-30s blocks=%d nan_d=%d nan_dmin=%d\n",
307 stage, num_blocks, nan_d, nan_dmin);
308 } else {
309 fprintf(stderr, "[LAYER_DEBUG] %-30s blocks=%d d_range=[%.3e, %.3e]\n",
310 stage, num_blocks, min_d, max_d);
311 }
312}
313
315{
316 static int cached = -2;
317 if (cached != -2) {
318 return cached;
319 }
320
321 const char *env = getenv("CK_Q8K_ACTIVATIONS");
322 if (!env || !env[0]) {
323 cached = ck_strict_parity_enabled() ? 0 : 1;
324 return cached;
325 }
326 if (env[0] == '0' || env[0] == 'n' || env[0] == 'N' ||
327 env[0] == 'f' || env[0] == 'F') {
328 cached = 0;
329 } else {
330 cached = 1;
331 }
332 return cached;
333}
334
335void ck_gemm_nt_quant(const float *A,
336 const void *B,
337 const float *bias,
338 float *C,
339 int M, int N, int K,
340 CKDataType dtype)
341{
342 switch (dtype) {
343 case CK_DT_FP32:
344 gemm_blocked_serial(A, (const float *)B, bias, C, M, N, K);
345 break;
346 case CK_DT_Q4_K:
347 gemm_nt_q4_k(A, B, bias, C, M, N, K);
348 break;
349 case CK_DT_Q6_K:
350 gemm_nt_q6_k(A, B, bias, C, M, N, K);
351 break;
352 case CK_DT_Q4_0:
353 gemm_nt_q4_0(A, B, bias, C, M, N, K);
354 break;
355 case CK_DT_Q4_1:
356 gemm_nt_q4_1(A, B, bias, C, M, N, K);
357 break;
358 case CK_DT_Q5_0:
359 gemm_nt_q5_0(A, B, bias, C, M, N, K);
360 break;
361 case CK_DT_Q5_1:
362 gemm_nt_q5_1(A, B, bias, C, M, N, K);
363 break;
364 case CK_DT_Q8_0:
365 gemm_nt_q8_0(A, B, bias, C, M, N, K);
366 break;
367 default:
368 break;
369 }
370}
371
372/* ============================================================================
373 * Q4_K (Q4_K_M) forward-only paths
374 * ============================================================================
375 *
376 * These helpers keep the same activation layouts as the fp32 code paths, but
377 * accept weight matrices stored as GGML-compatible Q4_K blocks. This is meant
378 * for weight-only quantized inference: activations remain fp32 by default, but
379 * decode can switch to Q8_K activations via CK_Q8K_ACTIVATIONS=1.
380 *
381 * Important constraints:
382 * - Q4_K kernels require K (the input dimension) to be a multiple of 256.
383 * - For attention output projection we assume the concatenated head vector
384 * has length aligned_embed_dim (i.e., num_heads * aligned_head_dim matches).
385 */
386
387static void ck_qkv_project_head_major_q4_k(const float *input,
388 const void *wq, const float *bq,
389 const void *wk, const float *bk,
390 const void *wv, const float *bv,
391 float *q, float *k, float *v,
392 int tokens,
393 int kv_stride_tokens,
394 int aligned_embed_dim,
395 int num_heads,
396 int num_kv_heads,
397 int aligned_head_dim)
398{
399 if (!input || !wq || !wk || !wv || !q || !k || !v) {
400 return;
401 }
402 if (kv_stride_tokens < tokens) {
403 return;
404 }
405
406 const size_t head_w_elems = (size_t)aligned_head_dim * (size_t)aligned_embed_dim;
407 const size_t head_w_bytes = ck_dtype_row_bytes(CK_DT_Q4_K, head_w_elems);
408 const size_t q_head_stride = (size_t)tokens * (size_t)aligned_head_dim;
409 const size_t kv_head_stride = (size_t)kv_stride_tokens * (size_t)aligned_head_dim;
410
411 const uint8_t *wq_bytes = (const uint8_t *)wq;
412 const uint8_t *wk_bytes = (const uint8_t *)wk;
413 const uint8_t *wv_bytes = (const uint8_t *)wv;
414
415 for (int h = 0; h < num_heads; ++h) {
416 const void *wq_h = wq_bytes + (size_t)h * head_w_bytes;
417 const float *bq_h = bq ? (bq + (size_t)h * (size_t)aligned_head_dim) : NULL;
418 float *q_h = q + (size_t)h * q_head_stride;
419
420 gemm_nt_q4_k(input, wq_h, bq_h, q_h,
421 tokens, aligned_head_dim, aligned_embed_dim);
422 }
423
424 for (int h = 0; h < num_kv_heads; ++h) {
425 const void *wk_h = wk_bytes + (size_t)h * head_w_bytes;
426 const void *wv_h = wv_bytes + (size_t)h * head_w_bytes;
427
428 const float *bk_h = bk ? (bk + (size_t)h * (size_t)aligned_head_dim) : NULL;
429 const float *bv_h = bv ? (bv + (size_t)h * (size_t)aligned_head_dim) : NULL;
430
431 float *k_h = k + (size_t)h * kv_head_stride;
432 float *v_h = v + (size_t)h * kv_head_stride;
433
434 gemm_nt_q4_k(input, wk_h, bk_h, k_h,
435 tokens, aligned_head_dim, aligned_embed_dim);
436 gemm_nt_q4_k(input, wv_h, bv_h, v_h,
437 tokens, aligned_head_dim, aligned_embed_dim);
438 }
439}
440
441static void ck_qkv_project_head_major_quant(const float *input,
442 const void *wq, const float *bq, CKDataType wq_dtype,
443 const void *wk, const float *bk, CKDataType wk_dtype,
444 const void *wv, const float *bv, CKDataType wv_dtype,
445 float *q, float *k, float *v,
446 int tokens,
447 int kv_stride_tokens,
448 int aligned_embed_dim,
449 int num_heads,
450 int num_kv_heads,
451 int aligned_head_dim)
452{
453 if (!input || !wq || !wk || !wv || !q || !k || !v) {
454 return;
455 }
456 if (kv_stride_tokens < tokens) {
457 return;
458 }
459
460 const size_t head_w_elems = (size_t)aligned_head_dim * (size_t)aligned_embed_dim;
461 const size_t q_head_stride = (size_t)tokens * (size_t)aligned_head_dim;
462 const size_t kv_head_stride = (size_t)kv_stride_tokens * (size_t)aligned_head_dim;
463
464 const size_t wq_head_bytes = ck_dtype_row_bytes(wq_dtype, head_w_elems);
465 const size_t wk_head_bytes = ck_dtype_row_bytes(wk_dtype, head_w_elems);
466 const size_t wv_head_bytes = ck_dtype_row_bytes(wv_dtype, head_w_elems);
467
468 const uint8_t *wq_bytes = (const uint8_t *)wq;
469 const uint8_t *wk_bytes = (const uint8_t *)wk;
470 const uint8_t *wv_bytes = (const uint8_t *)wv;
471
472 for (int h = 0; h < num_heads; ++h) {
473 const void *wq_h = (wq_dtype == CK_DT_FP32)
474 ? (const void *)((const float *)wq + (size_t)h * head_w_elems)
475 : (const void *)(wq_bytes + (size_t)h * wq_head_bytes);
476 const float *bq_h = bq ? (bq + (size_t)h * (size_t)aligned_head_dim) : NULL;
477 float *q_h = q + (size_t)h * q_head_stride;
478
479 ck_gemm_nt_quant(input, wq_h, bq_h, q_h,
480 tokens, aligned_head_dim, aligned_embed_dim, wq_dtype);
481 }
482
483 for (int h = 0; h < num_kv_heads; ++h) {
484 const void *wk_h = (wk_dtype == CK_DT_FP32)
485 ? (const void *)((const float *)wk + (size_t)h * head_w_elems)
486 : (const void *)(wk_bytes + (size_t)h * wk_head_bytes);
487 const void *wv_h = (wv_dtype == CK_DT_FP32)
488 ? (const void *)((const float *)wv + (size_t)h * head_w_elems)
489 : (const void *)(wv_bytes + (size_t)h * wv_head_bytes);
490
491 const float *bk_h = bk ? (bk + (size_t)h * (size_t)aligned_head_dim) : NULL;
492 const float *bv_h = bv ? (bv + (size_t)h * (size_t)aligned_head_dim) : NULL;
493
494 float *k_h = k + (size_t)h * kv_head_stride;
495 float *v_h = v + (size_t)h * kv_head_stride;
496
497 ck_gemm_nt_quant(input, wk_h, bk_h, k_h,
498 tokens, aligned_head_dim, aligned_embed_dim, wk_dtype);
499 ck_gemm_nt_quant(input, wv_h, bv_h, v_h,
500 tokens, aligned_head_dim, aligned_embed_dim, wv_dtype);
501 }
502}
503
504static void ck_attention_project_head_major_q4_k(const float *attn_out,
505 const void *wo,
506 const float *bo,
507 float *out,
508 float *scratch,
509 int tokens,
510 int aligned_embed_dim,
511 int num_heads,
512 int aligned_head_dim)
513{
514 if (!attn_out || !wo || !out || !scratch) {
515 return;
516 }
517
518 /* Flatten head-major [H, T, ad] into token-major [T, H*ad] */
519 const int K = num_heads * aligned_head_dim;
520 if (K != aligned_embed_dim) {
521 return;
522 }
523
524 const size_t head_in_stride = (size_t)tokens * (size_t)aligned_head_dim;
525
526 for (int t = 0; t < tokens; ++t) {
527 float *dst = scratch + (size_t)t * (size_t)aligned_embed_dim;
528 for (int h = 0; h < num_heads; ++h) {
529 const float *src = attn_out + (size_t)h * head_in_stride + (size_t)t * (size_t)aligned_head_dim;
530 memcpy(dst + (size_t)h * (size_t)aligned_head_dim,
531 src,
532 (size_t)aligned_head_dim * sizeof(float));
533 }
534 }
535
536 gemm_nt_q4_k(scratch, wo, bo, out,
537 tokens, aligned_embed_dim, aligned_embed_dim);
538}
539
540static void ck_attention_project_head_major_quant(const float *attn_out,
541 const void *wo,
542 const float *bo,
543 float *out,
544 float *scratch,
545 int tokens,
546 int aligned_embed_dim,
547 int num_heads,
548 int aligned_head_dim,
549 CKDataType wo_dtype)
550{
551 if (!attn_out || !wo || !out || !scratch) {
552 return;
553 }
554
555 if (wo_dtype == CK_DT_FP32) {
557 (const float *)wo,
558 bo,
559 out,
560 scratch,
561 tokens,
562 aligned_embed_dim,
563 num_heads,
564 aligned_head_dim);
565 return;
566 }
567
568 const int K = num_heads * aligned_head_dim;
569 if (K != aligned_embed_dim) {
570 return;
571 }
572
573 const size_t head_in_stride = (size_t)tokens * (size_t)aligned_head_dim;
574
575 for (int t = 0; t < tokens; ++t) {
576 float *dst = scratch + (size_t)t * (size_t)aligned_embed_dim;
577 for (int h = 0; h < num_heads; ++h) {
578 const float *src = attn_out + (size_t)h * head_in_stride + (size_t)t * (size_t)aligned_head_dim;
579 memcpy(dst + (size_t)h * (size_t)aligned_head_dim,
580 src,
581 (size_t)aligned_head_dim * sizeof(float));
582 }
583 }
584
585 ck_gemm_nt_quant(scratch, wo, bo, out,
586 tokens, aligned_embed_dim, aligned_embed_dim, wo_dtype);
587}
588
589static void ck_mlp_swiglu_forward_q4_k(const float *input,
590 const void *w1,
591 const float *b1,
592 const void *w2,
593 const float *b2,
594 float *fc1_out,
595 float *swiglu_out,
596 float *output,
597 int tokens,
598 int aligned_embed_dim,
599 int aligned_intermediate_dim)
600{
601 int up_dim = 2 * aligned_intermediate_dim;
602 gemm_nt_q4_k(input, w1, b1, fc1_out,
603 tokens, up_dim, aligned_embed_dim);
604
605 swiglu_forward(fc1_out, swiglu_out, tokens, aligned_intermediate_dim);
606
607 gemm_nt_q4_k(swiglu_out, w2, b2, output,
608 tokens, aligned_embed_dim, aligned_intermediate_dim);
609}
610
611static void ck_mlp_swiglu_forward_quant(const float *input,
612 const void *w1,
613 const float *b1,
614 CKDataType w1_dtype,
615 const void *w2,
616 const float *b2,
617 CKDataType w2_dtype,
618 float *fc1_out,
619 float *swiglu_out,
620 float *output,
621 int tokens,
622 int aligned_embed_dim,
623 int aligned_intermediate_dim)
624{
625 int up_dim = 2 * aligned_intermediate_dim;
626 ck_gemm_nt_quant(input, w1, b1, fc1_out,
627 tokens, up_dim, aligned_embed_dim, w1_dtype);
628
629 swiglu_forward(fc1_out, swiglu_out, tokens, aligned_intermediate_dim);
630
631 ck_gemm_nt_quant(swiglu_out, w2, b2, output,
632 tokens, aligned_embed_dim, aligned_intermediate_dim, w2_dtype);
633}
634
635static void ck_mlp_swiglu_forward_q4_k_q8_k(const float *input,
636 const void *w1,
637 const float *b1,
638 const void *w2,
639 const float *b2,
640 float *fc1_out,
641 float *swiglu_out,
642 float *output,
643 int aligned_embed_dim,
644 int aligned_intermediate_dim)
645{
646 if (!input || !w1 || !w2 || !fc1_out || !swiglu_out || !output) {
647 return;
648 }
649 if ((aligned_embed_dim % QK_K) != 0 || (aligned_intermediate_dim % QK_K) != 0) {
650 return;
651 }
652
653 const int up_dim = 2 * aligned_intermediate_dim;
654 const int q8_blocks_embed = aligned_embed_dim / QK_K;
655 const int q8_blocks_inter = aligned_intermediate_dim / QK_K;
656 const int q8_blocks_max = (q8_blocks_embed > q8_blocks_inter) ? q8_blocks_embed : q8_blocks_inter;
657 block_q8_K q8_buf[q8_blocks_max];
658
659 quantize_row_q8_k(input, q8_buf, aligned_embed_dim);
660 gemm_nt_q4_k_q8_k(q8_buf, w1, b1, fc1_out,
661 /*M=*/1, /*N=*/up_dim, /*K=*/aligned_embed_dim);
662
663 swiglu_forward(fc1_out, swiglu_out, /*tokens=*/1, aligned_intermediate_dim);
664
665 quantize_row_q8_k(swiglu_out, q8_buf, aligned_intermediate_dim);
666 gemm_nt_q4_k_q8_k(q8_buf, w2, b2, output,
667 /*M=*/1, /*N=*/aligned_embed_dim, /*K=*/aligned_intermediate_dim);
668}
669
670static void ck_qkv_project_head_major_ref(const float *input,
671 const float *wq, const float *bq,
672 const float *wk, const float *bk,
673 const float *wv, const float *bv,
674 float *q, float *k, float *v,
675 int tokens,
676 int kv_stride_tokens,
677 int aligned_embed_dim,
678 int num_heads,
679 int num_kv_heads,
680 int aligned_head_dim)
681{
682 if (!input || !wq || !wk || !wv || !q || !k || !v) {
683 return;
684 }
685 if (kv_stride_tokens < tokens) {
686 return;
687 }
688
689 size_t head_weight_stride = (size_t)aligned_head_dim * (size_t)aligned_embed_dim;
690 size_t q_head_stride = (size_t)tokens * (size_t)aligned_head_dim;
691 size_t kv_head_stride = (size_t)kv_stride_tokens * (size_t)aligned_head_dim;
692
693 for (int h = 0; h < num_heads; ++h) {
694 const float *wq_h = wq + (size_t)h * head_weight_stride;
695 const float *bq_h = bq ? (bq + (size_t)h * (size_t)aligned_head_dim) : NULL;
696 float *q_h = q + (size_t)h * q_head_stride;
697
698 gemm_naive_parallel(input, wq_h, bq_h, q_h,
699 tokens, aligned_head_dim, aligned_embed_dim);
700 }
701
702 for (int h = 0; h < num_kv_heads; ++h) {
703 const float *wk_h = wk + (size_t)h * head_weight_stride;
704 const float *wv_h = wv + (size_t)h * head_weight_stride;
705
706 const float *bk_h = bk ? (bk + (size_t)h * (size_t)aligned_head_dim) : NULL;
707 const float *bv_h = bv ? (bv + (size_t)h * (size_t)aligned_head_dim) : NULL;
708
709 float *k_h = k + (size_t)h * kv_head_stride;
710 float *v_h = v + (size_t)h * kv_head_stride;
711
712 gemm_naive_parallel(input, wk_h, bk_h, k_h,
713 tokens, aligned_head_dim, aligned_embed_dim);
714 gemm_naive_parallel(input, wv_h, bv_h, v_h,
715 tokens, aligned_head_dim, aligned_embed_dim);
716 }
717}
718
719static void ck_add_inplace(float *dst,
720 const float *src,
721 int tokens,
722 int aligned_embed_dim)
723{
724 size_t total = (size_t)tokens * (size_t)aligned_embed_dim;
725 for (size_t i = 0; i < total; ++i) {
726 dst[i] += src[i];
727 }
728}
729
730void ck_attention_project_head_major(const float *attn_out,
731 const float *wo,
732 const float *bo,
733 float *out,
734 float *scratch,
735 int tokens,
736 int aligned_embed_dim,
737 int num_heads,
738 int aligned_head_dim)
739{
740 if (!attn_out || !wo || !out) {
741 return;
742 }
743 if (num_heads > 1 && !scratch) {
744 return;
745 }
746
747 size_t head_in_stride = (size_t)tokens * (size_t)aligned_head_dim;
748 size_t head_weight_stride = (size_t)aligned_embed_dim * (size_t)aligned_head_dim;
749
750 for (int h = 0; h < num_heads; ++h) {
751 const float *head_in = attn_out + (size_t)h * head_in_stride;
752 const float *wo_h = wo + (size_t)h * head_weight_stride;
753
754 if (h == 0) {
755 gemm_blocked_serial(head_in, wo_h, bo, out,
756 tokens, aligned_embed_dim, aligned_head_dim);
757 } else {
758 gemm_blocked_serial(head_in, wo_h, NULL, scratch,
759 tokens, aligned_embed_dim, aligned_head_dim);
760 ck_add_inplace(out, scratch, tokens, aligned_embed_dim);
761 }
762 }
763}
764
765static void ck_attention_project_head_major_ref(const float *attn_out,
766 const float *wo,
767 const float *bo,
768 float *out,
769 float *scratch,
770 int tokens,
771 int aligned_embed_dim,
772 int num_heads,
773 int aligned_head_dim)
774{
775 if (!attn_out || !wo || !out) {
776 return;
777 }
778 if (num_heads > 1 && !scratch) {
779 return;
780 }
781
782 size_t head_in_stride = (size_t)tokens * (size_t)aligned_head_dim;
783 size_t head_weight_stride = (size_t)aligned_embed_dim * (size_t)aligned_head_dim;
784
785 for (int h = 0; h < num_heads; ++h) {
786 const float *head_in = attn_out + (size_t)h * head_in_stride;
787 const float *wo_h = wo + (size_t)h * head_weight_stride;
788
789 if (h == 0) {
790 gemm_naive_parallel(head_in, wo_h, bo, out,
791 tokens, aligned_embed_dim, aligned_head_dim);
792 } else {
793 gemm_naive_parallel(head_in, wo_h, NULL, scratch,
794 tokens, aligned_embed_dim, aligned_head_dim);
795 ck_add_inplace(out, scratch, tokens, aligned_embed_dim);
796 }
797 }
798}
799
801 const float *attn_out,
802 const float *wo,
803 float *d_attn_out,
804 float *d_wo,
805 float *d_bo,
806 int tokens,
807 int aligned_embed_dim,
808 int num_heads,
809 int aligned_head_dim)
810{
811 if (!d_out || !attn_out || !wo || !d_attn_out || !d_wo || !d_bo) {
812 return;
813 }
814
815 // Bias gradient: sum over tokens once (bias is applied once in forward).
816 for (int d = 0; d < aligned_embed_dim; ++d) {
817 d_bo[d] = 0.0f;
818 }
819 for (int t = 0; t < tokens; ++t) {
820 const float *row = d_out + (size_t)t * (size_t)aligned_embed_dim;
821 for (int d = 0; d < aligned_embed_dim; ++d) {
822 d_bo[d] += row[d];
823 }
824 }
825
826 size_t head_in_stride = (size_t)tokens * (size_t)aligned_head_dim;
827 size_t head_weight_stride = (size_t)aligned_embed_dim * (size_t)aligned_head_dim;
828
829 float *tmp_b = (float *)calloc((size_t)aligned_embed_dim, sizeof(float));
830 if (!tmp_b) {
831 return;
832 }
833
834 for (int h = 0; h < num_heads; ++h) {
835 const float *head_in = attn_out + (size_t)h * head_in_stride;
836 const float *wo_h = wo + (size_t)h * head_weight_stride;
837 float *d_head_in = d_attn_out + (size_t)h * head_in_stride;
838 float *d_wo_h = d_wo + (size_t)h * head_weight_stride;
839
840 memset(tmp_b, 0, (size_t)aligned_embed_dim * sizeof(float));
842 head_in,
843 wo_h,
844 d_head_in,
845 d_wo_h,
846 tmp_b,
847 tokens,
848 aligned_head_dim,
849 aligned_embed_dim,
850 1);
851 }
852
853 free(tmp_b);
854}
855
857 const float *d_k,
858 const float *d_v,
859 const float *input,
860 const float *wq,
861 const float *bq,
862 const float *wk,
863 const float *bk,
864 const float *wv,
865 const float *bv,
866 float *d_input,
867 float *d_wq,
868 float *d_bq,
869 float *d_wk,
870 float *d_bk,
871 float *d_wv,
872 float *d_bv,
873 float *scratch,
874 int tokens,
875 int aligned_embed_dim,
876 int num_heads,
877 int num_kv_heads,
878 int aligned_head_dim,
879 int num_threads)
880{
881 if (!d_q || !d_k || !d_v || !input || !wq || !wk || !wv ||
882 !d_input || !d_wq || !d_bq || !d_wk || !d_bk || !d_wv || !d_bv || !scratch) {
883 return;
884 }
885
886 size_t total_in = (size_t)tokens * (size_t)aligned_embed_dim;
887 for (size_t i = 0; i < total_in; ++i) {
888 d_input[i] = 0.0f;
889 }
890
891 size_t head_weight_stride = (size_t)aligned_head_dim * (size_t)aligned_embed_dim;
892 size_t head_out_stride = (size_t)tokens * (size_t)aligned_head_dim;
893
894 for (int h = 0; h < num_heads; ++h) {
895 const float *d_q_h = d_q + (size_t)h * head_out_stride;
896 const float *wq_h = wq + (size_t)h * head_weight_stride;
897 float *d_wq_h = d_wq + (size_t)h * head_weight_stride;
898 float *d_bq_h = d_bq + (size_t)h * (size_t)aligned_head_dim;
899
901 input,
902 wq_h,
903 scratch,
904 d_wq_h,
905 d_bq_h,
906 tokens,
907 aligned_embed_dim,
908 aligned_head_dim,
909 num_threads);
910 ck_add_inplace(d_input, scratch, tokens, aligned_embed_dim);
911 }
912
913 for (int h = 0; h < num_kv_heads; ++h) {
914 const float *d_k_h = d_k + (size_t)h * head_out_stride;
915 const float *d_v_h = d_v + (size_t)h * head_out_stride;
916
917 const float *wk_h = wk + (size_t)h * head_weight_stride;
918 const float *wv_h = wv + (size_t)h * head_weight_stride;
919
920 float *d_wk_h = d_wk + (size_t)h * head_weight_stride;
921 float *d_wv_h = d_wv + (size_t)h * head_weight_stride;
922
923 float *d_bk_h = d_bk + (size_t)h * (size_t)aligned_head_dim;
924 float *d_bv_h = d_bv + (size_t)h * (size_t)aligned_head_dim;
925
927 input,
928 wk_h,
929 scratch,
930 d_wk_h,
931 d_bk_h,
932 tokens,
933 aligned_embed_dim,
934 aligned_head_dim,
935 num_threads);
936 ck_add_inplace(d_input, scratch, tokens, aligned_embed_dim);
937
939 input,
940 wv_h,
941 scratch,
942 d_wv_h,
943 d_bv_h,
944 tokens,
945 aligned_embed_dim,
946 aligned_head_dim,
947 num_threads);
948 ck_add_inplace(d_input, scratch, tokens, aligned_embed_dim);
949 }
950}
951
952void ck_mlp_swiglu_forward(const float *input,
953 const float *w1,
954 const float *b1,
955 const float *w2,
956 const float *b2,
957 float *fc1_out,
958 float *swiglu_out,
959 float *output,
960 int tokens,
961 int aligned_embed_dim,
962 int aligned_intermediate_dim)
963{
964 int up_dim = 2 * aligned_intermediate_dim;
965 gemm_blocked_serial(input, w1, b1, fc1_out,
966 tokens, up_dim, aligned_embed_dim);
967
969 swiglu_forward_exact(fc1_out, swiglu_out, tokens, aligned_intermediate_dim);
970 } else {
971 swiglu_forward(fc1_out, swiglu_out, tokens, aligned_intermediate_dim);
972 }
973
974 gemm_blocked_serial(swiglu_out, w2, b2, output,
975 tokens, aligned_embed_dim, aligned_intermediate_dim);
976}
977
978static void ck_mlp_swiglu_forward_ref(const float *input,
979 const float *w1,
980 const float *b1,
981 const float *w2,
982 const float *b2,
983 float *fc1_out,
984 float *swiglu_out,
985 float *output,
986 int tokens,
987 int aligned_embed_dim,
988 int aligned_intermediate_dim)
989{
990 int up_dim = 2 * aligned_intermediate_dim;
991 gemm_naive_parallel(input, w1, b1, fc1_out,
992 tokens, up_dim, aligned_embed_dim);
993
995 swiglu_forward_exact(fc1_out, swiglu_out, tokens, aligned_intermediate_dim);
996 } else {
997 swiglu_forward(fc1_out, swiglu_out, tokens, aligned_intermediate_dim);
998 }
999
1000 gemm_naive_parallel(swiglu_out, w2, b2, output,
1001 tokens, aligned_embed_dim, aligned_intermediate_dim);
1002}
1003
1005{
1006 if (!p) {
1007 return;
1008 }
1009
1011 p->ln1_gamma,
1012 p->ln1_out,
1013 p->ln1_rstd,
1014 p->tokens,
1015 p->embed_dim,
1017 p->eps);
1018
1020 p->wq, p->bq,
1021 p->wk, p->bk,
1022 p->wv, p->bv,
1023 p->q, p->k, p->v,
1024 p->tokens,
1025 p->tokens,
1027 p->num_heads,
1028 p->num_kv_heads,
1029 p->aligned_head_dim);
1030
1031 if (p->rope_cos && p->rope_sin) {
1032 rope_forward_qk(p->q,
1033 p->k,
1034 p->rope_cos,
1035 p->rope_sin,
1036 p->num_heads,
1037 p->num_kv_heads,
1038 p->tokens,
1039 p->head_dim,
1041 p->rope_pos_offset);
1042 }
1043
1044 if (p->scores) {
1047 p->k,
1048 p->v,
1049 p->scores,
1050 p->attn_out,
1051 p->num_heads,
1052 p->num_kv_heads,
1053 p->tokens,
1054 p->head_dim,
1057 } else {
1059 p->k,
1060 p->v,
1061 p->scores,
1062 p->attn_out,
1063 p->num_heads,
1064 p->num_kv_heads,
1065 p->tokens,
1066 p->head_dim,
1069 }
1070 } else {
1072 p->k,
1073 p->v,
1074 p->attn_out,
1075 p->num_heads,
1076 p->num_kv_heads,
1077 p->tokens,
1078 p->head_dim,
1079 p->aligned_head_dim);
1080 }
1081
1083 p->wo,
1084 p->bo,
1085 p->proj_tmp,
1086 p->proj_scratch,
1087 p->tokens,
1089 p->num_heads,
1090 p->aligned_head_dim);
1091
1093 p->proj_tmp,
1094 p->residual1,
1095 p->tokens,
1097
1099 p->ln2_gamma,
1100 p->ln2_out,
1101 p->ln2_rstd,
1102 p->tokens,
1103 p->embed_dim,
1105 p->eps);
1106
1108 p->w1,
1109 p->b1,
1110 p->w2,
1111 p->b2,
1112 p->fc1_out,
1113 p->swiglu_out,
1114 p->mlp_out,
1115 p->tokens,
1118
1120 p->mlp_out,
1121 p->output,
1122 p->tokens,
1124}
1125
1127{
1128 if (!p) {
1129 return;
1130 }
1131
1133 p->ln1_gamma,
1134 p->ln1_out,
1135 p->ln1_rstd,
1136 p->tokens,
1137 p->embed_dim,
1139 p->eps);
1140
1142 p->wq, p->bq,
1143 p->wk, p->bk,
1144 p->wv, p->bv,
1145 p->q, p->k, p->v,
1146 p->tokens,
1147 p->tokens,
1149 p->num_heads,
1150 p->num_kv_heads,
1151 p->aligned_head_dim);
1152
1153 if (p->rope_cos && p->rope_sin) {
1154 rope_forward_qk(p->q,
1155 p->k,
1156 p->rope_cos,
1157 p->rope_sin,
1158 p->num_heads,
1159 p->num_kv_heads,
1160 p->tokens,
1161 p->head_dim,
1163 p->rope_pos_offset);
1164 }
1165
1166 if (p->scores) {
1169 p->k,
1170 p->v,
1171 p->scores,
1172 p->attn_out,
1173 p->num_heads,
1174 p->num_kv_heads,
1175 p->tokens,
1176 p->head_dim,
1179 } else {
1181 p->k,
1182 p->v,
1183 p->scores,
1184 p->attn_out,
1185 p->num_heads,
1186 p->num_kv_heads,
1187 p->tokens,
1188 p->head_dim,
1191 }
1192 } else {
1194 p->k,
1195 p->v,
1196 p->attn_out,
1197 p->num_heads,
1198 p->num_kv_heads,
1199 p->tokens,
1200 p->head_dim,
1201 p->aligned_head_dim);
1202 }
1203
1205 p->wo,
1206 p->bo,
1207 p->proj_tmp,
1208 p->proj_scratch,
1209 p->tokens,
1211 p->num_heads,
1212 p->aligned_head_dim);
1213
1215 p->proj_tmp,
1216 p->residual1,
1217 p->tokens,
1219
1221 p->ln2_gamma,
1222 p->ln2_out,
1223 p->ln2_rstd,
1224 p->tokens,
1225 p->embed_dim,
1227 p->eps);
1228
1230 p->w1,
1231 p->b1,
1232 p->w2,
1233 p->b2,
1234 p->fc1_out,
1235 p->swiglu_out,
1236 p->mlp_out,
1237 p->tokens,
1240
1242 p->mlp_out,
1243 p->output,
1244 p->tokens,
1246}
1247
1248void ck_mlp_swiglu_forward_fused_token(const float *input_row,
1249 const float *w1,
1250 const float *b1,
1251 const float *w2,
1252 const float *b2,
1253 float *swiglu_row,
1254 float *output_row,
1255 int aligned_embed_dim,
1256 int aligned_intermediate_dim)
1257{
1258 if (!input_row || !w1 || !w2 || !swiglu_row || !output_row) {
1259 return;
1260 }
1261
1262 const float *w_gate = w1;
1263 const float *w_up = w1 + (size_t)aligned_intermediate_dim * (size_t)aligned_embed_dim;
1264 const float *b_gate = b1;
1265 const float *b_up = b1 ? (b1 + aligned_intermediate_dim) : NULL;
1266
1267 gemm_swiglu_fused(input_row,
1268 w_gate,
1269 w_up,
1270 b_gate,
1271 b_up,
1272 swiglu_row,
1273 /*M=*/1,
1274 /*N=*/aligned_intermediate_dim,
1275 /*K=*/aligned_embed_dim);
1276
1277 gemm_blocked_serial(swiglu_row, w2, b2, output_row,
1278 /*M=*/1,
1279 /*N=*/aligned_embed_dim,
1280 /*K=*/aligned_intermediate_dim);
1281}
1282
1284 const float *w1,
1285 const float *b1,
1286 const float *w2,
1287 const float *b2,
1288 float *output_row,
1289 int aligned_embed_dim,
1290 int aligned_intermediate_dim)
1291{
1292 if (!input_row || !w1 || !w2 || !output_row) {
1293 return;
1294 }
1295
1296 // Split w1 into gate and up projections
1297 // w1 layout: [2 * aligned_intermediate_dim, aligned_embed_dim]
1298 // First half: W_gate [aligned_intermediate_dim, aligned_embed_dim]
1299 // Second half: W_up [aligned_intermediate_dim, aligned_embed_dim]
1300 const float *w_gate = w1;
1301 const float *w_up = w1 + (size_t)aligned_intermediate_dim * (size_t)aligned_embed_dim;
1302
1303 // Split b1 into gate and up biases (if present)
1304 const float *b_gate = b1;
1305 const float *b_up = b1 ? (b1 + aligned_intermediate_dim) : NULL;
1306
1307 // w2 is W_down: [aligned_embed_dim, aligned_intermediate_dim]
1308 const float *w_down = w2;
1309 const float *b_down = b2;
1310
1311 // Call the fully fused kernel - eliminates DRAM round-trip for swiglu
1312 // Uses aligned dimensions since weights are stored with alignment padding
1314 w_gate,
1315 w_up,
1316 w_down,
1317 b_gate,
1318 b_up,
1319 b_down,
1320 output_row,
1321 aligned_embed_dim,
1322 aligned_intermediate_dim);
1323}
1324
1326 int token_index,
1327 int cache_capacity)
1328{
1329 if (!p) {
1330 return;
1331 }
1332 if (!p->input || !p->ln1_gamma || !p->ln2_gamma || !p->ln1_out || !p->ln2_out ||
1333 !p->wq || !p->wk || !p->wv || !p->wo || !p->w1 || !p->w2 ||
1334 !p->k || !p->v ||
1335 !p->proj_tmp || !p->residual1 || !p->fc1_out || !p->swiglu_out || !p->mlp_out || !p->output) {
1336 return;
1337 }
1338 if (token_index < 0 || cache_capacity <= 0 || token_index >= cache_capacity) {
1339 return;
1340 }
1341 if (p->num_heads <= 0 || p->num_kv_heads <= 0 || p->aligned_head_dim <= 0) {
1342 return;
1343 }
1344
1345 const int D = p->embed_dim;
1346 const int aligned_D = p->aligned_embed_dim;
1347 const int H = p->num_heads;
1348 const int H_kv = p->num_kv_heads;
1349 const int hd = p->head_dim;
1350 const int ad = p->aligned_head_dim;
1351 const int aligned_intermediate = p->aligned_intermediate_dim;
1352
1353 /* Decode buffers are single-token; token_index only applies to KV cache. */
1354 const size_t token_slot = 0;
1355 const float *input_row = p->input + token_slot * (size_t)aligned_D;
1356 float *ln1_row = p->ln1_out + token_slot * (size_t)aligned_D;
1357 float *ln2_row = p->ln2_out + token_slot * (size_t)aligned_D;
1358 float *proj_row = p->proj_tmp + token_slot * (size_t)aligned_D;
1359 float *residual_row = p->residual1 + token_slot * (size_t)aligned_D;
1360 float *mlp_row = p->mlp_out + token_slot * (size_t)aligned_D;
1361 float *out_row = p->output + token_slot * (size_t)aligned_D;
1362
1363 float ln1_rstd_tmp = 0.0f;
1364 float ln2_rstd_tmp = 0.0f;
1365 float *ln1_rstd = p->ln1_rstd ? (p->ln1_rstd + token_slot) : &ln1_rstd_tmp;
1366 float *ln2_rstd = p->ln2_rstd ? (p->ln2_rstd + token_slot) : &ln2_rstd_tmp;
1367
1368 // Scratch for a single token in head-major layout: [head, aligned_head_dim].
1369 size_t q_elems = (size_t)H * (size_t)ad;
1370 size_t kv_elems = (size_t)H_kv * (size_t)ad;
1371 float q_token[q_elems];
1372 float k_token[kv_elems];
1373 float v_token[kv_elems];
1374 float attn_token[q_elems];
1375
1376 // LN1 / RMSNorm.
1377 rmsnorm_forward(input_row,
1378 p->ln1_gamma,
1379 ln1_row,
1380 ln1_rstd,
1381 /*tokens=*/1,
1382 D,
1383 aligned_D,
1384 p->eps);
1385
1386 // Project Q/K/V for the new token.
1388 p->wq, p->bq,
1389 p->wk, p->bk,
1390 p->wv, p->bv,
1391 q_token, k_token, v_token,
1392 aligned_D,
1393 H,
1394 H_kv,
1395 ad);
1396
1397 // RoPE for the new token at absolute position `p->rope_pos_offset`.
1398 if (p->rope_cos && p->rope_sin) {
1399 rope_forward_qk(q_token,
1400 k_token,
1401 p->rope_cos,
1402 p->rope_sin,
1403 H,
1404 H_kv,
1405 /*num_tokens=*/1,
1406 hd,
1407 ad,
1408 p->rope_pos_offset);
1409 }
1410
1411 // Update KV cache (stores k/v for this token and clears padded lanes).
1413 v_token,
1414 p->k,
1415 p->v,
1416 H_kv,
1417 token_index,
1418 cache_capacity,
1419 hd,
1420 ad);
1421
1422 // Decode attention for this token using the KV cache.
1424 p->k,
1425 p->v,
1426 attn_token,
1427 H,
1428 H_kv,
1429 /*kv_tokens=*/token_index + 1,
1430 cache_capacity,
1431 hd,
1432 ad);
1433
1434 // Output projection (Wo) into token-major buffer (decode-specialized).
1436 p->wo,
1437 p->bo,
1438 proj_row,
1439 D,
1440 aligned_D,
1441 H,
1442 ad);
1443
1444 // Residual + LN2 / RMSNorm.
1446 proj_row,
1447 residual_row,
1448 /*tokens=*/1,
1449 aligned_D);
1450
1451 rmsnorm_forward(residual_row,
1452 p->ln2_gamma,
1453 ln2_row,
1454 ln2_rstd,
1455 /*tokens=*/1,
1456 D,
1457 aligned_D,
1458 p->eps);
1459
1460 // MLP block for this token.
1461 int up_dim = 2 * aligned_intermediate;
1462 float *fc1_row = p->fc1_out + token_slot * (size_t)up_dim;
1463 float *swiglu_row = p->swiglu_out + token_slot * (size_t)aligned_intermediate;
1464
1465 ck_mlp_swiglu_forward(ln2_row,
1466 p->w1,
1467 p->b1,
1468 p->w2,
1469 p->b2,
1470 fc1_row,
1471 swiglu_row,
1472 mlp_row,
1473 /*tokens=*/1,
1474 aligned_D,
1475 aligned_intermediate);
1476
1477 // Final residual.
1478 ck_residual_add_token_major(residual_row,
1479 mlp_row,
1480 out_row,
1481 /*tokens=*/1,
1482 aligned_D);
1483}
1484
1486 int token_index,
1487 int cache_capacity)
1488{
1489 if (!p) {
1490 return;
1491 }
1492 if (!p->input || !p->ln1_gamma || !p->ln2_gamma || !p->ln1_out || !p->ln2_out ||
1493 !p->wq || !p->wk || !p->wv || !p->wo || !p->w1 || !p->w2 ||
1494 !p->k || !p->v || !p->swiglu_out ||
1495 !p->proj_tmp || !p->residual1 || !p->mlp_out || !p->output) {
1496 return;
1497 }
1498 if (token_index < 0 || cache_capacity <= 0 || token_index >= cache_capacity) {
1499 return;
1500 }
1501 if (p->num_heads <= 0 || p->num_kv_heads <= 0 || p->aligned_head_dim <= 0) {
1502 return;
1503 }
1504
1505 const int D = p->embed_dim;
1506 const int aligned_D = p->aligned_embed_dim;
1507 const int H = p->num_heads;
1508 const int H_kv = p->num_kv_heads;
1509 const int hd = p->head_dim;
1510 const int ad = p->aligned_head_dim;
1511 const int aligned_intermediate = p->aligned_intermediate_dim;
1512
1513 /* Decode buffers are single-token; token_index only applies to KV cache. */
1514 const size_t token_slot = 0;
1515 const float *input_row = p->input + token_slot * (size_t)aligned_D;
1516 float *ln1_row = p->ln1_out + token_slot * (size_t)aligned_D;
1517 float *ln2_row = p->ln2_out + token_slot * (size_t)aligned_D;
1518 float *proj_row = p->proj_tmp + token_slot * (size_t)aligned_D;
1519 float *residual_row = p->residual1 + token_slot * (size_t)aligned_D;
1520 float *swiglu_row = p->swiglu_out + token_slot * (size_t)aligned_intermediate;
1521 float *mlp_row = p->mlp_out + token_slot * (size_t)aligned_D;
1522 float *out_row = p->output + token_slot * (size_t)aligned_D;
1523
1524 float ln1_rstd_tmp = 0.0f;
1525 float ln2_rstd_tmp = 0.0f;
1526 float *ln1_rstd = p->ln1_rstd ? (p->ln1_rstd + token_slot) : &ln1_rstd_tmp;
1527 float *ln2_rstd = p->ln2_rstd ? (p->ln2_rstd + token_slot) : &ln2_rstd_tmp;
1528
1529 // Scratch for a single token in head-major layout: [head, aligned_head_dim].
1530 size_t q_elems = (size_t)H * (size_t)ad;
1531 size_t kv_elems = (size_t)H_kv * (size_t)ad;
1532 float q_token[q_elems];
1533 float k_token[kv_elems];
1534 float v_token[kv_elems];
1535 float attn_token[q_elems];
1536
1537 // LN1 / RMSNorm.
1538 rmsnorm_forward(input_row,
1539 p->ln1_gamma,
1540 ln1_row,
1541 ln1_rstd,
1542 /*tokens=*/1,
1543 D,
1544 aligned_D,
1545 p->eps);
1546
1547 // Project Q/K/V for the new token.
1549 p->wq, p->bq,
1550 p->wk, p->bk,
1551 p->wv, p->bv,
1552 q_token, k_token, v_token,
1553 aligned_D,
1554 H,
1555 H_kv,
1556 ad);
1557
1558 // RoPE for the new token at absolute position `p->rope_pos_offset`.
1559 if (p->rope_cos && p->rope_sin) {
1560 rope_forward_qk(q_token,
1561 k_token,
1562 p->rope_cos,
1563 p->rope_sin,
1564 H,
1565 H_kv,
1566 /*num_tokens=*/1,
1567 hd,
1568 ad,
1569 p->rope_pos_offset);
1570 }
1571
1572 // Update KV cache (stores k/v for this token and clears padded lanes).
1574 v_token,
1575 p->k,
1576 p->v,
1577 H_kv,
1578 token_index,
1579 cache_capacity,
1580 hd,
1581 ad);
1582
1583 // Decode attention for this token using the KV cache.
1585 p->k,
1586 p->v,
1587 attn_token,
1588 H,
1589 H_kv,
1590 /*kv_tokens=*/token_index + 1,
1591 cache_capacity,
1592 hd,
1593 ad);
1594
1595 // Output projection (Wo) into token-major buffer (decode-specialized).
1597 p->wo,
1598 p->bo,
1599 proj_row,
1600 D,
1601 aligned_D,
1602 H,
1603 ad);
1604
1605 // Residual + LN2 / RMSNorm.
1607 proj_row,
1608 residual_row,
1609 /*tokens=*/1,
1610 aligned_D);
1611
1612 rmsnorm_forward(residual_row,
1613 p->ln2_gamma,
1614 ln2_row,
1615 ln2_rstd,
1616 /*tokens=*/1,
1617 D,
1618 aligned_D,
1619 p->eps);
1620
1621 // MLP block for this token (fully fused - all 3 projections in one pass).
1622 // Eliminates DRAM round-trip for swiglu intermediate values.
1624 p->w1,
1625 p->b1,
1626 p->w2,
1627 p->b2,
1628 mlp_row,
1629 aligned_D,
1630 aligned_intermediate);
1631
1632 // Final residual.
1633 ck_residual_add_token_major(residual_row,
1634 mlp_row,
1635 out_row,
1636 /*tokens=*/1,
1637 aligned_D);
1638}
1639
1640static void ck_qkv_project_head_major_token_q4_k(const float *input_row,
1641 const void *wq, const float *bq,
1642 const void *wk, const float *bk,
1643 const void *wv, const float *bv,
1644 float *q_token,
1645 float *k_token,
1646 float *v_token,
1647 int aligned_embed_dim,
1648 int num_heads,
1649 int num_kv_heads,
1650 int aligned_head_dim)
1651{
1652 if (!input_row || !wq || !wk || !wv || !q_token || !k_token || !v_token) {
1653 return;
1654 }
1655
1656 const size_t head_w_elems = (size_t)aligned_head_dim * (size_t)aligned_embed_dim;
1657 const size_t head_w_bytes = ck_dtype_row_bytes(CK_DT_Q4_K, head_w_elems);
1658
1659 const uint8_t *wq_bytes = (const uint8_t *)wq;
1660 const uint8_t *wk_bytes = (const uint8_t *)wk;
1661 const uint8_t *wv_bytes = (const uint8_t *)wv;
1662
1663 for (int h = 0; h < num_heads; ++h) {
1664 const void *wq_h = wq_bytes + (size_t)h * head_w_bytes;
1665 const float *bq_h = bq ? (bq + (size_t)h * (size_t)aligned_head_dim) : NULL;
1666 float *q_h = q_token + (size_t)h * (size_t)aligned_head_dim;
1667 gemm_nt_q4_k(input_row, wq_h, bq_h, q_h,
1668 /*M=*/1, /*N=*/aligned_head_dim, /*K=*/aligned_embed_dim);
1669 }
1670
1671 for (int h = 0; h < num_kv_heads; ++h) {
1672 const void *wk_h = wk_bytes + (size_t)h * head_w_bytes;
1673 const void *wv_h = wv_bytes + (size_t)h * head_w_bytes;
1674 const float *bk_h = bk ? (bk + (size_t)h * (size_t)aligned_head_dim) : NULL;
1675 const float *bv_h = bv ? (bv + (size_t)h * (size_t)aligned_head_dim) : NULL;
1676 float *k_h = k_token + (size_t)h * (size_t)aligned_head_dim;
1677 float *v_h = v_token + (size_t)h * (size_t)aligned_head_dim;
1678 gemm_nt_q4_k(input_row, wk_h, bk_h, k_h,
1679 /*M=*/1, /*N=*/aligned_head_dim, /*K=*/aligned_embed_dim);
1680 gemm_nt_q4_k(input_row, wv_h, bv_h, v_h,
1681 /*M=*/1, /*N=*/aligned_head_dim, /*K=*/aligned_embed_dim);
1682 }
1683}
1684
1686 const void *wq, const float *bq,
1687 const void *wk, const float *bk,
1688 const void *wv, const float *bv,
1689 float *q_token,
1690 float *k_token,
1691 float *v_token,
1692 int aligned_embed_dim,
1693 int num_heads,
1694 int num_kv_heads,
1695 int aligned_head_dim)
1696{
1697 if (!input_q8 || !wq || !wk || !wv || !q_token || !k_token || !v_token) {
1698 return;
1699 }
1700
1701 const size_t head_w_elems = (size_t)aligned_head_dim * (size_t)aligned_embed_dim;
1702 const size_t head_w_bytes = ck_dtype_row_bytes(CK_DT_Q4_K, head_w_elems);
1703
1704 const uint8_t *wq_bytes = (const uint8_t *)wq;
1705 const uint8_t *wk_bytes = (const uint8_t *)wk;
1706 const uint8_t *wv_bytes = (const uint8_t *)wv;
1707
1708 for (int h = 0; h < num_heads; ++h) {
1709 const void *wq_h = wq_bytes + (size_t)h * head_w_bytes;
1710 const float *bq_h = bq ? (bq + (size_t)h * (size_t)aligned_head_dim) : NULL;
1711 float *q_h = q_token + (size_t)h * (size_t)aligned_head_dim;
1712 gemm_nt_q4_k_q8_k(input_q8, wq_h, bq_h, q_h,
1713 /*M=*/1, /*N=*/aligned_head_dim, /*K=*/aligned_embed_dim);
1714 }
1715
1716 for (int h = 0; h < num_kv_heads; ++h) {
1717 const void *wk_h = wk_bytes + (size_t)h * head_w_bytes;
1718 const void *wv_h = wv_bytes + (size_t)h * head_w_bytes;
1719 const float *bk_h = bk ? (bk + (size_t)h * (size_t)aligned_head_dim) : NULL;
1720 const float *bv_h = bv ? (bv + (size_t)h * (size_t)aligned_head_dim) : NULL;
1721 float *k_h = k_token + (size_t)h * (size_t)aligned_head_dim;
1722 float *v_h = v_token + (size_t)h * (size_t)aligned_head_dim;
1723 gemm_nt_q4_k_q8_k(input_q8, wk_h, bk_h, k_h,
1724 /*M=*/1, /*N=*/aligned_head_dim, /*K=*/aligned_embed_dim);
1725 gemm_nt_q4_k_q8_k(input_q8, wv_h, bv_h, v_h,
1726 /*M=*/1, /*N=*/aligned_head_dim, /*K=*/aligned_embed_dim);
1727 }
1728}
1729
1730static void ck_qkv_project_head_major_q4_k_q8_k(const float *input,
1731 const void *wq, const float *bq,
1732 const void *wk, const float *bk,
1733 const void *wv, const float *bv,
1734 float *q, float *k, float *v,
1735 int tokens,
1736 int kv_stride_tokens,
1737 int aligned_embed_dim,
1738 int num_heads,
1739 int num_kv_heads,
1740 int aligned_head_dim)
1741{
1742 if (!input || !wq || !wk || !wv || !q || !k || !v) {
1743 return;
1744 }
1745 if (tokens <= 0 || aligned_embed_dim <= 0) {
1746 return;
1747 }
1748 if (kv_stride_tokens < tokens) {
1749 return;
1750 }
1751 if ((aligned_embed_dim % QK_K) != 0) {
1752 return;
1753 }
1754
1755 const int q8_blocks = aligned_embed_dim / QK_K;
1756 block_q8_K q8_buf[q8_blocks];
1757 const size_t q_head_stride = (size_t)tokens * (size_t)aligned_head_dim;
1758 const size_t kv_head_stride = (size_t)kv_stride_tokens * (size_t)aligned_head_dim;
1759
1760 float q_token[num_heads * aligned_head_dim];
1761 float k_token[num_kv_heads * aligned_head_dim];
1762 float v_token[num_kv_heads * aligned_head_dim];
1763
1764 for (int t = 0; t < tokens; ++t) {
1765 const float *input_row = input + (size_t)t * (size_t)aligned_embed_dim;
1766 quantize_row_q8_k(input_row, q8_buf, aligned_embed_dim);
1767
1769 wq, bq,
1770 wk, bk,
1771 wv, bv,
1772 q_token,
1773 k_token,
1774 v_token,
1775 aligned_embed_dim,
1776 num_heads,
1777 num_kv_heads,
1778 aligned_head_dim);
1779
1780 for (int h = 0; h < num_heads; ++h) {
1781 float *q_dst = q + (size_t)h * q_head_stride + (size_t)t * (size_t)aligned_head_dim;
1782 memcpy(q_dst,
1783 q_token + (size_t)h * (size_t)aligned_head_dim,
1784 (size_t)aligned_head_dim * sizeof(float));
1785 }
1786
1787 for (int h = 0; h < num_kv_heads; ++h) {
1788 float *k_dst = k + (size_t)h * kv_head_stride + (size_t)t * (size_t)aligned_head_dim;
1789 float *v_dst = v + (size_t)h * kv_head_stride + (size_t)t * (size_t)aligned_head_dim;
1790 memcpy(k_dst,
1791 k_token + (size_t)h * (size_t)aligned_head_dim,
1792 (size_t)aligned_head_dim * sizeof(float));
1793 memcpy(v_dst,
1794 v_token + (size_t)h * (size_t)aligned_head_dim,
1795 (size_t)aligned_head_dim * sizeof(float));
1796 }
1797 }
1798}
1799
1800static void ck_attention_project_head_major_q4_k_q8_k(const float *attn_out,
1801 const void *wo,
1802 const float *bo,
1803 float *out,
1804 int tokens,
1805 int aligned_embed_dim,
1806 int num_heads,
1807 int aligned_head_dim)
1808{
1809 if (!attn_out || !wo || !out) {
1810 return;
1811 }
1812 if (tokens <= 0 || aligned_embed_dim <= 0) {
1813 return;
1814 }
1815 if ((aligned_embed_dim % QK_K) != 0) {
1816 return;
1817 }
1818
1819 const int K = num_heads * aligned_head_dim;
1820 if (K != aligned_embed_dim) {
1821 return;
1822 }
1823
1824 const int q8_blocks = aligned_embed_dim / QK_K;
1825 block_q8_K q8_buf[q8_blocks];
1826 float attn_token[aligned_embed_dim];
1827 const size_t head_stride = (size_t)tokens * (size_t)aligned_head_dim;
1828
1829 for (int t = 0; t < tokens; ++t) {
1830 for (int h = 0; h < num_heads; ++h) {
1831 const float *src = attn_out + (size_t)h * head_stride + (size_t)t * (size_t)aligned_head_dim;
1832 memcpy(attn_token + (size_t)h * (size_t)aligned_head_dim,
1833 src,
1834 (size_t)aligned_head_dim * sizeof(float));
1835 }
1836
1837 quantize_row_q8_k(attn_token, q8_buf, aligned_embed_dim);
1838 gemm_nt_q4_k_q8_k(q8_buf, wo, bo,
1839 out + (size_t)t * (size_t)aligned_embed_dim,
1840 /*M=*/1, /*N=*/aligned_embed_dim, /*K=*/aligned_embed_dim);
1841 }
1842}
1843
1844static void ck_mlp_swiglu_forward_q4_k_q8_k_prefill(const float *input,
1845 const void *w1,
1846 const float *b1,
1847 const void *w2,
1848 const float *b2,
1849 float *fc1_out,
1850 float *swiglu_out,
1851 float *output,
1852 int tokens,
1853 int aligned_embed_dim,
1854 int aligned_intermediate_dim)
1855{
1856 if (!input || !w1 || !w2 || !fc1_out || !swiglu_out || !output) {
1857 return;
1858 }
1859 if (tokens <= 0) {
1860 return;
1861 }
1862 if ((aligned_embed_dim % QK_K) != 0 || (aligned_intermediate_dim % QK_K) != 0) {
1863 return;
1864 }
1865
1866 const int up_dim = 2 * aligned_intermediate_dim;
1867 const int q8_blocks_embed = aligned_embed_dim / QK_K;
1868 const int q8_blocks_inter = aligned_intermediate_dim / QK_K;
1869 const int q8_blocks_max = (q8_blocks_embed > q8_blocks_inter) ? q8_blocks_embed : q8_blocks_inter;
1870 block_q8_K q8_buf[q8_blocks_max];
1871
1872 for (int t = 0; t < tokens; ++t) {
1873 const float *input_row = input + (size_t)t * (size_t)aligned_embed_dim;
1874 float *fc1_row = fc1_out + (size_t)t * (size_t)up_dim;
1875
1876 quantize_row_q8_k(input_row, q8_buf, aligned_embed_dim);
1877 gemm_nt_q4_k_q8_k(q8_buf, w1, b1, fc1_row,
1878 /*M=*/1, /*N=*/up_dim, /*K=*/aligned_embed_dim);
1879 }
1880
1881 swiglu_forward(fc1_out, swiglu_out, tokens, aligned_intermediate_dim);
1882
1883 for (int t = 0; t < tokens; ++t) {
1884 const float *swiglu_row = swiglu_out + (size_t)t * (size_t)aligned_intermediate_dim;
1885 float *out_row = output + (size_t)t * (size_t)aligned_embed_dim;
1886
1887 quantize_row_q8_k(swiglu_row, q8_buf, aligned_intermediate_dim);
1888 gemm_nt_q4_k_q8_k(q8_buf, w2, b2, out_row,
1889 /*M=*/1, /*N=*/aligned_embed_dim, /*K=*/aligned_intermediate_dim);
1890 }
1891}
1892
1893static void ck_qkv_project_head_major_token_quant(const float *input_row,
1894 const void *wq, const float *bq, CKDataType wq_dtype,
1895 const void *wk, const float *bk, CKDataType wk_dtype,
1896 const void *wv, const float *bv, CKDataType wv_dtype,
1897 float *q_token,
1898 float *k_token,
1899 float *v_token,
1900 int aligned_embed_dim,
1901 int num_heads,
1902 int num_kv_heads,
1903 int aligned_head_dim)
1904{
1905 if (!input_row || !wq || !wk || !wv || !q_token || !k_token || !v_token) {
1906 return;
1907 }
1908
1909 const size_t head_w_elems = (size_t)aligned_head_dim * (size_t)aligned_embed_dim;
1910 const size_t wq_head_bytes = ck_dtype_row_bytes(wq_dtype, head_w_elems);
1911 const size_t wk_head_bytes = ck_dtype_row_bytes(wk_dtype, head_w_elems);
1912 const size_t wv_head_bytes = ck_dtype_row_bytes(wv_dtype, head_w_elems);
1913
1914 const uint8_t *wq_bytes = (const uint8_t *)wq;
1915 const uint8_t *wk_bytes = (const uint8_t *)wk;
1916 const uint8_t *wv_bytes = (const uint8_t *)wv;
1917
1918 for (int h = 0; h < num_heads; ++h) {
1919 const void *wq_h = (wq_dtype == CK_DT_FP32)
1920 ? (const void *)((const float *)wq + (size_t)h * head_w_elems)
1921 : (const void *)(wq_bytes + (size_t)h * wq_head_bytes);
1922 const float *bq_h = bq ? (bq + (size_t)h * (size_t)aligned_head_dim) : NULL;
1923 float *q_h = q_token + (size_t)h * (size_t)aligned_head_dim;
1924 ck_gemm_nt_quant(input_row, wq_h, bq_h, q_h,
1925 /*M=*/1, /*N=*/aligned_head_dim, /*K=*/aligned_embed_dim, wq_dtype);
1926 }
1927
1928 for (int h = 0; h < num_kv_heads; ++h) {
1929 const void *wk_h = (wk_dtype == CK_DT_FP32)
1930 ? (const void *)((const float *)wk + (size_t)h * head_w_elems)
1931 : (const void *)(wk_bytes + (size_t)h * wk_head_bytes);
1932 const void *wv_h = (wv_dtype == CK_DT_FP32)
1933 ? (const void *)((const float *)wv + (size_t)h * head_w_elems)
1934 : (const void *)(wv_bytes + (size_t)h * wv_head_bytes);
1935 const float *bk_h = bk ? (bk + (size_t)h * (size_t)aligned_head_dim) : NULL;
1936 const float *bv_h = bv ? (bv + (size_t)h * (size_t)aligned_head_dim) : NULL;
1937 float *k_h = k_token + (size_t)h * (size_t)aligned_head_dim;
1938 float *v_h = v_token + (size_t)h * (size_t)aligned_head_dim;
1939 ck_gemm_nt_quant(input_row, wk_h, bk_h, k_h,
1940 /*M=*/1, /*N=*/aligned_head_dim, /*K=*/aligned_embed_dim, wk_dtype);
1941 ck_gemm_nt_quant(input_row, wv_h, bv_h, v_h,
1942 /*M=*/1, /*N=*/aligned_head_dim, /*K=*/aligned_embed_dim, wv_dtype);
1943 }
1944}
1945
1947{
1948 if (!p) {
1949 return;
1950 }
1951
1952 const int aligned_D = p->aligned_embed_dim;
1953 const int aligned_intermediate = p->aligned_intermediate_dim;
1954
1956 p->ln1_gamma,
1957 p->ln1_out,
1958 p->ln1_rstd,
1959 p->tokens,
1960 p->embed_dim,
1961 aligned_D,
1962 p->eps);
1963
1965 if ((aligned_D % QK_K) == 0 && (aligned_intermediate % QK_K) == 0) {
1967 p->wq, p->bq,
1968 p->wk, p->bk,
1969 p->wv, p->bv,
1970 p->q, p->k, p->v,
1971 p->tokens,
1972 p->tokens,
1973 aligned_D,
1974 p->num_heads,
1975 p->num_kv_heads,
1976 p->aligned_head_dim);
1977
1978 if (p->rope_cos && p->rope_sin) {
1979 rope_forward_qk(p->q,
1980 p->k,
1981 p->rope_cos,
1982 p->rope_sin,
1983 p->num_heads,
1984 p->num_kv_heads,
1985 p->tokens,
1986 p->head_dim,
1988 p->rope_pos_offset);
1989 }
1990
1991 if (p->scores) {
1993 p->k,
1994 p->v,
1995 p->scores,
1996 p->attn_out,
1997 p->num_heads,
1998 p->num_kv_heads,
1999 p->tokens,
2000 p->head_dim,
2003 } else {
2005 p->k,
2006 p->v,
2007 p->attn_out,
2008 p->num_heads,
2009 p->num_kv_heads,
2010 p->tokens,
2011 p->head_dim,
2012 p->aligned_head_dim);
2013 }
2014
2016 p->wo,
2017 p->bo,
2018 p->proj_tmp,
2019 p->tokens,
2020 aligned_D,
2021 p->num_heads,
2022 p->aligned_head_dim);
2023
2025 p->proj_tmp,
2026 p->residual1,
2027 p->tokens,
2028 aligned_D);
2029
2031 p->ln2_gamma,
2032 p->ln2_out,
2033 p->ln2_rstd,
2034 p->tokens,
2035 p->embed_dim,
2036 aligned_D,
2037 p->eps);
2038
2040 p->w1,
2041 p->b1,
2042 p->w2,
2043 p->b2,
2044 p->fc1_out,
2045 p->swiglu_out,
2046 p->mlp_out,
2047 p->tokens,
2048 aligned_D,
2049 aligned_intermediate);
2050
2052 p->mlp_out,
2053 p->output,
2054 p->tokens,
2055 aligned_D);
2056 return;
2057 }
2058 }
2059
2061 p->wq, p->bq,
2062 p->wk, p->bk,
2063 p->wv, p->bv,
2064 p->q, p->k, p->v,
2065 p->tokens,
2066 p->tokens,
2067 aligned_D,
2068 p->num_heads,
2069 p->num_kv_heads,
2070 p->aligned_head_dim);
2071
2072 if (p->rope_cos && p->rope_sin) {
2073 rope_forward_qk(p->q,
2074 p->k,
2075 p->rope_cos,
2076 p->rope_sin,
2077 p->num_heads,
2078 p->num_kv_heads,
2079 p->tokens,
2080 p->head_dim,
2082 p->rope_pos_offset);
2083 }
2084
2085 if (p->scores) {
2087 p->k,
2088 p->v,
2089 p->scores,
2090 p->attn_out,
2091 p->num_heads,
2092 p->num_kv_heads,
2093 p->tokens,
2094 p->head_dim,
2097 } else {
2099 p->k,
2100 p->v,
2101 p->attn_out,
2102 p->num_heads,
2103 p->num_kv_heads,
2104 p->tokens,
2105 p->head_dim,
2106 p->aligned_head_dim);
2107 }
2108
2110 p->wo,
2111 p->bo,
2112 p->proj_tmp,
2113 p->proj_scratch,
2114 p->tokens,
2116 p->num_heads,
2117 p->aligned_head_dim);
2118
2120 p->proj_tmp,
2121 p->residual1,
2122 p->tokens,
2124
2126 p->ln2_gamma,
2127 p->ln2_out,
2128 p->ln2_rstd,
2129 p->tokens,
2130 p->embed_dim,
2132 p->eps);
2133
2135 p->w1,
2136 p->b1,
2137 p->w2,
2138 p->b2,
2139 p->fc1_out,
2140 p->swiglu_out,
2141 p->mlp_out,
2142 p->tokens,
2145
2147 p->mlp_out,
2148 p->output,
2149 p->tokens,
2151}
2152
2154 int token_index,
2155 int cache_capacity)
2156{
2157 if (!p) {
2158 return;
2159 }
2160 if (!p->input || !p->ln1_gamma || !p->ln2_gamma || !p->ln1_out || !p->ln2_out ||
2161 !p->wq || !p->wk || !p->wv || !p->wo || !p->w1 || !p->w2 ||
2162 !p->k || !p->v ||
2163 !p->proj_tmp || !p->residual1 || !p->fc1_out || !p->swiglu_out || !p->mlp_out || !p->output) {
2164 return;
2165 }
2166 if (token_index < 0 || cache_capacity <= 0 || token_index >= cache_capacity) {
2167 return;
2168 }
2169
2170 const int D = p->embed_dim;
2171 const int aligned_D = p->aligned_embed_dim;
2172 const int H = p->num_heads;
2173 const int H_kv = p->num_kv_heads;
2174 const int hd = p->head_dim;
2175 const int ad = p->aligned_head_dim;
2176 const int aligned_intermediate = p->aligned_intermediate_dim;
2177 const int K_concat = H * ad;
2178
2179 /* Decode buffers are single-token; token_index only applies to KV cache. */
2180 const size_t token_slot = 0;
2181 const float *input_row = p->input + token_slot * (size_t)aligned_D;
2182 float *ln1_row = p->ln1_out + token_slot * (size_t)aligned_D;
2183 float *ln2_row = p->ln2_out + token_slot * (size_t)aligned_D;
2184 float *proj_row = p->proj_tmp + token_slot * (size_t)aligned_D;
2185 float *residual_row = p->residual1 + token_slot * (size_t)aligned_D;
2186 float *mlp_row = p->mlp_out + token_slot * (size_t)aligned_D;
2187 float *out_row = p->output + token_slot * (size_t)aligned_D;
2188
2189 float ln1_rstd_tmp = 0.0f;
2190 float ln2_rstd_tmp = 0.0f;
2191 float *ln1_rstd = p->ln1_rstd ? (p->ln1_rstd + token_slot) : &ln1_rstd_tmp;
2192 float *ln2_rstd = p->ln2_rstd ? (p->ln2_rstd + token_slot) : &ln2_rstd_tmp;
2193
2194 /* Scratch for a single token in head-major layout: [head, aligned_head_dim]. */
2195 size_t q_elems = (size_t)H * (size_t)ad;
2196 size_t kv_elems = (size_t)H_kv * (size_t)ad;
2197 float q_token[q_elems];
2198 float k_token[kv_elems];
2199 float v_token[kv_elems];
2200 float attn_token[q_elems];
2201
2202 /* LN1 / RMSNorm. */
2203 ck_debug_check_buffer("input_row", input_row, aligned_D);
2204 rmsnorm_forward(input_row,
2205 p->ln1_gamma,
2206 ln1_row,
2207 ln1_rstd,
2208 /*tokens=*/1,
2209 D,
2210 aligned_D,
2211 p->eps);
2212 ck_debug_check_buffer("ln1_out (after rmsnorm)", ln1_row, aligned_D);
2213
2215 if ((aligned_D % QK_K) == 0 && (aligned_intermediate % QK_K) == 0) {
2216 const int q8_blocks_embed = aligned_D / QK_K;
2217 const int q8_blocks_inter = aligned_intermediate / QK_K;
2218 const int q8_blocks_max = (q8_blocks_embed > q8_blocks_inter) ? q8_blocks_embed : q8_blocks_inter;
2219 block_q8_K q8_buf[q8_blocks_max];
2220
2221 /* Project Q/K/V with Q8_K activations. */
2222 quantize_row_q8_k(ln1_row, q8_buf, aligned_D);
2223 ck_debug_check_q8k("q8_buf (after quantize)", q8_buf, q8_blocks_embed);
2224 ck_debug_check_q4k_weights("wq weights", p->wq, (aligned_D / QK_K) * (H * ad));
2226 p->wq, p->bq,
2227 p->wk, p->bk,
2228 p->wv, p->bv,
2229 q_token, k_token, v_token,
2230 aligned_D,
2231 H,
2232 H_kv,
2233 ad);
2234 ck_debug_check_buffer("q_token (after QKV proj)", q_token, (int)q_elems);
2235 ck_debug_check_buffer("k_token (after QKV proj)", k_token, (int)kv_elems);
2236 ck_debug_check_buffer("v_token (after QKV proj)", v_token, (int)kv_elems);
2237
2238 /* RoPE for the new token at absolute position `p->rope_pos_offset`. */
2239 if (p->rope_cos && p->rope_sin) {
2240 rope_forward_qk(q_token,
2241 k_token,
2242 p->rope_cos,
2243 p->rope_sin,
2244 H,
2245 H_kv,
2246 /*num_tokens=*/1,
2247 hd,
2248 ad,
2249 p->rope_pos_offset);
2250 }
2251
2252 /* Update KV cache. */
2254 v_token,
2255 p->k,
2256 p->v,
2257 H_kv,
2258 token_index,
2259 cache_capacity,
2260 hd,
2261 ad);
2262
2263 /* Decode attention for this token using the KV cache. */
2265 p->k,
2266 p->v,
2267 attn_token,
2268 H,
2269 H_kv,
2270 /*kv_tokens=*/token_index + 1,
2271 cache_capacity,
2272 hd,
2273 ad);
2274 ck_debug_check_buffer("attn_token (after attention)", attn_token, (int)q_elems);
2275
2276 /* Quantized output projection (Wo) with Q8_K activations. */
2277 quantize_row_q8_k(attn_token, q8_buf, aligned_D);
2278 gemm_nt_q4_k_q8_k(q8_buf,
2279 p->wo,
2280 p->bo,
2281 proj_row,
2282 /*M=*/1,
2283 aligned_D,
2284 /*K=*/K_concat);
2285 ck_debug_check_buffer("proj_row (after Wo proj)", proj_row, aligned_D);
2286
2287 for (int j = D; j < aligned_D; ++j) {
2288 proj_row[j] = 0.0f;
2289 }
2290
2291 /* Residual + LN2 / RMSNorm. */
2293 proj_row,
2294 residual_row,
2295 /*tokens=*/1,
2296 aligned_D);
2297
2298 rmsnorm_forward(residual_row,
2299 p->ln2_gamma,
2300 ln2_row,
2301 ln2_rstd,
2302 /*tokens=*/1,
2303 D,
2304 aligned_D,
2305 p->eps);
2306
2307 /* MLP block for this token (Q8_K activations). */
2308 int up_dim = 2 * aligned_intermediate;
2309 float *fc1_row = p->fc1_out + token_slot * (size_t)up_dim;
2310 float *swiglu_row = p->swiglu_out + token_slot * (size_t)aligned_intermediate;
2311
2313 p->w1,
2314 p->b1,
2315 p->w2,
2316 p->b2,
2317 fc1_row,
2318 swiglu_row,
2319 mlp_row,
2320 aligned_D,
2321 aligned_intermediate);
2322 ck_debug_check_buffer("mlp_row (after MLP)", mlp_row, aligned_D);
2323
2324 /* Final residual. */
2325 ck_residual_add_token_major(residual_row,
2326 mlp_row,
2327 out_row,
2328 /*tokens=*/1,
2329 aligned_D);
2330 ck_debug_check_buffer("out_row (final output)", out_row, aligned_D);
2331 return;
2332 }
2333 }
2334
2335 /* Project Q/K/V for the new token (Q4_K weights). */
2337 p->wq, p->bq,
2338 p->wk, p->bk,
2339 p->wv, p->bv,
2340 q_token, k_token, v_token,
2341 aligned_D,
2342 H,
2343 H_kv,
2344 ad);
2345
2346 /* RoPE for the new token at absolute position `p->rope_pos_offset`. */
2347 if (p->rope_cos && p->rope_sin) {
2348 rope_forward_qk(q_token,
2349 k_token,
2350 p->rope_cos,
2351 p->rope_sin,
2352 H,
2353 H_kv,
2354 /*num_tokens=*/1,
2355 hd,
2356 ad,
2357 p->rope_pos_offset);
2358 }
2359
2360 /* Update KV cache. */
2362 v_token,
2363 p->k,
2364 p->v,
2365 H_kv,
2366 token_index,
2367 cache_capacity,
2368 hd,
2369 ad);
2370
2371 /* Decode attention for this token using the KV cache. */
2373 p->k,
2374 p->v,
2375 attn_token,
2376 H,
2377 H_kv,
2378 /*kv_tokens=*/token_index + 1,
2379 cache_capacity,
2380 hd,
2381 ad);
2382
2383 /* Quantized output projection: Wo is stored as a flattened Q4_K matrix. */
2384 gemm_nt_q4_k(attn_token,
2385 p->wo,
2386 p->bo,
2387 proj_row,
2388 /*M=*/1,
2389 aligned_D,
2390 /*K=*/K_concat);
2391
2392 for (int j = D; j < aligned_D; ++j) {
2393 proj_row[j] = 0.0f;
2394 }
2395
2396 /* Residual + LN2 / RMSNorm. */
2398 proj_row,
2399 residual_row,
2400 /*tokens=*/1,
2401 aligned_D);
2402
2403 rmsnorm_forward(residual_row,
2404 p->ln2_gamma,
2405 ln2_row,
2406 ln2_rstd,
2407 /*tokens=*/1,
2408 D,
2409 aligned_D,
2410 p->eps);
2411
2412 /* MLP block for this token. */
2413 int up_dim = 2 * aligned_intermediate;
2414 float *fc1_row = p->fc1_out + token_slot * (size_t)up_dim;
2415 float *swiglu_row = p->swiglu_out + token_slot * (size_t)aligned_intermediate;
2416
2418 p->w1,
2419 p->b1,
2420 p->w2,
2421 p->b2,
2422 fc1_row,
2423 swiglu_row,
2424 mlp_row,
2425 /*tokens=*/1,
2426 aligned_D,
2427 aligned_intermediate);
2428
2429 /* Final residual. */
2430 ck_residual_add_token_major(residual_row,
2431 mlp_row,
2432 out_row,
2433 /*tokens=*/1,
2434 aligned_D);
2435}
2436
2438{
2439 if (!p) {
2440 return;
2441 }
2442
2444 p->ln1_gamma,
2445 p->ln1_out,
2446 p->ln1_rstd,
2447 p->tokens,
2448 p->embed_dim,
2450 p->eps);
2451
2453 p->wq, p->bq, p->wq_dtype,
2454 p->wk, p->bk, p->wk_dtype,
2455 p->wv, p->bv, p->wv_dtype,
2456 p->q, p->k, p->v,
2457 p->tokens,
2458 p->tokens,
2460 p->num_heads,
2461 p->num_kv_heads,
2462 p->aligned_head_dim);
2463
2464 if (p->rope_cos && p->rope_sin) {
2465 rope_forward_qk(p->q,
2466 p->k,
2467 p->rope_cos,
2468 p->rope_sin,
2469 p->num_heads,
2470 p->num_kv_heads,
2471 p->tokens,
2472 p->head_dim,
2474 p->rope_pos_offset);
2475 }
2476
2477 if (p->scores) {
2479 p->k,
2480 p->v,
2481 p->scores,
2482 p->attn_out,
2483 p->num_heads,
2484 p->num_kv_heads,
2485 p->tokens,
2486 p->head_dim,
2489 } else {
2491 p->k,
2492 p->v,
2493 p->attn_out,
2494 p->num_heads,
2495 p->num_kv_heads,
2496 p->tokens,
2497 p->head_dim,
2498 p->aligned_head_dim);
2499 }
2500
2502 p->wo,
2503 p->bo,
2504 p->proj_tmp,
2505 p->proj_scratch,
2506 p->tokens,
2508 p->num_heads,
2510 p->wo_dtype);
2511
2513 p->proj_tmp,
2514 p->residual1,
2515 p->tokens,
2517
2519 p->ln2_gamma,
2520 p->ln2_out,
2521 p->ln2_rstd,
2522 p->tokens,
2523 p->embed_dim,
2525 p->eps);
2526
2528 p->w1,
2529 p->b1,
2530 p->w1_dtype,
2531 p->w2,
2532 p->b2,
2533 p->w2_dtype,
2534 p->fc1_out,
2535 p->swiglu_out,
2536 p->mlp_out,
2537 p->tokens,
2540
2542 p->mlp_out,
2543 p->output,
2544 p->tokens,
2546}
2547
2549 int token_index,
2550 int cache_capacity)
2551{
2552 if (!p) {
2553 return;
2554 }
2555 if (!p->input || !p->ln1_gamma || !p->ln2_gamma || !p->ln1_out || !p->ln2_out ||
2556 !p->wq || !p->wk || !p->wv || !p->wo || !p->w1 || !p->w2 ||
2557 !p->k || !p->v ||
2558 !p->proj_tmp || !p->proj_scratch || !p->residual1 || !p->fc1_out || !p->swiglu_out || !p->mlp_out || !p->output) {
2559 return;
2560 }
2561 if (token_index < 0 || cache_capacity <= 0 || token_index >= cache_capacity) {
2562 return;
2563 }
2564
2565 const int D = p->embed_dim;
2566 const int aligned_D = p->aligned_embed_dim;
2567 const int H = p->num_heads;
2568 const int H_kv = p->num_kv_heads;
2569 const int hd = p->head_dim;
2570 const int ad = p->aligned_head_dim;
2571 const int aligned_intermediate = p->aligned_intermediate_dim;
2572 const int K_concat = H * ad;
2573
2574 /* Decode buffers are single-token; token_index only applies to KV cache. */
2575 const size_t token_slot = 0;
2576 const float *input_row = p->input + token_slot * (size_t)aligned_D;
2577 float *ln1_row = p->ln1_out + token_slot * (size_t)aligned_D;
2578 float *ln2_row = p->ln2_out + token_slot * (size_t)aligned_D;
2579 float *proj_row = p->proj_tmp + token_slot * (size_t)aligned_D;
2580 float *residual_row = p->residual1 + token_slot * (size_t)aligned_D;
2581 float *mlp_row = p->mlp_out + token_slot * (size_t)aligned_D;
2582 float *out_row = p->output + token_slot * (size_t)aligned_D;
2583
2584 float ln1_rstd_tmp = 0.0f;
2585 float ln2_rstd_tmp = 0.0f;
2586 float *ln1_rstd = p->ln1_rstd ? (p->ln1_rstd + token_slot) : &ln1_rstd_tmp;
2587 float *ln2_rstd = p->ln2_rstd ? (p->ln2_rstd + token_slot) : &ln2_rstd_tmp;
2588
2589 size_t q_elems = (size_t)H * (size_t)ad;
2590 size_t kv_elems = (size_t)H_kv * (size_t)ad;
2591 float q_token[q_elems];
2592 float k_token[kv_elems];
2593 float v_token[kv_elems];
2594 float attn_token[q_elems];
2595
2596 rmsnorm_forward(input_row,
2597 p->ln1_gamma,
2598 ln1_row,
2599 ln1_rstd,
2600 /*tokens=*/1,
2601 D,
2602 aligned_D,
2603 p->eps);
2604
2606 p->wq, p->bq, p->wq_dtype,
2607 p->wk, p->bk, p->wk_dtype,
2608 p->wv, p->bv, p->wv_dtype,
2609 q_token, k_token, v_token,
2610 aligned_D,
2611 H,
2612 H_kv,
2613 ad);
2614
2615 if (p->rope_cos && p->rope_sin) {
2616 rope_forward_qk(q_token,
2617 k_token,
2618 p->rope_cos,
2619 p->rope_sin,
2620 H,
2621 H_kv,
2622 /*num_tokens=*/1,
2623 hd,
2624 ad,
2625 p->rope_pos_offset);
2626 }
2627
2629 v_token,
2630 p->k,
2631 p->v,
2632 H_kv,
2633 token_index,
2634 cache_capacity,
2635 hd,
2636 ad);
2637
2639 p->k,
2640 p->v,
2641 attn_token,
2642 H,
2643 H_kv,
2644 /*kv_tokens=*/token_index + 1,
2645 cache_capacity,
2646 hd,
2647 ad);
2648
2649 if (p->wo_dtype == CK_DT_FP32) {
2651 (const float *)p->wo,
2652 p->bo,
2653 proj_row,
2654 D,
2655 aligned_D,
2656 H,
2657 ad);
2658 } else {
2659 /* Quantized attention output projection - handle all quant types */
2660 ck_gemm_nt_quant(attn_token,
2661 p->wo,
2662 p->bo,
2663 proj_row,
2664 /*M=*/1,
2665 aligned_D,
2666 /*K=*/K_concat,
2667 p->wo_dtype);
2668 for (int j = D; j < aligned_D; ++j) {
2669 proj_row[j] = 0.0f;
2670 }
2671 }
2672
2674 proj_row,
2675 residual_row,
2676 /*tokens=*/1,
2677 aligned_D);
2678
2679 rmsnorm_forward(residual_row,
2680 p->ln2_gamma,
2681 ln2_row,
2682 ln2_rstd,
2683 /*tokens=*/1,
2684 D,
2685 aligned_D,
2686 p->eps);
2687
2688 int up_dim = 2 * aligned_intermediate;
2689 float *fc1_row = p->fc1_out + token_slot * (size_t)up_dim;
2690 float *swiglu_row = p->swiglu_out + token_slot * (size_t)aligned_intermediate;
2691
2693 p->w1,
2694 p->b1,
2695 p->w1_dtype,
2696 p->w2,
2697 p->b2,
2698 p->w2_dtype,
2699 fc1_row,
2700 swiglu_row,
2701 mlp_row,
2702 /*tokens=*/1,
2703 aligned_D,
2704 aligned_intermediate);
2705
2706 ck_residual_add_token_major(residual_row,
2707 mlp_row,
2708 out_row,
2709 /*tokens=*/1,
2710 aligned_D);
2711}
2712
2714{
2715 if (!p) {
2716 return;
2717 }
2718
2719 int T = p->tokens;
2720 int aligned_embed = p->aligned_embed_dim;
2721 int aligned_head = p->aligned_head_dim;
2722 int aligned_intermediate = p->aligned_intermediate_dim;
2723 int up_dim = 2 * aligned_intermediate;
2724 int num_threads = 1;
2725
2726 // 1) Residual add (output = residual1 + mlp_out)
2727 ck_residual_add_backward(p->d_output, p->d_residual1, p->d_mlp_out, T, aligned_embed);
2728
2729 // 2) MLP down proj backward
2731 p->swiglu_out,
2732 p->w2,
2733 p->d_swiglu_out,
2734 p->d_w2,
2735 p->d_b2,
2736 T,
2737 aligned_intermediate,
2738 aligned_embed,
2739 num_threads);
2740
2741 // 3) SwiGLU backward
2742 swiglu_backward(p->fc1_out, p->d_swiglu_out, p->d_fc1_out, T, aligned_intermediate);
2743
2744 // 4) MLP up proj backward
2746 p->ln2_out,
2747 p->w1,
2748 p->d_ln2_out,
2749 p->d_w1,
2750 p->d_b1,
2751 T,
2752 aligned_embed,
2753 up_dim,
2754 num_threads);
2755
2756 // 5) RMSNorm (ln2) backward; reuse d_output as scratch for d_residual1_from_ln2
2758 p->residual1,
2759 p->ln2_gamma,
2760 p->ln2_rstd,
2761 p->d_output,
2762 p->d_ln2_gamma,
2763 T,
2764 p->embed_dim,
2765 aligned_embed);
2766 ck_add_inplace(p->d_residual1, p->d_output, T, aligned_embed);
2767
2768 // 6) Residual add (residual1 = input + proj_tmp)
2769 ck_residual_add_backward(p->d_residual1, p->d_input, p->d_proj_tmp, T, aligned_embed);
2770
2771 // 7) Attention projection backward
2773 p->attn_out,
2774 p->wo,
2775 p->d_attn_out,
2776 p->d_wo,
2777 p->d_bo,
2778 T,
2779 aligned_embed,
2780 p->num_heads,
2781 aligned_head);
2782
2783 // 8) Attention backward
2785 p->q,
2786 p->k,
2787 p->v,
2788 p->scores,
2789 p->d_q,
2790 p->d_k,
2791 p->d_v,
2792 p->d_scores,
2793 p->num_heads,
2794 p->num_kv_heads,
2795 T,
2796 p->head_dim,
2797 aligned_head,
2799
2800 // 9) RoPE backward (if enabled)
2801 if (p->rope_cos && p->rope_sin) {
2803 p->d_k,
2804 p->d_q,
2805 p->d_k,
2806 p->rope_cos,
2807 p->rope_sin,
2808 p->num_heads,
2809 p->num_kv_heads,
2810 T,
2811 p->head_dim,
2812 aligned_head,
2813 p->rope_pos_offset);
2814 }
2815
2816 // 10) QKV projection backward (scratch uses d_proj_tmp)
2818 p->d_k,
2819 p->d_v,
2820 p->ln1_out,
2821 p->wq,
2822 p->bq,
2823 p->wk,
2824 p->bk,
2825 p->wv,
2826 p->bv,
2827 p->d_ln1_out,
2828 p->d_wq,
2829 p->d_bq,
2830 p->d_wk,
2831 p->d_bk,
2832 p->d_wv,
2833 p->d_bv,
2834 p->d_proj_tmp,
2835 T,
2836 aligned_embed,
2837 p->num_heads,
2838 p->num_kv_heads,
2839 aligned_head,
2840 num_threads);
2841
2842 // 11) RMSNorm (ln1) backward; reuse d_ln1_out as scratch for d_input_from_ln1
2844 p->input,
2845 p->ln1_gamma,
2846 p->ln1_rstd,
2847 p->d_ln1_out,
2848 p->d_ln1_gamma,
2849 T,
2850 p->embed_dim,
2851 aligned_embed);
2852 ck_add_inplace(p->d_input, p->d_ln1_out, T, aligned_embed);
2853}
CKDataType
Supported data types in C-Kernel-Engine.
@ CK_DT_Q4_K
@ CK_DT_Q4_0
@ CK_DT_Q8_0
@ CK_DT_Q5_0
@ CK_DT_FP32
@ CK_DT_Q6_K
@ CK_DT_Q4_1
@ CK_DT_Q5_1
static size_t ck_dtype_row_bytes(CKDataType dt, size_t n_elements)
Calculate total bytes for n_elements of given dtype.
void gemm_nt_q4_0(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
Matrix-matrix multiply: C[M,N] = A[M,K] @ B[N,K]^T + bias.
void attention_forward_causal_head_major_gqa_exact(const float *q, const float *k, const float *v, float *scores, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
void swiglu_forward_exact(const float *input, float *output, int tokens, int dim)
void gemm_naive_parallel(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
void swiglu_forward(const float *input, float *output, int tokens, int dim)
void gemm_swiglu_fused(const float *x, const float *W_gate, const float *W_up, const float *b_gate, const float *b_up, float *output, int M, int N, int K)
void swiglu_backward(const float *input, const float *d_output, float *d_input, int tokens, int dim)
void attention_flash_decode(float *out, const float *q, const float *k, const float *v, int T_q, int T_k, int H, int D_h, float scale)
Main flash attention function with SIMD dispatch.
void gemm_nt_q4_k(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void attention_forward_causal_head_major_gqa(const float *q, const float *k, const float *v, float *scores, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
void rope_backward_qk(const float *d_q_out, const float *d_k_out, float *d_q, float *d_k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset)
void gemm_nt_q4_1(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
GEMM with transposed Q4_1 weights: C = A @ B^T.
void gemm_nt_q4_k_q8_k(const void *A_q8, const void *B, const float *bias, float *C, int M, int N, int K)
void kv_cache_write_head_major(const float *__restrict k_token, const float *__restrict v_token, float *__restrict k_cache, float *__restrict v_cache, int num_kv_heads, int token_index, int cache_capacity, int head_dim, int aligned_head_dim)
void gemm_nt_q5_0(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void fc1_backward_kernel(const float *d_output, const float *fc1_input, const float *W_fc1, float *d_input, float *d_W_fc1, float *d_b_fc1, int T, int aligned_in, int aligned_out, int num_threads)
void gemm_nt_q6_k(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void gemm_nt_q8_0(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
void fc2_backward_kernel(const float *d_output, const float *fc2_input, const float *W_fc2, float *d_input, float *d_W_fc2, float *d_b_fc2, int T, int aligned_in, int aligned_out, int num_threads)
void quantize_row_q8_k(const float *x, void *y, int k)
void attention_forward_decode_head_major_gqa_regular(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
WARNING: This is NOT true flash attention!
void rmsnorm_forward(const float *input, const float *gamma, float *output, float *rstd_cache, int tokens, int d_model, int aligned_embed_dim, float eps)
void gemm_nt_q5_1(const float *A, const void *B, const float *bias, float *C, int M, int N, int K)
GEMM with transposed Q5_1 weights: C = A @ B^T.
void attention_forward_causal_head_major_gqa_flash(const float *q, const float *k, const float *v, float *output, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim)
void rope_forward_qk(float *q, float *k, const float *cos_cache, const float *sin_cache, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int pos_offset)
void fused_mlp_swiglu_decode_v2(const float *x, const float *W_gate, const float *W_up, const float *W_down, const float *b_gate, const float *b_up, const float *b_down, float *output, int D, int Hff)
void rmsnorm_backward(const float *d_output, const float *input, const float *gamma, const float *rstd_cache, float *d_input, float *d_gamma, int tokens, int d_model, int aligned_embed_dim)
void attention_backward_causal_head_major_gqa(const float *d_output, const float *q, const float *k, const float *v, const float *attn_weights, float *d_q, float *d_k, float *d_v, float *d_scores, int num_heads, int num_kv_heads, int num_tokens, int head_dim, int aligned_head_dim, int aligned_context_window)
int ck_strict_parity_enabled(void)
void gemm_blocked_serial(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
static void ck_add_inplace(float *dst, const float *src, int tokens, int aligned_embed_dim)
static void ck_qkv_project_head_major_quant(const float *input, const void *wq, const float *bq, CKDataType wq_dtype, const void *wk, const float *bk, CKDataType wk_dtype, const void *wv, const float *bv, CKDataType wv_dtype, float *q, float *k, float *v, int tokens, int kv_stride_tokens, int aligned_embed_dim, int num_heads, int num_kv_heads, int aligned_head_dim)
static void ck_attention_project_head_major_quant(const float *attn_out, const void *wo, const float *bo, float *out, float *scratch, int tokens, int aligned_embed_dim, int num_heads, int aligned_head_dim, CKDataType wo_dtype)
void ck_layer_backward_rmsnorm_swiglu(const CKLayerBackwardParams *p)
void ck_mlp_swiglu_forward_fused_token(const float *input_row, const float *w1, const float *b1, const float *w2, const float *b2, float *swiglu_row, float *output_row, int aligned_embed_dim, int aligned_intermediate_dim)
void ck_attention_project_head_major(const float *attn_out, const float *wo, const float *bo, float *out, float *scratch, int tokens, int aligned_embed_dim, int num_heads, int aligned_head_dim)
void ck_mlp_swiglu_forward(const float *input, const float *w1, const float *b1, const float *w2, const float *b2, float *fc1_out, float *swiglu_out, float *output, int tokens, int aligned_embed_dim, int aligned_intermediate_dim)
static void ck_attention_project_head_major_ref(const float *attn_out, const float *wo, const float *bo, float *out, float *scratch, int tokens, int aligned_embed_dim, int num_heads, int aligned_head_dim)
void ck_residual_add_backward(const float *d_out, float *d_a, float *d_b, int tokens, int aligned_embed_dim)
static void ck_mlp_swiglu_forward_quant(const float *input, const void *w1, const float *b1, CKDataType w1_dtype, const void *w2, const float *b2, CKDataType w2_dtype, float *fc1_out, float *swiglu_out, float *output, int tokens, int aligned_embed_dim, int aligned_intermediate_dim)
static void ck_qkv_project_head_major_token_q4_k_q8_k(const block_q8_K *input_q8, const void *wq, const float *bq, const void *wk, const float *bk, const void *wv, const float *bv, float *q_token, float *k_token, float *v_token, int aligned_embed_dim, int num_heads, int num_kv_heads, int aligned_head_dim)
static void ck_attention_project_head_major_q4_k(const float *attn_out, const void *wo, const float *bo, float *out, float *scratch, int tokens, int aligned_embed_dim, int num_heads, int aligned_head_dim)
static void ck_qkv_project_head_major_q4_k_q8_k(const float *input, const void *wq, const float *bq, const void *wk, const float *bk, const void *wv, const float *bv, float *q, float *k, float *v, int tokens, int kv_stride_tokens, int aligned_embed_dim, int num_heads, int num_kv_heads, int aligned_head_dim)
static void ck_qkv_project_head_major_ref(const float *input, const float *wq, const float *bq, const float *wk, const float *bk, const float *wv, const float *bv, float *q, float *k, float *v, int tokens, int kv_stride_tokens, int aligned_embed_dim, int num_heads, int num_kv_heads, int aligned_head_dim)
static int ck_q8k_activations_enabled(void)
void ck_layer_forward_rmsnorm_swiglu_quant(const CKLayerForwardParamsQ4K *p)
static int ck_layer_debug_enabled(void)
void ck_mlp_swiglu_forward_fully_fused_token(const float *input_row, const float *w1, const float *b1, const float *w2, const float *b2, float *output_row, int aligned_embed_dim, int aligned_intermediate_dim)
static void ck_mlp_swiglu_forward_q4_k_q8_k(const float *input, const void *w1, const float *b1, const void *w2, const float *b2, float *fc1_out, float *swiglu_out, float *output, int aligned_embed_dim, int aligned_intermediate_dim)
void ck_layer_forward_rmsnorm_swiglu_decode(const CKLayerForwardParams *p, int token_index, int cache_capacity)
void ck_layer_forward_rmsnorm_swiglu_q4_k(const CKLayerForwardParamsQ4K *p)
void ck_qkv_project_head_major(const float *input, const float *wq, const float *bq, const float *wk, const float *bk, const float *wv, const float *bv, float *q, float *k, float *v, int tokens, int kv_stride_tokens, int aligned_embed_dim, int num_heads, int num_kv_heads, int aligned_head_dim)
static void ck_debug_check_q8k(const char *stage, const void *q8_buf, int num_blocks)
static void ck_attention_project_head_major_q4_k_q8_k(const float *attn_out, const void *wo, const float *bo, float *out, int tokens, int aligned_embed_dim, int num_heads, int aligned_head_dim)
static void ck_mlp_swiglu_forward_q4_k(const float *input, const void *w1, const float *b1, const void *w2, const float *b2, float *fc1_out, float *swiglu_out, float *output, int tokens, int aligned_embed_dim, int aligned_intermediate_dim)
void ck_gemm_nt_quant(const float *A, const void *B, const float *bias, float *C, int M, int N, int K, CKDataType dtype)
void ck_attention_flash_decode_wrapper(const float *q_token, const float *k_cache, const float *v_cache, float *out_token, int num_heads, int num_kv_heads, int kv_tokens, int cache_capacity, int head_dim, int aligned_head_dim)
Wrapper to call TRUE flash attention from orchestration layer.
void ck_qkv_project_head_major_backward(const float *d_q, const float *d_k, const float *d_v, const float *input, const float *wq, const float *bq, const float *wk, const float *bk, const float *wv, const float *bv, float *d_input, float *d_wq, float *d_bq, float *d_wk, float *d_bk, float *d_wv, float *d_bv, float *scratch, int tokens, int aligned_embed_dim, int num_heads, int num_kv_heads, int aligned_head_dim, int num_threads)
void ck_residual_add_token_major(const float *a, const float *b, float *out, int tokens, int aligned_embed_dim)
void ck_layer_forward_rmsnorm_swiglu(const CKLayerForwardParams *p)
void ck_layer_forward_rmsnorm_swiglu_decode_fused(const CKLayerForwardParams *p, int token_index, int cache_capacity)
void ck_layer_forward_rmsnorm_swiglu_decode_q4_k(const CKLayerForwardParamsQ4K *p, int token_index, int cache_capacity)
static void ck_debug_check_q4k_weights(const char *stage, const void *q4_buf, int num_blocks)
static void ck_debug_check_buffer(const char *stage, const float *buf, int size)
static void ck_mlp_swiglu_forward_ref(const float *input, const float *w1, const float *b1, const float *w2, const float *b2, float *fc1_out, float *swiglu_out, float *output, int tokens, int aligned_embed_dim, int aligned_intermediate_dim)
void ck_layer_forward_rmsnorm_swiglu_ref(const CKLayerForwardParams *p)
static void ck_qkv_project_head_major_token_q4_k(const float *input_row, const void *wq, const float *bq, const void *wk, const float *bk, const void *wv, const float *bv, float *q_token, float *k_token, float *v_token, int aligned_embed_dim, int num_heads, int num_kv_heads, int aligned_head_dim)
static void ck_qkv_project_head_major_q4_k(const float *input, const void *wq, const float *bq, const void *wk, const float *bk, const void *wv, const float *bv, float *q, float *k, float *v, int tokens, int kv_stride_tokens, int aligned_embed_dim, int num_heads, int num_kv_heads, int aligned_head_dim)
static void ck_mlp_swiglu_forward_q4_k_q8_k_prefill(const float *input, const void *w1, const float *b1, const void *w2, const float *b2, float *fc1_out, float *swiglu_out, float *output, int tokens, int aligned_embed_dim, int aligned_intermediate_dim)
static void ck_qkv_project_head_major_token_quant(const float *input_row, const void *wq, const float *bq, CKDataType wq_dtype, const void *wk, const float *bk, CKDataType wk_dtype, const void *wv, const float *bv, CKDataType wv_dtype, float *q_token, float *k_token, float *v_token, int aligned_embed_dim, int num_heads, int num_kv_heads, int aligned_head_dim)
void ck_attention_project_head_major_backward(const float *d_out, const float *attn_out, const float *wo, float *d_attn_out, float *d_wo, float *d_bo, int tokens, int aligned_embed_dim, int num_heads, int aligned_head_dim)
void ck_layer_forward_rmsnorm_swiglu_decode_quant(const CKLayerForwardParamsQ4K *p, int token_index, int cache_capacity)
void ck_qkv_project_head_major_token(const float *input_row, const float *wq, const float *bq, const float *wk, const float *bk, const float *wv, const float *bv, float *q_token, float *k_token, float *v_token, int aligned_embed_dim, int num_heads, int num_kv_heads, int aligned_head_dim)
void ck_attention_project_head_major_decode_token(const float *attn_token, const float *wo, const float *bo, float *out_token, int embed_dim, int aligned_embed_dim, int num_heads, int aligned_head_dim)
Quantization block structures for weight-only quantization.
#define CK_FP16_TO_FP32(x)
#define QK_K
#define C(color)
Definition show_config.c:39