← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
axpy_kernels.c
Go to the documentation of this file.
1/**
2 * @file axpy_kernels.c
3 * @brief AXPY kernels for FP32: y = y + alpha * x
4 *
5 * CK-ENGINE KERNEL RULES:
6 * =======================
7 * 1. NO malloc/free - memory via bump allocator, pointers passed in
8 * 2. NO OpenMP - parallelization at orchestrator/codegen layer
9 * 3. API must define: inputs, outputs, workspace, and memory layouts
10 * 4. Pure computation - deterministic, no side effects
11 *
12 * After changes: make test && make llamacpp-parity-full
13 *
14 * Classic BLAS Level-1 operation used in MoE expert output accumulation.
15 * When gathering expert outputs: output += weight[i] * expert_output[i]
16 *
17 * Operations:
18 * - axpy_f32: y += alpha * x (in-place)
19 * - axpy_strided_f32: strided version for non-contiguous memory
20 * - weighted_sum_f32: sum multiple vectors with weights
21 */
22
23#include <stdint.h>
24#include <stddef.h>
25#include <stdatomic.h>
26#include <string.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <math.h>
30
31#include "ckernel_engine.h"
32#include "ckernel_dtype.h"
33#include "ck_threadpool.h"
34#include "bf16_utils.h"
35
36#ifdef __AVX512F__
37#include <immintrin.h>
38#endif
39
40#ifdef __AVX2__
41#include <immintrin.h>
42#endif
43
44void gemm_q4_k_q8_k_compact_rows4(float *output,
45 int output_stride,
46 const void *weights,
47 const void *const input_rows[4],
48 int rows,
49 int output_dim,
50 int input_dim);
51void gemm_q5_k_q8_k_compact_rows4(float *output,
52 int output_stride,
53 const void *weights,
54 const void *const input_rows[4],
55 int rows,
56 int output_dim,
57 int input_dim);
59 float *output,
60 const void *weights_packed,
61 const void *input_q8,
62 int rows,
63 int output_dim,
64 int input_dim);
68 const void *source, void *destination, int output_dim, int input_dim);
70 const void *input,
71 const void *packed_weight,
72 const float *bias,
73 float *output,
74 int rows,
75 int output_dim,
76 int input_dim);
78 const void *input,
79 const void *weight,
80 const float *bias,
81 float *output,
82 int rows,
83 int output_dim,
84 int input_dim);
85
86/* =============================================================================
87 * AXPY: y = y + alpha * x
88 *
89 * Core operation for MoE expert gathering:
90 * output = sum_i(weight_i * expert_output_i)
91 *
92 * Implemented as: output += weight * expert_output (called for each expert)
93 * ============================================================================= */
94
95/**
96 * @brief In-place AXPY: y += alpha * x
97 * @test test_axpy.py::TestAXPY::test_axpy_f32
98 * @test test_axpy.py::TestAXPY::test_axpy_vs_naive
99 *
100 * In-place scaled vector addition: y += alpha * x
101 * BLAS-like axpy operation.
102 *
103 * After changes: make test
104 */
105void axpy_f32(float *y,
106 const float *x,
107 float alpha,
108 int n)
109{
110 if (!y || !x || n <= 0) {
111 return;
112 }
113
114 int i = 0;
115
116#ifdef __AVX512F__
117 __m512 valpha = _mm512_set1_ps(alpha);
118 for (; i + 16 <= n; i += 16) {
119 __m512 vy = _mm512_loadu_ps(&y[i]);
120 __m512 vx = _mm512_loadu_ps(&x[i]);
121 vy = _mm512_fmadd_ps(vx, valpha, vy); /* y = y + alpha * x */
122 _mm512_storeu_ps(&y[i], vy);
123 }
124#endif
125
126#ifdef __AVX2__
127 __m256 valpha256 = _mm256_set1_ps(alpha);
128 for (; i + 8 <= n; i += 8) {
129 __m256 vy = _mm256_loadu_ps(&y[i]);
130 __m256 vx = _mm256_loadu_ps(&x[i]);
131 vy = _mm256_fmadd_ps(vx, valpha256, vy);
132 _mm256_storeu_ps(&y[i], vy);
133 }
134#endif
135
136 /* Scalar remainder */
137 for (; i < n; i++) {
138 y[i] += alpha * x[i];
139 }
140}
141
142/* =============================================================================
143 * Scaled copy: y = alpha * x
144 *
145 * First step when accumulating: initialize output with first expert's result.
146 * ============================================================================= */
147
148/**
149 * @brief Scaled copy: y = alpha * x
150 *
151 * @param y Output vector [n]
152 * @param x Input vector [n]
153 * @param alpha Scalar multiplier
154 * @param n Vector length
155 */
156void scal_copy_f32(float *y,
157 const float *x,
158 float alpha,
159 int n)
160{
161 if (!y || !x || n <= 0) {
162 return;
163 }
164
165 int i = 0;
166
167#ifdef __AVX512F__
168 __m512 valpha = _mm512_set1_ps(alpha);
169 for (; i + 16 <= n; i += 16) {
170 __m512 vx = _mm512_loadu_ps(&x[i]);
171 __m512 vy = _mm512_mul_ps(vx, valpha);
172 _mm512_storeu_ps(&y[i], vy);
173 }
174#endif
175
176#ifdef __AVX2__
177 __m256 valpha256 = _mm256_set1_ps(alpha);
178 for (; i + 8 <= n; i += 8) {
179 __m256 vx = _mm256_loadu_ps(&x[i]);
180 __m256 vy = _mm256_mul_ps(vx, valpha256);
181 _mm256_storeu_ps(&y[i], vy);
182 }
183#endif
184
185 for (; i < n; i++) {
186 y[i] = alpha * x[i];
187 }
188}
189
190/* =============================================================================
191 * Weighted sum: y = sum_i(weights[i] * x[i])
192 *
193 * Combine multiple expert outputs with their routing weights in one pass.
194 * More efficient than multiple axpy calls when all inputs are available.
195 * ============================================================================= */
196
197/**
198 * @brief Weighted sum of k vectors: y = sum_i(weights[i] * vectors[i])
199 *
200 * @param y Output vector [n]
201 * @param vectors Array of k input vector pointers, each [n]
202 * @param weights Array of k scalar weights
203 * @param k Number of vectors to combine
204 * @param n Vector length
205 */
206void weighted_sum_f32(float *y,
207 const float **vectors,
208 const float *weights,
209 int k,
210 int n)
211{
212 if (!y || !vectors || !weights || k <= 0 || n <= 0) {
213 return;
214 }
215
216 /* Initialize with first vector */
217 scal_copy_f32(y, vectors[0], weights[0], n);
218
219 /* Accumulate rest */
220 for (int i = 1; i < k; i++) {
221 axpy_f32(y, vectors[i], weights[i], n);
222 }
223}
224
225/* =============================================================================
226 * Zero-initialized AXPY accumulation
227 *
228 * Zero output first, then accumulate. Useful when output may contain garbage.
229 * ============================================================================= */
230
231/**
232 * @brief Zero output then accumulate: y = 0; y += alpha * x
233 *
234 * @param y Output vector [n], zeroed then accumulated
235 * @param x Input vector [n]
236 * @param alpha Scalar multiplier
237 * @param n Vector length
238 */
239void axpy_zero_f32(float *y,
240 const float *x,
241 float alpha,
242 int n)
243{
244 if (!y || n <= 0) {
245 return;
246 }
247
248 memset(y, 0, n * sizeof(float));
249
250 if (x) {
251 axpy_f32(y, x, alpha, n);
252 }
253}
254
255/* =============================================================================
256 * 2D batched AXPY for [tokens, hidden] shaped tensors
257 *
258 * Process multiple tokens at once, common in transformer inference.
259 * ============================================================================= */
260
261/**
262 * @brief Batched AXPY for 2D tensors: Y[t,:] += alpha * X[t,:]
263 *
264 * @param Y Output tensor [num_tokens, dim]
265 * @param X Input tensor [num_tokens, dim]
266 * @param alpha Scalar multiplier
267 * @param num_tokens Number of tokens
268 * @param dim Hidden dimension
269 * @param y_stride Stride between Y rows (for alignment)
270 * @param x_stride Stride between X rows
271 */
272void axpy_2d_f32(float *Y,
273 const float *X,
274 float alpha,
275 int num_tokens,
276 int dim,
277 int y_stride,
278 int x_stride)
279{
280 if (!Y || !X || num_tokens <= 0 || dim <= 0) {
281 return;
282 }
283
284 /* Default strides if not specified */
285 if (y_stride <= 0) y_stride = dim;
286 if (x_stride <= 0) x_stride = dim;
287
288 for (int t = 0; t < num_tokens; t++) {
289 axpy_f32(Y + t * y_stride, X + t * x_stride, alpha, dim);
290 }
291}
292
293/* =============================================================================
294 * MoE-specific: Accumulate expert output with routing weight
295 *
296 * Convenience wrapper with clear semantics for MoE usage.
297 * ============================================================================= */
298
299/**
300 * @brief Accumulate expert output: output += routing_weight * expert_output
301 *
302 * @param output Token output buffer [hidden_dim], accumulated in place
303 * @param expert_output Expert's output for this token [hidden_dim]
304 * @param routing_weight Softmax routing weight for this expert
305 * @param hidden_dim Hidden dimension
306 */
307void moe_accumulate_expert_f32(float *output,
308 const float *expert_output,
309 float routing_weight,
310 int hidden_dim)
311{
312 axpy_f32(output, expert_output, routing_weight, hidden_dim);
313}
314
315
316/* =============================================================================
317 * Routed MoE expert MLP with ReLU2 activation.
318 *
319 * expert_up layout: [n_experts, intermediate_dim, hidden_dim]
320 * expert_down layout: [n_experts, hidden_dim, intermediate_dim]
321 * output layout: [rows, hidden_dim]
322 * ============================================================================= */
323static inline size_t ck_moe_up_idx(int e, int i, int h, int intermediate_dim, int hidden_dim)
324{
325 return ((size_t)e * (size_t)intermediate_dim + (size_t)i) * (size_t)hidden_dim + (size_t)h;
326}
327
328static inline size_t ck_moe_down_idx(int e, int h, int i, int hidden_dim, int intermediate_dim)
329{
330 return ((size_t)e * (size_t)hidden_dim + (size_t)h) * (size_t)intermediate_dim + (size_t)i;
331}
332
333static int ck_moe_debug_enabled(void)
334{
335 const char *v = getenv("CK_DEBUG_MOE");
336 return v && v[0] && v[0] != '0';
337}
338
339static void ck_moe_debug_finite(const char *name, const float *x, size_t n)
340{
341 if (!ck_moe_debug_enabled() || !x) {
342 return;
343 }
344 size_t finite = 0;
345 size_t nan = 0;
346 size_t inf = 0;
347 float min_v = 0.0f;
348 float max_v = 0.0f;
349 int have = 0;
350 for (size_t i = 0; i < n; ++i) {
351 const float v = x[i];
352 if (isnan(v)) {
353 ++nan;
354 } else if (isinf(v)) {
355 ++inf;
356 } else {
357 ++finite;
358 if (!have || v < min_v) min_v = v;
359 if (!have || v > max_v) max_v = v;
360 have = 1;
361 }
362 }
363 fprintf(stderr,
364 "[CK_DEBUG_MOE] %s finite=%zu/%zu nan=%zu inf=%zu min=%g max=%g\n",
365 name,
366 finite,
367 n,
368 nan,
369 inf,
370 have ? min_v : 0.0f,
371 have ? max_v : 0.0f);
372}
373
374void moe_relu2_expert_forward_f32(const float *hidden,
375 const int *indices,
376 const float *routing_weights,
377 const float *expert_up,
378 const float *expert_down,
379 float *output,
380 int rows,
381 int hidden_dim,
382 int intermediate_dim,
383 int n_experts,
384 int top_k)
385{
386 if (!hidden || !indices || !routing_weights || !expert_up || !expert_down || !output ||
387 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0) {
388 return;
389 }
390
391 const size_t out_count = (size_t)rows * (size_t)hidden_dim;
392 for (size_t p = 0; p < out_count; ++p) output[p] = 0.0f;
393
394 float pre[intermediate_dim];
395 float gate[intermediate_dim];
396 float up[intermediate_dim];
397 float act[intermediate_dim];
398
399 for (int r = 0; r < rows; ++r) {
400 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
401 float *y = output + (size_t)r * (size_t)hidden_dim;
402 for (int slot = 0; slot < top_k; ++slot) {
403 const int e = indices[(size_t)r * (size_t)top_k + (size_t)slot];
404 if (e < 0 || e >= n_experts) continue;
405 const float route_w = routing_weights[(size_t)r * (size_t)top_k + (size_t)slot];
406
407 for (int i = 0; i < intermediate_dim; ++i) {
408 float v = 0.0f;
409 for (int h = 0; h < hidden_dim; ++h) {
410 v += expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] * x[h];
411 }
412 pre[i] = v;
413 act[i] = (v > 0.0f) ? v * v : 0.0f;
414 }
415
416 for (int h = 0; h < hidden_dim; ++h) {
417 float v = 0.0f;
418 for (int i = 0; i < intermediate_dim; ++i) {
419 v += expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)] * act[i];
420 }
421 y[h] += route_w * v;
422 }
423 }
424 }
425}
426
427
428
429static inline float ck_moe_sigmoid_f32(float x)
430{
431 return 1.0f / (1.0f + expf(-x));
432}
433
434static inline float ck_moe_silu_f32(float x)
435{
436 return x * ck_moe_sigmoid_f32(x);
437}
438
439static inline float ck_moe_bf16_round(float x)
440{
441 return bf16_to_float(float_to_bf16(x));
442}
443
444static inline float ck_moe_dsilu_f32(float x)
445{
446 const float sig = ck_moe_sigmoid_f32(x);
447 return sig + x * sig * (1.0f - sig);
448}
449
450void moe_swiglu_expert_forward_f32(const float *hidden,
451 const int *indices,
452 const float *routing_weights,
453 const float *expert_gate,
454 const float *expert_up,
455 const float *expert_down,
456 float *output,
457 int rows,
458 int hidden_dim,
459 int intermediate_dim,
460 int n_experts,
461 int top_k)
462{
463 if (!hidden || !indices || !routing_weights || !expert_gate || !expert_up || !expert_down || !output ||
464 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0) {
465 return;
466 }
467
468 for (size_t p = 0; p < (size_t)rows * (size_t)hidden_dim; ++p) output[p] = 0.0f;
469
470 float gate[intermediate_dim];
471 float up[intermediate_dim];
472 float act[intermediate_dim];
473
474 for (int r = 0; r < rows; ++r) {
475 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
476 float *y = output + (size_t)r * (size_t)hidden_dim;
477 for (int slot = 0; slot < top_k; ++slot) {
478 const int e = indices[(size_t)r * (size_t)top_k + (size_t)slot];
479 if (e < 0 || e >= n_experts) continue;
480 const float route_w = routing_weights[(size_t)r * (size_t)top_k + (size_t)slot];
481
482 for (int i = 0; i < intermediate_dim; ++i) {
483 float gv = 0.0f;
484 float uv = 0.0f;
485 for (int h = 0; h < hidden_dim; ++h) {
486 gv += expert_gate[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] * x[h];
487 uv += expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] * x[h];
488 }
489 gate[i] = gv;
490 up[i] = uv;
491 act[i] = ck_moe_silu_f32(gv) * uv;
492 }
493
494 for (int h = 0; h < hidden_dim; ++h) {
495 float v = 0.0f;
496 for (int i = 0; i < intermediate_dim; ++i) {
497 v += expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)] * act[i];
498 }
499 y[h] += route_w * v;
500 }
501 }
502 }
503}
504
506 const float *hidden,
507 const int *indices,
508 const float *routing_weights,
509 const uint16_t *expert_gate,
510 const uint16_t *expert_up,
511 const uint16_t *expert_down,
512 float *output,
513 int rows,
514 int hidden_dim,
515 int intermediate_dim,
516 int n_experts,
517 int top_k,
518 int row_begin,
519 int row_end)
520{
521 if (!hidden || !indices || !routing_weights || !expert_gate || !expert_up || !expert_down || !output ||
522 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0 ||
523 row_begin < 0 || row_begin >= row_end || row_end > rows) {
524 return;
525 }
526
527 float gate[intermediate_dim];
528 float up[intermediate_dim];
529 float act[intermediate_dim];
530
531 for (int r = row_begin; r < row_end; ++r) {
532 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
533 float *y = output + (size_t)r * (size_t)hidden_dim;
534 for (int h = 0; h < hidden_dim; ++h) y[h] = 0.0f;
535 for (int slot = 0; slot < top_k; ++slot) {
536 const int e = indices[(size_t)r * (size_t)top_k + (size_t)slot];
537 if (e < 0 || e >= n_experts) continue;
538 const float route_w = routing_weights[(size_t)r * (size_t)top_k + (size_t)slot];
539
540 for (int i = 0; i < intermediate_dim; ++i) {
541 float gv = 0.0f;
542 float uv = 0.0f;
543 for (int h = 0; h < hidden_dim; ++h) {
544 gv += bf16_to_float(expert_gate[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)]) * x[h];
545 uv += bf16_to_float(expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)]) * x[h];
546 }
547 gate[i] = gv;
548 up[i] = uv;
549 act[i] = ck_moe_silu_f32(gv) * uv;
550 }
551
552 for (int h = 0; h < hidden_dim; ++h) {
553 float v = 0.0f;
554 for (int i = 0; i < intermediate_dim; ++i) {
555 v += bf16_to_float(expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)]) * act[i];
556 }
557 y[h] += route_w * v;
558 }
559 }
560 }
561}
562
563void moe_swiglu_expert_forward_bf16(const float *hidden,
564 const int *indices,
565 const float *routing_weights,
566 const uint16_t *expert_gate,
567 const uint16_t *expert_up,
568 const uint16_t *expert_down,
569 float *output,
570 int rows,
571 int hidden_dim,
572 int intermediate_dim,
573 int n_experts,
574 int top_k)
575{
576 if (rows <= 0) return;
578 hidden, indices, routing_weights, expert_gate, expert_up, expert_down,
579 output, rows, hidden_dim, intermediate_dim, n_experts, top_k, 0, rows);
580}
581
583 const float *hidden,
584 const int *indices,
585 const float *routing_weights,
586 const uint16_t *expert_gate_up,
587 const uint16_t *expert_down,
588 float *output,
589 int rows,
590 int hidden_dim,
591 int intermediate_dim,
592 int n_experts,
593 int top_k)
594{
595 if (!hidden || !indices || !routing_weights || !expert_gate_up ||
596 !expert_down || !output || rows <= 0 || hidden_dim <= 0 ||
597 intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0) {
598 return;
599 }
600
601 float projection[2 * intermediate_dim];
602 float activation[intermediate_dim];
603 const size_t packed_expert_stride =
604 (size_t)2 * (size_t)intermediate_dim * (size_t)hidden_dim;
605 const size_t packed_up_offset =
606 (size_t)intermediate_dim * (size_t)hidden_dim;
607 for (int row = 0; row < rows; ++row) {
608 float *y = output + (size_t)row * (size_t)hidden_dim;
609 for (int hidden_col = 0; hidden_col < hidden_dim; ++hidden_col) {
610 y[hidden_col] = 0.0f;
611 }
612 }
613 for (int row = 0; row < rows; ++row) {
614 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
615 float *y = output + (size_t)row * (size_t)hidden_dim;
616 for (int slot = 0; slot < top_k; ++slot) {
617 const size_t route_index =
618 (size_t)row * (size_t)top_k + (size_t)slot;
619 const int expert = indices[route_index];
620 if (expert < 0 || expert >= n_experts) continue;
621 const uint16_t *packed =
622 expert_gate_up + (size_t)expert * packed_expert_stride;
623 const uint16_t *gate = packed;
624 const uint16_t *up = packed + packed_up_offset;
625 for (int intermediate = 0; intermediate < intermediate_dim;
626 ++intermediate) {
627 float gate_value = 0.0f;
628 float up_value = 0.0f;
629 const size_t row_offset =
630 (size_t)intermediate * (size_t)hidden_dim;
631 for (int hidden_col = 0; hidden_col < hidden_dim;
632 ++hidden_col) {
633 const float input =
634 ck_moe_bf16_round(x[hidden_col]);
635 gate_value +=
636 bf16_to_float(gate[row_offset + hidden_col]) * input;
637 up_value +=
638 bf16_to_float(up[row_offset + hidden_col]) * input;
639 }
640 projection[intermediate] =
641 ck_moe_bf16_round(gate_value);
642 projection[intermediate_dim + intermediate] =
643 ck_moe_bf16_round(up_value);
644 }
646 projection, activation, 1, intermediate_dim);
647
648 const float route_weight =
649 ck_moe_bf16_round(routing_weights[route_index]);
650 for (int hidden_col = 0; hidden_col < hidden_dim;
651 ++hidden_col) {
652 float value = 0.0f;
653 for (int intermediate = 0;
654 intermediate < intermediate_dim; ++intermediate) {
655 value += bf16_to_float(expert_down[
656 ck_moe_down_idx(expert, hidden_col, intermediate,
657 hidden_dim, intermediate_dim)]) *
658 activation[intermediate];
659 }
660 const float down_stored = ck_moe_bf16_round(value);
661 const float weighted = ck_moe_bf16_round(
662 down_stored * route_weight);
663 y[hidden_col] += weighted;
664 }
665 }
666 for (int hidden_col = 0; hidden_col < hidden_dim; ++hidden_col) {
667 y[hidden_col] = ck_moe_bf16_round(y[hidden_col]);
668 }
669 }
670}
671
672static size_t ck_moe_align64(size_t value)
673{
674 return (value + 63u) & ~(size_t)63u;
675}
676
678 int output_dim, int input_dim)
679{
680#if defined(__AVX512F__) && defined(__AVX512BW__) && defined(__AVX512DQ__)
681 if (output_dim <= 0 || input_dim <= 0 || output_dim % 16 != 0 ||
682 input_dim % 256 != 0) {
683 return 0;
684 }
685 return ck_moe_align64(
686 (size_t)((output_dim + 7) / 8) * (size_t)(input_dim / 256) *
688#else
689 (void)output_dim;
690 (void)input_dim;
691 return 0;
692#endif
693}
694
696 float *output,
697 const void *weights,
698 const void *input_q8,
699 int output_dim,
700 int input_dim,
701 void *scratch)
702{
703#if defined(__AVX512F__) && defined(__AVX512BW__) && defined(__AVX512DQ__)
704 if (scratch && output_dim > 0 && input_dim > 0 &&
705 output_dim % 16 == 0 && input_dim % 256 == 0) {
706 pack_q4_k_to_packed_meta_x8(weights, scratch, output_dim, input_dim);
708 input_q8, scratch, NULL, output, 1, output_dim, input_dim);
709 return;
710 }
711 gemv_q4_k_q8_k(output, weights, input_q8, output_dim, input_dim);
712#else
713 (void)scratch;
714 gemv_q4_k_q8_k(output, weights, input_q8, output_dim, input_dim);
715#endif
716}
717
719 float *output, const float *expert_output, float route_weight, int n)
720{
721 for (int i = 0; i < n; ++i) {
722 volatile float weighted = expert_output[i] * route_weight;
723 output[i] += weighted;
724 }
725}
726
728 int intermediate_dim)
729{
730 if (hidden_dim <= 0 || intermediate_dim <= 0 ||
731 hidden_dim % 256 != 0 || intermediate_dim % 256 != 0) {
732 return 0;
733 }
734
735 size_t bytes = ck_moe_align64(ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
736 bytes += ck_moe_align64(2u * (size_t)intermediate_dim * sizeof(float));
737 bytes += ck_moe_align64(ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)intermediate_dim));
738 bytes += ck_moe_align64((size_t)hidden_dim * sizeof(float));
739 return bytes;
740}
741
743 int intermediate_dim)
744{
745 if (hidden_dim <= 0 || intermediate_dim <= 0 ||
746 hidden_dim % 256 != 0 || intermediate_dim % QK8_0 != 0) {
747 return 0;
748 }
749
750 size_t bytes = ck_moe_align64(
751 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
752 bytes += ck_moe_align64(2u * (size_t)intermediate_dim * sizeof(float));
753 bytes += ck_moe_align64(
754 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim));
755 bytes += ck_moe_align64((size_t)hidden_dim * sizeof(float));
757 intermediate_dim, hidden_dim);
758 return bytes;
759}
760
762 int hidden_dim, int intermediate_dim)
763{
764 enum { batch_rows = 4 };
765 if (hidden_dim <= 0 || intermediate_dim <= 0 ||
766 hidden_dim % 256 != 0 || intermediate_dim % QK8_0 != 0) {
767 return 0;
768 }
769
770 size_t bytes = ck_moe_align64(
771 batch_rows * ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
772 bytes += 2u * ck_moe_align64(
773 batch_rows * (size_t)intermediate_dim * sizeof(float));
774 bytes += ck_moe_align64(
775 batch_rows * ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim));
776 bytes += ck_moe_align64(
777 batch_rows * (size_t)hidden_dim * sizeof(float));
778 return bytes;
779}
780
782 const float *hidden,
783 const int *indices,
784 const float *routing_weights,
785 const void *expert_gate,
786 const void *expert_up,
787 const void *expert_down,
788 float *output,
789 int rows,
790 int hidden_dim,
791 int intermediate_dim,
792 int n_experts,
793 int top_k,
794 void *workspace,
795 size_t workspace_bytes)
796{
797 const size_t required = moe_swiglu_expert_q4k_q5k_workspace_bytes(
798 hidden_dim, intermediate_dim);
799 if (!hidden || !indices || !routing_weights || !expert_gate || !expert_up ||
800 !expert_down || !output || !workspace || required == 0 ||
801 workspace_bytes < required || rows <= 0 || n_experts <= 0 ||
802 top_k <= 0 || top_k > n_experts) {
803 return -1;
804 }
805
806 const size_t hidden_q8_bytes = ck_moe_align64(
807 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
808 const size_t gate_up_bytes = ck_moe_align64(
809 2u * (size_t)intermediate_dim * sizeof(float));
810 const size_t act_q8_bytes = ck_moe_align64(
811 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)intermediate_dim));
812 uint8_t *cursor = (uint8_t *)workspace;
813 void *hidden_q8 = cursor;
814 cursor += hidden_q8_bytes;
815 float *gate_up = (float *)cursor;
816 cursor += gate_up_bytes;
817 void *act_q8 = cursor;
818 cursor += act_q8_bytes;
819 float *expert_output = (float *)cursor;
820
821 const size_t q4_row_bytes = ck_dtype_row_bytes(CK_DT_Q4_K, (size_t)hidden_dim);
822 const size_t q5_row_bytes = ck_dtype_row_bytes(CK_DT_Q5_K, (size_t)intermediate_dim);
823 const uint8_t *gate_base = (const uint8_t *)expert_gate;
824 const uint8_t *up_base = (const uint8_t *)expert_up;
825 const uint8_t *down_base = (const uint8_t *)expert_down;
826
827 memset(output, 0, (size_t)rows * (size_t)hidden_dim * sizeof(float));
828 for (int row = 0; row < rows; ++row) {
829 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
830 float *y = output + (size_t)row * (size_t)hidden_dim;
831 quantize_row_q8_k(x, hidden_q8, hidden_dim);
832
833 for (int slot = 0; slot < top_k; ++slot) {
834 const size_t route_index = (size_t)row * (size_t)top_k + (size_t)slot;
835 const int expert = indices[route_index];
836 if (expert < 0 || expert >= n_experts) {
837 return -2;
838 }
839
840 const size_t up_expert_offset =
841 (size_t)expert * (size_t)intermediate_dim * q4_row_bytes;
842 const size_t down_expert_offset =
843 (size_t)expert * (size_t)hidden_dim * q5_row_bytes;
844 gemv_q4_k_q8_k(gate_up,
845 gate_base + up_expert_offset,
846 hidden_q8,
847 intermediate_dim,
848 hidden_dim);
849 gemv_q4_k_q8_k(gate_up + intermediate_dim,
850 up_base + up_expert_offset,
851 hidden_q8,
852 intermediate_dim,
853 hidden_dim);
854 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
855 quantize_row_q8_k(gate_up, act_q8, intermediate_dim);
856 gemv_q5_k_q8_k(expert_output,
857 down_base + down_expert_offset,
858 act_q8,
859 hidden_dim,
860 intermediate_dim);
861
862 const float route_weight = routing_weights[route_index];
863 axpy_f32(y, expert_output, route_weight, hidden_dim);
864 }
865 }
866 return 0;
867}
868
870 const float *hidden,
871 const int *indices,
872 const float *routing_weights,
873 const void *expert_gate,
874 const void *expert_up,
875 const void *expert_down,
876 float *output,
877 int rows,
878 int hidden_dim,
879 int intermediate_dim,
880 int n_experts,
881 int top_k,
882 void *workspace,
883 size_t workspace_bytes)
884{
885 const size_t required = moe_swiglu_expert_q4k_q5k_workspace_bytes(
886 hidden_dim, intermediate_dim);
887 if (!hidden || !indices || !routing_weights || !expert_gate ||
888 !expert_up || !expert_down || !output || !workspace || required == 0 ||
889 workspace_bytes < required || rows <= 0 || n_experts <= 0 ||
890 top_k <= 0 || top_k > n_experts) {
891 return -1;
892 }
893
894 const size_t hidden_q8_bytes = ck_moe_align64(
895 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
896 const size_t gate_up_bytes = ck_moe_align64(
897 2u * (size_t)intermediate_dim * sizeof(float));
898 const size_t act_q8_bytes = ck_moe_align64(
899 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)intermediate_dim));
900 uint8_t *cursor = (uint8_t *)workspace;
901 void *hidden_q8 = cursor;
902 cursor += hidden_q8_bytes;
903 float *gate_up = (float *)cursor;
904 cursor += gate_up_bytes;
905 void *act_q8 = cursor;
906 cursor += act_q8_bytes;
907 float *expert_output = (float *)cursor;
908
909 const size_t q4_row_bytes = ck_dtype_row_bytes(
910 CK_DT_Q4_K, (size_t)hidden_dim);
911 const size_t q6_row_bytes = ck_dtype_row_bytes(
912 CK_DT_Q6_K, (size_t)intermediate_dim);
913 const uint8_t *gate_base = (const uint8_t *)expert_gate;
914 const uint8_t *up_base = (const uint8_t *)expert_up;
915 const uint8_t *down_base = (const uint8_t *)expert_down;
916
917 memset(output, 0, (size_t)rows * (size_t)hidden_dim * sizeof(float));
918 for (int row = 0; row < rows; ++row) {
919 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
920 float *y = output + (size_t)row * (size_t)hidden_dim;
921 quantize_row_q8_k(x, hidden_q8, hidden_dim);
922 for (int slot = 0; slot < top_k; ++slot) {
923 const size_t route_index =
924 (size_t)row * (size_t)top_k + (size_t)slot;
925 const int expert = indices[route_index];
926 if (expert < 0 || expert >= n_experts) return -2;
927 const size_t up_offset =
928 (size_t)expert * (size_t)intermediate_dim * q4_row_bytes;
929 const size_t down_offset =
930 (size_t)expert * (size_t)hidden_dim * q6_row_bytes;
931 gemv_q4_k_q8_k(gate_up, gate_base + up_offset, hidden_q8,
932 intermediate_dim, hidden_dim);
933 gemv_q4_k_q8_k(gate_up + intermediate_dim,
934 up_base + up_offset, hidden_q8,
935 intermediate_dim, hidden_dim);
936 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
937 quantize_row_q8_k(gate_up, act_q8, intermediate_dim);
938 gemv_q6_k_q8_k(expert_output, down_base + down_offset, act_q8,
939 hidden_dim, intermediate_dim);
940 axpy_f32(y, expert_output, routing_weights[route_index], hidden_dim);
941 }
942 }
943 return 0;
944}
945
947 const float *hidden,
948 const int *indices,
949 const float *routing_weights,
950 const void *expert_gate,
951 const void *expert_up,
952 const void *expert_down,
953 float *output,
954 int rows,
955 int hidden_dim,
956 int intermediate_dim,
957 int n_experts,
958 int top_k,
959 void *workspace,
960 size_t workspace_bytes)
961{
962 const size_t required = moe_swiglu_expert_q4k_q8_0_workspace_bytes(
963 hidden_dim, intermediate_dim);
964 if (!hidden || !indices || !routing_weights || !expert_gate ||
965 !expert_up || !expert_down || !output || !workspace || required == 0 ||
966 workspace_bytes < required || rows <= 0 || n_experts <= 0 ||
967 top_k <= 0 || top_k > n_experts) {
968 return -1;
969 }
970
971 const size_t hidden_q8_bytes = ck_moe_align64(
972 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
973 const size_t gate_up_bytes = ck_moe_align64(
974 2u * (size_t)intermediate_dim * sizeof(float));
975 const size_t act_q8_bytes = ck_moe_align64(
976 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim));
977 uint8_t *cursor = (uint8_t *)workspace;
978 void *hidden_q8 = cursor;
979 cursor += hidden_q8_bytes;
980 float *gate_up = (float *)cursor;
981 cursor += gate_up_bytes;
982 void *act_q8 = cursor;
983 cursor += act_q8_bytes;
984 float *expert_output = (float *)cursor;
985 cursor += ck_moe_align64((size_t)hidden_dim * sizeof(float));
986 void *projection_scratch = cursor;
987
988 const size_t gate_row_bytes = ck_dtype_row_bytes(
989 CK_DT_Q4_K, (size_t)hidden_dim);
990 const size_t down_row_bytes = ck_dtype_row_bytes(
991 CK_DT_Q8_0, (size_t)intermediate_dim);
992 const uint8_t *gate_base = (const uint8_t *)expert_gate;
993 const uint8_t *up_base = (const uint8_t *)expert_up;
994 const uint8_t *down_base = (const uint8_t *)expert_down;
995
996 memset(output, 0, (size_t)rows * (size_t)hidden_dim * sizeof(float));
997 for (int row = 0; row < rows; ++row) {
998 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
999 float *y = output + (size_t)row * (size_t)hidden_dim;
1000 quantize_row_q8_k(x, hidden_q8, hidden_dim);
1001 for (int slot = 0; slot < top_k; ++slot) {
1002 const size_t route_index =
1003 (size_t)row * (size_t)top_k + (size_t)slot;
1004 const int expert = indices[route_index];
1005 if (expert < 0 || expert >= n_experts) return -2;
1006 const size_t gate_offset =
1007 (size_t)expert * (size_t)intermediate_dim * gate_row_bytes;
1008 const size_t down_offset =
1009 (size_t)expert * (size_t)hidden_dim * down_row_bytes;
1011 gate_up, gate_base + gate_offset, hidden_q8,
1012 intermediate_dim, hidden_dim, projection_scratch);
1014 gate_up + intermediate_dim, up_base + gate_offset, hidden_q8,
1015 intermediate_dim, hidden_dim, projection_scratch);
1016 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
1017 quantize_row_q8_0(gate_up, act_q8, intermediate_dim);
1018 gemv_q8_0_q8_0(expert_output, down_base + down_offset, act_q8,
1019 hidden_dim, intermediate_dim);
1021 y, expert_output, routing_weights[route_index], hidden_dim);
1022 }
1023 }
1024 return 0;
1025}
1026
1028 const float *hidden,
1029 const int *indices,
1030 const float *routing_weights,
1031 const void *expert_gate,
1032 const void *expert_up,
1033 const void *expert_down,
1034 float *output,
1035 int rows,
1036 int hidden_dim,
1037 int intermediate_dim,
1038 int n_experts,
1039 int top_k,
1040 void *workspace,
1041 size_t workspace_bytes)
1042{
1043 const size_t required = moe_swiglu_expert_q4k_q8_0_workspace_bytes(
1044 hidden_dim, intermediate_dim);
1045 if (!hidden || !indices || !routing_weights || !expert_gate ||
1046 !expert_up || !expert_down || !output || !workspace || required == 0 ||
1047 workspace_bytes < required || rows <= 0 || n_experts <= 0 ||
1048 top_k <= 0 || top_k > n_experts) {
1049 return -1;
1050 }
1051
1052 const size_t hidden_q8_bytes = ck_moe_align64(
1053 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
1054 const size_t gate_up_bytes = ck_moe_align64(
1055 2u * (size_t)intermediate_dim * sizeof(float));
1056 const size_t act_q8_bytes = ck_moe_align64(
1057 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim));
1058 uint8_t *cursor = (uint8_t *)workspace;
1059 void *hidden_q8 = cursor;
1060 cursor += hidden_q8_bytes;
1061 float *gate_up = (float *)cursor;
1062 cursor += gate_up_bytes;
1063 void *act_q8 = cursor;
1064 cursor += act_q8_bytes;
1065 float *expert_output = (float *)cursor;
1066 cursor += ck_moe_align64((size_t)hidden_dim * sizeof(float));
1067 void *projection_scratch = cursor;
1068
1069 const size_t gate_row_bytes = ck_dtype_row_bytes(
1070 CK_DT_Q4_K, (size_t)hidden_dim);
1071 const size_t down_row_bytes = ck_dtype_row_bytes(
1072 CK_DT_Q5_0, (size_t)intermediate_dim);
1073 const uint8_t *gate_base = (const uint8_t *)expert_gate;
1074 const uint8_t *up_base = (const uint8_t *)expert_up;
1075 const uint8_t *down_base = (const uint8_t *)expert_down;
1076
1077 memset(output, 0, (size_t)rows * (size_t)hidden_dim * sizeof(float));
1078 for (int row = 0; row < rows; ++row) {
1079 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
1080 float *y = output + (size_t)row * (size_t)hidden_dim;
1081 quantize_row_q8_k(x, hidden_q8, hidden_dim);
1082 for (int slot = 0; slot < top_k; ++slot) {
1083 const size_t route_index =
1084 (size_t)row * (size_t)top_k + (size_t)slot;
1085 const int expert = indices[route_index];
1086 if (expert < 0 || expert >= n_experts) return -2;
1087 const size_t gate_offset =
1088 (size_t)expert * (size_t)intermediate_dim * gate_row_bytes;
1089 const size_t down_offset =
1090 (size_t)expert * (size_t)hidden_dim * down_row_bytes;
1092 gate_up, gate_base + gate_offset, hidden_q8,
1093 intermediate_dim, hidden_dim, projection_scratch);
1095 gate_up + intermediate_dim, up_base + gate_offset, hidden_q8,
1096 intermediate_dim, hidden_dim, projection_scratch);
1097 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
1098 quantize_row_q8_0(gate_up, act_q8, intermediate_dim);
1099 gemv_q5_0_q8_0(expert_output, down_base + down_offset, act_q8,
1100 hidden_dim, intermediate_dim);
1102 y, expert_output, routing_weights[route_index], hidden_dim);
1103 }
1104 }
1105 return 0;
1106}
1107
1109 const float *hidden,
1110 const int *indices,
1111 const float *routing_weights,
1112 const void *expert_gate,
1113 const void *expert_up,
1114 const void *expert_down,
1115 float *output,
1116 int rows,
1117 int hidden_dim,
1118 int intermediate_dim,
1119 int n_experts,
1120 int top_k,
1121 void *workspace,
1122 size_t workspace_bytes)
1123{
1124 const size_t required = moe_swiglu_expert_q4k_q5k_workspace_bytes(
1125 hidden_dim, intermediate_dim);
1126 if (!hidden || !indices || !routing_weights || !expert_gate ||
1127 !expert_up || !expert_down || !output || !workspace || required == 0 ||
1128 workspace_bytes < required || rows <= 0 || n_experts <= 0 ||
1129 top_k <= 0 || top_k > n_experts) {
1130 return -1;
1131 }
1132
1133 const size_t hidden_q8_bytes = ck_moe_align64(
1134 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
1135 const size_t gate_up_bytes = ck_moe_align64(
1136 2u * (size_t)intermediate_dim * sizeof(float));
1137 const size_t act_q8_bytes = ck_moe_align64(
1138 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)intermediate_dim));
1139 uint8_t *cursor = (uint8_t *)workspace;
1140 void *hidden_q8 = cursor;
1141 cursor += hidden_q8_bytes;
1142 float *gate_up = (float *)cursor;
1143 cursor += gate_up_bytes;
1144 void *act_q8 = cursor;
1145 cursor += act_q8_bytes;
1146 float *expert_output = (float *)cursor;
1147
1148 const size_t gate_row_bytes = ck_dtype_row_bytes(
1149 CK_DT_Q4_K, (size_t)hidden_dim);
1150 const size_t down_row_bytes = ck_dtype_row_bytes(
1151 CK_DT_Q4_K, (size_t)intermediate_dim);
1152 const uint8_t *gate_base = (const uint8_t *)expert_gate;
1153 const uint8_t *up_base = (const uint8_t *)expert_up;
1154 const uint8_t *down_base = (const uint8_t *)expert_down;
1155
1156 memset(output, 0, (size_t)rows * (size_t)hidden_dim * sizeof(float));
1157 for (int row = 0; row < rows; ++row) {
1158 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
1159 float *y = output + (size_t)row * (size_t)hidden_dim;
1160 quantize_row_q8_k(x, hidden_q8, hidden_dim);
1161 for (int slot = 0; slot < top_k; ++slot) {
1162 const size_t route_index =
1163 (size_t)row * (size_t)top_k + (size_t)slot;
1164 const int expert = indices[route_index];
1165 if (expert < 0 || expert >= n_experts) return -2;
1166 const size_t up_offset =
1167 (size_t)expert * (size_t)intermediate_dim * gate_row_bytes;
1168 const size_t down_offset =
1169 (size_t)expert * (size_t)hidden_dim * down_row_bytes;
1170 gemv_q4_k_q8_k(gate_up, gate_base + up_offset, hidden_q8,
1171 intermediate_dim, hidden_dim);
1172 gemv_q4_k_q8_k(gate_up + intermediate_dim,
1173 up_base + up_offset, hidden_q8,
1174 intermediate_dim, hidden_dim);
1175 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
1176 quantize_row_q8_k(gate_up, act_q8, intermediate_dim);
1177 gemv_q4_k_q8_k(expert_output, down_base + down_offset, act_q8,
1178 hidden_dim, intermediate_dim);
1179 axpy_f32(y, expert_output, routing_weights[route_index], hidden_dim);
1180 }
1181 }
1182 return 0;
1183}
1184
1186 const float *hidden,
1187 const float *routed,
1188 const void *shared_gate,
1189 const void *shared_up,
1190 const void *shared_down,
1191 float *output,
1192 int rows,
1193 int hidden_dim,
1194 int intermediate_dim,
1195 void *workspace,
1196 size_t workspace_bytes)
1197{
1198 const size_t required = moe_swiglu_expert_q4k_q5k_workspace_bytes(
1199 hidden_dim, intermediate_dim);
1200 if (!hidden || !shared_gate || !shared_up || !shared_down || !output ||
1201 !workspace || required == 0 || workspace_bytes < required || rows <= 0) {
1202 return -1;
1203 }
1204
1205 const size_t hidden_q8_bytes = ck_moe_align64(
1206 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
1207 const size_t gate_up_bytes = ck_moe_align64(
1208 2u * (size_t)intermediate_dim * sizeof(float));
1209 const size_t act_q8_bytes = ck_moe_align64(
1210 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)intermediate_dim));
1211 uint8_t *cursor = (uint8_t *)workspace;
1212 void *hidden_q8 = cursor;
1213 cursor += hidden_q8_bytes;
1214 float *gate_up = (float *)cursor;
1215 cursor += gate_up_bytes;
1216 void *act_q8 = cursor;
1217 cursor += act_q8_bytes;
1218 float *shared_output = (float *)cursor;
1219
1220 for (int row = 0; row < rows; ++row) {
1221 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
1222 float *y = output + (size_t)row * (size_t)hidden_dim;
1223 quantize_row_q8_k(x, hidden_q8, hidden_dim);
1224 gemv_q4_k_q8_k(gate_up, shared_gate, hidden_q8,
1225 intermediate_dim, hidden_dim);
1226 gemv_q4_k_q8_k(gate_up + intermediate_dim, shared_up, hidden_q8,
1227 intermediate_dim, hidden_dim);
1228 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
1229 quantize_row_q8_k(gate_up, act_q8, intermediate_dim);
1230 gemv_q6_k_q8_k(shared_output, shared_down, act_q8,
1231 hidden_dim, intermediate_dim);
1232 const float *route = routed
1233 ? routed + (size_t)row * (size_t)hidden_dim
1234 : NULL;
1235 for (int col = 0; col < hidden_dim; ++col) {
1236 y[col] = shared_output[col] + (route ? route[col] : 0.0f);
1237 }
1238 }
1239 return 0;
1240}
1241
1243 const float *hidden,
1244 const float *routed,
1245 const void *shared_gate,
1246 const void *shared_up,
1247 const void *shared_down,
1248 float *output,
1249 int rows,
1250 int hidden_dim,
1251 int intermediate_dim,
1252 void *workspace,
1253 size_t workspace_bytes)
1254{
1255 const size_t required = moe_swiglu_expert_q4k_q5k_workspace_bytes(
1256 hidden_dim, intermediate_dim);
1257 if (!hidden || !shared_gate || !shared_up || !shared_down || !output ||
1258 !workspace || required == 0 || workspace_bytes < required || rows <= 0) {
1259 return -1;
1260 }
1261
1262 const size_t hidden_q8_bytes = ck_moe_align64(
1263 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
1264 const size_t gate_up_bytes = ck_moe_align64(
1265 2u * (size_t)intermediate_dim * sizeof(float));
1266 const size_t act_q8_bytes = ck_moe_align64(
1267 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)intermediate_dim));
1268 uint8_t *cursor = (uint8_t *)workspace;
1269 void *hidden_q8 = cursor;
1270 cursor += hidden_q8_bytes;
1271 float *gate_up = (float *)cursor;
1272 cursor += gate_up_bytes;
1273 void *act_q8 = cursor;
1274 cursor += act_q8_bytes;
1275 float *shared_output = (float *)cursor;
1276
1277 for (int row = 0; row < rows; ++row) {
1278 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
1279 float *y = output + (size_t)row * (size_t)hidden_dim;
1280 quantize_row_q8_k(x, hidden_q8, hidden_dim);
1281 gemv_q4_k_q8_k(gate_up, shared_gate, hidden_q8,
1282 intermediate_dim, hidden_dim);
1283 gemv_q4_k_q8_k(gate_up + intermediate_dim, shared_up, hidden_q8,
1284 intermediate_dim, hidden_dim);
1285 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
1286 quantize_row_q8_k(gate_up, act_q8, intermediate_dim);
1287 gemv_q4_k_q8_k(shared_output, shared_down, act_q8,
1288 hidden_dim, intermediate_dim);
1289 const float *route = routed
1290 ? routed + (size_t)row * (size_t)hidden_dim
1291 : NULL;
1292 for (int col = 0; col < hidden_dim; ++col) {
1293 y[col] = shared_output[col] + (route ? route[col] : 0.0f);
1294 }
1295 }
1296 return 0;
1297}
1298
1299typedef struct {
1300 const float *hidden;
1301 const int *indices;
1302 const float *routing_weights;
1303 const void *expert_gate;
1304 const void *expert_up;
1305 const void *expert_down;
1306 float *output;
1307 int rows;
1308 int hidden_dim;
1309 int intermediate_dim;
1310 int n_experts;
1311 int top_k;
1312 uint8_t *workspace;
1313 size_t workspace_stride;
1314 int status[CK_THREADPOOL_MAX_THREADS];
1315} ck_moe_q4k_q5k_parallel_args_t;
1316
1317static void ck_moe_q4k_q5k_parallel_work(int ith, int nth, void *opaque)
1318{
1319 ck_moe_q4k_q5k_parallel_args_t *args =
1320 (ck_moe_q4k_q5k_parallel_args_t *)opaque;
1321 const int begin = (args->rows * ith) / nth;
1322 const int end = (args->rows * (ith + 1)) / nth;
1323 if (begin >= end) {
1324 args->status[ith] = 0;
1325 return;
1326 }
1328 args->hidden + (size_t)begin * (size_t)args->hidden_dim,
1329 args->indices + (size_t)begin * (size_t)args->top_k,
1330 args->routing_weights + (size_t)begin * (size_t)args->top_k,
1331 args->expert_gate,
1332 args->expert_up,
1333 args->expert_down,
1334 args->output + (size_t)begin * (size_t)args->hidden_dim,
1335 end - begin,
1336 args->hidden_dim,
1337 args->intermediate_dim,
1338 args->n_experts,
1339 args->top_k,
1340 args->workspace + (size_t)ith * args->workspace_stride,
1341 args->workspace_stride);
1342}
1343
1344typedef struct {
1345 const int *indices;
1346 const void *expert_gate;
1347 const void *expert_up;
1348 const void *expert_down;
1349 const void *hidden_q8;
1350 uint8_t *workspace;
1351 size_t workspace_stride;
1352 size_t hidden_q8_bytes;
1353 int hidden_dim;
1354 int intermediate_dim;
1355 int n_experts;
1356 int top_k;
1357 float *expert_output[CK_THREADPOOL_MAX_THREADS];
1358 int status[CK_THREADPOOL_MAX_THREADS];
1359} ck_moe_q4k_q5k_route_args_t;
1360
1361static void ck_moe_q4k_q5k_route_work(int ith, int nth, void *opaque)
1362{
1363 ck_moe_q4k_q5k_route_args_t *args =
1364 (ck_moe_q4k_q5k_route_args_t *)opaque;
1365 if (ith >= nth || ith >= args->top_k) return;
1366
1367 const int expert = args->indices[ith];
1368 if (expert < 0 || expert >= args->n_experts) {
1369 args->status[ith] = -2;
1370 return;
1371 }
1372
1373 const size_t gate_up_bytes = ck_moe_align64(
1374 2u * (size_t)args->intermediate_dim * sizeof(float));
1375 const size_t act_q8_bytes = ck_moe_align64(
1376 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)args->intermediate_dim));
1377 uint8_t *cursor = args->workspace + (size_t)ith * args->workspace_stride;
1378 cursor += args->hidden_q8_bytes;
1379 float *gate_up = (float *)cursor;
1380 cursor += gate_up_bytes;
1381 void *act_q8 = cursor;
1382 cursor += act_q8_bytes;
1383 float *expert_output = (float *)cursor;
1384 args->expert_output[ith] = expert_output;
1385
1386 const size_t q4_row_bytes = ck_dtype_row_bytes(
1387 CK_DT_Q4_K, (size_t)args->hidden_dim);
1388 const size_t q5_row_bytes = ck_dtype_row_bytes(
1389 CK_DT_Q5_K, (size_t)args->intermediate_dim);
1390 const size_t q4_expert_offset =
1391 (size_t)expert * (size_t)args->intermediate_dim * q4_row_bytes;
1392 const size_t q5_expert_offset =
1393 (size_t)expert * (size_t)args->hidden_dim * q5_row_bytes;
1394
1396 gate_up,
1397 (const uint8_t *)args->expert_gate + q4_expert_offset,
1398 args->hidden_q8, args->intermediate_dim, args->hidden_dim);
1400 gate_up + args->intermediate_dim,
1401 (const uint8_t *)args->expert_up + q4_expert_offset,
1402 args->hidden_q8, args->intermediate_dim, args->hidden_dim);
1403 swiglu_forward_ggml(gate_up, gate_up, 1, args->intermediate_dim);
1404 quantize_row_q8_k(gate_up, act_q8, args->intermediate_dim);
1406 expert_output,
1407 (const uint8_t *)args->expert_down + q5_expert_offset,
1408 act_q8, args->hidden_dim, args->intermediate_dim);
1409 args->status[ith] = 0;
1410}
1411
1413 const float *hidden,
1414 const int *indices,
1415 const float *routing_weights,
1416 const void *expert_gate,
1417 const void *expert_up,
1418 const void *expert_down,
1419 float *output,
1420 int hidden_dim,
1421 int intermediate_dim,
1422 int n_experts,
1423 int top_k,
1424 void *workspace,
1425 size_t workspace_bytes,
1426 size_t workspace_stride,
1427 ck_threadpool_t *pool)
1428{
1429 if (!pool || top_k <= 1 || top_k > CK_THREADPOOL_MAX_THREADS ||
1430 ck_threadpool_n_threads(pool) < top_k ||
1431 workspace_bytes < workspace_stride * (size_t)top_k) {
1432 return 1;
1433 }
1434
1435 const size_t hidden_q8_bytes = ck_moe_align64(
1436 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
1437 void *hidden_q8 = workspace;
1438 quantize_row_q8_k(hidden, hidden_q8, hidden_dim);
1439
1440 ck_moe_q4k_q5k_route_args_t args = {
1441 .indices = indices,
1442 .expert_gate = expert_gate,
1443 .expert_up = expert_up,
1444 .expert_down = expert_down,
1445 .hidden_q8 = hidden_q8,
1446 .workspace = (uint8_t *)workspace,
1447 .workspace_stride = workspace_stride,
1448 .hidden_q8_bytes = hidden_q8_bytes,
1449 .hidden_dim = hidden_dim,
1450 .intermediate_dim = intermediate_dim,
1451 .n_experts = n_experts,
1452 .top_k = top_k,
1453 .expert_output = {0},
1454 .status = {0},
1455 };
1457 pool, top_k, ck_moe_q4k_q5k_route_work, &args);
1458
1459 memset(output, 0, (size_t)hidden_dim * sizeof(float));
1460 for (int slot = 0; slot < top_k; ++slot) {
1461 if (args.status[slot] != 0 || !args.expert_output[slot]) {
1462 return args.status[slot] != 0 ? args.status[slot] : -1;
1463 }
1464 axpy_f32(
1465 output, args.expert_output[slot], routing_weights[slot], hidden_dim);
1466 }
1467 return 0;
1468}
1469
1471 const float *hidden,
1472 const int *indices,
1473 const float *routing_weights,
1474 const void *expert_gate,
1475 const void *expert_up,
1476 const void *expert_down,
1477 float *output,
1478 int rows,
1479 int hidden_dim,
1480 int intermediate_dim,
1481 int n_experts,
1482 int top_k,
1483 void *workspace,
1484 size_t workspace_bytes)
1485{
1486 const size_t stride = moe_swiglu_expert_q4k_q5k_workspace_bytes(
1487 hidden_dim, intermediate_dim);
1488 if (!hidden || !indices || !routing_weights || !expert_gate || !expert_up ||
1489 !expert_down || !output || !workspace || stride == 0 || rows <= 0 ||
1490 n_experts <= 0 || top_k <= 0 || top_k > n_experts) {
1491 return -1;
1492 }
1493
1494 ck_threadpool_t *pool = ck_threadpool_global();
1495 if (rows == 1) {
1496 const int route_status = ck_moe_q4k_q5k_route_parallel(
1497 hidden, indices, routing_weights,
1498 expert_gate, expert_up, expert_down, output,
1499 hidden_dim, intermediate_dim, n_experts, top_k,
1500 workspace, workspace_bytes, stride, pool);
1501 if (route_status <= 0) return route_status;
1502 }
1503
1504 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1505 if (active > rows) active = rows;
1507 const size_t workspace_workers = workspace_bytes / stride;
1508 if (workspace_workers == 0) return -1;
1509 if ((size_t)active > workspace_workers) active = (int)workspace_workers;
1510 if (active <= 1) {
1512 hidden, indices, routing_weights, expert_gate, expert_up, expert_down,
1513 output, rows, hidden_dim, intermediate_dim, n_experts, top_k,
1514 workspace, stride);
1515 }
1516
1517 ck_moe_q4k_q5k_parallel_args_t args = {
1518 .hidden = hidden,
1519 .indices = indices,
1520 .routing_weights = routing_weights,
1521 .expert_gate = expert_gate,
1522 .expert_up = expert_up,
1523 .expert_down = expert_down,
1524 .output = output,
1525 .rows = rows,
1526 .hidden_dim = hidden_dim,
1527 .intermediate_dim = intermediate_dim,
1528 .n_experts = n_experts,
1529 .top_k = top_k,
1530 .workspace = (uint8_t *)workspace,
1531 .workspace_stride = stride,
1532 .status = {0},
1533 };
1535 for (int ith = 0; ith < active; ++ith) {
1536 if (args.status[ith] != 0) return args.status[ith];
1537 }
1538 return 0;
1539}
1540
1542 const float *, const int *, const float *, const void *, const void *,
1543 const void *, float *, int, int, int, int, int, void *, size_t);
1544
1551
1552typedef struct {
1553 const float *hidden;
1554 const int *indices;
1555 const float *routing_weights;
1556 const void *expert_gate;
1557 const void *expert_up;
1558 const void *expert_down;
1559 float *output;
1560 int rows;
1561 int hidden_dim;
1562 int intermediate_dim;
1563 int n_experts;
1564 int top_k;
1565 uint8_t *workspace;
1566 size_t workspace_stride;
1568 int status[CK_THREADPOOL_MAX_THREADS];
1569} ck_moe_q4k_mixed_parallel_args_t;
1570
1571static void ck_moe_q4k_mixed_parallel_work(int ith, int nth, void *opaque)
1572{
1573 ck_moe_q4k_mixed_parallel_args_t *args =
1574 (ck_moe_q4k_mixed_parallel_args_t *)opaque;
1575 const int begin = (args->rows * ith) / nth;
1576 const int end = (args->rows * (ith + 1)) / nth;
1577 if (begin >= end) {
1578 args->status[ith] = 0;
1579 return;
1580 }
1581 args->status[ith] = args->serial_fn(
1582 args->hidden + (size_t)begin * (size_t)args->hidden_dim,
1583 args->indices + (size_t)begin * (size_t)args->top_k,
1584 args->routing_weights + (size_t)begin * (size_t)args->top_k,
1585 args->expert_gate,
1586 args->expert_up,
1587 args->expert_down,
1588 args->output + (size_t)begin * (size_t)args->hidden_dim,
1589 end - begin,
1590 args->hidden_dim,
1591 args->intermediate_dim,
1592 args->n_experts,
1593 args->top_k,
1594 args->workspace + (size_t)ith * args->workspace_stride,
1595 args->workspace_stride);
1596}
1597
1598typedef struct {
1599 const int *indices;
1600 const void *expert_gate;
1601 const void *expert_up;
1602 const void *expert_down;
1603 const void *hidden_q8;
1604 uint8_t *workspace;
1605 size_t workspace_stride;
1606 size_t hidden_q8_bytes;
1607 int hidden_dim;
1608 int intermediate_dim;
1609 int n_experts;
1610 int top_k;
1611 ck_moe_down_kind_t down_kind;
1612 float *expert_output[CK_THREADPOOL_MAX_THREADS];
1613 int status[CK_THREADPOOL_MAX_THREADS];
1614} ck_moe_q4k_mixed_route_args_t;
1615
1616static void ck_moe_q4k_mixed_route_work(int ith, int nth, void *opaque)
1617{
1618 ck_moe_q4k_mixed_route_args_t *args =
1619 (ck_moe_q4k_mixed_route_args_t *)opaque;
1620 if (ith >= nth || ith >= args->top_k) return;
1621
1622 const int expert = args->indices[ith];
1623 if (expert < 0 || expert >= args->n_experts) {
1624 args->status[ith] = -2;
1625 return;
1626 }
1627
1628 const size_t gate_up_bytes = ck_moe_align64(
1629 2u * (size_t)args->intermediate_dim * sizeof(float));
1630 const int q8_0_activation =
1631 args->down_kind == CK_MOE_DOWN_Q5_0 ||
1632 args->down_kind == CK_MOE_DOWN_Q8_0;
1633 const size_t act_q8_bytes = ck_moe_align64(ck_dtype_row_bytes(
1634 q8_0_activation ? CK_DT_Q8_0 : CK_DT_Q8_K,
1635 (size_t)args->intermediate_dim));
1636 uint8_t *cursor = args->workspace + (size_t)ith * args->workspace_stride;
1637 cursor += args->hidden_q8_bytes;
1638 float *gate_up = (float *)cursor;
1639 cursor += gate_up_bytes;
1640 void *act_q8 = cursor;
1641 cursor += act_q8_bytes;
1642 float *expert_output = (float *)cursor;
1643 args->expert_output[ith] = expert_output;
1644 cursor += ck_moe_align64((size_t)args->hidden_dim * sizeof(float));
1645 void *projection_scratch = cursor;
1646
1647 const size_t gate_row_bytes = ck_dtype_row_bytes(
1648 CK_DT_Q4_K, (size_t)args->hidden_dim);
1649 const size_t gate_offset =
1650 (size_t)expert * (size_t)args->intermediate_dim * gate_row_bytes;
1651 if (q8_0_activation) {
1653 gate_up, (const uint8_t *)args->expert_gate + gate_offset,
1654 args->hidden_q8, args->intermediate_dim, args->hidden_dim,
1655 projection_scratch);
1657 gate_up + args->intermediate_dim,
1658 (const uint8_t *)args->expert_up + gate_offset,
1659 args->hidden_q8, args->intermediate_dim, args->hidden_dim,
1660 projection_scratch);
1661 } else {
1663 gate_up, (const uint8_t *)args->expert_gate + gate_offset,
1664 args->hidden_q8, args->intermediate_dim, args->hidden_dim);
1666 gate_up + args->intermediate_dim,
1667 (const uint8_t *)args->expert_up + gate_offset,
1668 args->hidden_q8, args->intermediate_dim, args->hidden_dim);
1669 }
1670 swiglu_forward_ggml(gate_up, gate_up, 1, args->intermediate_dim);
1671 if (q8_0_activation) {
1672 quantize_row_q8_0(gate_up, act_q8, args->intermediate_dim);
1673 } else {
1674 quantize_row_q8_k(gate_up, act_q8, args->intermediate_dim);
1675 }
1676
1677 if (args->down_kind == CK_MOE_DOWN_Q6_K) {
1678 const size_t row_bytes = ck_dtype_row_bytes(
1679 CK_DT_Q6_K, (size_t)args->intermediate_dim);
1680 const size_t offset =
1681 (size_t)expert * (size_t)args->hidden_dim * row_bytes;
1683 expert_output, (const uint8_t *)args->expert_down + offset,
1684 act_q8, args->hidden_dim, args->intermediate_dim);
1685 } else if (args->down_kind == CK_MOE_DOWN_Q5_0) {
1686 const size_t row_bytes = ck_dtype_row_bytes(
1687 CK_DT_Q5_0, (size_t)args->intermediate_dim);
1688 const size_t offset =
1689 (size_t)expert * (size_t)args->hidden_dim * row_bytes;
1691 expert_output, (const uint8_t *)args->expert_down + offset,
1692 act_q8, args->hidden_dim, args->intermediate_dim);
1693 } else if (args->down_kind == CK_MOE_DOWN_Q8_0) {
1694 const size_t row_bytes = ck_dtype_row_bytes(
1695 CK_DT_Q8_0, (size_t)args->intermediate_dim);
1696 const size_t offset =
1697 (size_t)expert * (size_t)args->hidden_dim * row_bytes;
1699 expert_output, (const uint8_t *)args->expert_down + offset,
1700 act_q8, args->hidden_dim, args->intermediate_dim);
1701 } else {
1702 const size_t row_bytes = ck_dtype_row_bytes(
1703 CK_DT_Q4_K, (size_t)args->intermediate_dim);
1704 const size_t offset =
1705 (size_t)expert * (size_t)args->hidden_dim * row_bytes;
1707 expert_output, (const uint8_t *)args->expert_down + offset,
1708 act_q8, args->hidden_dim, args->intermediate_dim);
1709 }
1710 args->status[ith] = 0;
1711}
1712
1714 const float *hidden,
1715 const int *indices,
1716 const float *routing_weights,
1717 const void *expert_gate,
1718 const void *expert_up,
1719 const void *expert_down,
1720 float *output,
1721 int hidden_dim,
1722 int intermediate_dim,
1723 int n_experts,
1724 int top_k,
1725 void *workspace,
1726 size_t workspace_bytes,
1727 size_t workspace_stride,
1728 ck_threadpool_t *pool,
1729 ck_moe_down_kind_t down_kind)
1730{
1731 if (!pool || top_k <= 1 || top_k > CK_THREADPOOL_MAX_THREADS ||
1732 ck_threadpool_n_threads(pool) < top_k ||
1733 workspace_bytes < workspace_stride * (size_t)top_k) {
1734 return 1;
1735 }
1736
1737 const size_t hidden_q8_bytes = ck_moe_align64(
1738 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
1739 void *hidden_q8 = workspace;
1740 quantize_row_q8_k(hidden, hidden_q8, hidden_dim);
1741
1742 ck_moe_q4k_mixed_route_args_t args = {
1743 .indices = indices,
1744 .expert_gate = expert_gate,
1745 .expert_up = expert_up,
1746 .expert_down = expert_down,
1747 .hidden_q8 = hidden_q8,
1748 .workspace = (uint8_t *)workspace,
1749 .workspace_stride = workspace_stride,
1750 .hidden_q8_bytes = hidden_q8_bytes,
1751 .hidden_dim = hidden_dim,
1752 .intermediate_dim = intermediate_dim,
1753 .n_experts = n_experts,
1754 .top_k = top_k,
1755 .down_kind = down_kind,
1756 .expert_output = {0},
1757 .status = {0},
1758 };
1760 pool, top_k, ck_moe_q4k_mixed_route_work, &args);
1761
1762 memset(output, 0, (size_t)hidden_dim * sizeof(float));
1763 for (int slot = 0; slot < top_k; ++slot) {
1764 if (args.status[slot] != 0 || !args.expert_output[slot]) {
1765 return args.status[slot] != 0 ? args.status[slot] : -1;
1766 }
1767 if (down_kind == CK_MOE_DOWN_Q5_0 ||
1768 down_kind == CK_MOE_DOWN_Q8_0) {
1770 output, args.expert_output[slot], routing_weights[slot],
1771 hidden_dim);
1772 } else {
1773 axpy_f32(
1774 output, args.expert_output[slot], routing_weights[slot],
1775 hidden_dim);
1776 }
1777 }
1778 return 0;
1779}
1780
1782 const float *hidden,
1783 const int *indices,
1784 const float *routing_weights,
1785 const void *expert_gate,
1786 const void *expert_up,
1787 const void *expert_down,
1788 float *output,
1789 int rows,
1790 int hidden_dim,
1791 int intermediate_dim,
1792 int n_experts,
1793 int top_k,
1794 void *workspace,
1795 size_t workspace_bytes,
1797 ck_moe_down_kind_t down_kind)
1798{
1799 const int q8_0_activation =
1800 down_kind == CK_MOE_DOWN_Q5_0 || down_kind == CK_MOE_DOWN_Q8_0;
1801 const size_t stride = q8_0_activation
1802 ? moe_swiglu_expert_q4k_q8_0_workspace_bytes(hidden_dim, intermediate_dim)
1803 : moe_swiglu_expert_q4k_q5k_workspace_bytes(hidden_dim, intermediate_dim);
1804 if (!hidden || !indices || !routing_weights || !expert_gate || !expert_up ||
1805 !expert_down || !output || !workspace || !serial_fn || stride == 0 ||
1806 rows <= 0 || n_experts <= 0 || top_k <= 0 || top_k > n_experts) {
1807 return -1;
1808 }
1809
1810 ck_threadpool_t *pool = ck_threadpool_global();
1811 if (rows == 1) {
1812 const int route_status = ck_moe_q4k_mixed_route_parallel(
1813 hidden, indices, routing_weights, expert_gate, expert_up,
1814 expert_down, output, hidden_dim, intermediate_dim, n_experts,
1815 top_k, workspace, workspace_bytes, stride, pool, down_kind);
1816 if (route_status <= 0) return route_status;
1817 }
1818
1819 int active = pool ? ck_threadpool_n_threads(pool) : 1;
1820 if (active > rows) active = rows;
1822 const size_t workspace_workers = workspace_bytes / stride;
1823 if (workspace_workers == 0) return -1;
1824 if ((size_t)active > workspace_workers) active = (int)workspace_workers;
1825 if (active <= 1) {
1826 return serial_fn(
1827 hidden, indices, routing_weights, expert_gate, expert_up,
1828 expert_down, output, rows, hidden_dim, intermediate_dim, n_experts,
1829 top_k, workspace, stride);
1830 }
1831
1832 ck_moe_q4k_mixed_parallel_args_t args = {
1833 .hidden = hidden,
1834 .indices = indices,
1835 .routing_weights = routing_weights,
1836 .expert_gate = expert_gate,
1837 .expert_up = expert_up,
1838 .expert_down = expert_down,
1839 .output = output,
1840 .rows = rows,
1841 .hidden_dim = hidden_dim,
1842 .intermediate_dim = intermediate_dim,
1843 .n_experts = n_experts,
1844 .top_k = top_k,
1845 .workspace = (uint8_t *)workspace,
1846 .workspace_stride = stride,
1847 .serial_fn = serial_fn,
1848 .status = {0},
1849 };
1851 pool, active, ck_moe_q4k_mixed_parallel_work, &args);
1852 for (int ith = 0; ith < active; ++ith) {
1853 if (args.status[ith] != 0) return args.status[ith];
1854 }
1855 return 0;
1856}
1857
1859 const float *hidden,
1860 const int *indices,
1861 const float *routing_weights,
1862 const void *expert_gate,
1863 const void *expert_up,
1864 const void *expert_down,
1865 float *output,
1866 int rows,
1867 int hidden_dim,
1868 int intermediate_dim,
1869 int n_experts,
1870 int top_k,
1871 void *workspace,
1872 size_t workspace_bytes)
1873{
1875 hidden, indices, routing_weights, expert_gate, expert_up, expert_down,
1876 output, rows, hidden_dim, intermediate_dim, n_experts, top_k,
1877 workspace, workspace_bytes,
1879}
1880
1882 const float *hidden,
1883 const int *indices,
1884 const float *routing_weights,
1885 const void *expert_gate,
1886 const void *expert_up,
1887 const void *expert_down,
1888 float *output,
1889 int rows,
1890 int hidden_dim,
1891 int intermediate_dim,
1892 int n_experts,
1893 int top_k,
1894 void *workspace,
1895 size_t workspace_bytes)
1896{
1898 hidden, indices, routing_weights, expert_gate, expert_up, expert_down,
1899 output, rows, hidden_dim, intermediate_dim, n_experts, top_k,
1900 workspace, workspace_bytes,
1902}
1903
1905 const float *hidden,
1906 const int *indices,
1907 const float *routing_weights,
1908 const void *expert_gate,
1909 const void *expert_up,
1910 const void *expert_down,
1911 float *output,
1912 int rows,
1913 int hidden_dim,
1914 int intermediate_dim,
1915 int n_experts,
1916 int top_k,
1917 void *workspace,
1918 size_t workspace_bytes)
1919{
1921 hidden, indices, routing_weights, expert_gate, expert_up, expert_down,
1922 output, rows, hidden_dim, intermediate_dim, n_experts, top_k,
1923 workspace, workspace_bytes,
1925}
1926
1928 const float *hidden,
1929 const int *indices,
1930 const float *routing_weights,
1931 const void *expert_gate,
1932 const void *expert_up,
1933 const void *expert_down,
1934 float *output,
1935 int rows,
1936 int hidden_dim,
1937 int intermediate_dim,
1938 int n_experts,
1939 int top_k,
1940 void *workspace,
1941 size_t workspace_bytes)
1942{
1944 hidden, indices, routing_weights, expert_gate, expert_up, expert_down,
1945 output, rows, hidden_dim, intermediate_dim, n_experts, top_k,
1946 workspace, workspace_bytes,
1948}
1949
1951 const float *, const float *, const void *, const void *, const void *,
1952 float *, int, int, int, void *, size_t);
1953
1954typedef struct {
1955 const float *hidden;
1956 const float *routed;
1957 const void *shared_gate;
1958 const void *shared_up;
1959 const void *shared_down;
1960 float *output;
1961 int rows;
1962 int hidden_dim;
1963 int intermediate_dim;
1964 uint8_t *workspace;
1965 size_t workspace_stride;
1967 int status[CK_THREADPOOL_MAX_THREADS];
1968} ck_moe_shared_q4k_parallel_args_t;
1969
1970static void ck_moe_shared_q4k_parallel_work(int ith, int nth, void *opaque)
1971{
1972 ck_moe_shared_q4k_parallel_args_t *args =
1973 (ck_moe_shared_q4k_parallel_args_t *)opaque;
1974 const int begin = (args->rows * ith) / nth;
1975 const int end = (args->rows * (ith + 1)) / nth;
1976 if (begin >= end) {
1977 args->status[ith] = 0;
1978 return;
1979 }
1980 args->status[ith] = args->serial_fn(
1981 args->hidden + (size_t)begin * (size_t)args->hidden_dim,
1982 args->routed
1983 ? args->routed + (size_t)begin * (size_t)args->hidden_dim
1984 : NULL,
1985 args->shared_gate,
1986 args->shared_up,
1987 args->shared_down,
1988 args->output + (size_t)begin * (size_t)args->hidden_dim,
1989 end - begin,
1990 args->hidden_dim,
1991 args->intermediate_dim,
1992 args->workspace + (size_t)ith * args->workspace_stride,
1993 args->workspace_stride);
1994}
1995
1997 const float *hidden,
1998 const float *routed,
1999 const void *shared_gate,
2000 const void *shared_up,
2001 const void *shared_down,
2002 float *output,
2003 int rows,
2004 int hidden_dim,
2005 int intermediate_dim,
2006 void *workspace,
2007 size_t workspace_bytes,
2009{
2010 const size_t stride = moe_swiglu_expert_q4k_q5k_workspace_bytes(
2011 hidden_dim, intermediate_dim);
2012 if (!hidden || !shared_gate || !shared_up || !shared_down || !output ||
2013 !workspace || !serial_fn || stride == 0 || rows <= 0) {
2014 return -1;
2015 }
2016 ck_threadpool_t *pool = ck_threadpool_global();
2017 int active = pool ? ck_threadpool_n_threads(pool) : 1;
2018 if (active > rows) active = rows;
2020 const size_t workspace_workers = workspace_bytes / stride;
2021 if (workspace_workers == 0) return -1;
2022 if ((size_t)active > workspace_workers) active = (int)workspace_workers;
2023 if (active <= 1) {
2024 return serial_fn(
2025 hidden, routed, shared_gate, shared_up, shared_down, output, rows,
2026 hidden_dim, intermediate_dim, workspace, stride);
2027 }
2028
2029 ck_moe_shared_q4k_parallel_args_t args = {
2030 .hidden = hidden,
2031 .routed = routed,
2032 .shared_gate = shared_gate,
2033 .shared_up = shared_up,
2034 .shared_down = shared_down,
2035 .output = output,
2036 .rows = rows,
2037 .hidden_dim = hidden_dim,
2038 .intermediate_dim = intermediate_dim,
2039 .workspace = (uint8_t *)workspace,
2040 .workspace_stride = stride,
2041 .serial_fn = serial_fn,
2042 .status = {0},
2043 };
2045 pool, active, ck_moe_shared_q4k_parallel_work, &args);
2046 for (int ith = 0; ith < active; ++ith) {
2047 if (args.status[ith] != 0) return args.status[ith];
2048 }
2049 return 0;
2050}
2051
2053 const float *hidden,
2054 const float *routed,
2055 const void *shared_gate,
2056 const void *shared_up,
2057 const void *shared_down,
2058 float *output,
2059 int rows,
2060 int hidden_dim,
2061 int intermediate_dim,
2062 void *workspace,
2063 size_t workspace_bytes)
2064{
2066 hidden, routed, shared_gate, shared_up, shared_down, output, rows,
2067 hidden_dim, intermediate_dim, workspace, workspace_bytes,
2069}
2070
2072 const float *hidden,
2073 const float *routed,
2074 const void *shared_gate,
2075 const void *shared_up,
2076 const void *shared_down,
2077 float *output,
2078 int rows,
2079 int hidden_dim,
2080 int intermediate_dim,
2081 void *workspace,
2082 size_t workspace_bytes)
2083{
2085 hidden, routed, shared_gate, shared_up, shared_down, output, rows,
2086 hidden_dim, intermediate_dim, workspace, workspace_bytes,
2088}
2089
2090typedef struct {
2091 size_t hidden_q8_offset;
2092 size_t route_rows_offset;
2093 size_t slot_offsets_offset;
2094 size_t counts_offset;
2095 size_t cursors_offset;
2096 size_t workers_offset;
2097 size_t hidden_q8_row_bytes;
2098 size_t worker_stride;
2099 size_t total_bytes;
2100} ck_moe_q4k_q5k_bucket_layout_t;
2101
2102static int ck_moe_size_add(size_t a, size_t b, size_t *result)
2103{
2104 if (!result || a > SIZE_MAX - b) return -1;
2105 *result = a + b;
2106 return 0;
2107}
2108
2109static int ck_moe_size_mul(size_t a, size_t b, size_t *result)
2110{
2111 if (!result || (a != 0 && b > SIZE_MAX / a)) return -1;
2112 *result = a * b;
2113 return 0;
2114}
2115
2116static int ck_moe_bucket_layout(int rows,
2117 int hidden_dim,
2118 int intermediate_dim,
2119 int n_experts,
2120 int top_k,
2121 ck_moe_q4k_q5k_bucket_layout_t *layout)
2122{
2123 if (!layout || rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 ||
2124 n_experts <= 0 || top_k <= 0 || top_k > n_experts ||
2125 hidden_dim % 256 != 0 || intermediate_dim % 256 != 0) {
2126 return -1;
2127 }
2128
2129 memset(layout, 0, sizeof(*layout));
2130 layout->hidden_q8_row_bytes = ck_moe_align64(
2131 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim));
2132
2133 size_t gate_up_bytes = 0;
2134 size_t worker_bytes = 0;
2135 if (ck_moe_size_mul(8u * sizeof(float), (size_t)intermediate_dim,
2136 &gate_up_bytes) != 0) {
2137 return -1;
2138 }
2139 worker_bytes = ck_moe_align64(gate_up_bytes);
2140 if (ck_moe_size_add(
2141 worker_bytes,
2143 CK_DT_Q8_K, (size_t)hidden_dim)),
2144 &worker_bytes) != 0 ||
2146 worker_bytes,
2148 CK_DT_Q8_K, (size_t)intermediate_dim)),
2149 &worker_bytes) != 0 ||
2151 worker_bytes,
2152 ck_moe_align64(4u * (size_t)hidden_dim * sizeof(float)),
2153 &worker_bytes) != 0) {
2154 return -1;
2155 }
2156 layout->worker_stride = worker_bytes;
2157
2158 size_t cursor = 0;
2159 size_t bytes = 0;
2160 layout->hidden_q8_offset = cursor;
2161 if (ck_moe_size_mul((size_t)rows, layout->hidden_q8_row_bytes, &bytes) != 0 ||
2162 ck_moe_size_add(cursor, ck_moe_align64(bytes), &cursor) != 0) {
2163 return -1;
2164 }
2165
2166 layout->route_rows_offset = cursor;
2167 if (ck_moe_size_mul((size_t)rows, (size_t)top_k, &bytes) != 0 ||
2168 ck_moe_size_mul(bytes, sizeof(int), &bytes) != 0 ||
2169 ck_moe_size_add(cursor, ck_moe_align64(bytes), &cursor) != 0) {
2170 return -1;
2171 }
2172
2173 layout->slot_offsets_offset = cursor;
2174 if (ck_moe_size_mul((size_t)top_k, (size_t)n_experts + 1u, &bytes) != 0 ||
2175 ck_moe_size_mul(bytes, sizeof(int), &bytes) != 0 ||
2176 ck_moe_size_add(cursor, ck_moe_align64(bytes), &cursor) != 0) {
2177 return -1;
2178 }
2179
2180 layout->counts_offset = cursor;
2181 if (ck_moe_size_mul((size_t)n_experts, sizeof(int), &bytes) != 0 ||
2182 ck_moe_size_add(cursor, ck_moe_align64(bytes), &cursor) != 0) {
2183 return -1;
2184 }
2185
2186 layout->cursors_offset = cursor;
2187 if (ck_moe_size_mul((size_t)n_experts, sizeof(int), &bytes) != 0 ||
2188 ck_moe_size_add(cursor, ck_moe_align64(bytes), &cursor) != 0) {
2189 return -1;
2190 }
2191
2192 layout->workers_offset = cursor;
2194 layout->worker_stride, &bytes) != 0 ||
2195 ck_moe_size_add(cursor, ck_moe_align64(bytes), &cursor) != 0) {
2196 return -1;
2197 }
2198 layout->total_bytes = cursor;
2199 return 0;
2200}
2201
2203 int rows,
2204 int hidden_dim,
2205 int intermediate_dim,
2206 int n_experts,
2207 int top_k)
2208{
2209 ck_moe_q4k_q5k_bucket_layout_t layout;
2210 if (ck_moe_bucket_layout(rows, hidden_dim, intermediate_dim, n_experts,
2211 top_k, &layout) != 0) {
2212 return 0;
2213 }
2214 return layout.total_bytes;
2215}
2216
2217typedef struct {
2218 const float *hidden;
2219 uint8_t *hidden_q8;
2220 int rows;
2221 int hidden_dim;
2222 size_t hidden_q8_row_bytes;
2223} ck_moe_q4k_q5k_quantize_args_t;
2224
2225static void ck_moe_q4k_q5k_quantize_work(int ith, int nth, void *opaque)
2226{
2227 ck_moe_q4k_q5k_quantize_args_t *args =
2228 (ck_moe_q4k_q5k_quantize_args_t *)opaque;
2229 const int begin = (args->rows * ith) / nth;
2230 const int end = (args->rows * (ith + 1)) / nth;
2231 for (int row = begin; row < end; ++row) {
2233 args->hidden + (size_t)row * (size_t)args->hidden_dim,
2234 args->hidden_q8 + (size_t)row * args->hidden_q8_row_bytes,
2235 args->hidden_dim);
2236 }
2237}
2238
2239typedef struct {
2240 const int *bucket_rows;
2241 const int *bucket_offsets;
2242 const float *routing_weights;
2243 const uint8_t *hidden_q8;
2244 const uint8_t *gate_base;
2245 const uint8_t *up_base;
2246 const uint8_t *gate_packed_base;
2247 const uint8_t *up_packed_base;
2248 const uint8_t *down_base;
2249 float *output;
2250 uint8_t *workers;
2251 size_t worker_stride;
2252 size_t hidden_q8_row_bytes;
2253 size_t q4_expert_stride;
2254 size_t q4_packed_expert_stride;
2255 size_t q5_expert_stride;
2256 int hidden_dim;
2257 int intermediate_dim;
2258 int n_experts;
2259 int top_k;
2260 int slot;
2261 int total_tasks;
2262 atomic_int next_task;
2263} ck_moe_q4k_q5k_bucket_work_t;
2264
2266
2268 int n_experts,
2269 int position)
2270{
2271 int lo = 0;
2272 int hi = n_experts;
2273 while (lo < hi) {
2274 const int mid = lo + (hi - lo) / 2;
2275 if (offsets[mid + 1] <= position) {
2276 lo = mid + 1;
2277 } else {
2278 hi = mid;
2279 }
2280 }
2281 return lo;
2282}
2283
2284static void ck_moe_q4k_q5k_bucket_work(int ith, int nth, void *opaque)
2285{
2286 (void)nth;
2287 ck_moe_q4k_q5k_bucket_work_t *args =
2288 (ck_moe_q4k_q5k_bucket_work_t *)opaque;
2289 uint8_t *cursor = args->workers + (size_t)ith * args->worker_stride;
2290 float *gate_up = (float *)cursor;
2291 cursor += ck_moe_align64(
2292 8u * (size_t)args->intermediate_dim * sizeof(float));
2293 uint8_t *hidden_q8_batch = cursor;
2294 const size_t hidden_q8_batch_row_bytes = ck_dtype_row_bytes(
2295 CK_DT_Q8_K, (size_t)args->hidden_dim);
2296 cursor += ck_moe_align64(4u * hidden_q8_batch_row_bytes);
2297 void *act_q8 = cursor;
2298 cursor += ck_moe_align64(
2299 4u * ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)args->intermediate_dim));
2300 float *expert_output = (float *)cursor;
2301 const size_t act_q8_row_bytes = ck_dtype_row_bytes(
2302 CK_DT_Q8_K, (size_t)args->intermediate_dim);
2303
2304 for (;;) {
2305 const int task = atomic_fetch_add_explicit(
2306 &args->next_task, 1, memory_order_relaxed);
2307 if (task >= args->total_tasks) break;
2308
2309 int position = task * CK_MOE_Q4K_Q5K_TASK_ROWS;
2310 const int task_end = position + CK_MOE_Q4K_Q5K_TASK_ROWS <
2311 args->bucket_offsets[args->n_experts]
2312 ? position + CK_MOE_Q4K_Q5K_TASK_ROWS
2313 : args->bucket_offsets[args->n_experts];
2315 args->bucket_offsets, args->n_experts, position);
2316
2317 while (position < task_end && expert < args->n_experts) {
2318 const int expert_end = args->bucket_offsets[expert + 1];
2319 const int segment_end = expert_end < task_end
2320 ? expert_end : task_end;
2321 const uint8_t *gate = args->gate_base +
2322 (size_t)expert * args->q4_expert_stride;
2323 const uint8_t *up = args->up_base +
2324 (size_t)expert * args->q4_expert_stride;
2325 const uint8_t *gate_packed = args->gate_packed_base
2326 ? args->gate_packed_base +
2327 (size_t)expert * args->q4_packed_expert_stride
2328 : NULL;
2329 const uint8_t *up_packed = args->up_packed_base
2330 ? args->up_packed_base +
2331 (size_t)expert * args->q4_packed_expert_stride
2332 : NULL;
2333 const uint8_t *down = args->down_base +
2334 (size_t)expert * args->q5_expert_stride;
2335
2336 for (int i = position; i < segment_end; i += 4) {
2337 const int batch_rows = segment_end - i < 4
2338 ? segment_end - i : 4;
2339 const void *hidden_rows[4] = {NULL, NULL, NULL, NULL};
2340 const void *activation_rows[4] = {NULL, NULL, NULL, NULL};
2341 int output_rows[4] = {0, 0, 0, 0};
2342 for (int batch_row = 0; batch_row < batch_rows; ++batch_row) {
2343 const int row = args->bucket_rows[i + batch_row];
2344 output_rows[batch_row] = row;
2345 hidden_rows[batch_row] = args->hidden_q8 +
2346 (size_t)row * args->hidden_q8_row_bytes;
2347 if (gate_packed && up_packed) {
2348 memcpy(
2349 hidden_q8_batch +
2350 (size_t)batch_row * hidden_q8_batch_row_bytes,
2351 hidden_rows[batch_row],
2352 args->hidden_q8_row_bytes);
2353 }
2354 }
2355 for (int batch_row = batch_rows; batch_row < 4; ++batch_row) {
2356 hidden_rows[batch_row] = hidden_rows[0];
2357 }
2358
2359#if defined(CK_TARGET_ARM)
2360 {
2361 const int gate_up_stride = 2 * args->intermediate_dim;
2362 for (int batch_row = 0; batch_row < batch_rows; ++batch_row) {
2363 float *values = gate_up +
2364 (size_t)batch_row * (size_t)gate_up_stride;
2365 gemv_q4_k_q8_k(values, gate, hidden_rows[batch_row],
2366 args->intermediate_dim, args->hidden_dim);
2367 gemv_q4_k_q8_k(values + args->intermediate_dim, up,
2368 hidden_rows[batch_row],
2369 args->intermediate_dim, args->hidden_dim);
2370 }
2372 gate_up, gate_up, batch_rows, args->intermediate_dim);
2373 }
2374#else
2375 if (gate_packed && up_packed) {
2376 float *up_rows = gate_up +
2377 4u * (size_t)args->intermediate_dim;
2379 gate_up, gate_packed, hidden_q8_batch,
2380 batch_rows, args->intermediate_dim,
2381 args->hidden_dim);
2383 up_rows, up_packed, hidden_q8_batch,
2384 batch_rows, args->intermediate_dim,
2385 args->hidden_dim);
2387 gate_up, up_rows, gate_up, batch_rows,
2388 args->intermediate_dim);
2389 } else {
2390 const int gate_up_stride = 2 * args->intermediate_dim;
2392 gate_up, gate_up_stride, gate, hidden_rows, batch_rows,
2393 args->intermediate_dim, args->hidden_dim);
2395 gate_up + args->intermediate_dim, gate_up_stride, up,
2396 hidden_rows, batch_rows,
2397 args->intermediate_dim, args->hidden_dim);
2399 gate_up, gate_up, batch_rows, args->intermediate_dim);
2400 }
2401#endif
2402 for (int batch_row = 0; batch_row < batch_rows; ++batch_row) {
2403 void *activation = (uint8_t *)act_q8 +
2404 (size_t)batch_row * act_q8_row_bytes;
2406 gate_up + (size_t)batch_row *
2407 (size_t)args->intermediate_dim,
2408 activation, args->intermediate_dim);
2409 activation_rows[batch_row] = activation;
2410 }
2411 for (int batch_row = batch_rows; batch_row < 4; ++batch_row) {
2412 activation_rows[batch_row] = activation_rows[0];
2413 }
2415 expert_output, args->hidden_dim, down, activation_rows,
2416 batch_rows, args->hidden_dim, args->intermediate_dim);
2417
2418 for (int batch_row = 0; batch_row < batch_rows; ++batch_row) {
2419 const int row = output_rows[batch_row];
2420 const size_t route_index = (size_t)row *
2421 (size_t)args->top_k + (size_t)args->slot;
2422 axpy_f32(
2423 args->output + (size_t)row *
2424 (size_t)args->hidden_dim,
2425 expert_output + (size_t)batch_row *
2426 (size_t)args->hidden_dim,
2427 args->routing_weights[route_index], args->hidden_dim);
2428 }
2429 }
2430 position = segment_end;
2431 ++expert;
2432 }
2433 }
2434}
2435
2437 const float *hidden,
2438 const int *indices,
2439 const float *routing_weights,
2440 const void *expert_gate,
2441 const void *expert_up,
2442 const void *expert_down,
2443 const void *expert_gate_packed,
2444 const void *expert_up_packed,
2445 float *output,
2446 int rows,
2447 int hidden_dim,
2448 int intermediate_dim,
2449 int n_experts,
2450 int top_k,
2451 void *workspace,
2452 size_t workspace_bytes)
2453{
2454 ck_moe_q4k_q5k_bucket_layout_t layout;
2455 if (!hidden || !indices || !routing_weights || !expert_gate || !expert_up ||
2456 !expert_down || !output || !workspace ||
2457 ((expert_gate_packed == NULL) != (expert_up_packed == NULL)) ||
2458 ck_moe_bucket_layout(rows, hidden_dim, intermediate_dim, n_experts,
2459 top_k, &layout) != 0 ||
2460 workspace_bytes < layout.total_bytes) {
2461 return -1;
2462 }
2463#if defined(CK_TARGET_ARM)
2464 if (expert_gate_packed || expert_up_packed) return -1;
2465#endif
2466
2467 uint8_t *base = (uint8_t *)workspace;
2468 uint8_t *hidden_q8 = base + layout.hidden_q8_offset;
2469 int *route_rows = (int *)(base + layout.route_rows_offset);
2470 int *slot_offsets = (int *)(base + layout.slot_offsets_offset);
2471 int *counts = (int *)(base + layout.counts_offset);
2472 int *cursors = (int *)(base + layout.cursors_offset);
2473 uint8_t *workers = base + layout.workers_offset;
2474
2475 for (int slot = 0; slot < top_k; ++slot) {
2476 memset(counts, 0, (size_t)n_experts * sizeof(*counts));
2477 for (int row = 0; row < rows; ++row) {
2478 const int expert = indices[(size_t)row * (size_t)top_k +
2479 (size_t)slot];
2480 if (expert < 0 || expert >= n_experts) return -2;
2481 counts[expert] += 1;
2482 }
2483
2484 int *offsets = slot_offsets + (size_t)slot * ((size_t)n_experts + 1u);
2485 offsets[0] = 0;
2486 for (int expert = 0; expert < n_experts; ++expert) {
2487 offsets[expert + 1] = offsets[expert] + counts[expert];
2488 cursors[expert] = offsets[expert];
2489 }
2490 int *rows_for_slot = route_rows + (size_t)slot * (size_t)rows;
2491 for (int row = 0; row < rows; ++row) {
2492 const int expert = indices[(size_t)row * (size_t)top_k +
2493 (size_t)slot];
2494 rows_for_slot[cursors[expert]++] = row;
2495 }
2496 }
2497
2498 memset(output, 0, (size_t)rows * (size_t)hidden_dim * sizeof(float));
2499 ck_threadpool_t *pool = ck_threadpool_global();
2500 int active = pool ? ck_threadpool_n_threads(pool) : 1;
2501 if (active > rows) active = rows;
2503 if (active < 1) active = 1;
2504
2505 ck_moe_q4k_q5k_quantize_args_t quantize_args = {
2506 .hidden = hidden,
2507 .hidden_q8 = hidden_q8,
2508 .rows = rows,
2509 .hidden_dim = hidden_dim,
2510 .hidden_q8_row_bytes = layout.hidden_q8_row_bytes,
2511 };
2512 if (active > 1 && pool) {
2514 pool, active, ck_moe_q4k_q5k_quantize_work, &quantize_args);
2515 } else {
2516 ck_moe_q4k_q5k_quantize_work(0, 1, &quantize_args);
2517 }
2518
2519 const size_t q4_expert_stride = (size_t)intermediate_dim *
2520 ck_dtype_row_bytes(CK_DT_Q4_K, (size_t)hidden_dim);
2521#if defined(CK_TARGET_ARM)
2522 const size_t q4_packed_expert_stride = 0;
2523#else
2524 const size_t q4_packed_expert_stride =
2525 (size_t)((intermediate_dim + 7) / 8) *
2526 (size_t)(hidden_dim / 256) * q4_k_packed_vnni_x8_block_size();
2527#endif
2528 const size_t q5_expert_stride = (size_t)hidden_dim *
2529 ck_dtype_row_bytes(CK_DT_Q5_K, (size_t)intermediate_dim);
2530 for (int slot = 0; slot < top_k; ++slot) {
2531 ck_moe_q4k_q5k_bucket_work_t args = {
2532 .bucket_rows = route_rows + (size_t)slot * (size_t)rows,
2533 .bucket_offsets = slot_offsets +
2534 (size_t)slot * ((size_t)n_experts + 1u),
2535 .routing_weights = routing_weights,
2536 .hidden_q8 = hidden_q8,
2537 .gate_base = (const uint8_t *)expert_gate,
2538 .up_base = (const uint8_t *)expert_up,
2539 .gate_packed_base = (const uint8_t *)expert_gate_packed,
2540 .up_packed_base = (const uint8_t *)expert_up_packed,
2541 .down_base = (const uint8_t *)expert_down,
2542 .output = output,
2543 .workers = workers,
2544 .worker_stride = layout.worker_stride,
2545 .hidden_q8_row_bytes = layout.hidden_q8_row_bytes,
2546 .q4_expert_stride = q4_expert_stride,
2547 .q4_packed_expert_stride = q4_packed_expert_stride,
2548 .q5_expert_stride = q5_expert_stride,
2549 .hidden_dim = hidden_dim,
2550 .intermediate_dim = intermediate_dim,
2551 .n_experts = n_experts,
2552 .top_k = top_k,
2553 .slot = slot,
2554 .total_tasks = (rows + CK_MOE_Q4K_Q5K_TASK_ROWS - 1) /
2556 };
2557 atomic_init(&args.next_task, 0);
2558 int task_threads = active;
2559 if (task_threads > args.total_tasks) task_threads = args.total_tasks;
2560 if (active > 1 && pool) {
2562 pool, task_threads, ck_moe_q4k_q5k_bucket_work, &args);
2563 } else {
2564 ck_moe_q4k_q5k_bucket_work(0, 1, &args);
2565 }
2566 }
2567 return 0;
2568}
2569
2571 const float *hidden,
2572 const int *indices,
2573 const float *routing_weights,
2574 const void *expert_gate,
2575 const void *expert_up,
2576 const void *expert_down,
2577 float *output,
2578 int rows,
2579 int hidden_dim,
2580 int intermediate_dim,
2581 int n_experts,
2582 int top_k,
2583 void *workspace,
2584 size_t workspace_bytes)
2585{
2587 hidden, indices, routing_weights,
2588 expert_gate, expert_up, expert_down, NULL, NULL, output,
2589 rows, hidden_dim, intermediate_dim, n_experts, top_k,
2590 workspace, workspace_bytes);
2591}
2592
2594 const float *hidden,
2595 const int *indices,
2596 const float *routing_weights,
2597 const void *expert_gate,
2598 const void *expert_up,
2599 const void *expert_down,
2600 const void *expert_gate_packed,
2601 const void *expert_up_packed,
2602 float *output,
2603 int rows,
2604 int hidden_dim,
2605 int intermediate_dim,
2606 int n_experts,
2607 int top_k,
2608 void *workspace,
2609 size_t workspace_bytes)
2610{
2612 hidden, indices, routing_weights,
2613 expert_gate, expert_up, expert_down,
2614 expert_gate_packed, expert_up_packed, output,
2615 rows, hidden_dim, intermediate_dim, n_experts, top_k,
2616 workspace, workspace_bytes);
2617}
2618
2620 const float *hidden,
2621 const int *indices,
2622 const float *routing_weights,
2623 const void *expert_gate,
2624 const void *expert_up,
2625 const void *expert_down,
2626 float *output,
2627 int rows,
2628 int hidden_dim,
2629 int intermediate_dim,
2630 int n_experts,
2631 int top_k,
2632 void *workspace,
2633 size_t workspace_bytes)
2634{
2635 if (rows < 512) {
2637 hidden, indices, routing_weights,
2638 expert_gate, expert_up, expert_down, output,
2639 rows, hidden_dim, intermediate_dim, n_experts, top_k,
2640 workspace, workspace_bytes);
2641 }
2643 hidden, indices, routing_weights,
2644 expert_gate, expert_up, expert_down, output,
2645 rows, hidden_dim, intermediate_dim, n_experts, top_k,
2646 workspace, workspace_bytes);
2647}
2648
2650 int intermediate_dim)
2651{
2652 if (hidden_dim <= 0 || intermediate_dim <= 0 ||
2653 hidden_dim % 32 != 0 || intermediate_dim % 32 != 0) {
2654 return 0;
2655 }
2656
2657 size_t bytes = ck_moe_align64(
2658 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)hidden_dim));
2659 bytes += ck_moe_align64(2u * (size_t)intermediate_dim * sizeof(float));
2660 bytes += ck_moe_align64(
2661 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim));
2662 bytes += ck_moe_align64((size_t)hidden_dim * sizeof(float));
2663 return bytes;
2664}
2665
2667 const float *hidden,
2668 const float *routed,
2669 const void *shared_gate,
2670 const void *shared_up,
2671 const void *shared_down,
2672 const float *shared_gate_input,
2673 float *output,
2674 int rows,
2675 int hidden_dim,
2676 int intermediate_dim,
2677 void *workspace,
2678 size_t workspace_bytes)
2679{
2680 const size_t required = moe_swiglu_shared_q8_0_gated_workspace_bytes(
2681 hidden_dim, intermediate_dim);
2682 if (!hidden || !shared_gate || !shared_up || !shared_down ||
2683 !shared_gate_input || !output || !workspace || required == 0 ||
2684 workspace_bytes < required || rows <= 0) {
2685 return -1;
2686 }
2687
2688 const size_t hidden_q8_bytes = ck_moe_align64(
2689 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)hidden_dim));
2690 const size_t gate_up_bytes = ck_moe_align64(
2691 2u * (size_t)intermediate_dim * sizeof(float));
2692 const size_t activation_q8_bytes = ck_moe_align64(
2693 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim));
2694 uint8_t *cursor = (uint8_t *)workspace;
2695 void *hidden_q8 = cursor;
2696 cursor += hidden_q8_bytes;
2697 float *gate_up = (float *)cursor;
2698 cursor += gate_up_bytes;
2699 void *activation_q8 = cursor;
2700 cursor += activation_q8_bytes;
2701 float *shared_output = (float *)cursor;
2702
2703 for (int row = 0; row < rows; ++row) {
2704 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
2705 const float *routed_row = routed
2706 ? routed + (size_t)row * (size_t)hidden_dim
2707 : NULL;
2708 float *output_row = output + (size_t)row * (size_t)hidden_dim;
2709
2710 quantize_row_q8_0(x, hidden_q8, hidden_dim);
2711 gemv_q8_0_q8_0(gate_up, shared_gate, hidden_q8,
2712 intermediate_dim, hidden_dim);
2713 gemv_q8_0_q8_0(gate_up + intermediate_dim, shared_up, hidden_q8,
2714 intermediate_dim, hidden_dim);
2715 swiglu_forward_ggml(gate_up, gate_up, 1, intermediate_dim);
2716 quantize_row_q8_0(gate_up, activation_q8, intermediate_dim);
2717 gemv_q8_0_q8_0(shared_output, shared_down, activation_q8,
2718 hidden_dim, intermediate_dim);
2719
2720 float gate_value = 0.0f;
2722 x, shared_gate_input, NULL, &gate_value, 1, 1, hidden_dim);
2723 const float gate_scale = 1.0f / (1.0f + expf(-gate_value));
2724 for (int h = 0; h < hidden_dim; ++h) {
2725 const float routed_value = routed_row ? routed_row[h] : 0.0f;
2726 volatile float gated_shared = shared_output[h] * gate_scale;
2727 output_row[h] = routed_value + gated_shared;
2728 }
2729 }
2730 return 0;
2731}
2732
2734 const float *hidden,
2735 const float *routed,
2736 const void *shared_gate,
2737 const void *shared_up,
2738 const void *shared_down,
2739 const float *shared_gate_input,
2740 float *output,
2741 int rows,
2742 int hidden_dim,
2743 int intermediate_dim,
2744 void *workspace,
2745 size_t workspace_bytes,
2746 void (*down_projection)(float *, const void *, const void *, int, int))
2747{
2749 hidden_dim, intermediate_dim);
2750 if (!hidden || !shared_gate || !shared_up || !shared_down ||
2751 !shared_gate_input || !output || !workspace || required == 0 ||
2752 workspace_bytes < required || rows <= 0) {
2753 return -1;
2754 }
2755
2756 enum { CK_SHARED_Q4K_BATCH_ROWS = 4 };
2757 const size_t hidden_q8_stride =
2758 ck_dtype_row_bytes(CK_DT_Q8_K, (size_t)hidden_dim);
2759 const size_t activation_q8_stride =
2760 ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim);
2761 const size_t hidden_q8_bytes = ck_moe_align64(
2762 CK_SHARED_Q4K_BATCH_ROWS * hidden_q8_stride);
2763 const size_t projection_bytes = ck_moe_align64(
2764 CK_SHARED_Q4K_BATCH_ROWS * (size_t)intermediate_dim * sizeof(float));
2765 const size_t activation_q8_bytes = ck_moe_align64(
2766 CK_SHARED_Q4K_BATCH_ROWS * activation_q8_stride);
2767 uint8_t *cursor = (uint8_t *)workspace;
2768 void *hidden_q8 = cursor;
2769 cursor += hidden_q8_bytes;
2770 float *gate_values = (float *)cursor;
2771 cursor += projection_bytes;
2772 float *up_values = (float *)cursor;
2773 cursor += projection_bytes;
2774 void *activation_q8 = cursor;
2775 cursor += activation_q8_bytes;
2776 float *shared_output = (float *)cursor;
2777
2778 /* llama.cpp evaluates Q4_K prefill projections in complete four-row GEMM
2779 * groups, then uses the GEMV reduction order only for the residual tail.
2780 * Keeping that boundary here matters: tiny per-row reduction differences
2781 * can cross the following Q8_0 activation quantization threshold. */
2782 for (int row0 = 0; row0 < rows; row0 += CK_SHARED_Q4K_BATCH_ROWS) {
2783 int batch_rows = rows - row0;
2784 if (batch_rows > CK_SHARED_Q4K_BATCH_ROWS) {
2785 batch_rows = CK_SHARED_Q4K_BATCH_ROWS;
2786 }
2787 for (int local_row = 0; local_row < batch_rows; ++local_row) {
2788 const float *x = hidden +
2789 (size_t)(row0 + local_row) * (size_t)hidden_dim;
2791 x,
2792 (uint8_t *)hidden_q8 +
2793 (size_t)local_row * hidden_q8_stride,
2794 hidden_dim);
2795 }
2797 hidden_q8, shared_gate, NULL, gate_values,
2798 batch_rows, intermediate_dim, hidden_dim);
2800 hidden_q8, shared_up, NULL, up_values,
2801 batch_rows, intermediate_dim, hidden_dim);
2803 gate_values, up_values, gate_values, batch_rows, intermediate_dim);
2804
2805 for (int local_row = 0; local_row < batch_rows; ++local_row) {
2806 const int row = row0 + local_row;
2807 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
2808 const float *routed_row = routed
2809 ? routed + (size_t)row * (size_t)hidden_dim
2810 : NULL;
2811 float *output_row = output + (size_t)row * (size_t)hidden_dim;
2812 void *activation_q8_row = (uint8_t *)activation_q8 +
2813 (size_t)local_row * activation_q8_stride;
2814 float *shared_output_row = shared_output +
2815 (size_t)local_row * (size_t)hidden_dim;
2816
2818 gate_values + (size_t)local_row * (size_t)intermediate_dim,
2819 activation_q8_row, intermediate_dim);
2820 down_projection(
2821 shared_output_row, shared_down, activation_q8_row,
2822 hidden_dim, intermediate_dim);
2823
2824 float gate_value = 0.0f;
2826 x, shared_gate_input, NULL, &gate_value, 1, 1, hidden_dim);
2827 const float gate_scale = 1.0f / (1.0f + expf(-gate_value));
2828 for (int h = 0; h < hidden_dim; ++h) {
2829 const float routed_value = routed_row ? routed_row[h] : 0.0f;
2830 volatile float gated_shared =
2831 shared_output_row[h] * gate_scale;
2832 output_row[h] = routed_value + gated_shared;
2833 }
2834 }
2835 }
2836 return 0;
2837}
2838
2840 const float *hidden, const float *routed,
2841 const void *shared_gate, const void *shared_up, const void *shared_down,
2842 const float *shared_gate_input, float *output,
2843 int rows, int hidden_dim, int intermediate_dim,
2844 void *workspace, size_t workspace_bytes)
2845{
2847 hidden, routed, shared_gate, shared_up, shared_down, shared_gate_input,
2848 output, rows, hidden_dim, intermediate_dim, workspace, workspace_bytes,
2850}
2851
2853 const float *hidden,
2854 const float *routed,
2855 const void *shared_gate,
2856 const void *shared_up,
2857 const void *shared_down,
2858 const float *shared_gate_input,
2859 float *output,
2860 int rows,
2861 int hidden_dim,
2862 int intermediate_dim,
2863 void *workspace,
2864 size_t workspace_bytes)
2865{
2867 hidden, routed, shared_gate, shared_up, shared_down, shared_gate_input,
2868 output, rows, hidden_dim, intermediate_dim, workspace, workspace_bytes,
2870}
2871
2873 const float *, const float *, const void *, const void *, const void *,
2874 const float *, float *, int, int, int, void *, size_t);
2875
2876typedef struct {
2877 const float *hidden;
2878 const float *routed;
2879 const void *shared_gate;
2880 const void *shared_up;
2881 const void *shared_down;
2882 const float *shared_gate_input;
2883 float *output;
2884 int rows;
2885 int hidden_dim;
2886 int intermediate_dim;
2887 uint8_t *workspace;
2888 size_t workspace_stride;
2890 int status[CK_THREADPOOL_MAX_THREADS];
2891} ck_moe_shared_q8_0_parallel_args_t;
2892
2893static void ck_moe_shared_q8_0_parallel_work(int ith, int nth, void *opaque)
2894{
2895 ck_moe_shared_q8_0_parallel_args_t *args =
2896 (ck_moe_shared_q8_0_parallel_args_t *)opaque;
2897 const int begin = (args->rows * ith) / nth;
2898 const int end = (args->rows * (ith + 1)) / nth;
2899 if (begin >= end) {
2900 args->status[ith] = 0;
2901 return;
2902 }
2903
2904 args->status[ith] = args->serial_fn(
2905 args->hidden + (size_t)begin * (size_t)args->hidden_dim,
2906 args->routed
2907 ? args->routed + (size_t)begin * (size_t)args->hidden_dim
2908 : NULL,
2909 args->shared_gate,
2910 args->shared_up,
2911 args->shared_down,
2912 args->shared_gate_input,
2913 args->output + (size_t)begin * (size_t)args->hidden_dim,
2914 end - begin,
2915 args->hidden_dim,
2916 args->intermediate_dim,
2917 args->workspace + (size_t)ith * args->workspace_stride,
2918 args->workspace_stride);
2919}
2920
2922 const float *hidden,
2923 const float *routed,
2924 const void *shared_gate,
2925 const void *shared_up,
2926 const void *shared_down,
2927 const float *shared_gate_input,
2928 float *output,
2929 int rows,
2930 int hidden_dim,
2931 int intermediate_dim,
2932 void *workspace,
2933 size_t workspace_bytes,
2934 size_t stride,
2936{
2937 if (!hidden || !shared_gate || !shared_up || !shared_down ||
2938 !shared_gate_input || !output || !workspace || !serial_fn ||
2939 stride == 0 || rows <= 0) {
2940 return -1;
2941 }
2942
2943 ck_threadpool_t *pool = ck_threadpool_global();
2944 int active = pool ? ck_threadpool_n_threads(pool) : 1;
2945 if (active > rows) active = rows;
2947 const size_t workspace_workers = workspace_bytes / stride;
2948 if (workspace_workers == 0) return -1;
2949 if ((size_t)active > workspace_workers) active = (int)workspace_workers;
2950 if (active <= 1) {
2951 return serial_fn(
2952 hidden, routed, shared_gate, shared_up, shared_down,
2953 shared_gate_input, output, rows, hidden_dim, intermediate_dim,
2954 workspace, stride);
2955 }
2956
2957 ck_moe_shared_q8_0_parallel_args_t args = {
2958 .hidden = hidden,
2959 .routed = routed,
2960 .shared_gate = shared_gate,
2961 .shared_up = shared_up,
2962 .shared_down = shared_down,
2963 .shared_gate_input = shared_gate_input,
2964 .output = output,
2965 .rows = rows,
2966 .hidden_dim = hidden_dim,
2967 .intermediate_dim = intermediate_dim,
2968 .workspace = (uint8_t *)workspace,
2969 .workspace_stride = stride,
2970 .serial_fn = serial_fn,
2971 .status = {0},
2972 };
2974 pool, active, ck_moe_shared_q8_0_parallel_work, &args);
2975 for (int ith = 0; ith < active; ++ith) {
2976 if (args.status[ith] != 0) return args.status[ith];
2977 }
2978 return 0;
2979}
2980
2982 const float *hidden,
2983 const float *routed,
2984 const void *shared_gate,
2985 const void *shared_up,
2986 const void *shared_down,
2987 const float *shared_gate_input,
2988 float *output,
2989 int rows,
2990 int hidden_dim,
2991 int intermediate_dim,
2992 void *workspace,
2993 size_t workspace_bytes)
2994{
2996 hidden, routed, shared_gate, shared_up, shared_down, shared_gate_input,
2997 output, rows, hidden_dim, intermediate_dim, workspace, workspace_bytes,
2998 moe_swiglu_shared_q8_0_gated_workspace_bytes(hidden_dim, intermediate_dim),
3000}
3001
3003 const float *hidden,
3004 const float *routed,
3005 const void *shared_gate,
3006 const void *shared_up,
3007 const void *shared_down,
3008 const float *shared_gate_input,
3009 float *output,
3010 int rows,
3011 int hidden_dim,
3012 int intermediate_dim,
3013 void *workspace,
3014 size_t workspace_bytes)
3015{
3016 /* Gate/up use the output-parallel pairwise Q4_K provider. Do not wrap
3017 * that provider in a second dispatch on the same persistent pool. */
3019 hidden, routed, shared_gate, shared_up, shared_down, shared_gate_input,
3020 output, rows, hidden_dim, intermediate_dim, workspace, workspace_bytes);
3021}
3022
3024 const float *hidden,
3025 const float *routed,
3026 const void *shared_gate,
3027 const void *shared_up,
3028 const void *shared_down,
3029 const float *shared_gate_input,
3030 float *output,
3031 int rows,
3032 int hidden_dim,
3033 int intermediate_dim,
3034 void *workspace,
3035 size_t workspace_bytes)
3036{
3037 /* See the Q8_0-down variant above: inner projection dispatch owns the
3038 * pool so nested row dispatch would deadlock. */
3040 hidden, routed, shared_gate, shared_up, shared_down, shared_gate_input,
3041 output, rows, hidden_dim, intermediate_dim, workspace, workspace_bytes);
3042}
3043
3044void moe_swiglu_expert_backward_f32(const float *d_output,
3045 const float *hidden,
3046 const int *indices,
3047 const float *routing_weights,
3048 const float *expert_gate,
3049 const float *expert_up,
3050 const float *expert_down,
3051 float *d_hidden,
3052 float *d_routing_weights,
3053 float *d_expert_gate,
3054 float *d_expert_up,
3055 float *d_expert_down,
3056 int rows,
3057 int hidden_dim,
3058 int intermediate_dim,
3059 int n_experts,
3060 int top_k)
3061{
3062 if (!d_output || !hidden || !indices || !routing_weights || !expert_gate || !expert_up || !expert_down ||
3063 !d_hidden || !d_routing_weights || !d_expert_gate || !d_expert_up || !d_expert_down ||
3064 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0) {
3065 return;
3066 }
3067
3068 for (size_t p = 0; p < (size_t)rows * (size_t)hidden_dim; ++p) d_hidden[p] = 0.0f;
3069 for (size_t p = 0; p < (size_t)rows * (size_t)top_k; ++p) d_routing_weights[p] = 0.0f;
3070 for (size_t p = 0; p < (size_t)n_experts * (size_t)intermediate_dim * (size_t)hidden_dim; ++p) {
3071 d_expert_gate[p] = 0.0f;
3072 d_expert_up[p] = 0.0f;
3073 }
3074 for (size_t p = 0; p < (size_t)n_experts * (size_t)hidden_dim * (size_t)intermediate_dim; ++p) d_expert_down[p] = 0.0f;
3075
3076 float gate[intermediate_dim];
3077 float up[intermediate_dim];
3078 float silu_gate[intermediate_dim];
3079 float act[intermediate_dim];
3080 float d_act[intermediate_dim];
3081 float expert_out[hidden_dim];
3082
3083 for (int r = 0; r < rows; ++r) {
3084 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3085 const float *dy = d_output + (size_t)r * (size_t)hidden_dim;
3086 float *dx = d_hidden + (size_t)r * (size_t)hidden_dim;
3087
3088 for (int slot = 0; slot < top_k; ++slot) {
3089 const int e = indices[(size_t)r * (size_t)top_k + (size_t)slot];
3090 if (e < 0 || e >= n_experts) continue;
3091 const float route_w = routing_weights[(size_t)r * (size_t)top_k + (size_t)slot];
3092
3093 for (int i = 0; i < intermediate_dim; ++i) {
3094 float gv = 0.0f;
3095 float uv = 0.0f;
3096 for (int h = 0; h < hidden_dim; ++h) {
3097 gv += expert_gate[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] * x[h];
3098 uv += expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] * x[h];
3099 }
3100 gate[i] = gv;
3101 up[i] = uv;
3102 silu_gate[i] = ck_moe_silu_f32(gv);
3103 act[i] = silu_gate[i] * uv;
3104 d_act[i] = 0.0f;
3105 }
3106
3107 for (int h = 0; h < hidden_dim; ++h) {
3108 float v = 0.0f;
3109 for (int i = 0; i < intermediate_dim; ++i) {
3110 v += expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)] * act[i];
3111 }
3112 expert_out[h] = v;
3113 }
3114
3115 float d_route = 0.0f;
3116 for (int h = 0; h < hidden_dim; ++h) {
3117 const float d_expert_out = dy[h] * route_w;
3118 d_route += dy[h] * expert_out[h];
3119 for (int i = 0; i < intermediate_dim; ++i) {
3120 d_expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)] += d_expert_out * act[i];
3121 d_act[i] += d_expert_out * expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)];
3122 }
3123 }
3124 d_routing_weights[(size_t)r * (size_t)top_k + (size_t)slot] += d_route;
3125
3126 for (int i = 0; i < intermediate_dim; ++i) {
3127 const float d_up = d_act[i] * silu_gate[i];
3128 const float d_gate = d_act[i] * up[i] * ck_moe_dsilu_f32(gate[i]);
3129 for (int h = 0; h < hidden_dim; ++h) {
3130 d_expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] += d_up * x[h];
3131 d_expert_gate[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] += d_gate * x[h];
3132 dx[h] += d_up * expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] +
3133 d_gate * expert_gate[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)];
3134 }
3135 }
3136 }
3137 }
3138}
3139
3140void moe_swiglu_shared_forward_f32(const float *hidden,
3141 const float *routed,
3142 const float *shared_gate,
3143 const float *shared_up,
3144 const float *shared_down,
3145 float *output,
3146 int rows,
3147 int hidden_dim,
3148 int intermediate_dim)
3149{
3150 if (!hidden || !shared_gate || !shared_up || !shared_down || !output || rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0) {
3151 return;
3152 }
3153
3154 float gate[intermediate_dim];
3155 float up[intermediate_dim];
3156 float act[intermediate_dim];
3157
3158 for (int r = 0; r < rows; ++r) {
3159 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3160 const float *route = routed ? (routed + (size_t)r * (size_t)hidden_dim) : NULL;
3161 float *y = output + (size_t)r * (size_t)hidden_dim;
3162 for (int i = 0; i < intermediate_dim; ++i) {
3163 float gv = 0.0f;
3164 float uv = 0.0f;
3165 for (int h = 0; h < hidden_dim; ++h) {
3166 gv += shared_gate[(size_t)i * (size_t)hidden_dim + (size_t)h] * x[h];
3167 uv += shared_up[(size_t)i * (size_t)hidden_dim + (size_t)h] * x[h];
3168 }
3169 act[i] = ck_moe_silu_f32(gv) * uv;
3170 }
3171 for (int h = 0; h < hidden_dim; ++h) {
3172 float v = route ? route[h] : 0.0f;
3173 for (int i = 0; i < intermediate_dim; ++i) {
3174 v += shared_down[(size_t)h * (size_t)intermediate_dim + (size_t)i] * act[i];
3175 }
3176 y[h] = v;
3177 }
3178 }
3179}
3180
3182 const float *hidden,
3183 const float *routed,
3184 const uint16_t *shared_gate,
3185 const uint16_t *shared_up,
3186 const uint16_t *shared_down,
3187 float *output,
3188 int rows,
3189 int hidden_dim,
3190 int intermediate_dim,
3191 int row_begin,
3192 int row_end)
3193{
3194 if (!hidden || !shared_gate || !shared_up || !shared_down || !output ||
3195 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 ||
3196 row_begin < 0 || row_begin >= row_end || row_end > rows) {
3197 return;
3198 }
3199
3200 float gate[intermediate_dim];
3201 float up[intermediate_dim];
3202 float act[intermediate_dim];
3203
3204 for (int r = row_begin; r < row_end; ++r) {
3205 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3206 const float *route = routed ? (routed + (size_t)r * (size_t)hidden_dim) : NULL;
3207 float *y = output + (size_t)r * (size_t)hidden_dim;
3208 for (int i = 0; i < intermediate_dim; ++i) {
3209 float gv = 0.0f;
3210 float uv = 0.0f;
3211 for (int h = 0; h < hidden_dim; ++h) {
3212 gv += bf16_to_float(shared_gate[(size_t)i * (size_t)hidden_dim + (size_t)h]) * x[h];
3213 uv += bf16_to_float(shared_up[(size_t)i * (size_t)hidden_dim + (size_t)h]) * x[h];
3214 }
3215 gate[i] = gv;
3216 up[i] = uv;
3217 act[i] = ck_moe_silu_f32(gv) * uv;
3218 }
3219 for (int h = 0; h < hidden_dim; ++h) {
3220 float v = route ? route[h] : 0.0f;
3221 for (int i = 0; i < intermediate_dim; ++i) {
3222 v += bf16_to_float(shared_down[(size_t)h * (size_t)intermediate_dim + (size_t)i]) * act[i];
3223 }
3224 y[h] = v;
3225 }
3226 }
3227}
3228
3229void moe_swiglu_shared_forward_bf16(const float *hidden,
3230 const float *routed,
3231 const uint16_t *shared_gate,
3232 const uint16_t *shared_up,
3233 const uint16_t *shared_down,
3234 float *output,
3235 int rows,
3236 int hidden_dim,
3237 int intermediate_dim)
3238{
3239 if (rows <= 0) return;
3241 hidden, routed, shared_gate, shared_up, shared_down, output,
3242 rows, hidden_dim, intermediate_dim, 0, rows);
3243}
3244
3246 const float *hidden,
3247 const float *routed,
3248 const uint16_t *shared_gate,
3249 const uint16_t *shared_up,
3250 const uint16_t *shared_down,
3251 const uint16_t *shared_router,
3252 float *output,
3253 int rows,
3254 int hidden_dim,
3255 int intermediate_dim,
3256 int row_begin,
3257 int row_end)
3258{
3259 if (!hidden || !shared_gate || !shared_up || !shared_down ||
3260 !shared_router || !output || rows <= 0 || hidden_dim <= 0 ||
3261 intermediate_dim <= 0 || row_begin < 0 || row_begin >= row_end ||
3262 row_end > rows) {
3263 return;
3264 }
3265
3266 float activation[intermediate_dim];
3267 for (int row = row_begin; row < row_end; ++row) {
3268 const float *x = hidden + (size_t)row * (size_t)hidden_dim;
3269 const float *route = routed
3270 ? routed + (size_t)row * (size_t)hidden_dim
3271 : NULL;
3272 float *y = output + (size_t)row * (size_t)hidden_dim;
3273
3274 for (int intermediate = 0; intermediate < intermediate_dim;
3275 ++intermediate) {
3276 float gate_sum = 0.0f;
3277 float up_sum = 0.0f;
3278 const size_t weight_base =
3279 (size_t)intermediate * (size_t)hidden_dim;
3280 for (int hidden_col = 0; hidden_col < hidden_dim; ++hidden_col) {
3281 const float value = ck_moe_bf16_round(x[hidden_col]);
3282 gate_sum += bf16_to_float(
3283 shared_gate[weight_base + (size_t)hidden_col]) * value;
3284 up_sum += bf16_to_float(
3285 shared_up[weight_base + (size_t)hidden_col]) * value;
3286 }
3287 const float gate_value = ck_moe_bf16_round(gate_sum);
3288 const float up_value = ck_moe_bf16_round(up_sum);
3289 const float silu = ck_moe_bf16_round(
3290 ck_moe_silu_f32(gate_value));
3291 activation[intermediate] = ck_moe_bf16_round(silu * up_value);
3292 }
3293
3294 float router_sum = 0.0f;
3295 for (int hidden_col = 0; hidden_col < hidden_dim; ++hidden_col) {
3296 router_sum += bf16_to_float(shared_router[hidden_col]) *
3297 ck_moe_bf16_round(x[hidden_col]);
3298 }
3299 const float shared_scale = ck_moe_bf16_round(
3301
3302 for (int hidden_col = 0; hidden_col < hidden_dim; ++hidden_col) {
3303 float down_sum = 0.0f;
3304 const size_t weight_base =
3305 (size_t)hidden_col * (size_t)intermediate_dim;
3306 for (int intermediate = 0; intermediate < intermediate_dim;
3307 ++intermediate) {
3308 down_sum += bf16_to_float(
3309 shared_down[weight_base + (size_t)intermediate]) *
3310 activation[intermediate];
3311 }
3312 const float shared = ck_moe_bf16_round(down_sum);
3313 const float gated_shared = ck_moe_bf16_round(shared * shared_scale);
3314 const float routed_value = route
3315 ? ck_moe_bf16_round(route[hidden_col])
3316 : 0.0f;
3317 y[hidden_col] = ck_moe_bf16_round(routed_value + gated_shared);
3318 }
3319 }
3320}
3321
3323 const float *hidden,
3324 const float *routed,
3325 const uint16_t *shared_gate,
3326 const uint16_t *shared_up,
3327 const uint16_t *shared_down,
3328 const uint16_t *shared_router,
3329 float *output,
3330 int rows,
3331 int hidden_dim,
3332 int intermediate_dim)
3333{
3334 if (rows <= 0) return;
3336 hidden, routed, shared_gate, shared_up, shared_down, shared_router,
3337 output, rows, hidden_dim, intermediate_dim, 0, rows);
3338}
3339
3340/*
3341 * FarSkip shared-expert combine used by Instella-MoE.
3342 *
3343 * PyTorch constructs these values as:
3344 * mlp_output = routed + shared
3345 * residual_no_route = post_attn_residual + shared
3346 * main_output = post_attn_residual + mlp_output
3347 *
3348 * Keep the shared down projection in its own ascending FP32 reduction and
3349 * preserve those two explicit addition boundaries. Folding routed into the
3350 * down-projection accumulator changes the rounding contract.
3351 */
3353 const float *hidden,
3354 const float *routed,
3355 const float *post_attn_residual,
3356 const uint16_t *shared_gate,
3357 const uint16_t *shared_up,
3358 const uint16_t *shared_down,
3359 float *main_output,
3360 float *routed_free_output,
3361 int rows,
3362 int hidden_dim,
3363 int intermediate_dim,
3364 int row_begin,
3365 int row_end)
3366{
3367 if (!hidden || !routed || !post_attn_residual || !shared_gate || !shared_up ||
3368 !shared_down || !main_output || !routed_free_output || rows <= 0 ||
3369 hidden_dim <= 0 || intermediate_dim <= 0 || row_begin < 0 ||
3370 row_begin >= row_end || row_end > rows) {
3371 return;
3372 }
3373
3374 float act[intermediate_dim];
3375
3376 for (int r = row_begin; r < row_end; ++r) {
3377 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3378 const float *route = routed + (size_t)r * (size_t)hidden_dim;
3379 const float *residual = post_attn_residual + (size_t)r * (size_t)hidden_dim;
3380 float *main = main_output + (size_t)r * (size_t)hidden_dim;
3381 float *routed_free = routed_free_output + (size_t)r * (size_t)hidden_dim;
3382
3383 for (int i = 0; i < intermediate_dim; ++i) {
3384 float gv = 0.0f;
3385 float uv = 0.0f;
3386 for (int h = 0; h < hidden_dim; ++h) {
3387 gv += bf16_to_float(shared_gate[(size_t)i * (size_t)hidden_dim + (size_t)h]) * x[h];
3388 uv += bf16_to_float(shared_up[(size_t)i * (size_t)hidden_dim + (size_t)h]) * x[h];
3389 }
3390 act[i] = ck_moe_silu_f32(gv) * uv;
3391 }
3392
3393 for (int h = 0; h < hidden_dim; ++h) {
3394 float shared = 0.0f;
3395 for (int i = 0; i < intermediate_dim; ++i) {
3396 shared += bf16_to_float(shared_down[(size_t)h * (size_t)intermediate_dim + (size_t)i]) * act[i];
3397 }
3398 const float mlp_output = route[h] + shared;
3399 routed_free[h] = residual[h] + shared;
3400 main[h] = residual[h] + mlp_output;
3401 }
3402 }
3403}
3404
3405void farskip_swiglu_shared_combine_bf16(const float *hidden,
3406 const float *routed,
3407 const float *post_attn_residual,
3408 const uint16_t *shared_gate,
3409 const uint16_t *shared_up,
3410 const uint16_t *shared_down,
3411 float *main_output,
3412 float *routed_free_output,
3413 int rows,
3414 int hidden_dim,
3415 int intermediate_dim)
3416{
3417 if (rows <= 0) return;
3419 hidden, routed, post_attn_residual, shared_gate, shared_up, shared_down,
3420 main_output, routed_free_output, rows, hidden_dim, intermediate_dim,
3421 0, rows);
3422}
3423
3424void moe_swiglu_shared_backward_f32(const float *d_output,
3425 const float *hidden,
3426 const float *shared_gate,
3427 const float *shared_up,
3428 const float *shared_down,
3429 float *d_hidden,
3430 float *d_routed,
3431 float *d_shared_gate,
3432 float *d_shared_up,
3433 float *d_shared_down,
3434 int rows,
3435 int hidden_dim,
3436 int intermediate_dim)
3437{
3438 if (!d_output || !hidden || !shared_gate || !shared_up || !shared_down ||
3439 !d_hidden || !d_routed || !d_shared_gate || !d_shared_up || !d_shared_down ||
3440 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0) {
3441 return;
3442 }
3443
3444 for (size_t p = 0; p < (size_t)rows * (size_t)hidden_dim; ++p) {
3445 d_hidden[p] = 0.0f;
3446 d_routed[p] = d_output[p];
3447 }
3448 for (size_t p = 0; p < (size_t)intermediate_dim * (size_t)hidden_dim; ++p) {
3449 d_shared_gate[p] = 0.0f;
3450 d_shared_up[p] = 0.0f;
3451 }
3452 for (size_t p = 0; p < (size_t)hidden_dim * (size_t)intermediate_dim; ++p) d_shared_down[p] = 0.0f;
3453
3454 float gate[intermediate_dim];
3455 float up[intermediate_dim];
3456 float silu_gate[intermediate_dim];
3457 float act[intermediate_dim];
3458 float d_act[intermediate_dim];
3459
3460 for (int r = 0; r < rows; ++r) {
3461 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3462 const float *dy = d_output + (size_t)r * (size_t)hidden_dim;
3463 float *dx = d_hidden + (size_t)r * (size_t)hidden_dim;
3464
3465 for (int i = 0; i < intermediate_dim; ++i) {
3466 float gv = 0.0f;
3467 float uv = 0.0f;
3468 for (int h = 0; h < hidden_dim; ++h) {
3469 gv += shared_gate[(size_t)i * (size_t)hidden_dim + (size_t)h] * x[h];
3470 uv += shared_up[(size_t)i * (size_t)hidden_dim + (size_t)h] * x[h];
3471 }
3472 gate[i] = gv;
3473 up[i] = uv;
3474 silu_gate[i] = ck_moe_silu_f32(gv);
3475 act[i] = silu_gate[i] * uv;
3476 d_act[i] = 0.0f;
3477 }
3478
3479 for (int h = 0; h < hidden_dim; ++h) {
3480 for (int i = 0; i < intermediate_dim; ++i) {
3481 d_shared_down[(size_t)h * (size_t)intermediate_dim + (size_t)i] += dy[h] * act[i];
3482 d_act[i] += dy[h] * shared_down[(size_t)h * (size_t)intermediate_dim + (size_t)i];
3483 }
3484 }
3485
3486 for (int i = 0; i < intermediate_dim; ++i) {
3487 const float d_up = d_act[i] * silu_gate[i];
3488 const float d_gate = d_act[i] * up[i] * ck_moe_dsilu_f32(gate[i]);
3489 for (int h = 0; h < hidden_dim; ++h) {
3490 d_shared_up[(size_t)i * (size_t)hidden_dim + (size_t)h] += d_up * x[h];
3491 d_shared_gate[(size_t)i * (size_t)hidden_dim + (size_t)h] += d_gate * x[h];
3492 dx[h] += d_up * shared_up[(size_t)i * (size_t)hidden_dim + (size_t)h] +
3493 d_gate * shared_gate[(size_t)i * (size_t)hidden_dim + (size_t)h];
3494 }
3495 }
3496 }
3497}
3498
3499void moe_relu2_expert_forward_q5_0_q8_0(const float *hidden,
3500 const int *indices,
3501 const float *routing_weights,
3502 const void *expert_up,
3503 const void *expert_down,
3504 float *output,
3505 int rows,
3506 int hidden_dim,
3507 int intermediate_dim,
3508 int n_experts,
3509 int top_k)
3510{
3511 if (!hidden || !indices || !routing_weights || !expert_up || !expert_down || !output ||
3512 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0) {
3513 return;
3514 }
3515
3516 const size_t out_count = (size_t)rows * (size_t)hidden_dim;
3517 for (size_t p = 0; p < out_count; ++p) output[p] = 0.0f;
3518
3519 const size_t up_row_bytes = ck_dtype_row_bytes(CK_DT_Q5_0, (size_t)hidden_dim);
3520 const size_t down_row_bytes = ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim);
3521 const uint8_t *up_base = (const uint8_t *)expert_up;
3522 const uint8_t *down_base = (const uint8_t *)expert_down;
3523
3524 float up_row[hidden_dim];
3525 float down_row[intermediate_dim];
3526 float act[intermediate_dim];
3527
3528 for (int r = 0; r < rows; ++r) {
3529 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3530 float *y = output + (size_t)r * (size_t)hidden_dim;
3531 if (ck_moe_debug_enabled() && r == 0) {
3532 fprintf(stderr,
3533 "[CK_DEBUG_MOE] routed_q5q8 rows=%d hidden=%d intermediate=%d experts=%d top_k=%d up_row_bytes=%zu down_row_bytes=%zu\n",
3534 rows,
3535 hidden_dim,
3536 intermediate_dim,
3537 n_experts,
3538 top_k,
3539 up_row_bytes,
3540 down_row_bytes);
3541 fprintf(stderr, "[CK_DEBUG_MOE] routed slots:");
3542 for (int dbg_slot = 0; dbg_slot < top_k; ++dbg_slot) {
3543 fprintf(stderr,
3544 " (%d,%g)",
3545 indices[(size_t)r * (size_t)top_k + (size_t)dbg_slot],
3546 routing_weights[(size_t)r * (size_t)top_k + (size_t)dbg_slot]);
3547 }
3548 fprintf(stderr, "\n");
3549 ck_moe_debug_finite("routed.hidden[0]", x, (size_t)hidden_dim);
3550 ck_moe_debug_finite("routed.hidden_all", hidden, (size_t)rows * (size_t)hidden_dim);
3551 }
3552 for (int slot = 0; slot < top_k; ++slot) {
3553 const int e = indices[(size_t)r * (size_t)top_k + (size_t)slot];
3554 if (e < 0 || e >= n_experts) continue;
3555 const float route_w = routing_weights[(size_t)r * (size_t)top_k + (size_t)slot];
3556 const uint8_t *expert_up_base = up_base + (size_t)e * (size_t)intermediate_dim * up_row_bytes;
3557 const uint8_t *expert_down_base = down_base + (size_t)e * (size_t)hidden_dim * down_row_bytes;
3558
3559 for (int i = 0; i < intermediate_dim; ++i) {
3560 dequant_q5_0_row(expert_up_base + (size_t)i * up_row_bytes, up_row, (size_t)hidden_dim);
3561 float v = 0.0f;
3562 for (int h = 0; h < hidden_dim; ++h) v += up_row[h] * x[h];
3563 act[i] = (v > 0.0f) ? v * v : 0.0f;
3564 }
3565
3566 for (int h = 0; h < hidden_dim; ++h) {
3567 dequant_q8_0_row(expert_down_base + (size_t)h * down_row_bytes, down_row, (size_t)intermediate_dim);
3568 float v = 0.0f;
3569 for (int i = 0; i < intermediate_dim; ++i) v += down_row[i] * act[i];
3570 y[h] += route_w * v;
3571 }
3572 }
3573 if (ck_moe_debug_enabled() && r == 0) {
3574 ck_moe_debug_finite("routed.output[0]", y, (size_t)hidden_dim);
3575 ck_moe_debug_finite("routed.output_all", output, (size_t)rows * (size_t)hidden_dim);
3576 }
3577 }
3578}
3579
3580
3581void moe_relu2_expert_forward_q5_0_q5_0(const float *hidden,
3582 const int *indices,
3583 const float *routing_weights,
3584 const void *expert_up,
3585 const void *expert_down,
3586 float *output,
3587 int rows,
3588 int hidden_dim,
3589 int intermediate_dim,
3590 int n_experts,
3591 int top_k)
3592{
3593 if (!hidden || !indices || !routing_weights || !expert_up || !expert_down || !output ||
3594 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0) {
3595 return;
3596 }
3597
3598 const size_t out_count = (size_t)rows * (size_t)hidden_dim;
3599 for (size_t p = 0; p < out_count; ++p) output[p] = 0.0f;
3600
3601 const size_t up_row_bytes = ck_dtype_row_bytes(CK_DT_Q5_0, (size_t)hidden_dim);
3602 const size_t down_row_bytes = ck_dtype_row_bytes(CK_DT_Q5_0, (size_t)intermediate_dim);
3603 const uint8_t *up_base = (const uint8_t *)expert_up;
3604 const uint8_t *down_base = (const uint8_t *)expert_down;
3605
3606 float up_row[hidden_dim];
3607 float down_row[intermediate_dim];
3608 float act[intermediate_dim];
3609
3610 for (int r = 0; r < rows; ++r) {
3611 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3612 float *y = output + (size_t)r * (size_t)hidden_dim;
3613 if (ck_moe_debug_enabled() && r == 0) {
3614 fprintf(stderr,
3615 "[CK_DEBUG_MOE] routed_q5q5 rows=%d hidden=%d intermediate=%d experts=%d top_k=%d up_row_bytes=%zu down_row_bytes=%zu\n",
3616 rows,
3617 hidden_dim,
3618 intermediate_dim,
3619 n_experts,
3620 top_k,
3621 up_row_bytes,
3622 down_row_bytes);
3623 fprintf(stderr, "[CK_DEBUG_MOE] routed slots:");
3624 for (int dbg_slot = 0; dbg_slot < top_k; ++dbg_slot) {
3625 fprintf(stderr,
3626 " (%d,%g)",
3627 indices[(size_t)r * (size_t)top_k + (size_t)dbg_slot],
3628 routing_weights[(size_t)r * (size_t)top_k + (size_t)dbg_slot]);
3629 }
3630 fprintf(stderr, "\n");
3631 ck_moe_debug_finite("routed.hidden[0]", x, (size_t)hidden_dim);
3632 ck_moe_debug_finite("routed.hidden_all", hidden, (size_t)rows * (size_t)hidden_dim);
3633 }
3634 for (int slot = 0; slot < top_k; ++slot) {
3635 const int e = indices[(size_t)r * (size_t)top_k + (size_t)slot];
3636 if (e < 0 || e >= n_experts) continue;
3637 const float route_w = routing_weights[(size_t)r * (size_t)top_k + (size_t)slot];
3638 const uint8_t *expert_up_base = up_base + (size_t)e * (size_t)intermediate_dim * up_row_bytes;
3639 const uint8_t *expert_down_base = down_base + (size_t)e * (size_t)hidden_dim * down_row_bytes;
3640
3641 for (int i = 0; i < intermediate_dim; ++i) {
3642 dequant_q5_0_row(expert_up_base + (size_t)i * up_row_bytes, up_row, (size_t)hidden_dim);
3643 float v = 0.0f;
3644 for (int h = 0; h < hidden_dim; ++h) v += up_row[h] * x[h];
3645 act[i] = (v > 0.0f) ? v * v : 0.0f;
3646 }
3647
3648 for (int h = 0; h < hidden_dim; ++h) {
3649 dequant_q5_0_row(expert_down_base + (size_t)h * down_row_bytes, down_row, (size_t)intermediate_dim);
3650 float v = 0.0f;
3651 for (int i = 0; i < intermediate_dim; ++i) v += down_row[i] * act[i];
3652 y[h] += route_w * v;
3653 }
3654 }
3655 if (ck_moe_debug_enabled() && r == 0) {
3656 ck_moe_debug_finite("routed.output[0]", y, (size_t)hidden_dim);
3657 ck_moe_debug_finite("routed.output_all", output, (size_t)rows * (size_t)hidden_dim);
3658 }
3659 }
3660}
3661
3662void moe_relu2_shared_forward_q5_1_q8_0(const float *hidden,
3663 const float *routed,
3664 const void *shared_up,
3665 const void *shared_down,
3666 float *output,
3667 int rows,
3668 int hidden_dim,
3669 int intermediate_dim)
3670{
3671 if (!hidden || !shared_up || !shared_down || !output || rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0) {
3672 return;
3673 }
3674
3675 const size_t up_row_bytes = ck_dtype_row_bytes(CK_DT_Q5_1, (size_t)hidden_dim);
3676 const size_t down_row_bytes = ck_dtype_row_bytes(CK_DT_Q8_0, (size_t)intermediate_dim);
3677 const uint8_t *up_base = (const uint8_t *)shared_up;
3678 const uint8_t *down_base = (const uint8_t *)shared_down;
3679
3680 float up_row[hidden_dim];
3681 float down_row[intermediate_dim];
3682 float act[intermediate_dim];
3683
3684 for (int r = 0; r < rows; ++r) {
3685 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3686 const float *route = routed ? (routed + (size_t)r * (size_t)hidden_dim) : NULL;
3687 float *y = output + (size_t)r * (size_t)hidden_dim;
3688 float x_alias[hidden_dim];
3689 if (output == hidden) {
3690 memcpy(x_alias, x, (size_t)hidden_dim * sizeof(float));
3691 x = x_alias;
3692 }
3693
3694 if (ck_moe_debug_enabled() && r == 0) {
3695 fprintf(stderr,
3696 "[CK_DEBUG_MOE] shared_q5q8 rows=%d hidden=%d intermediate=%d up_row_bytes=%zu down_row_bytes=%zu alias=%d\n",
3697 rows,
3698 hidden_dim,
3699 intermediate_dim,
3700 up_row_bytes,
3701 down_row_bytes,
3702 output == hidden);
3703 ck_moe_debug_finite("shared.hidden[0]", x, (size_t)hidden_dim);
3704 ck_moe_debug_finite("shared.hidden_all", hidden, (size_t)rows * (size_t)hidden_dim);
3705 ck_moe_debug_finite("shared.routed[0]", route, (size_t)hidden_dim);
3706 if (routed) ck_moe_debug_finite("shared.routed_all", routed, (size_t)rows * (size_t)hidden_dim);
3707 }
3708
3709 for (int i = 0; i < intermediate_dim; ++i) {
3710 dequant_q5_1_row(up_base + (size_t)i * up_row_bytes, up_row, (size_t)hidden_dim);
3711 float v = 0.0f;
3712 for (int h = 0; h < hidden_dim; ++h) v += up_row[h] * x[h];
3713 act[i] = (v > 0.0f) ? v * v : 0.0f;
3714 }
3715
3716 for (int h = 0; h < hidden_dim; ++h) {
3717 dequant_q8_0_row(down_base + (size_t)h * down_row_bytes, down_row, (size_t)intermediate_dim);
3718 float v = route ? route[h] : 0.0f;
3719 for (int i = 0; i < intermediate_dim; ++i) v += down_row[i] * act[i];
3720 y[h] = v;
3721 }
3722
3723 if (ck_moe_debug_enabled() && r == 0) {
3724 ck_moe_debug_finite("shared.output[0]", y, (size_t)hidden_dim);
3725 ck_moe_debug_finite("shared.output_all", output, (size_t)rows * (size_t)hidden_dim);
3726 }
3727 }
3728}
3729
3730void moe_relu2_expert_backward_f32(const float *d_output,
3731 const float *hidden,
3732 const int *indices,
3733 const float *routing_weights,
3734 const float *expert_up,
3735 const float *expert_down,
3736 float *d_hidden,
3737 float *d_routing_weights,
3738 float *d_expert_up,
3739 float *d_expert_down,
3740 int rows,
3741 int hidden_dim,
3742 int intermediate_dim,
3743 int n_experts,
3744 int top_k)
3745{
3746 if (!d_output || !hidden || !indices || !routing_weights || !expert_up || !expert_down ||
3747 !d_hidden || !d_routing_weights || !d_expert_up || !d_expert_down ||
3748 rows <= 0 || hidden_dim <= 0 || intermediate_dim <= 0 || n_experts <= 0 || top_k <= 0) {
3749 return;
3750 }
3751
3752 for (size_t p = 0; p < (size_t)rows * (size_t)hidden_dim; ++p) d_hidden[p] = 0.0f;
3753 for (size_t p = 0; p < (size_t)rows * (size_t)top_k; ++p) d_routing_weights[p] = 0.0f;
3754 for (size_t p = 0; p < (size_t)n_experts * (size_t)intermediate_dim * (size_t)hidden_dim; ++p) d_expert_up[p] = 0.0f;
3755 for (size_t p = 0; p < (size_t)n_experts * (size_t)hidden_dim * (size_t)intermediate_dim; ++p) d_expert_down[p] = 0.0f;
3756
3757 float pre[intermediate_dim];
3758 float act[intermediate_dim];
3759 float d_act[intermediate_dim];
3760 float d_pre[intermediate_dim];
3761 float expert_out[hidden_dim];
3762
3763 for (int r = 0; r < rows; ++r) {
3764 const float *x = hidden + (size_t)r * (size_t)hidden_dim;
3765 const float *dy = d_output + (size_t)r * (size_t)hidden_dim;
3766 float *dx = d_hidden + (size_t)r * (size_t)hidden_dim;
3767
3768 for (int slot = 0; slot < top_k; ++slot) {
3769 const int e = indices[(size_t)r * (size_t)top_k + (size_t)slot];
3770 if (e < 0 || e >= n_experts) continue;
3771 const float route_w = routing_weights[(size_t)r * (size_t)top_k + (size_t)slot];
3772
3773 for (int i = 0; i < intermediate_dim; ++i) {
3774 float v = 0.0f;
3775 for (int h = 0; h < hidden_dim; ++h) {
3776 v += expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] * x[h];
3777 }
3778 pre[i] = v;
3779 act[i] = (v > 0.0f) ? v * v : 0.0f;
3780 d_act[i] = 0.0f;
3781 }
3782
3783 for (int h = 0; h < hidden_dim; ++h) {
3784 float v = 0.0f;
3785 for (int i = 0; i < intermediate_dim; ++i) {
3786 v += expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)] * act[i];
3787 }
3788 expert_out[h] = v;
3789 }
3790
3791 float d_route = 0.0f;
3792 for (int h = 0; h < hidden_dim; ++h) {
3793 const float d_expert_out = dy[h] * route_w;
3794 d_route += dy[h] * expert_out[h];
3795 for (int i = 0; i < intermediate_dim; ++i) {
3796 d_expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)] += d_expert_out * act[i];
3797 d_act[i] += d_expert_out * expert_down[ck_moe_down_idx(e, h, i, hidden_dim, intermediate_dim)];
3798 }
3799 }
3800 d_routing_weights[(size_t)r * (size_t)top_k + (size_t)slot] += d_route;
3801
3802 for (int i = 0; i < intermediate_dim; ++i) {
3803 d_pre[i] = (pre[i] > 0.0f) ? d_act[i] * 2.0f * pre[i] : 0.0f;
3804 }
3805
3806 for (int i = 0; i < intermediate_dim; ++i) {
3807 const float dpi = d_pre[i];
3808 for (int h = 0; h < hidden_dim; ++h) {
3809 d_expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)] += dpi * x[h];
3810 dx[h] += dpi * expert_up[ck_moe_up_idx(e, i, h, intermediate_dim, hidden_dim)];
3811 }
3812 }
3813 }
3814 }
3815}
static float ck_moe_silu_f32(float x)
void axpy_f32(float *y, const float *x, float alpha, int n)
In-place AXPY: y += alpha * x.
size_t moe_swiglu_expert_q4k_q5k_workspace_bytes(int hidden_dim, int intermediate_dim)
static void ck_moe_q4k_q5k_route_work(int ith, int nth, void *opaque)
void moe_accumulate_expert_f32(float *output, const float *expert_output, float routing_weight, int hidden_dim)
Accumulate expert output: output += routing_weight * expert_output.
static int ck_moe_q4k_mixed_route_parallel(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes, size_t workspace_stride, ck_threadpool_t *pool, ck_moe_down_kind_t down_kind)
static void ck_moe_q4k_q5k_parallel_work(int ith, int nth, void *opaque)
static size_t ck_moe_align64(size_t value)
static float ck_moe_bf16_round(float x)
static int ck_moe_debug_enabled(void)
static size_t ck_moe_up_idx(int e, int i, int h, int intermediate_dim, int hidden_dim)
int(* ck_moe_shared_workspace_fn)(const float *, const float *, const void *, const void *, const void *, float *, int, int, int, void *, size_t)
void moe_swiglu_shared_forward_bf16(const float *hidden, const float *routed, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim)
void moe_relu2_expert_forward_q5_0_q8_0(const float *hidden, const int *indices, const float *routing_weights, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
static size_t ck_moe_down_idx(int e, int h, int i, int hidden_dim, int intermediate_dim)
int moe_swiglu_expert_forward_q4k_q8_0_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
void moe_swiglu_shared_forward_f32(const float *hidden, const float *routed, const float *shared_gate, const float *shared_up, const float *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim)
static void ck_moe_q4k_llama_projection(float *output, const void *weights, const void *input_q8, int output_dim, int input_dim, void *scratch)
void gemm_q5_k_q8_k_compact_rows4(float *output, int output_stride, const void *weights, const void *const input_rows[4], int rows, int output_dim, int input_dim)
void axpy_zero_f32(float *y, const float *x, float alpha, int n)
Zero output then accumulate: y = 0; y += alpha * x.
int moe_swiglu_shared_forward_q8_0_gated_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
void moe_swiglu_shared_forward_bf16_row_range(const float *hidden, const float *routed, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, int row_begin, int row_end)
void moe_swiglu_shared_backward_f32(const float *d_output, const float *hidden, const float *shared_gate, const float *shared_up, const float *shared_down, float *d_hidden, float *d_routed, float *d_shared_gate, float *d_shared_up, float *d_shared_down, int rows, int hidden_dim, int intermediate_dim)
static int ck_moe_size_mul(size_t a, size_t b, size_t *result)
void pack_q4_k_to_packed_meta_x8(const void *source, void *destination, int output_dim, int input_dim)
void moe_swiglu_expert_forward_bf16(const float *hidden, const int *indices, const float *routing_weights, const uint16_t *expert_gate, const uint16_t *expert_up, const uint16_t *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
static void ck_moe_q4k_mixed_parallel_work(int ith, int nth, void *opaque)
void moe_relu2_expert_backward_f32(const float *d_output, const float *hidden, const int *indices, const float *routing_weights, const float *expert_up, const float *expert_down, float *d_hidden, float *d_routing_weights, float *d_expert_up, float *d_expert_down, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
int moe_swiglu_expert_forward_q4k_q4k_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
int moe_swiglu_shared_forward_q4k_q6k_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
int moe_swiglu_expert_forward_q4k_q8_0_parallel_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
int moe_swiglu_expert_forward_q4k_q5_0_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
static float ck_moe_dsilu_f32(float x)
static void ck_moe_shared_q4k_parallel_work(int ith, int nth, void *opaque)
int moe_swiglu_expert_forward_q4k_q5k_parallel_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
void moe_swiglu_shared_forward_bf16_gated(const float *hidden, const float *routed, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, const uint16_t *shared_router, float *output, int rows, int hidden_dim, int intermediate_dim)
void moe_relu2_expert_forward_f32(const float *hidden, const int *indices, const float *routing_weights, const float *expert_up, const float *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
void gemm_q4_k_q8_k_packed_vnni_x8_compact_order_rows4(float *output, const void *weights_packed, const void *input_q8, int rows, int output_dim, int input_dim)
static int ck_moe_q4k_mixed_parallel_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes, ck_moe_expert_workspace_fn serial_fn, ck_moe_down_kind_t down_kind)
void weighted_sum_f32(float *y, const float **vectors, const float *weights, int k, int n)
Weighted sum of k vectors: y = sum_i(weights[i] * vectors[i])
size_t q4_k_packed_meta_x8_block_size(void)
static int ck_moe_shared_gated_parallel_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes, size_t stride, ck_moe_shared_gated_workspace_fn serial_fn)
void gemm_nt_q4_k_q8_k_pairwise_split_min_parallel_dispatch(const void *input, const void *weight, const float *bias, float *output, int rows, int output_dim, int input_dim)
int moe_swiglu_expert_forward_q4k_q4k_parallel_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
void moe_swiglu_shared_forward_bf16_gated_row_range(const float *hidden, const float *routed, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, const uint16_t *shared_router, float *output, int rows, int hidden_dim, int intermediate_dim, int row_begin, int row_end)
static int ck_moe_bucket_expert_for_position(const int *offsets, int n_experts, int position)
static int ck_moe_swiglu_expert_forward_q4k_q5k_bucketed_impl(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, const void *expert_gate_packed, const void *expert_up_packed, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
int moe_swiglu_expert_forward_q4k_q5_0_parallel_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
void axpy_2d_f32(float *Y, const float *X, float alpha, int num_tokens, int dim, int y_stride, int x_stride)
Batched AXPY for 2D tensors: Y[t,:] += alpha * X[t,:].
void moe_swiglu_expert_forward_bf16_row_range(const float *hidden, const int *indices, const float *routing_weights, const uint16_t *expert_gate, const uint16_t *expert_up, const uint16_t *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, int row_begin, int row_end)
size_t moe_swiglu_shared_q8_0_gated_workspace_bytes(int hidden_dim, int intermediate_dim)
void moe_relu2_shared_forward_q5_1_q8_0(const float *hidden, const float *routed, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim)
static void ck_moe_llama_weighted_accumulate(float *output, const float *expert_output, float route_weight, int n)
void moe_relu2_expert_forward_q5_0_q5_0(const float *hidden, const int *indices, const float *routing_weights, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
static int ck_moe_size_add(size_t a, size_t b, size_t *result)
size_t q4_k_packed_vnni_x8_block_size(void)
static size_t ck_moe_q4k_llama_projection_scratch_bytes(int output_dim, int input_dim)
int moe_swiglu_expert_forward_q4k_q5k_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
int moe_swiglu_shared_forward_q8_0_gated_parallel_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
int moe_swiglu_shared_forward_q4k_q4k_parallel_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
static void ck_moe_shared_q8_0_parallel_work(int ith, int nth, void *opaque)
static int ck_moe_shared_q4k_parallel_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes, ck_moe_shared_workspace_fn serial_fn)
static void ck_moe_q4k_q5k_bucket_work(int ith, int nth, void *opaque)
static int ck_moe_shared_q4k_gated_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes, void(*down_projection)(float *, const void *, const void *, int, int))
int moe_swiglu_expert_forward_q4k_q5k_bucketed_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
static int ck_moe_q4k_q5k_route_parallel(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes, size_t workspace_stride, ck_threadpool_t *pool)
int(* ck_moe_expert_workspace_fn)(const float *, const int *, const float *, const void *, const void *, const void *, float *, int, int, int, int, int, void *, size_t)
void gemm_nt_q4_k_packed_meta_x8_q8_k_gemv_order(const void *input, const void *packed_weight, const float *bias, float *output, int rows, int output_dim, int input_dim)
static void ck_moe_debug_finite(const char *name, const float *x, size_t n)
int moe_swiglu_expert_forward_q4k_q5k_auto_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
size_t moe_swiglu_expert_q4k_q8_0_workspace_bytes(int hidden_dim, int intermediate_dim)
size_t moe_swiglu_shared_q4k_q8_0_gated_workspace_bytes(int hidden_dim, int intermediate_dim)
@ CK_MOE_Q4K_Q5K_TASK_ROWS
void farskip_swiglu_shared_combine_bf16(const float *hidden, const float *routed, const float *post_attn_residual, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, float *main_output, float *routed_free_output, int rows, int hidden_dim, int intermediate_dim)
void farskip_swiglu_shared_combine_bf16_row_range(const float *hidden, const float *routed, const float *post_attn_residual, const uint16_t *shared_gate, const uint16_t *shared_up, const uint16_t *shared_down, float *main_output, float *routed_free_output, int rows, int hidden_dim, int intermediate_dim, int row_begin, int row_end)
static void ck_moe_q4k_q5k_quantize_work(int ith, int nth, void *opaque)
int moe_swiglu_shared_forward_q4k_q5_0_gated_parallel_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
int moe_swiglu_shared_forward_q4k_q5_0_gated_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
static float ck_moe_sigmoid_f32(float x)
size_t moe_swiglu_expert_q4k_q5k_bucketed_workspace_bytes(int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
int moe_swiglu_shared_forward_q4k_q4k_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
void moe_swiglu_expert_forward_f32(const float *hidden, const int *indices, const float *routing_weights, const float *expert_gate, const float *expert_up, const float *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
static int ck_moe_bucket_layout(int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, ck_moe_q4k_q5k_bucket_layout_t *layout)
void moe_swiglu_packed_expert_forward_bf16(const float *hidden, const int *indices, const float *routing_weights, const uint16_t *expert_gate_up, const uint16_t *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
int moe_swiglu_shared_forward_q4k_q8_0_gated_parallel_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
int moe_swiglu_expert_forward_q4k_q6k_parallel_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
void gemm_q4_k_q8_k_compact_rows4(float *output, int output_stride, const void *weights, const void *const input_rows[4], int rows, int output_dim, int input_dim)
void moe_swiglu_expert_backward_f32(const float *d_output, const float *hidden, const int *indices, const float *routing_weights, const float *expert_gate, const float *expert_up, const float *expert_down, float *d_hidden, float *d_routing_weights, float *d_expert_gate, float *d_expert_up, float *d_expert_down, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k)
int moe_swiglu_shared_forward_q4k_q6k_parallel_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
int moe_swiglu_expert_forward_q4k_q5k_bucketed_prepared_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, const void *expert_gate_packed, const void *expert_up_packed, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
static void ck_moe_q4k_mixed_route_work(int ith, int nth, void *opaque)
int(* ck_moe_shared_gated_workspace_fn)(const float *, const float *, const void *, const void *, const void *, const float *, float *, int, int, int, void *, size_t)
void scal_copy_f32(float *y, const float *x, float alpha, int n)
Scaled copy: y = alpha * x.
int moe_swiglu_expert_forward_q4k_q6k_workspace(const float *hidden, const int *indices, const float *routing_weights, const void *expert_gate, const void *expert_up, const void *expert_down, float *output, int rows, int hidden_dim, int intermediate_dim, int n_experts, int top_k, void *workspace, size_t workspace_bytes)
int moe_swiglu_shared_forward_q4k_q8_0_gated_workspace(const float *hidden, const float *routed, const void *shared_gate, const void *shared_up, const void *shared_down, const float *shared_gate_input, float *output, int rows, int hidden_dim, int intermediate_dim, void *workspace, size_t workspace_bytes)
ck_moe_down_kind_t
@ CK_MOE_DOWN_Q4_K
@ CK_MOE_DOWN_Q5_0
@ CK_MOE_DOWN_Q8_0
@ CK_MOE_DOWN_Q6_K
static uint16_t float_to_bf16(float f)
Definition bf16_utils.h:90
static float bf16_to_float(uint16_t v)
Definition bf16_utils.h:38
int main(int argc, char **argv)
Definition ck_cli_v5.c:110
Persistent pthread thread pool for CK-Engine inference.
#define CK_THREADPOOL_MAX_THREADS
void ck_threadpool_dispatch_n(ck_threadpool_t *pool, int active_threads, ck_work_fn_t fn, void *args)
ck_threadpool_t * ck_threadpool_global(void)
int ck_threadpool_n_threads(const ck_threadpool_t *pool)
@ CK_DT_Q4_K
@ CK_DT_Q8_0
@ CK_DT_Q8_K
@ CK_DT_Q5_0
@ CK_DT_Q5_K
@ CK_DT_Q6_K
@ 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 swiglu_forward_pytorch_bf16_storage(const float *input, float *output, int tokens, int dim)
void dequant_q5_0_row(const void *src, float *dst, size_t n_elements)
Dequantize Q5_0 row (multiple blocks)
void gemv_q5_0_q8_0(float *y, const void *W, const void *x_q8, int M, int K)
Matrix-vector multiply with Q5_0 weights and Q8_0 input.
void gemv_q5_k_q8_k(float *y, const void *W, const void *x_q8, int M, int K)
void gemv_q6_k_q8_k(float *y, const void *W, const void *x_q8, int M, int K)
GEMV: y = W @ x where W is Q6_K and x is Q8_K.
void quantize_row_q8_k(const float *x, void *y, int k)
void dequant_q8_0_row(const void *src, float *dst, size_t n_elements)
Dequantize Q8_0 row (multiple blocks)
void quantize_row_q8_0(const float *x, void *y, int k)
Quantize FP32 to Q8_0 format (scalar reference)
void gemv_q8_0_q8_0(float *y, const void *W, const void *x_q8, int M, int K)
Matrix-vector multiply with Q8_0 weights and Q8_0 input.
void gemv_q4_k_q8_k(float *y, const void *W, const void *x_q8, int M, int K)
void dequant_q5_1_row(const void *src, float *dst, size_t n_elements)
Dequantize Q5_1 row (multiple blocks)
void swiglu_forward_ggml(const float *input, float *output, int tokens, int dim)
void swiglu_forward_ggml_split(const float *gate, const float *up, float *output, int tokens, int dim)
void gemm_nt_f32_llama_production(const float *A, const float *B, const float *bias, float *C, int M, int N, int K)
#define QK8_0
int const int32_t * offsets
Definition true_bpe.h:198
uint32_t end
Definition utf8.c:215
static void silu(float *x, int n)