char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Aaron Teoggml-cpu(s390x): add repack support for q4_0 (#28667)4ea6d1bb6

char/aliceai-t5-moe
191.5 KiB4841 linesraw
1#define GGML_COMMON_IMPL_CPP
2#define GGML_COMMON_DECL_CPP
3#include "ggml-common.h"
4#include "ggml-backend-impl.h"
5
6#include "ggml-impl.h"
7#include "ggml-cpu.h"
8#include "ggml-cpu-impl.h"
9#include "simd-mappings.h"
10#include "traits.h"
11
12#include "arch-fallback.h"
13
14#include <cmath>
15#include <cstring>
16#include <cassert>
17#include <cstdio>  // for GGML_ASSERT
18
19#include "repack.h"
20
21#if defined(__GNUC__)
22#pragma GCC diagnostic ignored "-Woverlength-strings"
23#endif
24
25#define UNUSED GGML_UNUSED
26
27static inline int nearest_int(float fval) {
28    assert(fabsf(fval) <= 4194303.f);
29    float val = fval + 12582912.f;
30    int i; memcpy(&i, &val, sizeof(int));
31    return (i & 0x007fffff) - 0x00400000;
32}
33
34// Functions to create the interleaved data layout formats
35
36// interleave 4 block_q4_0s in blocks of blck_size_interleave
37// returns an interleaved block_q4_0x4
38// in the interleaved block_q4_0x4, place deltas for 4 block_q4_0 blocks
39// first, then interleave quants from 4 block_q4_0s in blocks of blck_size_interleave
40//
41// - in                  : an array of block_q4_0 pointers
42// - blck_size_interleave : the block_q4_0 quants bytes are interleaved in blocks of
43//                         blck_size_interleave bytes
44// - xor_mask            : the mask to convert the nibbles in block_q4_0 quants bytes
45//                         from bias offset form to pure sign form (this saves subtract
46//                         operations durin unpacking)
47//
48
49extern "C" {
50
51#if defined __riscv_zvfh
52void ggml_quantize_mat_q8_0_4x1_generic(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t k) {
53    assert(QK8_0 == 32);
54    assert(k % QK8_0 == 0);
55    const int nb = k / QK8_0;
56
57    block_q8_0x4 * GGML_RESTRICT y = (block_q8_0x4 *) vy;
58
59    // scalar
60    const int blck_size_interleave = 1;
61    float srcv[4][QK8_0];
62    float id[4];
63
64    for (int i = 0; i < nb; i++) {
65        for (int row_iter = 0; row_iter < 4; row_iter++) {
66            float amax = 0.0f; // absolute max
67
68            for (int j = 0; j < QK8_0; j++) {
69                srcv[row_iter][j] = x[row_iter * k + i * QK8_0 + j];
70                amax = MAX(amax, fabsf(srcv[row_iter][j]));
71            }
72
73            const float d = amax / ((1 << 7) - 1);
74            id[row_iter] = d ? 1.0f / d : 0.0f;
75
76            y[i].d[row_iter] = GGML_CPU_FP32_TO_FP16(d);
77        }
78
79        for (int j = 0; j < QK8_0 * 4; j++) {
80            int src_offset = (j / (4 * blck_size_interleave)) * blck_size_interleave;
81            int src_id = (j % (4 * blck_size_interleave)) / blck_size_interleave;
82            src_offset += (j % blck_size_interleave);
83
84            float x0 = srcv[src_id][src_offset] * id[src_id];
85            y[i].qs[j] = roundf(x0);
86        }
87    }
88}
89
90void ggml_quantize_mat_q8_K_4x1_generic(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t k) {
91    assert(QK_K == 256);
92    assert(k % QK_K == 0);
93    const int nb = k / QK_K;
94
95    block_q8_Kx4 * GGML_RESTRICT y = (block_q8_Kx4 *) vy;
96
97    const int blck_size_interleave = 1;
98    float srcv[4][QK_K];
99    float iscale[4];
100
101    for (int i = 0; i < nb; i++) {
102        for (int row_iter = 0; row_iter < 4; row_iter++) {
103            float amax = 0.0f; // absolute max
104            float max = 0;
105
106            for (int j = 0; j < QK_K; j++) {
107                srcv[row_iter][j] = x[row_iter * k + i * QK_K + j];
108                // Update the maximum value of the corresponding super block
109                if(amax < fabsf(srcv[row_iter][j])) {
110                    amax = fabsf(srcv[row_iter][j]);
111                    max = srcv[row_iter][j];
112                }
113            }
114
115            iscale[row_iter] = amax ? -127.f/max : 0;
116            y[i].d[row_iter] = amax ? 1/iscale[row_iter] : 0;
117        }
118
119        for (int j = 0; j < QK_K / 4; j++) {
120            y[i].bsums[j] = 0;
121        }
122        for (int j = 0; j < QK_K * 4; j++) {
123            int src_id = j % 4;
124            int src_offset = j / 4;
125            int index = ((j >> 6) << 2) + (j & 3);
126
127            float x0 = srcv[src_id][src_offset] * iscale[src_id];
128            y[i].qs[j] = nearest_int(x0);
129            y[i].bsums[index] += y[i].qs[j];
130        }
131    }
132}
133#endif
134
135void ggml_quantize_mat_q8_0_4x4_generic(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t k) {
136    assert(QK8_0 == 32);
137    assert(k % QK8_0 == 0);
138    const int nb = k / QK8_0;
139
140    block_q8_0x4 * GGML_RESTRICT y = (block_q8_0x4 *) vy;
141
142    // scalar
143    const int blck_size_interleave = 4;
144    float srcv[4][QK8_0];
145    float id[4];
146
147    for (int i = 0; i < nb; i++) {
148        for (int row_iter = 0; row_iter < 4; row_iter++) {
149            float amax = 0.0f; // absolute max
150
151            for (int j = 0; j < QK8_0; j++) {
152                srcv[row_iter][j] = x[row_iter * k + i * QK8_0 + j];
153                amax = MAX(amax, fabsf(srcv[row_iter][j]));
154            }
155
156            const float d = amax / ((1 << 7) - 1);
157            id[row_iter] = d ? 1.0f / d : 0.0f;
158
159            y[i].d[row_iter] = GGML_CPU_FP32_TO_FP16(d);
160        }
161
162        for (int j = 0; j < QK8_0 * 4; j++) {
163            int src_offset = (j / (4 * blck_size_interleave)) * blck_size_interleave;
164            int src_id = (j % (4 * blck_size_interleave)) / blck_size_interleave;
165            src_offset += (j % blck_size_interleave);
166
167            float x0 = srcv[src_id][src_offset] * id[src_id];
168            y[i].qs[j] = roundf(x0);
169        }
170    }
171}
172
173void ggml_quantize_mat_q8_0_4x8_generic(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t k) {
174    assert(QK8_0 == 32);
175    assert(k % QK8_0 == 0);
176    const int nb = k / QK8_0;
177
178    block_q8_0x4 * GGML_RESTRICT y = (block_q8_0x4 *) vy;
179
180    // scalar
181    const int blck_size_interleave = 8;
182    float srcv[4][QK8_0];
183    float id[4];
184
185    for (int i = 0; i < nb; i++) {
186        for (int row_iter = 0; row_iter < 4; row_iter++) {
187            float amax = 0.0f; // absolute max
188
189            for (int j = 0; j < QK8_0; j++) {
190                srcv[row_iter][j] = x[row_iter * k + i * QK8_0 + j];
191                amax = MAX(amax, fabsf(srcv[row_iter][j]));
192            }
193
194            const float d = amax / ((1 << 7) - 1);
195            id[row_iter] = d ? 1.0f / d : 0.0f;
196
197            y[i].d[row_iter] = GGML_CPU_FP32_TO_FP16(d);
198        }
199
200        for (int j = 0; j < QK8_0 * 4; j++) {
201            int src_offset = (j / (4 * blck_size_interleave)) * blck_size_interleave;
202            int src_id = (j % (4 * blck_size_interleave)) / blck_size_interleave;
203            src_offset += (j % blck_size_interleave);
204
205            float x0 = srcv[src_id][src_offset] * id[src_id];
206            y[i].qs[j] = roundf(x0);
207        }
208    }
209}
210
211void ggml_quantize_mat_q8_K_4x4_generic(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t k) {
212    assert(QK_K == 256);
213    assert(k % QK_K == 0);
214    const int nb = k / QK_K;
215
216    block_q8_Kx4 * GGML_RESTRICT y = (block_q8_Kx4 *) vy;
217
218    // scalar
219    const int blck_size_interleave = 4;
220    float srcv[4][QK_K];
221    float iscale[4];
222
223    for (int i = 0; i < nb; i++) {
224        for (int row_iter = 0; row_iter < 4; row_iter++) {
225            float amax = 0.0f; // absolute max
226            float max = 0;
227
228            for (int j = 0; j < QK_K; j++) {
229                srcv[row_iter][j] = x[row_iter * k + i * QK_K + j];
230                // Update the maximum value of the corresponding super block
231                if(amax < fabsf(srcv[row_iter][j])) {
232                    amax = fabsf(srcv[row_iter][j]);
233                    max = srcv[row_iter][j];
234                }
235            }
236
237            iscale[row_iter] = amax ? -127.f/max : 0;
238
239            y[i].d[row_iter] = amax ? 1/iscale[row_iter] : 0;
240        }
241
242        for (int j = 0; j < QK_K / 4; j++) {
243            y[i].bsums[j] = 0;
244        }
245
246        // Quants values are interleaved in sequence of four bytes from corresponding super blocks
247        // Bsums values are interleaved in sequence of four bsums from each super block taken for interleaving
248        // i.e first four bsums from the first super block, followed by first four bsums from second super block and so on
249        for (int j = 0; j < QK_K * 4; j++) {
250            int src_offset = (j / (4 * blck_size_interleave)) * blck_size_interleave;
251            int src_id     = (j % (4 * blck_size_interleave)) / blck_size_interleave;
252            src_offset += (j % blck_size_interleave);
253            int index = (((j & 15) >> 2) << 2) + ((j >> 8) << 4) + ((j >> 6) & 3);
254
255            float x0 = srcv[src_id][src_offset] * iscale[src_id];
256            y[i].qs[j] = nearest_int(x0);
257            y[i].bsums[index] += y[i].qs[j];
258        }
259    }
260}
261
262void ggml_quantize_mat_q8_K_4x8_generic(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t k) {
263    assert(QK_K == 256);
264    assert(k % QK_K == 0);
265    const int nb = k / QK_K;
266
267    block_q8_Kx4 * GGML_RESTRICT y = (block_q8_Kx4 *) vy;
268
269    // scalar
270    const int blck_size_interleave = 8;
271    float srcv[4][QK_K];
272    float iscale[4];
273
274    for (int i = 0; i < nb; i++) {
275        for (int row_iter = 0; row_iter < 4; row_iter++) {
276            float amax = 0.0f; // absolute max
277            float max = 0;
278
279            for (int j = 0; j < QK_K; j++) {
280                srcv[row_iter][j] = x[row_iter * k + i * QK_K + j];
281                // Update the maximum value of the corresponding super block
282                if(amax < fabsf(srcv[row_iter][j])) {
283                    amax = fabsf(srcv[row_iter][j]);
284                    max = srcv[row_iter][j];
285                }
286            }
287
288            iscale[row_iter] = amax ? -127.f/max : 0;
289
290            y[i].d[row_iter] = amax ? 1/iscale[row_iter] : 0;
291        }
292
293        for (int j = 0; j < QK_K / 4; j++) {
294            y[i].bsums[j] = 0;
295        }
296
297        // Quants values are interleaved in sequence of eight bytes from corresponding super blocks
298        // Bsums values are interleaved in sequence of four bsums from each super block taken for interleaving
299        // i.e first four bsums from the first super block, followed by first four bsums from second super block and so on
300        for (int j = 0; j < QK_K * 4; j++) {
301            int src_offset = (j / (4 * blck_size_interleave)) * blck_size_interleave;
302            int src_id     = (j % (4 * blck_size_interleave)) / blck_size_interleave;
303            src_offset += (j % blck_size_interleave);
304            int index = (((j & 31) >> 3) << 2) + ((j >> 8) << 4) + ((j >> 6) & 3);
305
306            float x0 = srcv[src_id][src_offset] * iscale[src_id];
307            y[i].qs[j] = nearest_int(x0);
308            y[i].bsums[index] += y[i].qs[j];
309        }
310    }
311}
312
313} // extern "C"
314
315template <int64_t INTER_SIZE, ggml_type PARAM_TYPE>
316void ggml_quantize_mat_t(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t nrow, int64_t n_per_row);
317
318template <> void ggml_quantize_mat_t<4, GGML_TYPE_Q8_0>(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t nrow, int64_t n_per_row) {
319    assert(nrow == 4);
320    UNUSED(nrow);
321    ggml_quantize_mat_q8_0_4x4(x, vy, n_per_row);
322}
323
324template <> void ggml_quantize_mat_t<8, GGML_TYPE_Q8_0>(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t nrow, int64_t n_per_row) {
325    assert(nrow == 4);
326    UNUSED(nrow);
327    ggml_quantize_mat_q8_0_4x8(x, vy, n_per_row);
328}
329
330template <> void ggml_quantize_mat_t<4, GGML_TYPE_Q8_K>(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t nrow, int64_t n_per_row) {
331    assert(nrow == 4);
332    UNUSED(nrow);
333    ggml_quantize_mat_q8_K_4x4(x, vy, n_per_row);
334}
335
336template <> void ggml_quantize_mat_t<8, GGML_TYPE_Q8_K>(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t nrow, int64_t n_per_row) {
337    assert(nrow == 4);
338    UNUSED(nrow);
339    ggml_quantize_mat_q8_K_4x8(x, vy, n_per_row);
340}
341
342#if defined __riscv_zvfh
343template <> void ggml_quantize_mat_t<1, GGML_TYPE_Q8_0>(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t nrow, int64_t n_per_row) {
344    assert(nrow == 4);
345    UNUSED(nrow);
346    ggml_quantize_mat_q8_0_4x1(x, vy, n_per_row);
347}
348
349template <> void ggml_quantize_mat_t<1, GGML_TYPE_Q8_K>(const float * GGML_RESTRICT x, void * GGML_RESTRICT vy, int64_t nrow, int64_t n_per_row) {
350    assert(nrow == 4);
351    UNUSED(nrow);
352    ggml_quantize_mat_q8_K_4x1(x, vy, n_per_row);
353}
354#endif
355
356template <int M, int N>
357static void ggml_gemv_q6_K_NxM_q8_K_generic_impl(int                        n,
358                                                 float * GGML_RESTRICT      s,
359                                                 size_t                     bs,
360                                                 const void * GGML_RESTRICT vx,
361                                                 const void * GGML_RESTRICT vy,
362                                                 int                        nr,
363                                                 int                        nc) {
364    constexpr int blocklen          = M;
365    constexpr int ncols_interleaved = N;
366    const int     qk                = QK_K;
367    const int     nb                = n / qk;
368    const int     blocks_per_half   = 64 / blocklen;
369
370    assert(n % qk == 0);
371    assert(nc % ncols_interleaved == 0);
372
373    UNUSED(bs);
374    UNUSED(nr);
375
376    float sumf[8];
377
378    const block_q8_K * a_ptr = (const block_q8_K *) vy;
379    for (int x = 0; x < nc / ncols_interleaved; x++) {
380        const block_q6_Kx8 * b_ptr = (const block_q6_Kx8 *) vx + (x * nb);
381
382        for (int j = 0; j < ncols_interleaved; j++) {
383            sumf[j] = 0.0f;
384        }
385
386        for (int l = 0; l < nb; l++) {
387            for (int k = 0; k < (qk / (2 * blocklen)); k++) {
388                const int base_l = (k / blocks_per_half) * 128 + (k % blocks_per_half) * blocklen;
389                const int base_h = base_l + 64;
390
391                const int scale_idx_l = base_l / 16;
392                const int scale_idx_h = base_h / 16;
393
394                const int qh_shift_l = ((base_l % 128) / 32) * 2;
395                const int qh_shift_h = ((base_h % 128) / 32) * 2;
396
397                const int qh_half_l = (base_l / 128) * 32;
398                const int qh_half_h = (base_h / 128) * 32;
399
400                for (int j = 0; j < ncols_interleaved; j++) {
401                    const int8_t scale_l = b_ptr[l].scales[scale_idx_l * ncols_interleaved + j];
402                    const int8_t scale_h = b_ptr[l].scales[scale_idx_h * ncols_interleaved + j];
403
404                    int sumi_l = 0;
405                    int sumi_h = 0;
406
407                    for (int i = 0; i < blocklen; i++) {
408                        const int ql_pos = k * ncols_interleaved * blocklen + j * blocklen + i;
409                        const int l_4    = b_ptr[l].ql[ql_pos] & 0xF;
410                        const int hi_4   = (b_ptr[l].ql[ql_pos] >> 4) & 0xF;
411
412                        const int qh_idx_l    = qh_half_l + ((base_l + i) % 32);
413                        const int qh_chunk_l  = qh_idx_l / blocklen;
414                        const int qh_pos_l    = qh_idx_l % blocklen;
415                        const int qh_offset_l = qh_chunk_l * (blocklen * ncols_interleaved) + j * blocklen + qh_pos_l;
416                        const int hi_2_l      = (b_ptr[l].qh[qh_offset_l] >> qh_shift_l) & 0x3;
417
418                        const int qh_idx_h    = qh_half_h + ((base_h + i) % 32);
419                        const int qh_chunk_h  = qh_idx_h / blocklen;
420                        const int qh_pos_h    = qh_idx_h % blocklen;
421                        const int qh_offset_h = qh_chunk_h * (blocklen * ncols_interleaved) + j * blocklen + qh_pos_h;
422                        const int hi_2_h      = (b_ptr[l].qh[qh_offset_h] >> qh_shift_h) & 0x3;
423
424                        const int q_l = ((hi_2_l << 4) | l_4) - 32;
425                        const int q_h = ((hi_2_h << 4) | hi_4) - 32;
426
427                        const int8_t a_l = a_ptr[l].qs[base_l + i];
428                        const int8_t a_h = a_ptr[l].qs[base_h + i];
429
430                        sumi_l += q_l * a_l;
431                        sumi_h += q_h * a_h;
432                    }
433
434                    sumf[j] +=
435                        (sumi_l * scale_l + sumi_h * scale_h) * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * a_ptr[l].d;
436                }
437            }
438        }
439
440        for (int j = 0; j < ncols_interleaved; j++) {
441            s[x * ncols_interleaved + j] = sumf[j];
442        }
443    }
444}
445
446template <int M, int N>
447static void ggml_gemm_q6_K_NxM_q8_K_generic_impl(int                        n,
448                                                 float * GGML_RESTRICT      s,
449                                                 size_t                     bs,
450                                                 const void * GGML_RESTRICT vx,
451                                                 const void * GGML_RESTRICT vy,
452                                                 int                        nr,
453                                                 int                        nc) {
454    constexpr int blocklen          = M;
455    constexpr int ncols_interleaved = N;
456    const int     qk                = QK_K;
457    const int     nb                = n / qk;
458    const int     blocks_per_half   = 64 / blocklen;
459    const int     q8_half_stride    = 512;
460    const int     q8_low_high_step  = 256;
461
462    assert(n % qk == 0);
463    assert(nr % 4 == 0);
464    assert(nc % ncols_interleaved == 0);
465
466    UNUSED(bs);
467
468    float sumf[4][8];
469
470    for (int y = 0; y < nr / 4; y++) {
471        const block_q8_Kx4 * a_ptr = (const block_q8_Kx4 *) vy + (y * nb);
472        for (int x = 0; x < nc / ncols_interleaved; x++) {
473            const block_q6_Kx8 * b_ptr = (const block_q6_Kx8 *) vx + (x * nb);
474
475            for (int m = 0; m < 4; m++) {
476                for (int j = 0; j < ncols_interleaved; j++) {
477                    sumf[m][j] = 0.0f;
478                }
479            }
480
481            for (int l = 0; l < nb; l++) {
482                for (int k = 0; k < (qk / (2 * blocklen)); k++) {
483                    const int base_l = (k / blocks_per_half) * 128 + (k % blocks_per_half) * blocklen;
484                    const int base_h = base_l + 64;
485
486                    const int scale_idx_l = base_l / 16;
487                    const int scale_idx_h = base_h / 16;
488
489                    const int qh_shift_l = ((base_l % 128) / 32) * 2;
490                    const int qh_shift_h = ((base_h % 128) / 32) * 2;
491
492                    const int qh_half_l = (base_l / 128) * 32;
493                    const int qh_half_h = (base_h / 128) * 32;
494
495                    const int q8_base = (k / blocks_per_half) * q8_half_stride + (k % blocks_per_half) * (blocklen * 4);
496
497                    for (int m = 0; m < 4; m++) {
498                        for (int j = 0; j < ncols_interleaved; j++) {
499                            const int8_t scale_l = b_ptr[l].scales[scale_idx_l * ncols_interleaved + j];
500                            const int8_t scale_h = b_ptr[l].scales[scale_idx_h * ncols_interleaved + j];
501
502                            int sumi_l = 0;
503                            int sumi_h = 0;
504
505                            for (int i = 0; i < blocklen; i++) {
506                                const int ql_pos = k * ncols_interleaved * blocklen + j * blocklen + i;
507                                const int l_4    = b_ptr[l].ql[ql_pos] & 0xF;
508                                const int hi_4   = (b_ptr[l].ql[ql_pos] >> 4) & 0xF;
509
510                                const int qh_idx_l   = qh_half_l + ((base_l + i) % 32);
511                                const int qh_chunk_l = qh_idx_l / blocklen;
512                                const int qh_pos_l   = qh_idx_l % blocklen;
513                                const int qh_offset_l =
514                                    qh_chunk_l * (blocklen * ncols_interleaved) + j * blocklen + qh_pos_l;
515                                const int hi_2_l = (b_ptr[l].qh[qh_offset_l] >> qh_shift_l) & 0x3;
516
517                                const int qh_idx_h   = qh_half_h + ((base_h + i) % 32);
518                                const int qh_chunk_h = qh_idx_h / blocklen;
519                                const int qh_pos_h   = qh_idx_h % blocklen;
520                                const int qh_offset_h =
521                                    qh_chunk_h * (blocklen * ncols_interleaved) + j * blocklen + qh_pos_h;
522                                const int hi_2_h = (b_ptr[l].qh[qh_offset_h] >> qh_shift_h) & 0x3;
523
524                                const int q_l = ((hi_2_l << 4) | l_4) - 32;
525                                const int q_h = ((hi_2_h << 4) | hi_4) - 32;
526
527                                const int8_t q8_l = a_ptr[l].qs[q8_base + m * blocklen + i];
528                                const int8_t q8_h = a_ptr[l].qs[q8_base + m * blocklen + i + q8_low_high_step];
529
530                                sumi_l += q_l * q8_l;
531                                sumi_h += q_h * q8_h;
532                            }
533
534                            sumf[m][j] += (sumi_l * scale_l + sumi_h * scale_h) * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) *
535                                          a_ptr[l].d[m];
536                        }
537                    }
538                }
539            }
540
541            for (int m = 0; m < 4; m++) {
542                for (int j = 0; j < ncols_interleaved; j++) {
543                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j];
544                }
545            }
546        }
547    }
548}
549
550template <int M, int N>
551static void ggml_gemv_q5_K_NxM_q8_K_generic_impl(int                        n,
552                                                 float * GGML_RESTRICT      s,
553                                                 size_t                     bs,
554                                                 const void * GGML_RESTRICT vx,
555                                                 const void * GGML_RESTRICT vy,
556                                                 int                        nr,
557                                                 int                        nc) {
558    constexpr int         blocklen          = M;
559    constexpr int         ncols_interleaved = N;
560    const int             qk                = QK_K;
561    const int             nb                = n / qk;
562    static const uint32_t kmask1            = 0x3f3f3f3f;
563    static const uint32_t kmask2            = 0x0f0f0f0f;
564    static const uint32_t kmask3            = 0x03030303;
565
566    assert(n % qk == 0);
567    assert(nc % ncols_interleaved == 0);
568
569    UNUSED(bs);
570    UNUSED(nr);
571
572    float    sumf[ncols_interleaved];
573    float    sum_minf[ncols_interleaved];
574    uint32_t utmp[32];
575    int      sumi1;
576    int      sumi2;
577    int      sumi;
578
579    const block_q8_K * a_ptr = (const block_q8_K *) vy;
580    for (int x = 0; x < nc / ncols_interleaved; x++) {
581        const block_q5_Kx8 * b_ptr = (const block_q5_Kx8 *) vx + (x * nb);
582
583        for (int j = 0; j < ncols_interleaved; j++) {
584            sumf[j]     = 0.0;
585            sum_minf[j] = 0.0;
586        }
587        for (int l = 0; l < nb; l++) {
588            for (int sb = 0; sb < 8; sb++) {
589                memcpy(utmp + sb * 4, b_ptr[l].scales + sb * K_SCALE_SIZE, K_SCALE_SIZE);
590                utmp[sb * 4 + 3]      = ((utmp[sb * 4 + 2] >> 4) & kmask2) | (((utmp[sb * 4 + 1] >> 6) & kmask3) << 4);
591                const uint32_t uaux_0 = utmp[sb * 4 + 1] & kmask1;
592                utmp[sb * 4 + 1]      = (utmp[sb * 4 + 2] & kmask2) | (((utmp[sb * 4 + 0] >> 6) & kmask3) << 4);
593                utmp[sb * 4 + 2]      = uaux_0;
594                utmp[sb * 4 + 0] &= kmask1;
595            }
596            for (int k = 0; k < (qk / (2 * blocklen)); k++) {
597                constexpr int scale_stride = 32;
598                uint8_t *     scales_0     = (uint8_t *) utmp + (k / (32 / blocklen)) * scale_stride;
599                uint8_t *     scales_1     = (uint8_t *) utmp + (k / (32 / blocklen)) * scale_stride + 16;
600
601                const int qh_shift = (k / (32 / blocklen)) * 2;
602                for (int j = 0; j < ncols_interleaved; j++) {
603                    sumi1 = 0;
604                    sumi2 = 0;
605                    sumi  = 0;
606                    for (int i = 0; i < blocklen; ++i) {
607                        const int b_qs_offset = k * ncols_interleaved * blocklen + j * blocklen + i;
608
609                        const int qh_idx      = (k * blocklen + i) % 32;
610                        const int qh_chunk    = qh_idx / blocklen;
611                        const int qh_pos      = qh_idx % blocklen;
612                        const int b_qh_offset = qh_chunk * (blocklen * ncols_interleaved) + j * blocklen + qh_pos;
613
614                        const uint8_t qh_val = b_ptr[l].qh[b_qh_offset];
615                        const uint8_t h0     = (qh_val >> qh_shift) & 1;
616                        const uint8_t h1     = (qh_val >> (qh_shift + 1)) & 1;
617
618                        const int v0 = (int8_t) ((b_ptr[l].qs[b_qs_offset] & 0xF) | (h0 << 4));
619                        const int v1 = (int8_t) ((b_ptr[l].qs[b_qs_offset] >> 4) | (h1 << 4));
620
621                        const int q8_offset = (k / (32 / blocklen)) * 64 + (k % (32 / blocklen)) * blocklen + i;
622
623                        sumi1 = (v0 * a_ptr[l].qs[q8_offset]);
624                        sumi2 = (v1 * a_ptr[l].qs[q8_offset + 32]);
625                        sumi1 = sumi1 * scales_0[j];
626                        sumi2 = sumi2 * scales_1[j];
627                        sumi += sumi1 + sumi2;
628                    }
629                    sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * a_ptr[l].d;
630                }
631            }
632            for (int sb = 0; sb < 8; sb++) {
633                uint8_t * mins = (uint8_t *) utmp + 8 + sb * 16;
634                for (int j = 0; j < ncols_interleaved; j++) {
635                    sum_minf[j] += mins[j] * (a_ptr[l].bsums[sb * 2] + a_ptr[l].bsums[sb * 2 + 1]) *
636                                   GGML_CPU_FP16_TO_FP32(b_ptr[l].dmin[j]) * a_ptr[l].d;
637                }
638            }
639        }
640        for (int j = 0; j < ncols_interleaved; j++) {
641            s[x * ncols_interleaved + j] = sumf[j] - sum_minf[j];
642        }
643    }
644}
645
646template <int M, int N>
647static void ggml_gemm_q5_K_NxM_q8_K_generic_impl(int                        n,
648                                                 float * GGML_RESTRICT      s,
649                                                 size_t                     bs,
650                                                 const void * GGML_RESTRICT vx,
651                                                 const void * GGML_RESTRICT vy,
652                                                 int                        nr,
653                                                 int                        nc) {
654    constexpr int         blocklen          = M;
655    constexpr int         ncols_interleaved = N;
656    const int             qk                = QK_K;
657    const int             nb                = n / qk;
658    static const uint32_t kmask1            = 0x3f3f3f3f;
659    static const uint32_t kmask2            = 0x0f0f0f0f;
660    static const uint32_t kmask3            = 0x03030303;
661
662    assert(n % qk == 0);
663    assert(nr % 4 == 0);
664    assert(nc % ncols_interleaved == 0);
665
666    float    sumf[4][ncols_interleaved];
667    float    sum_minf[4][ncols_interleaved];
668    uint32_t utmp[32];
669    int      sumi1;
670    int      sumi2;
671    int      sumi;
672
673    for (int y = 0; y < nr / 4; y++) {
674        const block_q8_Kx4 * a_ptr = (const block_q8_Kx4 *) vy + (y * nb);
675        for (int x = 0; x < nc / ncols_interleaved; x++) {
676            const block_q5_Kx8 * b_ptr = (const block_q5_Kx8 *) vx + (x * nb);
677            for (int m = 0; m < 4; m++) {
678                for (int j = 0; j < ncols_interleaved; j++) {
679                    sumf[m][j]     = 0.0;
680                    sum_minf[m][j] = 0.0;
681                }
682            }
683            for (int l = 0; l < nb; l++) {
684                for (int sb = 0; sb < 8; sb++) {
685                    memcpy(utmp + sb * 4, b_ptr[l].scales + sb * K_SCALE_SIZE, K_SCALE_SIZE);
686                    utmp[sb * 4 + 3] = ((utmp[sb * 4 + 2] >> 4) & kmask2) | (((utmp[sb * 4 + 1] >> 6) & kmask3) << 4);
687                    const uint32_t uaux_0 = utmp[sb * 4 + 1] & kmask1;
688                    utmp[sb * 4 + 1]      = (utmp[sb * 4 + 2] & kmask2) | (((utmp[sb * 4 + 0] >> 6) & kmask3) << 4);
689                    utmp[sb * 4 + 2]      = uaux_0;
690                    utmp[sb * 4 + 0] &= kmask1;
691                }
692                for (int k = 0; k < (qk / (2 * blocklen)); k++) {
693                    constexpr int scale_stride = 32;
694                    uint8_t *     scales_0     = (uint8_t *) utmp + (k / (32 / blocklen)) * scale_stride;
695                    uint8_t *     scales_1     = (uint8_t *) utmp + (k / (32 / blocklen)) * scale_stride + 16;
696
697                    const int qh_shift = (k / (32 / blocklen)) * 2;
698                    for (int m = 0; m < 4; m++) {
699                        for (int j = 0; j < ncols_interleaved; j++) {
700                            sumi1 = 0;
701                            sumi2 = 0;
702                            sumi  = 0;
703                            for (int i = 0; i < blocklen; ++i) {
704                                const int b_qs_offset = k * ncols_interleaved * blocklen + j * blocklen + i;
705
706                                const int qh_idx   = (k * blocklen + i) % 32;
707                                const int qh_chunk = qh_idx / blocklen;
708                                const int qh_pos   = qh_idx % blocklen;
709                                const int b_qh_offset =
710                                    qh_chunk * (blocklen * ncols_interleaved) + j * blocklen + qh_pos;
711
712                                const uint8_t qh_val = b_ptr[l].qh[b_qh_offset];
713                                const uint8_t h0     = (qh_val >> qh_shift) & 1;
714                                const uint8_t h1     = (qh_val >> (qh_shift + 1)) & 1;
715
716                                const int v0 = (int8_t) ((b_ptr[l].qs[b_qs_offset] & 0xF) | (h0 << 4));
717                                const int v1 = (int8_t) ((b_ptr[l].qs[b_qs_offset] >> 4) | (h1 << 4));
718
719                                const int q8_offset = (k / (32 / blocklen)) * 256 +
720                                                      (k % (32 / blocklen)) * 4 * blocklen + m * blocklen + i;
721
722                                sumi1 = (v0 * a_ptr[l].qs[q8_offset]);
723                                sumi2 = (v1 * a_ptr[l].qs[q8_offset + 128]);
724                                sumi1 = sumi1 * scales_0[j];
725                                sumi2 = sumi2 * scales_1[j];
726                                sumi += sumi1 + sumi2;
727                            }
728                            sumf[m][j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * a_ptr[l].d[m];
729                        }
730                    }
731                }
732                for (int sb = 0; sb < 8; sb++) {
733                    uint8_t * mins = (uint8_t *) utmp + 8 + sb * 16;
734                    for (int m = 0; m < 4; m++) {
735                        const int16_t * bsums = a_ptr[l].bsums + (sb * 8) + (m * 4) - ((sb % 2) * 6);
736                        for (int j = 0; j < ncols_interleaved; j++) {
737                            sum_minf[m][j] += mins[j] * (bsums[0] + bsums[1]) *
738                                              GGML_CPU_FP16_TO_FP32(b_ptr[l].dmin[j]) * a_ptr[l].d[m];
739                        }
740                    }
741                }
742            }
743            for (int m = 0; m < 4; m++) {
744                for (int j = 0; j < ncols_interleaved; j++) {
745                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j] - sum_minf[m][j];
746                }
747            }
748        }
749    }
750}
751
752extern "C" {
753
754void ggml_gemv_q4_0_4x4_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
755    const int qk = QK8_0;
756    const int nb = n / qk;
757    const int ncols_interleaved = 4;
758    const int blocklen = 4;
759
760    assert(nr == 1);
761    assert(n % qk == 0);
762    assert(nc % ncols_interleaved == 0);
763
764    UNUSED(s);
765    UNUSED(bs);
766    UNUSED(vx);
767    UNUSED(vy);
768    UNUSED(nr);
769    UNUSED(nc);
770    UNUSED(nb);
771    UNUSED(ncols_interleaved);
772    UNUSED(blocklen);
773
774    float sumf[4];
775    int sumi;
776
777    const block_q8_0 * a_ptr = (const block_q8_0 *) vy;
778    for (int x = 0; x < nc / ncols_interleaved; x++) {
779        const block_q4_0x4 * b_ptr = (const block_q4_0x4 *) vx + (x * nb);
780
781        for (int j = 0; j < ncols_interleaved; j++) sumf[j] = 0.0;
782        for (int l = 0; l < nb; l++) {
783            for (int k = 0; k < (qk / (2 * blocklen)); k++) {
784                for (int j = 0; j < ncols_interleaved; j++) {
785                    sumi = 0;
786                    for (int i = 0; i < blocklen; ++i) {
787                        const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] << 4);
788                        const int v1 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0xF0);
789                        sumi += ((v0 * a_ptr[l].qs[k * blocklen + i]) + (v1 * a_ptr[l].qs[k * blocklen + i + qk / 2])) >> 4;
790                    }
791                    sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d);
792                }
793            }
794        }
795        for (int j = 0; j < ncols_interleaved; j++) s[x * ncols_interleaved + j] = sumf[j];
796    }
797}
798
799void ggml_gemv_q4_0_4x8_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
800    const int qk = QK8_0;
801    const int nb = n / qk;
802    const int ncols_interleaved = 4;
803    const int blocklen = 8;
804
805    assert (n % qk == 0);
806    assert (nc % ncols_interleaved == 0);
807
808    UNUSED(s);
809    UNUSED(bs);
810    UNUSED(vx);
811    UNUSED(vy);
812    UNUSED(nr);
813    UNUSED(nc);
814    UNUSED(nb);
815    UNUSED(ncols_interleaved);
816    UNUSED(blocklen);
817
818    float sumf[4];
819    int sumi;
820
821    const block_q8_0 * a_ptr = (const block_q8_0 *) vy;
822    for (int x = 0; x < nc / ncols_interleaved; x++) {
823        const block_q4_0x4 * b_ptr = (const block_q4_0x4 *) vx + (x * nb);
824
825        for (int j = 0; j < ncols_interleaved; j++) sumf[j] = 0.0;
826        for (int l = 0; l < nb; l++) {
827            for (int k = 0; k < (qk / (2 * blocklen)); k++) {
828                for (int j = 0; j < ncols_interleaved; j++) {
829                    sumi = 0;
830                    for (int i = 0; i < blocklen; ++i) {
831                        const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] << 4);
832                        const int v1 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0xF0);
833                        sumi += ((v0 * a_ptr[l].qs[k * blocklen + i]) + (v1 * a_ptr[l].qs[k * blocklen + i + qk / 2])) >> 4;
834                    }
835                    sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d);
836                }
837            }
838        }
839        for (int j = 0; j < ncols_interleaved; j++) s[x * ncols_interleaved + j] = sumf[j];
840    }
841}
842
843void ggml_gemv_q4_0_8x8_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
844    const int qk = QK8_0;
845    const int nb = n / qk;
846    const int ncols_interleaved = 8;
847    const int blocklen = 8;
848
849    assert (n % qk == 0);
850    assert (nc % ncols_interleaved == 0);
851
852    UNUSED(s);
853    UNUSED(bs);
854    UNUSED(vx);
855    UNUSED(vy);
856    UNUSED(nr);
857    UNUSED(nc);
858    UNUSED(nb);
859    UNUSED(ncols_interleaved);
860    UNUSED(blocklen);
861
862    float sumf[8];
863    int sumi;
864
865    const block_q8_0 * a_ptr = (const block_q8_0 *) vy;
866    for (int x = 0; x < nc / ncols_interleaved; x++) {
867        const block_q4_0x8 * b_ptr = (const block_q4_0x8 *) vx + (x * nb);
868
869        for (int j = 0; j < ncols_interleaved; j++) sumf[j] = 0.0;
870        for (int l = 0; l < nb; l++) {
871            for (int k = 0; k < (qk / (2 * blocklen)); k++) {
872                for (int j = 0; j < ncols_interleaved; j++) {
873                    sumi = 0;
874                    for (int i = 0; i < blocklen; ++i) {
875                        const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] << 4);
876                        const int v1 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0xF0);
877                        sumi += ((v0 * a_ptr[l].qs[k * blocklen + i]) + (v1 * a_ptr[l].qs[k * blocklen + i + qk / 2])) >> 4;
878                    }
879                    sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d);
880                }
881            }
882        }
883        for (int j = 0; j < ncols_interleaved; j++) s[x * ncols_interleaved + j] = sumf[j];
884    }
885}
886
887void ggml_gemv_q4_K_8x4_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
888    const int qk = QK_K;
889    const int nb = n / qk;
890    const int ncols_interleaved = 8;
891    const int blocklen = 4;
892    static const uint32_t kmask1 = 0x3f3f3f3f;
893    static const uint32_t kmask2 = 0x0f0f0f0f;
894    static const uint32_t kmask3 = 0x03030303;
895
896    assert (n % qk == 0);
897    assert (nc % ncols_interleaved == 0);
898
899    UNUSED(bs);
900    UNUSED(nr);
901
902    float sumf[8];
903    float sum_minf[8];
904    uint32_t utmp[32];
905    int sumi1;
906    int sumi2;
907    int sumi;
908
909    const block_q8_K * a_ptr = (const block_q8_K *) vy;
910    for (int x = 0; x < nc / ncols_interleaved; x++) {
911        const block_q4_Kx8 * b_ptr = (const block_q4_Kx8 *) vx + (x * nb);
912
913        for (int j = 0; j < ncols_interleaved; j++) {
914            sumf[j] = 0.0;
915            sum_minf[j] = 0.0;
916        }
917        for (int l = 0; l < nb; l++) {
918            for (int sb = 0; sb < 8; sb++) {
919                memcpy(utmp + sb * 4, b_ptr[l].scales + sb * 12, 12);
920                utmp[sb * 4 + 3] = ((utmp[sb * 4 + 2] >> 4) & kmask2) | (((utmp[sb * 4 + 1] >> 6) & kmask3) << 4);
921                const uint32_t uaux_0 = utmp[sb * 4 + 1] & kmask1;
922                utmp[sb * 4 + 1] = (utmp[sb * 4 + 2] & kmask2) | (((utmp[sb * 4 + 0] >> 6) & kmask3) << 4);
923                utmp[sb * 4 + 2] = uaux_0;
924                utmp[sb * 4 + 0] &= kmask1;
925            }
926            for (int k = 0; k < (qk / (2 * blocklen)); k++) {
927                uint8_t * scales_0 = (uint8_t *) utmp + (k / 8) * 32;
928                uint8_t * scales_1 = (uint8_t *) utmp + (k / 8) * 32 + 16;
929                for (int j = 0; j < ncols_interleaved; j++) {
930                    sumi1 = 0;
931                    sumi2 = 0;
932                    sumi = 0;
933                    for (int i = 0; i < blocklen; ++i) {
934                        const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0xF);
935                        const int v1 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4);
936                        sumi1 = (v0 * a_ptr[l].qs[(k / 8) * 64 + (k % 8) * blocklen + i]);
937                        sumi2 = (v1 * a_ptr[l].qs[(k / 8) * 64 + (k % 8) * blocklen + i + 32]);
938                        sumi1 = sumi1 * scales_0[j];
939                        sumi2 = sumi2 * scales_1[j];
940                        sumi += sumi1 + sumi2;
941                    }
942                    sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * a_ptr[l].d;
943                }
944            }
945            for (int sb = 0; sb < 8; sb++) {
946                uint8_t * mins = (uint8_t *) utmp + 8 + sb * 16;
947                for (int j = 0; j < ncols_interleaved; j++) {
948                    sum_minf[j] += mins[j] * (a_ptr[l].bsums[sb * 2] + a_ptr[l].bsums[sb * 2 + 1]) * GGML_CPU_FP16_TO_FP32(b_ptr[l].dmin[j]) * a_ptr[l].d;
949                }
950            }
951        }
952        for (int j = 0; j < ncols_interleaved; j++) {
953            s[x * ncols_interleaved + j] = sumf[j] - sum_minf[j];
954        }
955    }
956}
957
958void ggml_gemv_q4_K_8x8_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
959    const int qk = QK_K;
960    const int nb = n / qk;
961    const int ncols_interleaved = 8;
962    const int blocklen = 8;
963    static const uint32_t kmask1 = 0x3f3f3f3f;
964    static const uint32_t kmask2 = 0x0f0f0f0f;
965    static const uint32_t kmask3 = 0x03030303;
966
967    assert (n % qk == 0);
968    assert (nc % ncols_interleaved == 0);
969
970    UNUSED(bs);
971    UNUSED(nr);
972
973    float sumf[8];
974    float sum_minf[8];
975    uint32_t utmp[32];
976    int sumi1;
977    int sumi2;
978    int sumi;
979
980    const block_q8_K * a_ptr = (const block_q8_K *) vy;
981    for (int x = 0; x < nc / ncols_interleaved; x++) {
982        const block_q4_Kx8 * b_ptr = (const block_q4_Kx8 *) vx + (x * nb);
983
984        for (int j = 0; j < ncols_interleaved; j++) {
985            sumf[j] = 0.0;
986            sum_minf[j] = 0.0;
987        }
988        for (int l = 0; l < nb; l++) {
989            for (int sb = 0; sb < 8; sb++) {
990                memcpy(utmp + sb * 4, b_ptr[l].scales + sb * 12, 12);
991                utmp[sb * 4 + 3] = ((utmp[sb * 4 + 2] >> 4) & kmask2) | (((utmp[sb * 4 + 1] >> 6) & kmask3) << 4);
992                const uint32_t uaux_0 = utmp[sb * 4 + 1] & kmask1;
993                utmp[sb * 4 + 1] = (utmp[sb * 4 + 2] & kmask2) | (((utmp[sb * 4 + 0] >> 6) & kmask3) << 4);
994                utmp[sb * 4 + 2] = uaux_0;
995                utmp[sb * 4 + 0] &= kmask1;
996            }
997            for (int k = 0; k < (qk / (2 * blocklen)); k++) {
998                uint8_t *scales_0 = (uint8_t*) utmp + (k / 4) * 32;
999                uint8_t *scales_1 = (uint8_t*) utmp + (k / 4) * 32 + 16;
1000                for (int j = 0; j < ncols_interleaved; j++) {
1001                    sumi1 = 0;
1002                    sumi2 = 0;
1003                    sumi = 0;
1004                    for (int i = 0; i < blocklen; ++i) {
1005                        const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0xF);
1006                        const int v1 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4);
1007                        sumi1 = (v0 * a_ptr[l].qs[(k >> 2) * 64 + (k % 4) * blocklen + i]);
1008                        sumi2 = (v1 * a_ptr[l].qs[(k >> 2) * 64 + (k % 4) * blocklen + i + 32]);
1009                        sumi1 = sumi1 * scales_0[j];
1010                        sumi2 = sumi2 * scales_1[j];
1011                        sumi += sumi1 + sumi2;
1012                    }
1013                    sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * a_ptr[l].d;
1014                }
1015            }
1016            for (int sb = 0; sb < 8; sb++) {
1017                uint8_t *mins = (uint8_t*) utmp + 8 + sb * 16;
1018                for (int j = 0; j < ncols_interleaved; j++) {
1019                    sum_minf[j] += mins[j] * (a_ptr[l].bsums[sb * 2] + a_ptr[l].bsums[sb * 2 + 1]) * GGML_CPU_FP16_TO_FP32(b_ptr[l].dmin[j]) * a_ptr[l].d;
1020                }
1021            }
1022        }
1023        for (int j = 0; j < ncols_interleaved; j++) {
1024            s[x * ncols_interleaved + j] = sumf[j] - sum_minf[j];
1025        }
1026    }
1027}
1028
1029void ggml_gemv_q2_K_8x8_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1030    const int qk = QK_K;
1031    const int nb = n / qk;
1032    const int ncols_interleaved = 8;
1033    const int blocklen = 8;
1034
1035    assert (n % qk == 0);
1036    assert (nc % ncols_interleaved == 0);
1037
1038    UNUSED(s);
1039    UNUSED(bs);
1040    UNUSED(vx);
1041    UNUSED(vy);
1042    UNUSED(nr);
1043    UNUSED(nc);
1044    UNUSED(nb);
1045    UNUSED(ncols_interleaved);
1046    UNUSED(blocklen);
1047
1048    float sumf[8];
1049    float sum_minf[8];
1050    int sumi1,sumi2,sumi3,sumi4;
1051    int sumi;
1052
1053    const block_q8_K * a_ptr = (const block_q8_K *)vy;
1054    for(int x = 0; x < nc / ncols_interleaved; x++) {
1055        const block_q2_Kx8 * b_ptr = (const block_q2_Kx8 *) vx + (x * nb);
1056        for (int j = 0; j < ncols_interleaved; j++) {
1057            sumf[j] = 0.0;
1058            sum_minf[j] = 0.0;
1059        }
1060        for (int l = 0; l < nb; l++) {
1061            for (int k = 0; k < (qk / (4 * blocklen)); k++) {
1062                const uint8_t *scales_0 = b_ptr[l].scales + (k / 4) * 64 ;
1063                const uint8_t *scales_1 = b_ptr[l].scales + (k / 4) * 64 + 16;
1064                const uint8_t *scales_2 = b_ptr[l].scales + (k / 4) * 64 + 32;
1065                const uint8_t *scales_3 = b_ptr[l].scales + (k / 4) * 64 + 48;
1066                for (int j = 0; j < ncols_interleaved; j++) {
1067                    sumi1 = 0;
1068                    sumi2 = 0;
1069                    sumi3 = 0;
1070                    sumi4 = 0;
1071                    sumi = 0;
1072                    int offset = ((k / 2) % 2) + j * 2;
1073                    for (int i = 0; i < blocklen; ++i){
1074                        const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 3);
1075                        const int v1 = (int8_t) ((b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 2 ) & 3);
1076                        const int v2 = (int8_t) ((b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4 ) & 3);
1077                        const int v3 = (int8_t) ((b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 6 ) & 3);
1078                        sumi1 = (v0 * a_ptr[l].qs[(k >> 2) * 128 + (k % 4) * blocklen + i]);
1079                        sumi2 = (v1 * a_ptr[l].qs[(k >> 2) * 128 + (k % 4) * blocklen + i + 32]);
1080                        sumi3 = (v2 * a_ptr[l].qs[(k >> 2) * 128 + (k % 4) * blocklen + i + 64]);
1081                        sumi4 = (v3 * a_ptr[l].qs[(k >> 2) * 128 + (k % 4) * blocklen + i + 96]);
1082
1083                        sumi1 = sumi1 * (scales_0[offset] & 0xF);
1084                        sumi2 = sumi2 * (scales_1[offset] & 0xF);
1085                        sumi3 = sumi3 * (scales_2[offset] & 0xF);
1086                        sumi4 = sumi4 * (scales_3[offset] & 0xF);
1087                        sumi += sumi1 + sumi2 + sumi3 + sumi4;
1088                    }
1089                    sumf[j] += sumi * GGML_FP16_TO_FP32(b_ptr[l].d[j]) * a_ptr[l].d;
1090                }
1091            }
1092            for(int sb = 0; sb < 8; sb++) {
1093                const uint8_t *mins = b_ptr[l].scales + sb * 16;
1094                for(int j = 0; j < ncols_interleaved; j++){
1095                    sum_minf[j] += ((mins[j * 2] >> 4) * a_ptr[l].bsums[sb * 2] + (mins[(j * 2)+ 1] >> 4) * a_ptr[l].bsums[sb * 2 + 1]) * GGML_FP16_TO_FP32(b_ptr[l].dmin[j]) * a_ptr[l].d;
1096                }
1097            }
1098        }
1099        for (int j = 0; j < ncols_interleaved; j++) {
1100            s[x * ncols_interleaved + j] = sumf[j] - sum_minf[j];
1101        }
1102    }
1103}
1104
1105void ggml_gemv_q5_K_8x4_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1106    ggml_gemv_q5_K_NxM_q8_K_generic_impl<4, 8>(n, s, bs, vx, vy, nr, nc);
1107}
1108
1109void ggml_gemv_q5_K_8x8_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1110    ggml_gemv_q5_K_NxM_q8_K_generic_impl<8, 8>(n, s, bs, vx, vy, nr, nc);
1111}
1112
1113
1114void ggml_gemv_q6_K_8x4_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1115    ggml_gemv_q6_K_NxM_q8_K_generic_impl<4, 8>(n, s, bs, vx, vy, nr, nc);
1116}
1117
1118void ggml_gemv_q6_K_8x8_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1119    ggml_gemv_q6_K_NxM_q8_K_generic_impl<8, 8>(n, s, bs, vx, vy, nr, nc);
1120}
1121
1122void ggml_gemv_iq4_nl_4x4_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1123    const int qk = QK8_0;
1124    const int nb = n / qk;
1125    const int ncols_interleaved = 4;
1126    const int blocklen = 4;
1127
1128    assert(nr == 1);
1129    assert(n % qk == 0);
1130    assert(nc % ncols_interleaved == 0);
1131
1132    UNUSED(bs);
1133    UNUSED(nr);
1134
1135    float sumf[4];
1136    int sumi;
1137
1138    const block_q8_0 * a_ptr = (const block_q8_0 *) vy;
1139    for (int x = 0; x < nc / ncols_interleaved; x++) {
1140        const block_iq4_nlx4 * b_ptr = (const block_iq4_nlx4 *) vx + (x * nb);
1141
1142        for (int j = 0; j < ncols_interleaved; j++) sumf[j] = 0.0;
1143        for (int l = 0; l < nb; l++) {
1144            for (int k = 0; k < (qk / (2 * blocklen)); k++) {
1145                for (int j = 0; j < ncols_interleaved; j++) {
1146                    sumi = 0;
1147                    for (int i = 0; i < blocklen; ++i) {
1148                        const int v0 = kvalues_iq4nl[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0x0F];
1149                        const int v1 = kvalues_iq4nl[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4];
1150                        sumi += ((v0 * a_ptr[l].qs[k * blocklen + i]) + (v1 * a_ptr[l].qs[k * blocklen + i + qk / 2]));
1151                    }
1152                    sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d);
1153                }
1154            }
1155        }
1156        for (int j = 0; j < ncols_interleaved; j++) s[x * ncols_interleaved + j] = sumf[j];
1157    }
1158}
1159
1160void ggml_gemv_iq4_nl_8x8_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1161    const int qk = QK8_0;
1162    const int nb = n / qk;
1163    const int ncols_interleaved = 8;
1164    const int blocklen = 8;
1165
1166    assert(nr == 1);
1167    assert(n % qk == 0);
1168    assert(nc % ncols_interleaved == 0);
1169
1170    UNUSED(bs);
1171    UNUSED(nr);
1172
1173    float sumf[8];
1174    int sumi;
1175
1176    const block_q8_0 * a_ptr = (const block_q8_0 *) vy;
1177    for (int x = 0; x < nc / ncols_interleaved; x++) {
1178        const block_iq4_nlx8 * b_ptr = (const block_iq4_nlx8 *) vx + (x * nb);
1179
1180        for (int j = 0; j < ncols_interleaved; j++) sumf[j] = 0.0;
1181        for (int l = 0; l < nb; l++) {
1182            for (int k = 0; k < (qk / (2 * blocklen)); k++) {
1183                for (int j = 0; j < ncols_interleaved; j++) {
1184                    sumi = 0;
1185                    for (int i = 0; i < blocklen; ++i) {
1186                        const int v0 = kvalues_iq4nl[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0x0F];
1187                        const int v1 = kvalues_iq4nl[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4];
1188                        sumi += ((v0 * a_ptr[l].qs[k * blocklen + i]) + (v1 * a_ptr[l].qs[k * blocklen + i + qk / 2]));
1189                    }
1190                    sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d);
1191                }
1192            }
1193        }
1194        for (int j = 0; j < ncols_interleaved; j++) s[x * ncols_interleaved + j] = sumf[j];
1195    }
1196}
1197
1198void ggml_gemv_mxfp4_4x4_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1199    const int qk = QK8_0;
1200    const int nb = n / qk;
1201    const int ncols_interleaved = 4;
1202    const int blocklen = 4;
1203
1204    assert(nr == 1);
1205    assert(n % qk == 0);
1206    assert(nc % ncols_interleaved == 0);
1207
1208    UNUSED(bs);
1209    UNUSED(nr);
1210
1211    float sumf[4];
1212    int sumi;
1213
1214    const block_q8_0 * a_ptr = (const block_q8_0 *) vy;
1215    for (int x = 0; x < nc / ncols_interleaved; x++) {
1216        const block_mxfp4x4 * b_ptr = (const block_mxfp4x4 *) vx + (x * nb);
1217
1218        for (int j = 0; j < ncols_interleaved; j++) sumf[j] = 0.0;
1219        for (int l = 0; l < nb; l++) {
1220            for (int k = 0; k < (qk / (2 * blocklen)); k++) {
1221                for (int j = 0; j < ncols_interleaved; j++) {
1222                    sumi = 0;
1223                    for (int i = 0; i < blocklen; ++i) {
1224                        const int v0 = kvalues_mxfp4[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0x0F];
1225                        const int v1 = kvalues_mxfp4[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4];
1226                        sumi += ((v0 * a_ptr[l].qs[k * blocklen + i]) + (v1 * a_ptr[l].qs[k * blocklen + i + qk / 2]));
1227                    }
1228                    sumf[j] += sumi * GGML_CPU_E8M0_TO_FP32_HALF(b_ptr[l].e[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d);
1229                }
1230            }
1231        }
1232        for (int j = 0; j < ncols_interleaved; j++) s[x * ncols_interleaved + j] = sumf[j];
1233    }
1234}
1235
1236void ggml_gemv_mxfp4_8x8_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1237    const int qk = QK8_0;
1238    const int nb = n / qk;
1239    const int ncols_interleaved = 8;
1240    const int blocklen = 8;
1241
1242    assert(nr == 1);
1243    assert(n % qk == 0);
1244    assert(nc % ncols_interleaved == 0);
1245
1246    UNUSED(bs);
1247    UNUSED(nr);
1248
1249    float sumf[8];
1250    int sumi;
1251
1252    const block_q8_0 * a_ptr = (const block_q8_0 *) vy;
1253    for (int x = 0; x < nc / ncols_interleaved; x++) {
1254        const block_mxfp4x8 * b_ptr = (const block_mxfp4x8 *) vx + (x * nb);
1255
1256        for (int j = 0; j < ncols_interleaved; j++) sumf[j] = 0.0;
1257        for (int l = 0; l < nb; l++) {
1258            for (int k = 0; k < (qk / (2 * blocklen)); k++) {
1259                for (int j = 0; j < ncols_interleaved; j++) {
1260                    sumi = 0;
1261                    for (int i = 0; i < blocklen; ++i) {
1262                        const int v0 = kvalues_mxfp4[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0x0F];
1263                        const int v1 = kvalues_mxfp4[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4];
1264                        sumi += ((v0 * a_ptr[l].qs[k * blocklen + i]) + (v1 * a_ptr[l].qs[k * blocklen + i + qk / 2]));
1265                    }
1266                    sumf[j] += sumi * GGML_CPU_E8M0_TO_FP32_HALF(b_ptr[l].e[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d);
1267                }
1268            }
1269        }
1270        for (int j = 0; j < ncols_interleaved; j++) s[x * ncols_interleaved + j] = sumf[j];
1271    }
1272}
1273
1274void ggml_gemv_q8_0_4x4_q8_0_generic(int                        n,
1275                                     float * GGML_RESTRICT      s,
1276                                     size_t                     bs,
1277                                     const void * GGML_RESTRICT vx,
1278                                     const void * GGML_RESTRICT vy,
1279                                     int                        nr,
1280                                     int                        nc) {
1281    const int qk                = QK8_0;
1282    const int nb                = n / qk;
1283    const int ncols_interleaved = 4;
1284    const int blocklen          = 4;
1285
1286    assert(nr == 1);
1287    assert(n % qk == 0);
1288    assert(nc % ncols_interleaved == 0);
1289
1290    UNUSED(bs);
1291    UNUSED(nr);
1292
1293    float sumf[4];
1294    int   sumi;
1295
1296    const block_q8_0 * a_ptr = (const block_q8_0 *) vy;
1297    for (int x = 0; x < nc / ncols_interleaved; x++) {
1298        const block_q8_0x4 * b_ptr = (const block_q8_0x4 *) vx + (x * nb);
1299
1300        for (int j = 0; j < ncols_interleaved; j++) {
1301            sumf[j] = 0.0;
1302        }
1303        for (int l = 0; l < nb; l++) {
1304            for (int k = 0; k < (qk / blocklen); k++) {
1305                for (int j = 0; j < ncols_interleaved; j++) {
1306                    sumi = 0;
1307                    for (int i = 0; i < blocklen; ++i) {
1308                        const int v0 = b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i];
1309                        sumi += v0 * a_ptr[l].qs[k * blocklen + i];
1310                    }
1311                    sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d);
1312                }
1313            }
1314        }
1315        for (int j = 0; j < ncols_interleaved; j++) {
1316            s[x * ncols_interleaved + j] = sumf[j];
1317        }
1318    }
1319}
1320
1321void ggml_gemv_q8_0_4x8_q8_0_generic(int                        n,
1322                                     float * GGML_RESTRICT      s,
1323                                     size_t                     bs,
1324                                     const void * GGML_RESTRICT vx,
1325                                     const void * GGML_RESTRICT vy,
1326                                     int                        nr,
1327                                     int                        nc) {
1328    const int qk                = QK8_0;
1329    const int nb                = n / qk;
1330    const int ncols_interleaved = 4;
1331    const int blocklen          = 8;
1332
1333    assert(nr == 1);
1334    assert(n % qk == 0);
1335    assert(nc % ncols_interleaved == 0);
1336
1337    UNUSED(bs);
1338    UNUSED(nr);
1339
1340    float sumf[4];
1341    int   sumi;
1342
1343    const block_q8_0 * a_ptr = (const block_q8_0 *) vy;
1344    for (int x = 0; x < nc / ncols_interleaved; x++) {
1345        const block_q8_0x4 * b_ptr = (const block_q8_0x4 *) vx + (x * nb);
1346
1347        for (int j = 0; j < ncols_interleaved; j++) {
1348            sumf[j] = 0.0;
1349        }
1350        for (int l = 0; l < nb; l++) {
1351            for (int k = 0; k < (qk / blocklen); k++) {
1352                for (int j = 0; j < ncols_interleaved; j++) {
1353                    sumi = 0;
1354                    for (int i = 0; i < blocklen; ++i) {
1355                        const int v0 = b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i];
1356                        sumi += v0 * a_ptr[l].qs[k * blocklen + i];
1357                    }
1358                    sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d);
1359                }
1360            }
1361        }
1362        for (int j = 0; j < ncols_interleaved; j++) {
1363            s[x * ncols_interleaved + j] = sumf[j];
1364        }
1365    }
1366}
1367
1368// Only enable these for RISC-V.
1369#if defined __riscv_zvfh
1370void ggml_gemv_q4_0_16x1_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1371    const int qk = QK8_0;
1372    const int nb = n / qk;
1373    const int ncols_interleaved = 16;
1374    const int blocklen = 1;
1375
1376    assert (n % qk == 0);
1377    assert (nc % ncols_interleaved == 0);
1378
1379    UNUSED(s);
1380    UNUSED(bs);
1381    UNUSED(vx);
1382    UNUSED(vy);
1383    UNUSED(nr);
1384    UNUSED(nc);
1385    UNUSED(nb);
1386    UNUSED(ncols_interleaved);
1387    UNUSED(blocklen);
1388
1389    float sumf[16];
1390    int sumi;
1391
1392    const block_q8_0 * a_ptr = (const block_q8_0 *) vy;
1393    for (int x = 0; x < nc / ncols_interleaved; x++) {
1394        const block_q4_0x16 * b_ptr = (const block_q4_0x16 *) vx + (x * nb);
1395
1396        for (int j = 0; j < ncols_interleaved; j++) sumf[j] = 0.0;
1397        for (int l = 0; l < nb; l++) {
1398            for (int k = 0; k < (qk / (2 * blocklen)); k++) {
1399                for (int j = 0; j < ncols_interleaved; j++) {
1400                    sumi = 0;
1401                    for (int i = 0; i < blocklen; ++i) {
1402                        const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] << 4);
1403                        const int v1 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0xF0);
1404                        sumi += ((v0 * a_ptr[l].qs[k * blocklen + i]) + (v1 * a_ptr[l].qs[k * blocklen + i + qk / 2])) >> 4;
1405                    }
1406                    sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d);
1407                }
1408            }
1409        }
1410        for (int j = 0; j < ncols_interleaved; j++) s[x * ncols_interleaved + j] = sumf[j];
1411    }
1412}
1413
1414void ggml_gemv_q4_K_16x1_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1415    const int qk = QK_K;
1416    const int nb = n / qk;
1417    const int ncols_interleaved = 16;
1418    const int blocklen = 1;
1419    assert (n % qk == 0);
1420    assert (nc % ncols_interleaved == 0);
1421    UNUSED(s);
1422    UNUSED(bs);
1423    UNUSED(vx);
1424    UNUSED(vy);
1425    UNUSED(nr);
1426    UNUSED(nc);
1427    UNUSED(nb);
1428    UNUSED(ncols_interleaved);
1429    UNUSED(blocklen);
1430    float sumf[16];
1431    float sum_minf[16];
1432    uint8_t scales[128];
1433    uint8_t mins[128];
1434    int sumi1;
1435    int sumi2;
1436    int sumi;
1437    const block_q8_K * a_ptr = (const block_q8_K *) vy;
1438    for (int x = 0; x < nc / ncols_interleaved; x++) {
1439        const block_q4_Kx16 * b_ptr = (const block_q4_Kx16 *) vx + (x * nb);
1440        for (int j = 0; j < ncols_interleaved; j++) {
1441            sumf[j] = 0.0f;
1442            sum_minf[j] = 0.0f;
1443        }
1444        for (int l = 0; l < nb; l++) {
1445            for (int i = 0; i < 128; i++) {
1446                scales[i] = b_ptr[l].scales[i] & 0x0F;
1447                mins[i] = b_ptr[l].scales[i] >> 4;
1448            }
1449            for (int i = 0; i < 64; i++) {
1450                scales[i] |= (b_ptr[l].scales[128 + i] & 0x03) << 4;
1451                mins[i] |= (b_ptr[l].scales[128 + i] & 0x0C) << 2;
1452                scales[i + 64] |= (b_ptr[l].scales[128 + i] & 0x30);
1453                mins[i + 64] |= (b_ptr[l].scales[128 + i] & 0xC0) >> 2;
1454            }
1455            for (int sb = 0; sb < 8; sb++) {
1456                uint8_t *min = &mins[sb * 16];
1457                for (int j = 0; j < ncols_interleaved; j++) {
1458                    sum_minf[j] += min[j] * (a_ptr[l].bsums[sb * 2] + a_ptr[l].bsums[sb * 2 + 1]) * GGML_CPU_FP16_TO_FP32(b_ptr[l].dmin[j]) * a_ptr[l].d;
1459                }
1460            }
1461            for (int sb = 0; sb < 8; sb += 2) {
1462                uint8_t *scales_0 = &scales[sb * 16];
1463                uint8_t *scales_1 = &scales[(sb + 1) * 16];
1464                for (int i = 0; i < QK4_0; i++) {
1465                    for (int j = 0; j < ncols_interleaved; j++) {
1466                        sumi1 = 0;
1467                        sumi2 = 0;
1468                        sumi = 0;
1469                        const int v0 = (int8_t) (b_ptr[l].qs[sb * 256 + i * 16 + j] & 0xF);
1470                        const int v1 = (int8_t) (b_ptr[l].qs[sb * 256 + i * 16 + j] >> 4);
1471                        sumi1 = (v0 * a_ptr[l].qs[sb * 32 + i]);
1472                        sumi2 = (v1 * a_ptr[l].qs[sb * 32 + 32 + i]);
1473                        sumi1 = sumi1 * scales_0[j];
1474                        sumi2 = sumi2 * scales_1[j];
1475                        sumi += sumi1 + sumi2;
1476                        sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * a_ptr[l].d;
1477                    }
1478                }
1479            }
1480        }
1481        for (int j = 0; j < ncols_interleaved; j++) {
1482            s[x * ncols_interleaved + j] = sumf[j] - sum_minf[j];
1483        }
1484    }
1485}
1486
1487void ggml_gemv_iq4_nl_16x1_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1488    const int qk = QK8_0;
1489    const int nb = n / qk;
1490    const int ncols_interleaved = 16;
1491    const int blocklen = 1;
1492
1493    assert(nr == 1);
1494    assert(n % qk == 0);
1495    assert(nc % ncols_interleaved == 0);
1496
1497    UNUSED(bs);
1498    UNUSED(nr);
1499
1500    float sumf[16];
1501    int sumi;
1502
1503    const block_q8_0 * a_ptr = (const block_q8_0 *) vy;
1504    for (int x = 0; x < nc / ncols_interleaved; x++) {
1505        const block_iq4_nlx16 * b_ptr = (const block_iq4_nlx16 *) vx + (x * nb);
1506
1507        for (int j = 0; j < ncols_interleaved; j++) sumf[j] = 0.0;
1508        for (int l = 0; l < nb; l++) {
1509            for (int k = 0; k < (qk / (2 * blocklen)); k++) {
1510                for (int j = 0; j < ncols_interleaved; j++) {
1511                    sumi = 0;
1512                    for (int i = 0; i < blocklen; ++i) {
1513                        const int v0 = kvalues_iq4nl[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0x0F];
1514                        const int v1 = kvalues_iq4nl[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4];
1515                        sumi += ((v0 * a_ptr[l].qs[k * blocklen + i]) + (v1 * a_ptr[l].qs[k * blocklen + i + qk / 2]));
1516                    }
1517                    sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d);
1518                }
1519            }
1520        }
1521        for (int j = 0; j < ncols_interleaved; j++) s[x * ncols_interleaved + j] = sumf[j];
1522    }
1523}
1524
1525void ggml_gemv_q8_0_16x1_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1526    const int qk                = QK8_0;
1527    const int nb                = n / qk;
1528    const int ncols_interleaved = 16;
1529    const int blocklen          = 1;
1530
1531    assert(nr == 1);
1532    assert(n % qk == 0);
1533    assert(nc % ncols_interleaved == 0);
1534
1535    UNUSED(bs);
1536    UNUSED(nr);
1537
1538    float sumf[16];
1539    int   sumi;
1540
1541    const block_q8_0 * a_ptr = (const block_q8_0 *) vy;
1542    for (int x = 0; x < nc / ncols_interleaved; x++) {
1543        const block_q8_0x16 * b_ptr = (const block_q8_0x16 *) vx + (x * nb);
1544
1545        for (int j = 0; j < ncols_interleaved; j++) {
1546            sumf[j] = 0.0;
1547        }
1548        for (int l = 0; l < nb; l++) {
1549            for (int k = 0; k < (qk / blocklen); k++) {
1550                for (int j = 0; j < ncols_interleaved; j++) {
1551                    sumi = 0;
1552                    for (int i = 0; i < blocklen; ++i) {
1553                        const int v0 = b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i];
1554                        sumi += v0 * a_ptr[l].qs[k * blocklen + i];
1555                    }
1556                    sumf[j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d);
1557                }
1558            }
1559        }
1560        for (int j = 0; j < ncols_interleaved; j++) {
1561            s[x * ncols_interleaved + j] = sumf[j];
1562        }
1563    }
1564}
1565
1566void ggml_gemv_q2_K_16x1_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1567    assert(n % QK_K == 0);
1568    assert(nr == 1);
1569    assert(nc % 16 == 0);
1570
1571    UNUSED(bs);
1572    UNUSED(nr);
1573
1574    const int nb = n / QK_K;
1575    const block_q2_Kx16 * x = (const block_q2_Kx16 *)vx;
1576    const block_q8_K    * y = (const block_q8_K *)vy;
1577
1578    // Layout: Even-Low(0,2,4,6), Odd-Low(1,3,5,7), Even-High(8...), Odd-High(9...)
1579    const int sb_perm[16] = {
1580        0, 4, 1, 5, 2, 6, 3, 7,  // 0-7
1581        8, 12, 9, 13, 10, 14, 11, 15 // 8-15
1582    };
1583
1584    for (int col_tile = 0; col_tile < nc; col_tile += 16) {
1585        const block_q2_Kx16 * x_ptr = x + (col_tile / 16) * nb;
1586        const block_q8_K    * y_ptr = y;
1587
1588        float sumf[16] = {0};
1589
1590        // Loop over K-blocks
1591        for (int k_block = 0; k_block < nb; ++k_block) {
1592            int32_t isum[16]  = {0};
1593            int32_t summs[16] = {0};
1594
1595            const uint8_t * qs_rhs = x_ptr[k_block].qs;
1596            const uint8_t * sc_rhs = x_ptr[k_block].scales;
1597            const int8_t  * qs_lhs = y_ptr[k_block].qs;
1598            const int16_t * bs_lhs = y_ptr[k_block].bsums;
1599
1600            // Iterate over sub-blocks 0..15
1601            for (int sb = 0; sb < 16; ++sb) {
1602                // Correction Term
1603                int16_t bsum = bs_lhs[sb];
1604                int scale_offset = sb_perm[sb] * 16;
1605
1606                for (int col = 0; col < 16; ++col) {
1607                    uint8_t sc_val = sc_rhs[scale_offset + col];
1608                    summs[col] += bsum * (sc_val >> 4); // Min is high 4 bits
1609                }
1610
1611                // Main Dot Product
1612                // Calculate base offsets for Q2 unpacking based on SB
1613                int byte_base;
1614                if (sb < 8) byte_base = (sb % 2 == 0) ? 0 : 16;
1615                else        byte_base = (sb % 2 == 0) ? 32 : 48;
1616
1617                int shift = ((sb / 2) % 4) * 2;
1618
1619                for (int col = 0; col < 16; ++col) {
1620                    uint8_t sc_val = sc_rhs[scale_offset + col];
1621                    int32_t d_sb = sc_val & 0xF; // Scale is low 4 bits
1622
1623                    // Process 16 elements (l=0..15)
1624                    for (int l = 0; l < 16; ++l) {
1625                        // Q2: Interleaved by column. Byte `l` contains 4 k-values.
1626                        int qs_idx = (byte_base + l) * 16 + col;
1627                        uint8_t q2_val = (qs_rhs[qs_idx] >> shift) & 3;
1628
1629                        // Q8: Linear access
1630                        int k = sb * 16 + l;
1631                        int8_t q8_val = qs_lhs[k];
1632
1633                        isum[col] += q8_val * q2_val * d_sb;
1634                    }
1635                }
1636            }
1637
1638            // Finalize K-Block
1639            for (int col = 0; col < 16; ++col) {
1640                float d_lhs = y_ptr[k_block].d;
1641                float d_rhs = GGML_FP16_TO_FP32(x_ptr[k_block].d[col]);
1642                float dm_rhs = GGML_FP16_TO_FP32(x_ptr[k_block].dmin[col]);
1643
1644                float d_all = d_lhs * d_rhs;
1645                float d_min = d_lhs * dm_rhs;
1646
1647                sumf[col] += (isum[col] * d_all) - (summs[col] * d_min);
1648            }
1649        }
1650
1651        for (int col = 0; col < 16; ++col) {
1652            s[col_tile + col] = sumf[col];
1653        }
1654    }
1655}
1656#endif
1657
1658void ggml_gemm_q4_0_4x4_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1659    const int qk = QK8_0;
1660    const int nb = n / qk;
1661    const int ncols_interleaved = 4;
1662    const int blocklen = 4;
1663
1664    assert (n % qk == 0);
1665    assert (nr % 4 == 0);
1666    assert (nc % ncols_interleaved == 0);
1667
1668    UNUSED(s);
1669    UNUSED(bs);
1670    UNUSED(vx);
1671    UNUSED(vy);
1672    UNUSED(nr);
1673    UNUSED(nc);
1674    UNUSED(nb);
1675    UNUSED(ncols_interleaved);
1676    UNUSED(blocklen);
1677
1678    {
1679        float sumf[4][4];
1680        int sumi;
1681
1682        for (int y = 0; y < nr / 4; y++) {
1683            const block_q8_0x4 * a_ptr = (const block_q8_0x4 *) vy + (y * nb);
1684            for (int x = 0; x < nc / ncols_interleaved; x++) {
1685                const block_q4_0x4 * b_ptr = (const block_q4_0x4 *) vx + (x * nb);
1686                for (int m = 0; m < 4; m++) {
1687                    for (int j = 0; j < ncols_interleaved; j++) sumf[m][j] = 0.0;
1688                }
1689                for (int l = 0; l < nb; l++) {
1690                    for (int k = 0; k < (qk / (2 * blocklen)); k++) {
1691                        for (int m = 0; m < 4; m++) {
1692                            for (int j = 0; j < ncols_interleaved; j++) {
1693                                sumi = 0;
1694                                for (int i = 0; i < blocklen; ++i) {
1695                                    const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] << 4);
1696                                    const int v1 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0xF0);
1697                                    sumi += ((v0 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i]) +
1698                                            (v1 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i + qk / 2 * 4])) >> 4;
1699                                }
1700                                sumf[m][j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d[m]);
1701                            }
1702                        }
1703                    }
1704                }
1705                for (int m = 0; m < 4; m++) {
1706                    for (int j = 0; j < ncols_interleaved; j++)
1707                        s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j];
1708                }
1709            }
1710        }
1711    }
1712}
1713
1714void ggml_gemm_q4_0_4x8_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1715    const int qk = QK8_0;
1716    const int nb = n / qk;
1717    const int ncols_interleaved = 4;
1718    const int blocklen = 8;
1719
1720    assert (n % qk == 0);
1721    assert (nr % 4 == 0);
1722    assert (nc % ncols_interleaved == 0);
1723
1724    UNUSED(s);
1725    UNUSED(bs);
1726    UNUSED(vx);
1727    UNUSED(vy);
1728    UNUSED(nr);
1729    UNUSED(nc);
1730    UNUSED(nb);
1731    UNUSED(ncols_interleaved);
1732    UNUSED(blocklen);
1733
1734    float sumf[4][4];
1735    int sumi;
1736
1737    for (int y = 0; y < nr / 4; y++) {
1738        const block_q8_0x4 * a_ptr = (const block_q8_0x4 *) vy + (y * nb);
1739        for (int x = 0; x < nc / ncols_interleaved; x++) {
1740            const block_q4_0x4 * b_ptr = (const block_q4_0x4 *) vx + (x * nb);
1741            for (int m = 0; m < 4; m++) {
1742                for (int j = 0; j < ncols_interleaved; j++) sumf[m][j] = 0.0;
1743            }
1744            for (int l = 0; l < nb; l++) {
1745                for (int k = 0; k < (qk / (2 * blocklen)); k++) {
1746                    for (int m = 0; m < 4; m++) {
1747                        for (int j = 0; j < ncols_interleaved; j++) {
1748                            sumi = 0;
1749                            for (int i = 0; i < blocklen; ++i) {
1750                                const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] << 4);
1751                                const int v1 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0xF0);
1752                                sumi += ((v0 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i]) +
1753                                        (v1 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i + qk / 2 * 4])) >> 4;
1754                            }
1755                            sumf[m][j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d[m]);
1756                        }
1757                    }
1758                }
1759            }
1760            for (int m = 0; m < 4; m++) {
1761                for (int j = 0; j < ncols_interleaved; j++)
1762                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j];
1763            }
1764        }
1765    }
1766}
1767
1768void ggml_gemm_q4_0_8x8_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1769    const int qk = QK8_0;
1770    const int nb = n / qk;
1771    const int ncols_interleaved = 8;
1772    const int blocklen = 8;
1773
1774    assert (n % qk == 0);
1775    assert (nr % 4 == 0);
1776    assert (nc % ncols_interleaved == 0);
1777
1778    UNUSED(s);
1779    UNUSED(bs);
1780    UNUSED(vx);
1781    UNUSED(vy);
1782    UNUSED(nr);
1783    UNUSED(nc);
1784    UNUSED(nb);
1785    UNUSED(ncols_interleaved);
1786    UNUSED(blocklen);
1787
1788    float sumf[4][8];
1789    int sumi;
1790
1791    for (int y = 0; y < nr / 4; y++) {
1792        const block_q8_0x4 * a_ptr = (const block_q8_0x4 *) vy + (y * nb);
1793        for (int x = 0; x < nc / ncols_interleaved; x++) {
1794            const block_q4_0x8 * b_ptr = (const block_q4_0x8 *) vx + (x * nb);
1795            for (int m = 0; m < 4; m++) {
1796                for (int j = 0; j < ncols_interleaved; j++) sumf[m][j] = 0.0;
1797            }
1798            for (int l = 0; l < nb; l++) {
1799                for (int k = 0; k < (qk / (2 * blocklen)); k++) {
1800                    for (int m = 0; m < 4; m++) {
1801                        for (int j = 0; j < ncols_interleaved; j++) {
1802                            sumi = 0;
1803                            for (int i = 0; i < blocklen; ++i) {
1804                                const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] << 4);
1805                                const int v1 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0xF0);
1806                                sumi += ((v0 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i]) +
1807                                         (v1 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i + qk / 2 * 4])) >> 4;
1808                            }
1809                            sumf[m][j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d[m]);
1810                        }
1811                    }
1812                }
1813            }
1814            for (int m = 0; m < 4; m++) {
1815                for (int j = 0; j < ncols_interleaved; j++)
1816                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j];
1817            }
1818        }
1819    }
1820}
1821
1822void ggml_gemm_q4_K_8x4_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1823    const int qk = QK_K;
1824    const int nb = n / qk;
1825    const int ncols_interleaved = 8;
1826    const int blocklen = 4;
1827    static const uint32_t kmask1 = 0x3f3f3f3f;
1828    static const uint32_t kmask2 = 0x0f0f0f0f;
1829    static const uint32_t kmask3 = 0x03030303;
1830
1831    assert (n % qk == 0);
1832    assert (nr % 4 == 0);
1833    assert (nc % ncols_interleaved == 0);
1834
1835    UNUSED(nb);
1836    UNUSED(ncols_interleaved);
1837    UNUSED(blocklen);
1838
1839    float sumf[4][8];
1840    float sum_minf[4][8];
1841    uint32_t utmp[32];
1842    int sumi1;
1843    int sumi2;
1844    int sumi;
1845
1846    for (int y = 0; y < nr / 4; y++) {
1847        const block_q8_Kx4 * a_ptr = (const block_q8_Kx4 *) vy + (y * nb);
1848        for (int x = 0; x < nc / ncols_interleaved; x++) {
1849            const block_q4_Kx8 * b_ptr = (const block_q4_Kx8 *) vx + (x * nb);
1850            for (int m = 0; m < 4; m++) {
1851                for (int j = 0; j < ncols_interleaved; j++) {
1852                    sumf[m][j] = 0.0;
1853                    sum_minf[m][j] = 0.0;
1854                }
1855            }
1856            for (int l = 0; l < nb; l++) {
1857                for (int sb = 0; sb < 8; sb++) {
1858                    memcpy(utmp + sb * 4, b_ptr[l].scales + sb * 12, 12);
1859                    utmp[sb * 4 + 3] = ((utmp[sb * 4 + 2] >> 4) & kmask2) | (((utmp[sb * 4 + 1] >> 6) & kmask3) << 4);
1860                    const uint32_t uaux_0 = utmp[sb * 4 + 1] & kmask1;
1861                    utmp[sb * 4 + 1] = (utmp[sb * 4 + 2] & kmask2) | (((utmp[sb * 4 + 0] >> 6) & kmask3) << 4);
1862                    utmp[sb * 4 + 2] = uaux_0;
1863                    utmp[sb * 4 + 0] &= kmask1;
1864                }
1865                for (int k = 0; k < (qk / (2 * blocklen)); k++) {
1866                    uint8_t * scales_0 = (uint8_t *) utmp + (k / 8) * 32;
1867                    uint8_t * scales_1 = (uint8_t *) utmp + (k / 8) * 32 + 16;
1868                    for (int m = 0; m < 4; m++) {
1869                        for (int j = 0; j < ncols_interleaved; j++) {
1870                            sumi1 = 0;
1871                            sumi2 = 0;
1872                            sumi = 0;
1873                            for (int i = 0; i < blocklen; ++i) {
1874                                const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0xF);
1875                                const int v1 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4);
1876                                sumi1 = (v0 * a_ptr[l].qs[(k / 8) * 256 + (k % 8) * 4 * blocklen + m * blocklen + i]);
1877                                sumi2 = (v1 * a_ptr[l].qs[(k / 8) * 256 + (k % 8) * 4 * blocklen + m * blocklen + i + 128]);
1878                                sumi1 = sumi1 * scales_0[j];
1879                                sumi2 = sumi2 * scales_1[j];
1880                                sumi += sumi1 + sumi2;
1881                            }
1882                            sumf[m][j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * a_ptr[l].d[m];
1883                        }
1884                    }
1885                }
1886                for (int sb = 0; sb < 8; sb++) {
1887                    uint8_t * mins = (uint8_t *) utmp + 8 + sb * 16;
1888                    for(int m = 0; m < 4; m++) {
1889                        const int16_t * bsums = a_ptr[l].bsums + (sb * 8) + (m * 4) - ((sb % 2) * 6);
1890                        for(int j = 0; j < ncols_interleaved; j++) {
1891                            sum_minf[m][j] += mins[j] * (bsums[0] + bsums[1]) * GGML_CPU_FP16_TO_FP32(b_ptr[l].dmin[j]) * a_ptr[l].d[m];
1892                        }
1893                    }
1894                }
1895            }
1896            for (int m = 0; m < 4; m++) {
1897                for (int j = 0; j < ncols_interleaved; j++) {
1898                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j] - sum_minf[m][j];
1899                }
1900            }
1901        }
1902    }
1903}
1904
1905void ggml_gemm_q4_K_8x8_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1906    const int qk = QK_K;
1907    const int nb = n / qk;
1908    const int ncols_interleaved = 8;
1909    const int blocklen = 8;
1910    static const uint32_t kmask1 = 0x3f3f3f3f;
1911    static const uint32_t kmask2 = 0x0f0f0f0f;
1912    static const uint32_t kmask3 = 0x03030303;
1913
1914    assert (n % qk == 0);
1915    assert (nr % 4 == 0);
1916    assert (nc % ncols_interleaved == 0);
1917
1918    UNUSED(bs);
1919
1920    float sumf[4][8];
1921    float sum_minf[4][8];
1922    uint32_t utmp[32];
1923    int sumi1;
1924    int sumi2;
1925    int sumi;
1926
1927    for (int y = 0; y < nr / 4; y++) {
1928        const block_q8_Kx4 * a_ptr = (const block_q8_Kx4 *) vy + (y * nb);
1929        for (int x = 0; x < nc / ncols_interleaved; x++) {
1930            const block_q4_Kx8 * b_ptr = (const block_q4_Kx8 *) vx + (x * nb);
1931            for (int m = 0; m < 4; m++) {
1932                for (int j = 0; j < ncols_interleaved; j++) {
1933                    sumf[m][j] = 0.0;
1934                    sum_minf[m][j] = 0.0;
1935                }
1936            }
1937            for (int l = 0; l < nb; l++) {
1938                for (int sb = 0; sb < 8; sb++) {
1939                    memcpy(utmp + sb * 4, b_ptr[l].scales + sb * 12, 12);
1940                    utmp[sb * 4 + 3] = ((utmp[sb * 4 + 2] >> 4) & kmask2) | (((utmp[sb * 4 + 1] >> 6) & kmask3) << 4);
1941                    const uint32_t uaux_0 = utmp[sb * 4 + 1] & kmask1;
1942                    utmp[sb * 4 + 1] = (utmp[sb * 4 + 2] & kmask2) | (((utmp[sb * 4 + 0] >> 6) & kmask3) << 4);
1943                    utmp[sb * 4 + 2] = uaux_0;
1944                    utmp[sb * 4 + 0] &= kmask1;
1945                }
1946                for (int k = 0; k < (qk / (2 * blocklen)); k++) {
1947                    uint8_t *scales_0 = (uint8_t*) utmp + (k / 4) * 32;
1948                    uint8_t *scales_1 = (uint8_t*) utmp + (k / 4) * 32 + 16;
1949                    for (int m = 0; m < 4; m++) {
1950                        for (int j = 0; j < ncols_interleaved; j++) {
1951                            sumi1 = 0;
1952                            sumi2 = 0;
1953                            sumi = 0;
1954                            for (int i = 0; i < blocklen; ++i) {
1955                                const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0xF);
1956                                const int v1 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4);
1957                                sumi1 = (v0 * a_ptr[l].qs[(k >> 2) * 256 + (k % 4) * 4 * blocklen + m * blocklen + i]);
1958                                sumi2 = (v1 * a_ptr[l].qs[(k >> 2) * 256 + (k % 4) * 4 * blocklen + m * blocklen + i + 128]);
1959                                sumi1 = sumi1 * scales_0[j];
1960                                sumi2 = sumi2 * scales_1[j];
1961                                sumi += sumi1 + sumi2;
1962                            }
1963                            sumf[m][j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * a_ptr[l].d[m];
1964                        }
1965                    }
1966                }
1967                for (int sb = 0; sb < 8; sb++) {
1968                    uint8_t *mins = (uint8_t*) utmp + 8 + sb * 16;
1969                    for(int m = 0; m < 4; m++) {
1970                        const int16_t *bsums = a_ptr[l].bsums + (sb * 8) + (m * 4) - ((sb % 2) * 6);
1971                        for(int j = 0; j < ncols_interleaved; j++) {
1972                            sum_minf[m][j] += mins[j] * (bsums[0] + bsums[1]) * GGML_CPU_FP16_TO_FP32(b_ptr[l].dmin[j]) * a_ptr[l].d[m];
1973                        }
1974                    }
1975                }
1976            }
1977            for (int m = 0; m < 4; m++) {
1978                for (int j = 0; j < ncols_interleaved; j++) {
1979                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j] - sum_minf[m][j];
1980                }
1981            }
1982        }
1983    }
1984}
1985
1986void ggml_gemm_q2_K_8x8_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
1987    const int qk = QK_K;
1988    const int nb = n / qk;
1989    const int ncols_interleaved = 8;
1990    const int blocklen = 8;
1991
1992    assert (n % qk == 0);
1993    assert (nr % 4 == 0);
1994    assert (nc % ncols_interleaved == 0);
1995
1996    UNUSED(s);
1997    UNUSED(bs);
1998    UNUSED(vx);
1999    UNUSED(vy);
2000    UNUSED(nr);
2001    UNUSED(nc);
2002    UNUSED(nb);
2003    UNUSED(ncols_interleaved);
2004    UNUSED(blocklen);
2005
2006    float sumf[4][8];
2007    float sum_minf[4][8];
2008    int sumi1, sumi2, sumi3, sumi4;
2009    int sumi;
2010
2011    for (int y = 0; y < nr / 4; y++) {
2012        const block_q8_Kx4 * a_ptr = (const block_q8_Kx4 *) vy + (y * nb);
2013        for (int x = 0; x < nc / ncols_interleaved; x++) {
2014            const block_q2_Kx8 * b_ptr = (const block_q2_Kx8 *) vx + (x * nb);
2015            for (int m = 0; m < 4; m++) {
2016                for (int j = 0; j < ncols_interleaved; j++) {
2017                    sumf[m][j] = 0.0;
2018                    sum_minf[m][j] = 0.0;
2019                }
2020            }
2021            for (int l = 0; l < nb; l++) {
2022                for (int k = 0; k < (qk / (4 * blocklen)); k++) {
2023
2024                    const uint8_t *scales_0 = b_ptr[l].scales + (k / 4) * 64 ;
2025                    const uint8_t *scales_1 = b_ptr[l].scales + (k / 4) * 64 + 16;
2026                    const uint8_t *scales_2 = b_ptr[l].scales + (k / 4) * 64 + 32;
2027                    const uint8_t *scales_3 = b_ptr[l].scales + (k / 4) * 64 + 48;
2028                    for (int m = 0; m < 4; m++) {
2029                        for (int j = 0; j < ncols_interleaved; j++) {
2030                            sumi1 = 0;
2031                            sumi2 = 0;
2032                            sumi3 = 0;
2033                            sumi4 = 0;
2034                            sumi = 0;
2035                            int offset = ((k / 2) % 2) + j * 2;
2036                            for (int i = 0; i < blocklen; ++i){
2037                                const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 3);
2038                                const int v1 = (int8_t) ((b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 2 ) & 3);
2039                                const int v2 = (int8_t) ((b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4 ) & 3);
2040                                const int v3 = (int8_t) ((b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 6 ) & 3);
2041                                sumi1 = (v0 * a_ptr[l].qs[(k >> 2) * 512 + (k % 4) * 4 * blocklen + m * blocklen + i]);
2042                                sumi2 = (v1 * a_ptr[l].qs[(k >> 2) * 512  + (k % 4) * 4 * blocklen + m * blocklen + i + 128]);
2043                                sumi3 = (v2 * a_ptr[l].qs[(k >> 2) * 512  + (k % 4) * 4 * blocklen + m * blocklen + i + 256]);
2044                                sumi4 = (v3 * a_ptr[l].qs[(k >> 2) * 512  + (k % 4) * 4 * blocklen + m * blocklen + i + 384]);
2045                                sumi1 = sumi1 * (scales_0[offset] & 0xF);
2046                                sumi2 = sumi2 * (scales_1[offset] & 0xF);
2047                                sumi3 = sumi3 * (scales_2[offset] & 0xF);
2048                                sumi4 = sumi4 * (scales_3[offset] & 0xF);
2049                                sumi += sumi1 + sumi2 + sumi3 + sumi4;
2050                            }
2051                            sumf[m][j] += sumi * GGML_FP16_TO_FP32(b_ptr[l].d[j]) * a_ptr[l].d[m];
2052                        }
2053                    }
2054                }
2055                for(int sb = 0; sb < 8; sb++) {
2056                    const uint8_t *mins = b_ptr[l].scales + sb * 16;
2057                    for(int m = 0; m < 4; m++) {
2058                        const int16_t *bsums = a_ptr[l].bsums + (sb * 8) + (m * 4) - ((sb % 2) *  6);
2059                        for(int j = 0; j < ncols_interleaved; j++) {
2060                            int mins_prod = ((mins[j * 2] >> 4) * bsums[0] + (mins[(j * 2)+ 1] >> 4) * bsums[1]);
2061                            sum_minf[m][j] += (mins_prod) * GGML_FP16_TO_FP32(b_ptr[l].dmin[j]) * a_ptr[l].d[m];
2062                        }
2063                    }
2064                }
2065            }
2066
2067            for (int m = 0; m < 4; m++) {
2068                for (int j = 0; j < ncols_interleaved; j++) {
2069                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j] - sum_minf[m][j];
2070                }
2071            }
2072        }
2073    }
2074}
2075
2076void ggml_gemm_q5_K_8x4_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
2077    ggml_gemm_q5_K_NxM_q8_K_generic_impl<4, 8>(n, s, bs, vx, vy, nr, nc);
2078}
2079
2080void ggml_gemm_q5_K_8x8_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
2081    ggml_gemm_q5_K_NxM_q8_K_generic_impl<8, 8>(n, s, bs, vx, vy, nr, nc);
2082}
2083
2084void ggml_gemm_q6_K_8x4_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
2085    ggml_gemm_q6_K_NxM_q8_K_generic_impl<4, 8>(n, s, bs, vx, vy, nr, nc);
2086}
2087
2088void ggml_gemm_q6_K_8x8_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
2089   ggml_gemm_q6_K_NxM_q8_K_generic_impl<8, 8>(n, s, bs, vx, vy, nr, nc);
2090}
2091
2092void ggml_gemm_iq4_nl_4x4_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
2093    const int qk = QK8_0;
2094    const int nb = n / qk;
2095    const int ncols_interleaved = 4;
2096    const int blocklen = 4;
2097
2098    assert (n % qk == 0);
2099    assert (nr % 4 == 0);
2100    assert (nc % ncols_interleaved == 0);
2101
2102    UNUSED(s);
2103    UNUSED(bs);
2104    UNUSED(vx);
2105    UNUSED(vy);
2106    UNUSED(nr);
2107    UNUSED(nc);
2108    UNUSED(nb);
2109    UNUSED(ncols_interleaved);
2110    UNUSED(blocklen);
2111
2112    {
2113        float sumf[4][4];
2114        int sumi;
2115
2116        for (int y = 0; y < nr / 4; y++) {
2117            const block_q8_0x4 * a_ptr = (const block_q8_0x4 *) vy + (y * nb);
2118            for (int x = 0; x < nc / ncols_interleaved; x++) {
2119                const block_iq4_nlx4 * b_ptr = (const block_iq4_nlx4 *) vx + (x * nb);
2120                for (int m = 0; m < 4; m++) {
2121                    for (int j = 0; j < ncols_interleaved; j++) sumf[m][j] = 0.0;
2122                }
2123                for (int l = 0; l < nb; l++) {
2124                    for (int k = 0; k < (qk / (2 * blocklen)); k++) {
2125                        for (int m = 0; m < 4; m++) {
2126                            for (int j = 0; j < ncols_interleaved; j++) {
2127                                sumi = 0;
2128                                for (int i = 0; i < blocklen; ++i) {
2129                                    const int v0 = kvalues_iq4nl[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0x0F];
2130                                    const int v1 = kvalues_iq4nl[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4];
2131                                    sumi += ((v0 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i]) +
2132                                            (v1 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i + qk / 2 * 4]));
2133                                }
2134                                sumf[m][j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d[m]);
2135                            }
2136                        }
2137                    }
2138                }
2139                for (int m = 0; m < 4; m++) {
2140                    for (int j = 0; j < ncols_interleaved; j++)
2141                        s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j];
2142                }
2143            }
2144        }
2145    }
2146}
2147
2148void ggml_gemm_iq4_nl_8x8_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
2149    const int qk = QK8_0;
2150    const int nb = n / qk;
2151    const int ncols_interleaved = 8;
2152    const int blocklen = 8;
2153
2154    assert(n % qk == 0);
2155    assert(nr % 4 == 0);
2156    assert(nc % ncols_interleaved == 0);
2157
2158    float sumf[4][8];
2159    int sumi;
2160
2161    for (int y = 0; y < nr / 4; y++) {
2162        const block_q8_0x4 * a_ptr = (const block_q8_0x4 *) vy + (y * nb);
2163        for (int x = 0; x < nc / ncols_interleaved; x++) {
2164            const block_iq4_nlx8 * b_ptr = (const block_iq4_nlx8 *) vx + (x * nb);
2165            for (int m = 0; m < 4; m++) {
2166                for (int j = 0; j < ncols_interleaved; j++) sumf[m][j] = 0.0;
2167            }
2168            for (int l = 0; l < nb; l++) {
2169                for (int k = 0; k < (qk / (2 * blocklen)); k++) {
2170                    for (int m = 0; m < 4; m++) {
2171                        for (int j = 0; j < ncols_interleaved; j++) {
2172                            sumi = 0;
2173                            for (int i = 0; i < blocklen; ++i) {
2174                                const int v0 = kvalues_iq4nl[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0x0F];
2175                                const int v1 = kvalues_iq4nl[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4];
2176                                sumi += ((v0 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i]) +
2177                                         (v1 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i + qk / 2 * 4]));
2178                            }
2179                            sumf[m][j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d[m]);
2180                        }
2181                    }
2182                }
2183            }
2184            for (int m = 0; m < 4; m++) {
2185                for (int j = 0; j < ncols_interleaved; j++)
2186                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j];
2187            }
2188        }
2189    }
2190}
2191
2192void ggml_gemm_mxfp4_4x4_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
2193    const int qk = QK8_0;
2194    const int nb = n / qk;
2195    const int ncols_interleaved = 4;
2196    const int blocklen = 4;
2197
2198    assert(n % qk == 0);
2199    assert(nr % 4 == 0);
2200    assert(nc % ncols_interleaved == 0);
2201
2202    float sumf[4][4];
2203    int sumi;
2204
2205    for (int y = 0; y < nr / 4; y++) {
2206        const block_q8_0x4 * a_ptr = (const block_q8_0x4 *) vy + (y * nb);
2207        for (int x = 0; x < nc / ncols_interleaved; x++) {
2208            const block_mxfp4x4 * b_ptr = (const block_mxfp4x4 *) vx + (x * nb);
2209            for (int m = 0; m < 4; m++) {
2210                for (int j = 0; j < ncols_interleaved; j++) sumf[m][j] = 0.0;
2211            }
2212            for (int l = 0; l < nb; l++) {
2213                for (int k = 0; k < (qk / (2 * blocklen)); k++) {
2214                    for (int m = 0; m < 4; m++) {
2215                        for (int j = 0; j < ncols_interleaved; j++) {
2216                            sumi = 0;
2217                            for (int i = 0; i < blocklen; ++i) {
2218                                const int v0 = kvalues_mxfp4[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0x0F];
2219                                const int v1 = kvalues_mxfp4[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4];
2220                                sumi += ((v0 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i]) +
2221                                         (v1 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i + qk / 2 * 4]));
2222                            }
2223                            sumf[m][j] += sumi * GGML_CPU_E8M0_TO_FP32_HALF(b_ptr[l].e[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d[m]);
2224                        }
2225                    }
2226                }
2227            }
2228            for (int m = 0; m < 4; m++) {
2229                for (int j = 0; j < ncols_interleaved; j++)
2230                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j];
2231            }
2232        }
2233    }
2234}
2235
2236void ggml_gemm_mxfp4_8x8_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
2237    const int qk = QK8_0;
2238    const int nb = n / qk;
2239    const int ncols_interleaved = 8;
2240    const int blocklen = 8;
2241
2242    assert(n % qk == 0);
2243    assert(nr % 4 == 0);
2244    assert(nc % ncols_interleaved == 0);
2245
2246    float sumf[4][8];
2247    int sumi;
2248
2249    for (int y = 0; y < nr / 4; y++) {
2250        const block_q8_0x4 * a_ptr = (const block_q8_0x4 *) vy + (y * nb);
2251        for (int x = 0; x < nc / ncols_interleaved; x++) {
2252            const block_mxfp4x8 * b_ptr = (const block_mxfp4x8 *) vx + (x * nb);
2253            for (int m = 0; m < 4; m++) {
2254                for (int j = 0; j < ncols_interleaved; j++) sumf[m][j] = 0.0;
2255            }
2256            for (int l = 0; l < nb; l++) {
2257                for (int k = 0; k < (qk / (2 * blocklen)); k++) {
2258                    for (int m = 0; m < 4; m++) {
2259                        for (int j = 0; j < ncols_interleaved; j++) {
2260                            sumi = 0;
2261                            for (int i = 0; i < blocklen; ++i) {
2262                                const int v0 = kvalues_mxfp4[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0x0F];
2263                                const int v1 = kvalues_mxfp4[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4];
2264                                sumi += ((v0 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i]) +
2265                                         (v1 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i + qk / 2 * 4]));
2266                            }
2267                            sumf[m][j] += sumi * GGML_CPU_E8M0_TO_FP32_HALF(b_ptr[l].e[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d[m]);
2268                        }
2269                    }
2270                }
2271            }
2272            for (int m = 0; m < 4; m++) {
2273                for (int j = 0; j < ncols_interleaved; j++)
2274                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j];
2275            }
2276        }
2277    }
2278}
2279
2280void ggml_gemm_q8_0_4x4_q8_0_generic(int                        n,
2281                                     float * GGML_RESTRICT      s,
2282                                     size_t                     bs,
2283                                     const void * GGML_RESTRICT vx,
2284                                     const void * GGML_RESTRICT vy,
2285                                     int                        nr,
2286                                     int                        nc) {
2287    const int qk                = QK8_0;
2288    const int nb                = n / qk;
2289    const int ncols_interleaved = 4;
2290    const int blocklen          = 4;
2291
2292    assert(n % qk == 0);
2293    assert(nr % 4 == 0);
2294    assert(nc % ncols_interleaved == 0);
2295
2296    float sumf[4][4];
2297    int   sumi;
2298
2299    for (int y = 0; y < nr / 4; y++) {
2300        const block_q8_0x4 * a_ptr = (const block_q8_0x4 *) vy + (y * nb);
2301        for (int x = 0; x < nc / ncols_interleaved; x++) {
2302            const block_q8_0x4 * b_ptr = (const block_q8_0x4 *) vx + (x * nb);
2303            for (int m = 0; m < 4; m++) {
2304                for (int j = 0; j < ncols_interleaved; j++) {
2305                    sumf[m][j] = 0.0;
2306                }
2307            }
2308            for (int l = 0; l < nb; l++) {
2309                for (int k = 0; k < (qk / blocklen); k++) {
2310                    for (int m = 0; m < 4; m++) {
2311                        for (int j = 0; j < ncols_interleaved; j++) {
2312                            sumi = 0;
2313                            for (int i = 0; i < blocklen; ++i) {
2314                                const int v0 = b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i];
2315                                sumi += v0 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i];
2316                            }
2317                            sumf[m][j] +=
2318                                sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d[m]);
2319                        }
2320                    }
2321                }
2322            }
2323            for (int m = 0; m < 4; m++) {
2324                for (int j = 0; j < ncols_interleaved; j++) {
2325                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j];
2326                }
2327            }
2328        }
2329    }
2330}
2331
2332
2333
2334void ggml_gemm_q8_0_4x8_q8_0_generic(int                        n,
2335                                     float * GGML_RESTRICT      s,
2336                                     size_t                     bs,
2337                                     const void * GGML_RESTRICT vx,
2338                                     const void * GGML_RESTRICT vy,
2339                                     int                        nr,
2340                                     int                        nc) {
2341    const int qk                = QK8_0;
2342    const int nb                = n / qk;
2343    const int ncols_interleaved = 4;
2344    const int blocklen          = 8;
2345
2346    assert(n % qk == 0);
2347    assert(nr % 4 == 0);
2348    assert(nc % ncols_interleaved == 0);
2349
2350    float sumf[4][4];
2351    int   sumi;
2352
2353    for (int y = 0; y < nr / 4; y++) {
2354        const block_q8_0x4 * a_ptr = (const block_q8_0x4 *) vy + (y * nb);
2355        for (int x = 0; x < nc / ncols_interleaved; x++) {
2356            const block_q8_0x4 * b_ptr = (const block_q8_0x4 *) vx + (x * nb);
2357            for (int m = 0; m < 4; m++) {
2358                for (int j = 0; j < ncols_interleaved; j++) {
2359                    sumf[m][j] = 0.0;
2360                }
2361            }
2362            for (int l = 0; l < nb; l++) {
2363                for (int k = 0; k < (qk / blocklen); k++) {
2364                    for (int m = 0; m < 4; m++) {
2365                        for (int j = 0; j < ncols_interleaved; j++) {
2366                            sumi = 0;
2367                            for (int i = 0; i < blocklen; ++i) {
2368                                const int v0 = b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i];
2369                                sumi += v0 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i];
2370                            }
2371                            sumf[m][j] +=
2372                                sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d[m]);
2373                        }
2374                    }
2375                }
2376            }
2377            for (int m = 0; m < 4; m++) {
2378                for (int j = 0; j < ncols_interleaved; j++) {
2379                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j];
2380                }
2381            }
2382        }
2383    }
2384}
2385
2386// Only enable these for RISC-V.
2387#if defined __riscv_zvfh
2388void ggml_gemm_q4_0_16x1_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
2389    const int qk = QK8_0;
2390    const int nb = n / qk;
2391    const int ncols_interleaved = 16;
2392    const int blocklen = 1;
2393
2394    assert (n % qk == 0);
2395    assert (nr % 4 == 0);
2396    assert (nc % ncols_interleaved == 0);
2397
2398    UNUSED(s);
2399    UNUSED(bs);
2400    UNUSED(vx);
2401    UNUSED(vy);
2402    UNUSED(nr);
2403    UNUSED(nc);
2404    UNUSED(nb);
2405    UNUSED(ncols_interleaved);
2406    UNUSED(blocklen);
2407
2408    float sumf[4][16];
2409    int sumi;
2410
2411    for (int y = 0; y < nr / 4; y++) {
2412        const block_q8_0x4 * a_ptr = (const block_q8_0x4 *) vy + (y * nb);
2413        for (int x = 0; x < nc / ncols_interleaved; x++) {
2414            const block_q4_0x16 * b_ptr = (const block_q4_0x16 *) vx + (x * nb);
2415            for (int m = 0; m < 4; m++) {
2416                for (int j = 0; j < ncols_interleaved; j++) sumf[m][j] = 0.0;
2417            }
2418            for (int l = 0; l < nb; l++) {
2419                for (int k = 0; k < (qk / (2 * blocklen)); k++) {
2420                    for (int m = 0; m < 4; m++) {
2421                        for (int j = 0; j < ncols_interleaved; j++) {
2422                            sumi = 0;
2423                            for (int i = 0; i < blocklen; ++i) {
2424                                const int v0 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] << 4);
2425                                const int v1 = (int8_t) (b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0xF0);
2426                                sumi += ((v0 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i]) +
2427                                         (v1 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i + qk / 2 * 4])) >> 4;
2428                            }
2429                            sumf[m][j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d[m]);
2430                        }
2431                    }
2432                }
2433            }
2434            for (int m = 0; m < 4; m++) {
2435                for (int j = 0; j < ncols_interleaved; j++)
2436                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j];
2437            }
2438        }
2439    }
2440}
2441
2442void ggml_gemm_q4_K_16x1_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
2443    const int qk = QK_K;
2444    const int nb = n / qk;
2445    const int ncols_interleaved = 16;
2446    const int blocklen = 1;
2447
2448    assert (n % qk == 0);
2449    assert (nr % 4 == 0);
2450    assert (nc % ncols_interleaved == 0);
2451
2452    UNUSED(s);
2453    UNUSED(bs);
2454    UNUSED(vx);
2455    UNUSED(vy);
2456    UNUSED(nr);
2457    UNUSED(nc);
2458    UNUSED(nb);
2459    UNUSED(ncols_interleaved);
2460    UNUSED(blocklen);
2461
2462    float sumf[4][16];
2463    float sum_minf[4][16];
2464    uint8_t scales[128];
2465    uint8_t mins[128];
2466    int sumi1;
2467    int sumi2;
2468    int sumi;
2469
2470    for (int y = 0; y < nr / 4; y++) {
2471        const block_q8_Kx4 * a_ptr = (const block_q8_Kx4 *) vy + (y * nb);
2472        for (int x = 0; x < nc / ncols_interleaved; x++) {
2473            const block_q4_Kx16 * b_ptr = (const block_q4_Kx16 *) vx + (x * nb);
2474            for (int m = 0; m < 4; m++) {
2475                for (int j = 0; j < ncols_interleaved; j++) {
2476                    sumf[m][j] = 0.0;
2477                    sum_minf[m][j] = 0.0;
2478                }
2479            }
2480            for (int l = 0; l < nb; l++) {
2481                for (int i = 0; i < 128; i++) {
2482                    scales[i] = b_ptr[l].scales[i] & 0x0F;
2483                    mins[i] = b_ptr[l].scales[i] >> 4;
2484                }
2485                for (int i = 0; i < 64; i++) {
2486                    scales[i] |= (b_ptr[l].scales[128 + i] & 0x03) << 4;
2487                    mins[i] |= (b_ptr[l].scales[128 + i] & 0x0C) << 2;
2488                    scales[i + 64] |= (b_ptr[l].scales[128 + i] & 0x30);
2489                    mins[i + 64] |= (b_ptr[l].scales[128 + i] & 0xC0) >> 2;
2490                }
2491
2492                for (int sb = 0; sb < 8; sb++) {
2493                    uint8_t *min = &mins[sb * 16];
2494                    for(int m = 0; m < 4; m++) {
2495                        const int16_t bsums = a_ptr[l].bsums[sb * 8 + m] + a_ptr[l].bsums[sb * 8 + m + 4];
2496                        for(int j = 0; j < ncols_interleaved; j++) {
2497                            sum_minf[m][j] += min[j] * bsums * GGML_CPU_FP16_TO_FP32(b_ptr[l].dmin[j]) * a_ptr[l].d[m];
2498                        }
2499                    }
2500                }
2501
2502                for (int sb = 0; sb < 8; sb += 2) {
2503                    uint8_t *scales_0 = &scales[sb * 16];
2504                    uint8_t *scales_1 = &scales[(sb + 1) * 16];
2505
2506                    for (int i = 0; i < QK4_0; i++) {
2507                        for (int m = 0; m < 4; m++) {
2508                            for (int j = 0; j < ncols_interleaved; j++) {
2509                                sumi1 = 0;
2510                                sumi2 = 0;
2511                                sumi = 0;
2512
2513                                const int v0 = (int8_t) (b_ptr[l].qs[sb * 256 + i * 16 + j] & 0xF);
2514                                const int v1 = (int8_t) (b_ptr[l].qs[sb * 256 + i * 16 + j] >> 4);
2515                                sumi1 = (v0 * a_ptr[l].qs[sb * 4 * 32 + i * 4 + m]);
2516                                sumi2 = (v1 * a_ptr[l].qs[sb * 4 * 32 + 32 * 4 + i * 4 + m]);
2517                                sumi1 = sumi1 * scales_0[j];
2518                                sumi2 = sumi2 * scales_1[j];
2519                                sumi += sumi1 + sumi2;
2520
2521                                sumf[m][j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * a_ptr[l].d[m];
2522                            }
2523                        }
2524                    }
2525                }
2526            }
2527            for (int m = 0; m < 4; m++) {
2528                for (int j = 0; j < ncols_interleaved; j++) {
2529                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j] - sum_minf[m][j];
2530                }
2531            }
2532        }
2533    }
2534}
2535
2536void ggml_gemm_iq4_nl_16x1_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
2537    const int qk = QK8_0;
2538    const int nb = n / qk;
2539    const int ncols_interleaved = 16;
2540    const int blocklen = 1;
2541
2542    assert(n % qk == 0);
2543    assert(nr % 4 == 0);
2544    assert(nc % ncols_interleaved == 0);
2545
2546    float sumf[4][16];
2547    int sumi;
2548
2549    for (int y = 0; y < nr / 4; y++) {
2550        const block_q8_0x4 * a_ptr = (const block_q8_0x4 *) vy + (y * nb);
2551        for (int x = 0; x < nc / ncols_interleaved; x++) {
2552            const block_iq4_nlx16 * b_ptr = (const block_iq4_nlx16 *) vx + (x * nb);
2553            for (int m = 0; m < 4; m++) {
2554                for (int j = 0; j < ncols_interleaved; j++) sumf[m][j] = 0.0;
2555            }
2556            for (int l = 0; l < nb; l++) {
2557                for (int k = 0; k < (qk / (2 * blocklen)); k++) {
2558                    for (int m = 0; m < 4; m++) {
2559                        for (int j = 0; j < ncols_interleaved; j++) {
2560                            sumi = 0;
2561                            for (int i = 0; i < blocklen; ++i) {
2562                                const int v0 = kvalues_iq4nl[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] & 0x0F];
2563                                const int v1 = kvalues_iq4nl[b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i] >> 4];
2564                                sumi += ((v0 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i]) +
2565                                         (v1 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i + (qk / 2) * 4]));
2566                            }
2567                            sumf[m][j] += sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d[m]);
2568                        }
2569                    }
2570                }
2571            }
2572            for (int m = 0; m < 4; m++) {
2573                for (int j = 0; j < ncols_interleaved; j++)
2574                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j];
2575            }
2576        }
2577    }
2578}
2579
2580void ggml_gemm_q8_0_16x1_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
2581    const int qk                = QK8_0;
2582    const int nb                = n / qk;
2583    const int ncols_interleaved = 16;
2584    const int blocklen          = 1;
2585
2586    assert(n % qk == 0);
2587    assert(nr % 4 == 0);
2588    assert(nc % ncols_interleaved == 0);
2589
2590    float sumf[4][16];
2591    int   sumi;
2592
2593    for (int y = 0; y < nr / 4; y++) {
2594        const block_q8_0x4 * a_ptr = (const block_q8_0x4 *) vy + (y * nb);
2595        for (int x = 0; x < nc / ncols_interleaved; x++) {
2596            const block_q8_0x16 * b_ptr = (const block_q8_0x16 *) vx + (x * nb);
2597            for (int m = 0; m < 4; m++) {
2598                for (int j = 0; j < ncols_interleaved; j++) {
2599                    sumf[m][j] = 0.0;
2600                }
2601            }
2602            for (int l = 0; l < nb; l++) {
2603                for (int k = 0; k < (qk / blocklen); k++) {
2604                    for (int m = 0; m < 4; m++) {
2605                        for (int j = 0; j < ncols_interleaved; j++) {
2606                            sumi = 0;
2607                            for (int i = 0; i < blocklen; ++i) {
2608                                const int v0 = b_ptr[l].qs[k * ncols_interleaved * blocklen + j * blocklen + i];
2609                                sumi += v0 * a_ptr[l].qs[k * 4 * blocklen + m * blocklen + i];
2610                            }
2611                            sumf[m][j] +=
2612                                sumi * GGML_CPU_FP16_TO_FP32(b_ptr[l].d[j]) * GGML_CPU_FP16_TO_FP32(a_ptr[l].d[m]);
2613                        }
2614                    }
2615                }
2616            }
2617            for (int m = 0; m < 4; m++) {
2618                for (int j = 0; j < ncols_interleaved; j++) {
2619                    s[(y * 4 + m) * bs + x * ncols_interleaved + j] = sumf[m][j];
2620                }
2621            }
2622        }
2623    }
2624}
2625
2626
2627void ggml_gemm_q2_K_16x1_q8_K_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, const void * GGML_RESTRICT vy, int nr, int nc) {
2628    assert(n % QK_K == 0);
2629    assert(nr % 4 == 0);
2630    assert(nc % 16 == 0);
2631    const int nb = n / QK_K;
2632    const block_q2_Kx16 * x = (const block_q2_Kx16 *)vx;
2633    const block_q8_Kx4  * y = (const block_q8_Kx4 *)vy;
2634
2635    const int sb_perm[16] = {
2636        0, 4, 1, 5, 2, 6, 3, 7,
2637        8, 12, 9, 13, 10, 14, 11, 15
2638    };
2639
2640    // Iterate Rows in tiles of 4
2641    for (int row_tile = 0; row_tile < nr; row_tile += 4) {
2642        // Iterate Columns in tiles of 16
2643        for (int col_tile = 0; col_tile < nc; col_tile += 16) {
2644
2645            const block_q2_Kx16 * x_ptr = x + (col_tile / 16) * nb;
2646            const block_q8_Kx4  * y_ptr = y + (row_tile / 4) * nb;
2647
2648            float sumf[4][16];
2649            memset(sumf, 0, sizeof(sumf));
2650
2651            for (int k_block = 0; k_block < nb; ++k_block) {
2652                int32_t isum[4][16];
2653                int32_t summs[4][16];
2654                memset(isum, 0, sizeof(isum));
2655                memset(summs, 0, sizeof(summs));
2656
2657                const uint8_t * qs_rhs = x_ptr[k_block].qs;
2658                const uint8_t * sc_rhs = x_ptr[k_block].scales;
2659                const int8_t  * qs_lhs = y_ptr[k_block].qs;
2660                const int16_t * bs_lhs = y_ptr[k_block].bsums;
2661
2662                for (int sb = 0; sb < 16; ++sb) {
2663                    int scale_offset = sb_perm[sb] * 16;
2664
2665                    int byte_base;
2666                    if (sb < 8) byte_base = (sb % 2 == 0) ? 0 : 16;
2667                    else        byte_base = (sb % 2 == 0) ? 32 : 48;
2668                    int shift = ((sb / 2) % 4) * 2;
2669
2670                    for (int col = 0; col < 16; ++col) {
2671                        uint8_t sc_val = sc_rhs[scale_offset + col];
2672                        int32_t d_sb = sc_val & 0xF;
2673                        int32_t m_sb = sc_val >> 4;
2674
2675                        // Correction Term
2676                        for (int r = 0; r < 4; ++r) {
2677                            int bsum_idx = (sb / 4) * 16 + r * 4 + (sb % 4);
2678                            summs[r][col] += bs_lhs[bsum_idx] * m_sb;
2679                        }
2680
2681                        // Main Dot Product
2682                        for (int l = 0; l < 16; ++l) {
2683                            int qs_idx = (byte_base + l) * 16 + col;
2684                            uint8_t q2_val = (qs_rhs[qs_idx] >> shift) & 3;
2685
2686                            // Calculate Q8 index for this specific k and row
2687                            int k = sb * 16 + l;
2688                            int q8_idx = (k / 4) * 16 + (k % 4);
2689
2690                            for (int r = 0; r < 4; ++r) {
2691                                // Add r*4 to jump to the correct row within the 4x4 chunk
2692                                int8_t q8_val = qs_lhs[q8_idx + r * 4];
2693                                isum[r][col] += q8_val * q2_val * d_sb;
2694                            }
2695                        }
2696                    }
2697                }
2698
2699                // Finalize K-Block
2700                for (int col = 0; col < 16; ++col) {
2701                    float d_rhs = GGML_FP16_TO_FP32(x_ptr[k_block].d[col]);
2702                    float dm_rhs = GGML_FP16_TO_FP32(x_ptr[k_block].dmin[col]);
2703
2704                    for (int r = 0; r < 4; ++r) {
2705                        float d_lhs = y_ptr[k_block].d[r];
2706                        float d_all = d_lhs * d_rhs;
2707                        float d_min = d_lhs * dm_rhs;
2708                        sumf[r][col] += (isum[r][col] * d_all) - (summs[r][col] * d_min);
2709                    }
2710                }
2711            }
2712
2713            for (int r = 0; r < 4; ++r) {
2714                for (int col = 0; col < 16; ++col) {
2715                    s[(row_tile + r) * bs + (col_tile + col)] = sumf[r][col];
2716                }
2717            }
2718        }
2719    }
2720}
2721#endif
2722
2723} // extern "C"
2724
2725static block_q8_0x4 make_block_q8_0x4(block_q8_0 * in, unsigned int blck_size_interleave) {
2726    block_q8_0x4 out;
2727
2728    for (int i = 0; i < 4; i++) {
2729        out.d[i] = in[i].d;
2730    }
2731
2732    const int end = QK8_0 * 4 / blck_size_interleave;
2733    for (int i = 0; i < end; ++i) {
2734        int src_id     = i % 4;
2735        int src_offset = (i / 4) * blck_size_interleave;
2736        int dst_offset = i * blck_size_interleave;
2737        memcpy(&out.qs[dst_offset], &in[src_id].qs[src_offset], blck_size_interleave);
2738    }
2739    return out;
2740}
2741
2742static block_q4_0x4 make_block_q4_0x4(block_q4_0 * in, int blck_size_interleave) {
2743    block_q4_0x4 out;
2744
2745    for (int i = 0; i < 4; i++) {
2746        out.d[i] = in[i].d;
2747    }
2748
2749    const int end = QK4_0 * 2 / blck_size_interleave;
2750
2751    if (blck_size_interleave == 8) {
2752        const uint64_t xor_mask = 0x8888888888888888ULL;
2753        for (int i = 0; i < end; ++i) {
2754            int src_id = i % 4;
2755            int src_offset = (i / 4) * blck_size_interleave;
2756            int dst_offset = i * blck_size_interleave;
2757
2758            uint64_t elems;
2759            // Using memcpy to avoid unaligned memory accesses
2760            memcpy(&elems, &in[src_id].qs[src_offset], sizeof(uint64_t));
2761            elems ^= xor_mask;
2762            memcpy(&out.qs[dst_offset], &elems, sizeof(uint64_t));
2763        }
2764    } else if (blck_size_interleave == 4) {
2765        const uint32_t xor_mask = 0x88888888;
2766        for (int i = 0; i < end; ++i) {
2767            int src_id = i % 4;
2768            int src_offset = (i / 4) * blck_size_interleave;
2769            int dst_offset = i * blck_size_interleave;
2770
2771            uint32_t elems;
2772            memcpy(&elems, &in[src_id].qs[src_offset], sizeof(uint32_t));
2773            elems ^= xor_mask;
2774            memcpy(&out.qs[dst_offset], &elems, sizeof(uint32_t));
2775        }
2776    } else {
2777        GGML_ASSERT(false);
2778    }
2779
2780    return out;
2781}
2782
2783// interleave 8 block_q4_0s in blocks of blck_size_interleave
2784// returns an interleaved block_q4_0x8
2785// in the interleaved block_q4_0x8, place deltas for 8 block_q4_0 blocks
2786// first, then interleave quants from 8 block_q4_0s in blocks of blck_size_interleave
2787static block_q4_0x8 make_block_q4_0x8(block_q4_0 * in, unsigned int blck_size_interleave) {
2788    block_q4_0x8 out;
2789
2790    for (int i = 0; i < 8; i++) {
2791        out.d[i] = in[i].d;
2792    }
2793
2794    const int end = QK4_0 * 4 / blck_size_interleave;
2795    const uint64_t xor_mask = 0x8888888888888888ULL;
2796
2797    for (int i = 0; i < end; ++i) {
2798        int src_id = i % 8;
2799        int src_offset = (i / 8) * blck_size_interleave;
2800        int dst_offset = i * blck_size_interleave;
2801
2802        uint64_t elems;
2803        memcpy(&elems, &in[src_id].qs[src_offset], sizeof(uint64_t));
2804        elems ^= xor_mask;
2805        memcpy(&out.qs[dst_offset], &elems, sizeof(uint64_t));
2806    }
2807
2808    return out;
2809}
2810
2811static block_q4_0x16 make_block_q4_0x16(block_q4_0 * in, unsigned int blck_size_interleave) {
2812    block_q4_0x16 out;
2813
2814    for (int i = 0; i < 16; i++) {
2815        out.d[i] = in[i].d;
2816    }
2817
2818    const int end = QK4_0 * 8 / blck_size_interleave;
2819
2820    if (blck_size_interleave == 1) {
2821        const uint8_t xor_mask = 0x88;
2822        for (int i = 0; i < end; ++i) {
2823            int src_id = i % 16;
2824            int src_offset = i / 16;
2825            int dst_offset = i;
2826
2827            out.qs[dst_offset] = in[src_id].qs[src_offset] ^ xor_mask;
2828        }
2829    } else {
2830        GGML_ASSERT(false);
2831    }
2832
2833    return out;
2834}
2835
2836static block_q4_Kx8 make_block_q4_Kx8(block_q4_K * in, unsigned int blck_size_interleave) {
2837    block_q4_Kx8 out;
2838    //Delta(scale) and dmin values of the eight Q4_K structures are copied onto the output interleaved structure
2839    for (int i = 0; i < 8; i++) {
2840        out.d[i] = in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d;
2841    }
2842
2843    for (int i = 0; i < 8; i++) {
2844        out.dmin[i] = in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.dmin;
2845    }
2846
2847    const int end = QK_K * 4 / blck_size_interleave;
2848
2849    // Interleave Q4_K quants by taking 8 bytes at a time
2850    for (int i = 0; i < end; ++i) {
2851        int src_id = i % 8;
2852        int src_offset = (i / 8) * blck_size_interleave;
2853        int dst_offset = i * blck_size_interleave;
2854
2855        // buffer large enough for the max interleave block size (8 bytes)
2856        uint64_t elems;
2857        memcpy(&elems, &in[src_id].qs[src_offset], blck_size_interleave);
2858        memcpy(&out.qs[dst_offset], &elems, blck_size_interleave);
2859    }
2860
2861    // The below logic is designed so as to unpack and rearrange scales and mins values in Q4_K
2862    // Currently the Q4_K structure has 8 scales and 8 mins packed in 12 bytes ( 6 bits for each value)
2863    // The output Q4_Kx8 structure has 96 bytes
2864    // Every 12 byte is packed such that it contains scales and mins for corresponding sub blocks from Q4_K structure
2865    // For eg - First 12 bytes contains 8 scales and 8 mins - each of first sub block from different Q4_K structures
2866    uint8_t s[8], m[8];
2867
2868    for (int i = 0; i < 4; i++) {
2869        for (int j = 0; j < 8; j++) {
2870            s[j] = in[j].scales[i] & 63;
2871            m[j] = in[j].scales[i + 4] & 63;
2872        }
2873
2874        out.scales[i * 12]      = (s[0] & 63) + ((s[4] & 48) << 2);
2875        out.scales[i * 12 + 1]  = (s[1] & 63) + ((s[5] & 48) << 2);
2876        out.scales[i * 12 + 2]  = (s[2] & 63) + ((s[6] & 48) << 2);
2877        out.scales[i * 12 + 3]  = (s[3] & 63) + ((s[7] & 48) << 2);
2878        out.scales[i * 12 + 4]  = (m[0] & 63) + ((m[4] & 48) << 2);
2879        out.scales[i * 12 + 5]  = (m[1] & 63) + ((m[5] & 48) << 2);
2880        out.scales[i * 12 + 6]  = (m[2] & 63) + ((m[6] & 48) << 2);
2881        out.scales[i * 12 + 7]  = (m[3] & 63) + ((m[7] & 48) << 2);
2882        out.scales[i * 12 + 8]  = (s[4] & 15) + ((m[4] & 15) << 4);
2883        out.scales[i * 12 + 9]  = (s[5] & 15) + ((m[5] & 15) << 4);
2884        out.scales[i * 12 + 10] = (s[6] & 15) + ((m[6] & 15) << 4);
2885        out.scales[i * 12 + 11] = (s[7] & 15) + ((m[7] & 15) << 4);
2886
2887    }
2888
2889    for (int i = 0; i < 4; i++) {
2890        for (int j = 0; j < 8; j++) {
2891            s[j] = ((in[j].scales[i] & 192) >> 2) | (in[j].scales[i+8] & 15);
2892            m[j] = ((in[j].scales[i + 4] & 192) >> 2) | ((in[j].scales[i+8] & 240) >> 4);
2893        }
2894
2895        out.scales[i * 12 + 48] = (s[0] & 63) + ((s[4] & 48) << 2);
2896        out.scales[i * 12 + 49] = (s[1] & 63) + ((s[5] & 48) << 2);
2897        out.scales[i * 12 + 50] = (s[2] & 63) + ((s[6] & 48) << 2);
2898        out.scales[i * 12 + 51] = (s[3] & 63) + ((s[7] & 48) << 2);
2899        out.scales[i * 12 + 52] = (m[0] & 63) + ((m[4] & 48) << 2);
2900        out.scales[i * 12 + 53] = (m[1] & 63) + ((m[5] & 48) << 2);
2901        out.scales[i * 12 + 54] = (m[2] & 63) + ((m[6] & 48) << 2);
2902        out.scales[i * 12 + 55] = (m[3] & 63) + ((m[7] & 48) << 2);
2903        out.scales[i * 12 + 56] = (s[4] & 15) + ((m[4] & 15) << 4);
2904        out.scales[i * 12 + 57] = (s[5] & 15) + ((m[5] & 15) << 4);
2905        out.scales[i * 12 + 58] = (s[6] & 15) + ((m[6] & 15) << 4);
2906        out.scales[i * 12 + 59] = (s[7] & 15) + ((m[7] & 15) << 4);
2907
2908    }
2909
2910    return out;
2911}
2912
2913static block_q4_Kx16 make_block_q4_Kx16(block_q4_K * in, unsigned int blck_size_interleave) {
2914    block_q4_Kx16 out;
2915    //Delta(scale) and dmin values of the 16 Q4_K structures are copied onto the output interleaved structure
2916    for (int i = 0; i < 16; i++) {
2917        out.d[i] = in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d;
2918    }
2919
2920    for (int i = 0; i < 16; i++) {
2921        out.dmin[i] = in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.dmin;
2922    }
2923
2924    const int end = QK_K * 8 / blck_size_interleave;
2925
2926    if (blck_size_interleave == 1) {
2927        for (int i = 0; i < end; ++i) {
2928            int src_id = i % 16;
2929            int src_offset = i / 16;
2930            int dst_offset = i;
2931
2932            out.qs[dst_offset] = in[src_id].qs[src_offset];
2933        }
2934
2935        // RVV repacking.
2936        //
2937        // Extract sums and mins for all 8 sub-blocks for each block of Q4_K.
2938        uint8_t s[128], m[128];
2939        for (int i = 0; i < 4; i++) {
2940            for (int j = 0; j < 16; j++) {
2941                s[i * 16 + j] = in[j].scales[i] & 63;
2942                m[i * 16 + j] = in[j].scales[i + 4] & 63;
2943            }
2944        }
2945        for (int i = 0; i < 4; i++) {
2946            for (int j = 0; j < 16; j++) {
2947                s[64 + i * 16 + j] = ((in[j].scales[i] & 192) >> 2) | (in[j].scales[i+8] & 15);
2948                m[64 + i * 16 + j] = ((in[j].scales[i + 4] & 192) >> 2) | ((in[j].scales[i+8] & 240) >> 4);
2949            }
2950        }
2951
2952        for (int i = 0; i < 128; i++) {
2953            out.scales[i] = (s[i] & 15) | ((m[i] & 15) << 4);
2954        }
2955        for (int i = 0; i < 64; i++) {
2956            out.scales[128 + i] = ((s[i] & 48) >> 4) | ((m[i] & 48) >> 2) | (s[64 + i] & 48) | ((m[64 + i] & 48) << 2);
2957        }
2958    } else {
2959        GGML_ASSERT(false);
2960    }
2961
2962    return out;
2963}
2964
2965static block_q2_Kx8 make_block_q2_Kx8(block_q2_K * in, unsigned int blck_size_interleave) {
2966    block_q2_Kx8 out;
2967
2968    // Delta(scale) and dmin values of the eight Q2_K structures are copied onto the output interleaved structure
2969    for (int i = 0; i < 8; i++) {
2970        out.d[i] = in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d;
2971    }
2972
2973    for (int i = 0; i < 8; i++) {
2974        out.dmin[i] = in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.dmin;
2975    }
2976
2977    const int end = QK_K * 2 / blck_size_interleave;
2978
2979    // Interleave Q2_K quants by taking 8 bytes at a time
2980    for (int i = 0; i < end; ++i) {
2981        int src_id = i % 8;
2982        int src_offset = (i / 8) * blck_size_interleave;
2983        int dst_offset = i * blck_size_interleave;
2984
2985        uint64_t elems;
2986        memcpy(&elems, &in[src_id].qs[src_offset], sizeof(uint64_t));
2987        memcpy(&out.qs[dst_offset], &elems, sizeof(uint64_t));
2988    }
2989
2990    // The below logic is designed so as to unpack and rearrange scales and mins values in Q2_K
2991    // Currently the Q2_K structure has 16 scales and 16 mins packed in 16 bytes ( 4 bits for each value)
2992    // The output Q2_Kx8 structure has 128 bytes for storing scales and mins
2993    // Every 16 byte is packed such that it contains scales and mins for corresponding sub blocks from Q2_K structure
2994    // For eg - First 16 bytes contains 16 scales and 16 mins - each of first and second sub blocks from different Q2_K structures
2995
2996    for (int i = 0; i < 128; i++) {
2997        // Index for selecting which q2k super block
2998        int src1 = (i % 16) / 2;
2999        // Index for selecting scale
3000        int src2 = ((i / 16) * 2) + (i % 2);
3001
3002        out.scales[i] = in[src1].scales[src2];
3003    }
3004    return out;
3005}
3006
3007static block_q5_Kx8 make_block_q5_Kx8(block_q5_K * in, unsigned int blck_size_interleave) {
3008    block_q5_Kx8 out;
3009    //Delta(scale) and dmin values of the eight Q5_K structures are copied onto the output interleaved structure
3010    for (int i = 0; i < 8; i++) {
3011        out.d[i] = in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d;
3012    }
3013
3014    for (int i = 0; i < 8; i++) {
3015        out.dmin[i] = in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.dmin;
3016    }
3017
3018    const int end = QK_K * 4 / blck_size_interleave;
3019
3020    // Interleave Q5_K quants by taking blck_size_interleave bytes at a time
3021    for (int i = 0; i < end; ++i) {
3022        int src_id     = i % 8;
3023        int src_offset = (i / 8) * blck_size_interleave;
3024        int dst_offset = i * blck_size_interleave;
3025
3026        memcpy(&out.qs[dst_offset], &in[src_id].qs[src_offset], blck_size_interleave);
3027    }
3028
3029    // Repeat for high bits with the same chunk size, since
3030    // the high bits are interleaved in Q5_K and the index is
3031    // qh_idx = (qs_idx % 32);
3032    // qh_val = qh[qh_idx] >> (qs_idx / 32);
3033    for (int i = 0; i < end / 4; ++i) {
3034        int src_id     = i % 8;
3035        int src_offset = (i / 8) * blck_size_interleave;
3036        int dst_offset = i * blck_size_interleave;
3037
3038        memcpy(&out.qh[dst_offset], &in[src_id].qh[src_offset], blck_size_interleave);
3039    }
3040
3041    // The below logic is copied over from Q4_K
3042    // The point is to unpack all the scales and mins for each sub block every time we load 12 bytes.
3043    // Currently the Q5_K structure has 8 scales and 8 mins packed in 12 bytes ( 6 bits for each value)
3044    // The output Q5_Kx8 structure has 96 bytes
3045    // Every 12 byte is packed such that it contains scales and mins for corresponding sub blocks from Q5_K structure
3046    // For eg - First 12 bytes contains 8 scales and 8 mins - each of first sub block from different Q5_K structures
3047    uint8_t s[8], m[8];
3048
3049    for (int i = 0; i < 4; i++) {
3050        for (int j = 0; j < 8; j++) {
3051            s[j] = in[j].scales[i] & 63;
3052            m[j] = in[j].scales[i + 4] & 63;
3053        }
3054
3055        out.scales[i * 12]      = (s[0] & 63) + ((s[4] & 48) << 2);
3056        out.scales[i * 12 + 1]  = (s[1] & 63) + ((s[5] & 48) << 2);
3057        out.scales[i * 12 + 2]  = (s[2] & 63) + ((s[6] & 48) << 2);
3058        out.scales[i * 12 + 3]  = (s[3] & 63) + ((s[7] & 48) << 2);
3059        out.scales[i * 12 + 4]  = (m[0] & 63) + ((m[4] & 48) << 2);
3060        out.scales[i * 12 + 5]  = (m[1] & 63) + ((m[5] & 48) << 2);
3061        out.scales[i * 12 + 6]  = (m[2] & 63) + ((m[6] & 48) << 2);
3062        out.scales[i * 12 + 7]  = (m[3] & 63) + ((m[7] & 48) << 2);
3063        out.scales[i * 12 + 8]  = (s[4] & 15) + ((m[4] & 15) << 4);
3064        out.scales[i * 12 + 9]  = (s[5] & 15) + ((m[5] & 15) << 4);
3065        out.scales[i * 12 + 10] = (s[6] & 15) + ((m[6] & 15) << 4);
3066        out.scales[i * 12 + 11] = (s[7] & 15) + ((m[7] & 15) << 4);
3067    }
3068
3069    for (int i = 0; i < 4; i++) {
3070        for (int j = 0; j < 8; j++) {
3071            s[j] = ((in[j].scales[i] & 192) >> 2) | (in[j].scales[i + 8] & 15);
3072            m[j] = ((in[j].scales[i + 4] & 192) >> 2) | ((in[j].scales[i + 8] & 240) >> 4);
3073        }
3074
3075        out.scales[i * 12 + 48] = (s[0] & 63) + ((s[4] & 48) << 2);
3076        out.scales[i * 12 + 49] = (s[1] & 63) + ((s[5] & 48) << 2);
3077        out.scales[i * 12 + 50] = (s[2] & 63) + ((s[6] & 48) << 2);
3078        out.scales[i * 12 + 51] = (s[3] & 63) + ((s[7] & 48) << 2);
3079        out.scales[i * 12 + 52] = (m[0] & 63) + ((m[4] & 48) << 2);
3080        out.scales[i * 12 + 53] = (m[1] & 63) + ((m[5] & 48) << 2);
3081        out.scales[i * 12 + 54] = (m[2] & 63) + ((m[6] & 48) << 2);
3082        out.scales[i * 12 + 55] = (m[3] & 63) + ((m[7] & 48) << 2);
3083        out.scales[i * 12 + 56] = (s[4] & 15) + ((m[4] & 15) << 4);
3084        out.scales[i * 12 + 57] = (s[5] & 15) + ((m[5] & 15) << 4);
3085        out.scales[i * 12 + 58] = (s[6] & 15) + ((m[6] & 15) << 4);
3086        out.scales[i * 12 + 59] = (s[7] & 15) + ((m[7] & 15) << 4);
3087    }
3088
3089    return out;
3090}
3091
3092static block_q6_Kx8 make_block_q6_Kx8(block_q6_K * in, unsigned int blck_size_interleave) {
3093    block_q6_Kx8  out;
3094    constexpr int n_blocks = 8;  // Kx8
3095    for (int i = 0; i < n_blocks; i++) {
3096        out.d[i] = in[i].d;
3097    }
3098
3099    const int end_ls = QK_K * 4 / blck_size_interleave;
3100    // Interleave Q6_K quants by taking blck_size_interleave bytes at a time
3101    for (int i = 0; i < end_ls; ++i) {
3102        int src_id     = i % n_blocks;
3103        int src_offset = (i / n_blocks) * blck_size_interleave;
3104        int dst_offset = i * blck_size_interleave;
3105
3106        uint64_t elem_ls;
3107        memcpy(&elem_ls, &in[src_id].ql[src_offset], blck_size_interleave);
3108        memcpy(&out.ql[dst_offset], &elem_ls, blck_size_interleave);
3109    }
3110
3111    // Interleave high bits using same chunk size as low bits
3112    const int end_hs = end_ls / 2;
3113    for (int i = 0; i < end_hs; ++i) {
3114        int src_id     = i % n_blocks;
3115        int src_offset = (i / n_blocks) * blck_size_interleave;
3116        int dst_offset = i * blck_size_interleave;
3117
3118        uint64_t elem_hs;
3119        memcpy(&elem_hs, &in[src_id].qh[src_offset], blck_size_interleave);
3120        memcpy(&out.qh[dst_offset], &elem_hs, blck_size_interleave);
3121    }
3122
3123    // The below logic is designed so as to unpack and rearrange scales in Q6_K
3124    // The output Q6_Kx8 structure interleaves the 8 bit scales in the same fashion as the quants
3125    // Q6_K structure has an 8-bit scale per 16 elements -> 16 scales
3126    // scales: [0 bl0 0 bl1 ... 0 bl7][1 bl0 ... 1 bl7] ... [15 bl0 ... 15 bl7]  (bl = block)
3127    constexpr int n_scales = QK_K / 16;
3128
3129    for (int i = 0; i < n_blocks; i++) {
3130        for (int j = 0; j < n_scales; j++) {
3131            out.scales[j * n_blocks + i] = in[i].scales[j];
3132        }
3133    }
3134
3135    return out;
3136}
3137
3138static block_q2_Kx16 make_block_q2_Kx16(const block_q2_K * in, unsigned int blck_size_interleave) {
3139    block_q2_Kx16 out;
3140    constexpr int N_COLS = 16;
3141
3142    // 1. Copy Super-Scales (d) and Super-Mins (dmin)
3143    for (int i = 0; i < N_COLS; i++) {
3144        out.d[i]    = in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d;
3145        out.dmin[i] = in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.dmin;
3146    }
3147
3148    // 2. Interleave Q2_K Data
3149    const int bytes_per_col = 64;
3150    const int total_bytes = N_COLS * bytes_per_col;
3151    const int end = total_bytes / blck_size_interleave;
3152
3153    for (int i = 0; i < end; ++i) {
3154        int src_col_id = i % N_COLS;
3155        int src_offset = (i / N_COLS) * blck_size_interleave;
3156        int dst_offset = i * blck_size_interleave;
3157        memcpy(&out.qs[dst_offset], &in[src_col_id].qs[src_offset], blck_size_interleave);
3158    }
3159
3160    // 3. Repack Scales into the Optimized "Sequential-Parallel" Layout
3161    int out_idx = 0;
3162
3163    // Arrays define the sub-block order for each group
3164    const int even_low_sbs[]  = {0, 2, 4, 6};
3165    const int odd_low_sbs[]   = {1, 3, 5, 7};
3166    const int even_high_sbs[] = {8, 10, 12, 14};
3167    const int odd_high_sbs[]  = {9, 11, 13, 15};
3168
3169    // Pack Group 1: Even-Low
3170    for (int sb : even_low_sbs) {
3171        for (int col = 0; col < N_COLS; col++) {
3172            out.scales[out_idx++] = in[col].scales[sb];
3173        }
3174    }
3175
3176    // Pack Group 2: Odd-Low
3177    for (int sb : odd_low_sbs) {
3178        for (int col = 0; col < N_COLS; col++) {
3179            out.scales[out_idx++] = in[col].scales[sb];
3180        }
3181    }
3182
3183    // Pack Group 3: Even-High
3184    for (int sb : even_high_sbs) {
3185        for (int col = 0; col < N_COLS; col++) {
3186            out.scales[out_idx++] = in[col].scales[sb];
3187        }
3188    }
3189
3190    // Pack Group 4: Odd-High
3191    for (int sb : odd_high_sbs) {
3192        for (int col = 0; col < N_COLS; col++) {
3193            out.scales[out_idx++] = in[col].scales[sb];
3194        }
3195    }
3196
3197    return out;
3198}
3199
3200static int repack_q4_0_to_q4_0_4_bl(struct ggml_tensor * t, int interleave_block, const void * GGML_RESTRICT data, size_t data_size) {
3201    GGML_ASSERT(t->type == GGML_TYPE_Q4_0);
3202    GGML_ASSERT(interleave_block == 4 || interleave_block == 8);
3203    constexpr int nrows_interleaved = 4;
3204
3205    block_q4_0x4 * dst = (block_q4_0x4 *)t->data;
3206    const block_q4_0 * src = (const block_q4_0 *)data;
3207    block_q4_0 dst_tmp[4];
3208    int nrow = ggml_nrows(t);
3209    int nblocks = t->ne[0] / QK4_0;
3210
3211    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q4_0));
3212
3213    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % 8 != 0) {
3214        return -1;
3215    }
3216
3217    for (int b = 0; b < nrow; b += nrows_interleaved) {
3218        for (int64_t x = 0; x < nblocks; x++) {
3219            for (int i = 0; i < nrows_interleaved; i++) {
3220                dst_tmp[i] = src[x + i * nblocks];
3221            }
3222            *dst++ = make_block_q4_0x4(dst_tmp, interleave_block);
3223        }
3224        src += nrows_interleaved * nblocks;
3225    }
3226    return 0;
3227
3228    GGML_UNUSED(data_size);
3229}
3230
3231static int repack_q4_K_to_q4_K_8_bl(struct ggml_tensor * t, int interleave_block, const void * GGML_RESTRICT data, size_t data_size) {
3232    GGML_ASSERT(t->type == GGML_TYPE_Q4_K);
3233    GGML_ASSERT(interleave_block == 8 || interleave_block == 4);
3234    constexpr int nrows_interleaved = 8;
3235
3236    block_q4_Kx8 * dst = (block_q4_Kx8*)t->data;
3237    const block_q4_K * src = (const block_q4_K*) data;
3238    block_q4_K dst_tmp[8];
3239    int nrow = ggml_nrows(t);
3240    int nblocks = t->ne[0] / QK_K;
3241
3242    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q4_K));
3243
3244    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % 8 != 0) {
3245        return -1;
3246    }
3247
3248    for (int b = 0; b < nrow; b += nrows_interleaved) {
3249        for (int64_t x = 0; x < nblocks; x++) {
3250            for (int i  = 0; i < nrows_interleaved; i++ ) {
3251                dst_tmp[i] = src[x + i * nblocks];
3252            }
3253            *dst++ = make_block_q4_Kx8(dst_tmp, interleave_block);
3254        }
3255        src += nrows_interleaved * nblocks;
3256    }
3257    return 0;
3258
3259    GGML_UNUSED(data_size);
3260}
3261
3262static int repack_q4_K_to_q4_K_16_bl(struct ggml_tensor * t, int interleave_block, const void * GGML_RESTRICT data, size_t data_size) {
3263    GGML_ASSERT(t->type == GGML_TYPE_Q4_K);
3264    constexpr int nrows_interleaved = 16;
3265
3266    block_q4_Kx16 * dst = (block_q4_Kx16*)t->data;
3267    const block_q4_K * src = (const block_q4_K*) data;
3268    block_q4_K dst_tmp[16];
3269    int nrow = ggml_nrows(t);
3270    int nblocks = t->ne[0] / QK_K;
3271
3272    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q4_K));
3273
3274    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % 8 != 0) {
3275        return -1;
3276    }
3277
3278    for (int b = 0; b < nrow; b += nrows_interleaved) {
3279        for (int64_t x = 0; x < nblocks; x++) {
3280            for (int i  = 0; i < nrows_interleaved; i++ ) {
3281                dst_tmp[i] = src[x + i * nblocks];
3282            }
3283            *dst++ = make_block_q4_Kx16(dst_tmp, interleave_block);
3284        }
3285        src += nrows_interleaved * nblocks;
3286    }
3287    return 0;
3288
3289    GGML_UNUSED(data_size);
3290}
3291
3292static int repack_q2_K_to_q2_K_8_bl(struct ggml_tensor * t, int interleave_block, const void * GGML_RESTRICT data, size_t data_size) {
3293    GGML_ASSERT(t->type == GGML_TYPE_Q2_K);
3294    GGML_ASSERT(interleave_block == 8);
3295    constexpr int nrows_interleaved = 8;
3296
3297    block_q2_Kx8 * dst = (block_q2_Kx8*)t->data;
3298    const block_q2_K * src = (const block_q2_K*) data;
3299    block_q2_K dst_tmp[8];
3300    int nrow = ggml_nrows(t);
3301    int nblocks = t->ne[0] / QK_K;
3302
3303    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q2_K));
3304
3305    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % 8 != 0) {
3306        return -1;
3307    }
3308
3309    for (int b = 0; b < nrow; b += nrows_interleaved) {
3310        for (int64_t x = 0; x < nblocks; x++) {
3311            for (int i = 0; i < nrows_interleaved; i++) {
3312                dst_tmp[i] = src[x + i * nblocks];
3313            }
3314            *dst++ = make_block_q2_Kx8(dst_tmp, interleave_block);
3315        }
3316        src += nrows_interleaved * nblocks;
3317    }
3318    return 0;
3319
3320    GGML_UNUSED(data_size);
3321}
3322
3323static int repack_q2_K_to_q2_K_16_bl(struct ggml_tensor * t, int interleave_block, const void * GGML_RESTRICT data, size_t data_size) {
3324    GGML_ASSERT(t->type == GGML_TYPE_Q2_K);
3325    constexpr int nrows_interleaved = 16;
3326
3327    block_q2_Kx16 * dst = (block_q2_Kx16*)t->data;
3328    const block_q2_K * src = (const block_q2_K*) data;
3329
3330    block_q2_K dst_tmp[nrows_interleaved];
3331
3332    int nrow = ggml_nrows(t);
3333    int nblocks = t->ne[0] / QK_K;
3334
3335    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q2_K));
3336
3337    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % 8 != 0) {
3338        return -1;
3339    }
3340
3341    for (int b = 0; b < nrow; b += nrows_interleaved) {
3342        for (int64_t x = 0; x < nblocks; x++) {
3343            // This loop gathers 16 separate blocks (one from each column)
3344            // that correspond to the same K-dimension chunk.
3345            for (int i  = 0; i < nrows_interleaved; i++ ) {
3346                dst_tmp[i] = src[x + i * nblocks];
3347            }
3348
3349            *dst++ = make_block_q2_Kx16(dst_tmp, interleave_block);
3350        }
3351        src += nrows_interleaved * nblocks;
3352    }
3353    return 0;
3354
3355    GGML_UNUSED(data_size);
3356}
3357
3358static int repack_q4_0_to_q4_0_16_bl(struct ggml_tensor * t, int interleave_block, const void * GGML_RESTRICT data, size_t data_size) {
3359    GGML_ASSERT(t->type == GGML_TYPE_Q4_0);
3360    constexpr int nrows_interleaved = 16;
3361
3362    block_q4_0x16 * dst = (block_q4_0x16*)t->data;
3363    const block_q4_0 * src = (const block_q4_0*) data;
3364    block_q4_0 dst_tmp[16];
3365    int nrow = ggml_nrows(t);
3366    int nblocks = t->ne[0] / QK4_0;
3367
3368    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q4_0));
3369
3370    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % 8 != 0) {
3371        return -1;
3372    }
3373
3374    for (int b = 0; b < nrow; b += nrows_interleaved) {
3375        for (int64_t x = 0; x < nblocks; x++) {
3376            for (int i  = 0; i < nrows_interleaved; i++ ) {
3377                dst_tmp[i] = src[x + i * nblocks];
3378            }
3379            *dst++ = make_block_q4_0x16(dst_tmp, interleave_block);
3380        }
3381        src += nrows_interleaved * nblocks;
3382    }
3383    return 0;
3384
3385    GGML_UNUSED(data_size);
3386}
3387
3388static int repack_q5_K_to_q5_K_8_bl(struct ggml_tensor *       t,
3389                                    int                        interleave_block,
3390                                    const void * GGML_RESTRICT data,
3391                                    size_t                     data_size) {
3392    GGML_ASSERT(t->type == GGML_TYPE_Q5_K);
3393    GGML_ASSERT(interleave_block == 4 || interleave_block == 8);
3394    constexpr int nrows_interleaved = 8;
3395
3396    block_q5_Kx8 *     dst = (block_q5_Kx8 *) t->data;
3397    const block_q5_K * src = (const block_q5_K *) data;
3398    block_q5_K         dst_tmp[8];
3399    int                nrow    = ggml_nrows(t);
3400    int                nblocks = t->ne[0] / QK_K;
3401
3402    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q5_K));
3403
3404    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % 8 != 0) {
3405        return -1;
3406    }
3407
3408    for (int b = 0; b < nrow; b += nrows_interleaved) {
3409        for (int64_t x = 0; x < nblocks; x++) {
3410            for (int i = 0; i < nrows_interleaved; i++) {
3411                dst_tmp[i] = src[x + i * nblocks];
3412            }
3413            *dst++ = make_block_q5_Kx8(dst_tmp, interleave_block);
3414        }
3415        src += nrows_interleaved * nblocks;
3416    }
3417    return 0;
3418}
3419
3420static int repack_q6_K_to_q6_K_8_bl(struct ggml_tensor * t, int interleave_block, const void * GGML_RESTRICT data, size_t data_size) {
3421    GGML_ASSERT(t->type == GGML_TYPE_Q6_K);
3422    GGML_ASSERT(interleave_block == 4 || interleave_block == 8);
3423    constexpr int nrows_interleaved = 8;
3424
3425    block_q6_Kx8 * dst = (block_q6_Kx8 *)t->data;
3426    const block_q6_K * src = (const block_q6_K *) data;
3427    block_q6_K dst_tmp[8];
3428    int nrow = ggml_nrows(t);
3429    int nblocks = t->ne[0] / QK_K;
3430
3431    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q6_K));
3432
3433    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % 8 != 0) {
3434        return -1;
3435    }
3436
3437    for (int b = 0; b < nrow; b += nrows_interleaved) {
3438        for (int64_t x = 0; x < nblocks; x++) {
3439            for (int i = 0; i < nrows_interleaved; i++) {
3440                dst_tmp[i] = src[x + i * nblocks];
3441            }
3442            *dst++ = make_block_q6_Kx8(dst_tmp, interleave_block);
3443        }
3444        src += nrows_interleaved * nblocks;
3445    }
3446    return 0;
3447}
3448
3449static int repack_q4_0_to_q4_0_8_bl(struct ggml_tensor * t, int interleave_block, const void * GGML_RESTRICT data, size_t data_size) {
3450    GGML_ASSERT(t->type == GGML_TYPE_Q4_0);
3451    GGML_ASSERT(interleave_block == 8);
3452    constexpr int nrows_interleaved = 8;
3453
3454    block_q4_0x8 * dst = (block_q4_0x8*)t->data;
3455    const block_q4_0 * src = (const block_q4_0*) data;
3456    block_q4_0 dst_tmp[8];
3457    int nrow = ggml_nrows(t);
3458    int nblocks = t->ne[0] / QK4_0;
3459
3460    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q4_0));
3461
3462    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % 8 != 0) {
3463        return -1;
3464    }
3465
3466    for (int b = 0; b < nrow; b += nrows_interleaved) {
3467        for (int64_t x = 0; x < nblocks; x++) {
3468            for (int i  = 0; i < nrows_interleaved; i++ ) {
3469                dst_tmp[i] = src[x + i * nblocks];
3470            }
3471            *dst++ = make_block_q4_0x8(dst_tmp, interleave_block);
3472        }
3473        src += nrows_interleaved * nblocks;
3474    }
3475    return 0;
3476
3477    GGML_UNUSED(data_size);
3478}
3479
3480static int repack_q8_0_to_q8_0_4_bl(struct ggml_tensor *       t,
3481                                    int                        interleave_block,
3482                                    const void * GGML_RESTRICT data,
3483                                    size_t                     data_size) {
3484    GGML_ASSERT(t->type == GGML_TYPE_Q8_0);
3485    GGML_ASSERT(interleave_block == 4 || interleave_block == 8);
3486    constexpr int nrows_interleaved = 4;
3487
3488    block_q8_0x4 *     dst = (block_q8_0x4 *) t->data;
3489    const block_q8_0 * src = (const block_q8_0 *) data;
3490    block_q8_0         dst_tmp[4];
3491    int                nrow    = ggml_nrows(t);
3492    int                nblocks = t->ne[0] / QK8_0;
3493
3494    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q8_0));
3495
3496    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % 8 != 0) {
3497        return -1;
3498    }
3499
3500    for (int b = 0; b < nrow; b += nrows_interleaved) {
3501        for (int64_t x = 0; x < nblocks; x++) {
3502            for (int i = 0; i < nrows_interleaved; i++) {
3503                dst_tmp[i] = src[x + i * nblocks];
3504            }
3505            *dst++ = make_block_q8_0x4(dst_tmp, interleave_block);
3506        }
3507        src += nrows_interleaved * nblocks;
3508    }
3509    return 0;
3510}
3511
3512static block_q8_0x16 make_block_q8_0x16(block_q8_0 * in, unsigned int blck_size_interleave) {
3513    block_q8_0x16 out;
3514
3515    for (int i = 0; i < 16; i++) {
3516        out.d[i] = in[i].d;
3517    }
3518
3519    const int end = QK8_0 * 16 / blck_size_interleave;
3520
3521    if (blck_size_interleave == 1) {
3522        for (int i = 0; i < end; ++i) {
3523            int src_id     = i % 16;
3524            int src_offset = i / 16;
3525            int dst_offset = i;
3526            out.qs[dst_offset] = in[src_id].qs[src_offset];
3527        }
3528    } else {
3529        GGML_ASSERT(false);
3530    }
3531
3532    return out;
3533}
3534
3535static int repack_q8_0_to_q8_0_16_bl(struct ggml_tensor *       t,
3536                                    int                        interleave_block,
3537                                    const void * GGML_RESTRICT data,
3538                                    size_t                     data_size) {
3539    GGML_ASSERT(t->type == GGML_TYPE_Q8_0);
3540    constexpr int nrows_interleaved = 16;
3541
3542    block_q8_0x16 *     dst = (block_q8_0x16 *) t->data;
3543    const block_q8_0 * src = (const block_q8_0 *) data;
3544    block_q8_0         dst_tmp[16];
3545    int                nrow    = ggml_nrows(t);
3546    int                nblocks = t->ne[0] / QK8_0;
3547
3548    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q8_0));
3549
3550    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % 8 != 0) {
3551        return -1;
3552    }
3553
3554    for (int b = 0; b < nrow; b += nrows_interleaved) {
3555        for (int64_t x = 0; x < nblocks; x++) {
3556            for (int i = 0; i < nrows_interleaved; i++) {
3557                dst_tmp[i] = src[x + i * nblocks];
3558            }
3559            *dst++ = make_block_q8_0x16(dst_tmp, interleave_block);
3560        }
3561        src += nrows_interleaved * nblocks;
3562    }
3563    return 0;
3564}
3565
3566static block_iq4_nlx4 make_block_iq4_nlx4(block_iq4_nl * in, unsigned int blck_size_interleave) {
3567    block_iq4_nlx4 out;
3568
3569    for (int i = 0; i < 4; i++) {
3570        out.d[i] = in[i].d;
3571    }
3572
3573    const int end = QK4_NL * 2 / blck_size_interleave;
3574
3575    // TODO: this branch seems wrong
3576    //if (blck_size_interleave == 8) {
3577    //    for (int i = 0; i < end; ++i) {
3578    //        int src_id = i % 4;
3579    //        int src_offset = (i / 4) * blck_size_interleave;
3580    //        int dst_offset = i * blck_size_interleave;
3581
3582    //        // Using memcpy to avoid unaligned memory accesses
3583    //        memcpy(&out.qs[dst_offset], &in[src_id].qs[src_offset], sizeof(uint64_t));
3584    //    }
3585    //} else
3586    if (blck_size_interleave == 4) {
3587        for (int i = 0; i < end; ++i) {
3588            int src_id = i % 4;
3589            int src_offset = (i / 4) * blck_size_interleave;
3590            int dst_offset = i * blck_size_interleave;
3591
3592            memcpy(&out.qs[dst_offset], &in[src_id].qs[src_offset], sizeof(uint32_t));
3593        }
3594    } else {
3595        GGML_ASSERT(false);
3596    }
3597
3598    return out;
3599}
3600
3601static int repack_iq4_nl_to_iq4_nl_4_bl(struct ggml_tensor * t, int interleave_block, const void * GGML_RESTRICT data, size_t data_size) {
3602    GGML_ASSERT(t->type == GGML_TYPE_IQ4_NL);
3603    GGML_ASSERT(interleave_block == 4);
3604
3605    const block_iq4_nl   * src = (const block_iq4_nl   *)data;
3606          block_iq4_nlx4 * dst = (      block_iq4_nlx4 *)t->data;
3607
3608    block_iq4_nl dst_tmp[4];
3609
3610    int nrow = ggml_nrows(t);
3611    int nrows_interleaved = 4;
3612    int nblocks = t->ne[0] / QK4_NL;
3613
3614    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_iq4_nl));
3615
3616    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % 8 != 0) {
3617        return -1;
3618    }
3619
3620    for (int b = 0; b < nrow; b += nrows_interleaved) {
3621        for (int64_t x = 0; x < nblocks; x++) {
3622            for (int i = 0; i < nrows_interleaved; i++) {
3623                dst_tmp[i] = src[x + i * nblocks];
3624            }
3625            *dst++ = make_block_iq4_nlx4(dst_tmp, interleave_block);
3626        }
3627        src += nrows_interleaved * nblocks;
3628    }
3629    return 0;
3630
3631    GGML_UNUSED(data_size);
3632}
3633
3634static block_iq4_nlx8 make_block_iq4_nlx8(block_iq4_nl * in, unsigned int blck_size_interleave) {
3635    block_iq4_nlx8 out;
3636
3637    for (int i = 0; i < 8; i++) {
3638        out.d[i] = in[i].d;
3639    }
3640
3641    const int end = QK4_NL * 4 / blck_size_interleave;
3642
3643    if (blck_size_interleave == 8) {
3644        for (int i = 0; i < end; ++i) {
3645            int src_id = i % 8;
3646            int src_offset = (i / 8) * blck_size_interleave;
3647            int dst_offset = i * blck_size_interleave;
3648
3649            memcpy(&out.qs[dst_offset], &in[src_id].qs[src_offset], sizeof(uint64_t));
3650        }
3651    } else {
3652        GGML_ASSERT(false);
3653    }
3654
3655    return out;
3656}
3657
3658static int repack_iq4_nl_to_iq4_nl_8_bl(struct ggml_tensor * t, int interleave_block, const void * GGML_RESTRICT data, size_t data_size) {
3659    GGML_ASSERT(t->type == GGML_TYPE_IQ4_NL);
3660    GGML_ASSERT(interleave_block == 8);
3661
3662    const block_iq4_nl   * src = (const block_iq4_nl   *)data;
3663          block_iq4_nlx8 * dst = (      block_iq4_nlx8 *)t->data;
3664
3665    block_iq4_nl dst_tmp[8];
3666
3667    int nrow = ggml_nrows(t);
3668    int nrows_interleaved = 8;
3669    int nblocks = t->ne[0] / QK4_NL;
3670
3671    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_iq4_nl));
3672
3673    if (t->ne[1] % nrows_interleaved != 0) {
3674        return -1;
3675    }
3676
3677    for (int b = 0; b < nrow; b += nrows_interleaved) {
3678        for (int64_t x = 0; x < nblocks; x++) {
3679            for (int i = 0; i < nrows_interleaved; i++) {
3680                dst_tmp[i] = src[x + i * nblocks];
3681            }
3682            *dst++ = make_block_iq4_nlx8(dst_tmp, interleave_block);
3683        }
3684        src += nrows_interleaved * nblocks;
3685    }
3686    return 0;
3687
3688    GGML_UNUSED(data_size);
3689}
3690
3691static block_iq4_nlx16 make_block_iq4_nlx16(block_iq4_nl * in, unsigned int blck_size_interleave) {
3692    block_iq4_nlx16 out;
3693
3694    for (int i = 0; i < 16; i++) {
3695        out.d[i] = in[i].d;
3696    }
3697
3698    const int end = QK4_NL * 8 / blck_size_interleave;
3699
3700    if (blck_size_interleave == 1) {
3701        for (int i = 0; i < end; ++i) {
3702            int src_id = i % 16;
3703            int src_offset = i / 16;
3704            int dst_offset = i;
3705
3706            out.qs[dst_offset] = in[src_id].qs[src_offset];
3707        }
3708    } else {
3709        GGML_ASSERT(false);
3710    }
3711
3712    return out;
3713}
3714
3715static int repack_iq4_nl_to_iq4_nl_16_bl(struct ggml_tensor * t, int interleave_block, const void * GGML_RESTRICT data, size_t data_size) {
3716    GGML_ASSERT(t->type == GGML_TYPE_IQ4_NL);
3717    GGML_ASSERT(interleave_block == 1);
3718
3719    const block_iq4_nl    * src = (const block_iq4_nl   *)data;
3720          block_iq4_nlx16 * dst = (      block_iq4_nlx16 *)t->data;
3721
3722    block_iq4_nl dst_tmp[16];
3723
3724    int nrow = ggml_nrows(t);
3725    int nrows_interleaved = 16;
3726    int nblocks = t->ne[0] / QK4_NL;
3727
3728    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_iq4_nl));
3729
3730    if (t->ne[1] % nrows_interleaved != 0) {
3731        return -1;
3732    }
3733
3734    for (int b = 0; b < nrow; b += nrows_interleaved) {
3735        for (int64_t x = 0; x < nblocks; x++) {
3736            for (int i = 0; i < nrows_interleaved; i++) {
3737                dst_tmp[i] = src[x + i * nblocks];
3738            }
3739            *dst++ = make_block_iq4_nlx16(dst_tmp, interleave_block);
3740        }
3741        src += nrows_interleaved * nblocks;
3742    }
3743    return 0;
3744
3745    GGML_UNUSED(data_size);
3746}
3747
3748static block_mxfp4x4 make_block_mxfp4x4(block_mxfp4 * in, unsigned int blck_size_interleave) {
3749    block_mxfp4x4 out;
3750
3751    for (int i = 0; i < 4; i++) {
3752        out.e[i] = in[i].e;
3753    }
3754
3755    const int end = QK_MXFP4 * 2 / blck_size_interleave;
3756
3757    if (blck_size_interleave == 4) {
3758        for (int i = 0; i < end; ++i) {
3759            int src_id = i % 4;
3760            int src_offset = (i / 4) * blck_size_interleave;
3761            int dst_offset = i * blck_size_interleave;
3762
3763            memcpy(&out.qs[dst_offset], &in[src_id].qs[src_offset], sizeof(uint32_t));
3764        }
3765    } else {
3766        GGML_ASSERT(false);
3767    }
3768
3769    return out;
3770}
3771
3772static int repack_mxfp4_to_mxfp4_4_bl(struct ggml_tensor * t, int interleave_block, const void * GGML_RESTRICT data, size_t data_size) {
3773    GGML_ASSERT(t->type == GGML_TYPE_MXFP4);
3774    GGML_ASSERT(interleave_block == 4);
3775
3776    const block_mxfp4   * src = (const block_mxfp4   *)data;
3777          block_mxfp4x4 * dst = (      block_mxfp4x4 *)t->data;
3778
3779    block_mxfp4 dst_tmp[4];
3780
3781    int nrow = ggml_nrows(t);
3782    int nrows_interleaved = 4;
3783    int nblocks = t->ne[0] / QK_MXFP4;
3784
3785    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_mxfp4));
3786
3787    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % 8 != 0) {
3788        return -1;
3789    }
3790
3791    for (int b = 0; b < nrow; b += nrows_interleaved) {
3792        for (int64_t x = 0; x < nblocks; x++) {
3793            for (int i = 0; i < nrows_interleaved; i++) {
3794                dst_tmp[i] = src[x + i * nblocks];
3795            }
3796            *dst++ = make_block_mxfp4x4(dst_tmp, interleave_block);
3797        }
3798        src += nrows_interleaved * nblocks;
3799    }
3800    return 0;
3801
3802    GGML_UNUSED(data_size);
3803}
3804
3805static block_mxfp4x8 make_block_mxfp4x8(block_mxfp4 * in, unsigned int blck_size_interleave) {
3806    block_mxfp4x8 out;
3807
3808    for (int i = 0; i < 8; i++) {
3809        out.e[i] = in[i].e;
3810    }
3811
3812    const int end = QK_MXFP4 * 4 / blck_size_interleave;
3813
3814    if (blck_size_interleave == 8) {
3815        for (int i = 0; i < end; ++i) {
3816            int src_id = i % 8;
3817            int src_offset = (i / 8) * blck_size_interleave;
3818            int dst_offset = i * blck_size_interleave;
3819
3820            memcpy(&out.qs[dst_offset], &in[src_id].qs[src_offset], sizeof(uint64_t));
3821        }
3822    } else {
3823        GGML_ASSERT(false);
3824    }
3825
3826    return out;
3827}
3828
3829static int repack_mxfp4_to_mxfp4_8_bl(struct ggml_tensor * t, int interleave_block, const void * GGML_RESTRICT data, size_t data_size) {
3830    GGML_ASSERT(t->type == GGML_TYPE_MXFP4);
3831    GGML_ASSERT(interleave_block == 8);
3832
3833    const block_mxfp4   * src = (const block_mxfp4   *)data;
3834          block_mxfp4x8 * dst = (      block_mxfp4x8 *)t->data;
3835
3836    block_mxfp4 dst_tmp[8];
3837
3838    int nrow = ggml_nrows(t);
3839    int nrows_interleaved = 8;
3840    int nblocks = t->ne[0] / QK_MXFP4;
3841
3842    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_mxfp4));
3843
3844    if (t->ne[1] % nrows_interleaved != 0) {
3845        return -1;
3846    }
3847
3848    for (int b = 0; b < nrow; b += nrows_interleaved) {
3849        for (int64_t x = 0; x < nblocks; x++) {
3850            for (int i = 0; i < nrows_interleaved; i++) {
3851                dst_tmp[i] = src[x + i * nblocks];
3852            }
3853            *dst++ = make_block_mxfp4x8(dst_tmp, interleave_block);
3854        }
3855        src += nrows_interleaved * nblocks;
3856    }
3857    return 0;
3858
3859    GGML_UNUSED(data_size);
3860}
3861
3862namespace ggml::cpu::repack {
3863// repack
3864template <typename BLOC_TYPE, int64_t INTER_SIZE, int64_t NB_COLS>
3865int repack(struct ggml_tensor *, const void *, size_t);
3866
3867// TODO: generalise.
3868template <> int repack<block_q4_0, 4, 4>(struct ggml_tensor * t, const void * data, size_t data_size) {
3869    return repack_q4_0_to_q4_0_4_bl(t, 4, data, data_size);
3870}
3871
3872template <> int repack<block_q4_0, 8, 4>(struct ggml_tensor * t, const void * data, size_t data_size) {
3873    return repack_q4_0_to_q4_0_4_bl(t, 8, data, data_size);
3874}
3875
3876template <> int repack<block_q4_0, 8, 8>(struct ggml_tensor * t, const void * data, size_t data_size) {
3877    return repack_q4_0_to_q4_0_8_bl(t, 8, data, data_size);
3878}
3879
3880template <> int repack<block_q4_K, 8, 8>(struct ggml_tensor * t, const void * data, size_t data_size) {
3881    return repack_q4_K_to_q4_K_8_bl(t, 8, data, data_size);
3882}
3883
3884template <> int repack<block_q4_K, 4, 8>(struct ggml_tensor * t, const void * data, size_t data_size) {
3885    return repack_q4_K_to_q4_K_8_bl(t, 4, data, data_size);
3886}
3887
3888template <> int repack<block_q2_K, 8, 8>(struct ggml_tensor * t, const void * data, size_t data_size) {
3889    return repack_q2_K_to_q2_K_8_bl(t, 8, data, data_size);
3890}
3891
3892template <> int repack<block_q5_K, 4, 8>(struct ggml_tensor * t, const void * data, size_t data_size) {
3893    return repack_q5_K_to_q5_K_8_bl(t, 4, data, data_size);
3894}
3895
3896template <> int repack<block_q5_K, 8, 8>(struct ggml_tensor * t, const void * data, size_t data_size) {
3897    return repack_q5_K_to_q5_K_8_bl(t, 8, data, data_size);
3898}
3899
3900template <> int repack<block_q6_K, 4, 8>(struct ggml_tensor * t, const void * data, size_t data_size) {
3901    return repack_q6_K_to_q6_K_8_bl(t, 4, data, data_size);
3902}
3903
3904template <> int repack<block_q6_K, 8, 8>(struct ggml_tensor * t, const void * data, size_t data_size) {
3905    return repack_q6_K_to_q6_K_8_bl(t, 8, data, data_size);
3906}
3907
3908template <> int repack<block_iq4_nl, 4, 4>(struct ggml_tensor * t, const void * data, size_t data_size) {
3909    return repack_iq4_nl_to_iq4_nl_4_bl(t, 4, data, data_size);
3910}
3911
3912// TODO: needs to be revisited
3913//template <> int repack<block_iq4_nl, 8, 4>(struct ggml_tensor * t, const void * data, size_t data_size) {
3914//    return repack_iq4_nl_to_iq4_nl_4_bl(t, 8, data, data_size);
3915//}
3916
3917template <> int repack<block_iq4_nl, 8, 8>(struct ggml_tensor * t, const void * data, size_t data_size) {
3918    return repack_iq4_nl_to_iq4_nl_8_bl(t, 8, data, data_size);
3919}
3920
3921template <> int repack<block_mxfp4, 4, 4>(struct ggml_tensor * t, const void * data, size_t data_size) {
3922    return repack_mxfp4_to_mxfp4_4_bl(t, 4, data, data_size);
3923}
3924
3925template <> int repack<block_mxfp4, 8, 8>(struct ggml_tensor * t, const void * data, size_t data_size) {
3926    return repack_mxfp4_to_mxfp4_8_bl(t, 8, data, data_size);
3927}
3928
3929template <> int repack<block_q8_0, 4, 4>(struct ggml_tensor * t, const void * data, size_t data_size) {
3930    return repack_q8_0_to_q8_0_4_bl(t, 4, data, data_size);
3931}
3932
3933template <> int repack<block_q8_0, 8, 4>(struct ggml_tensor * t, const void * data, size_t data_size) {
3934    return repack_q8_0_to_q8_0_4_bl(t, 8, data, data_size);
3935}
3936
3937#if defined __riscv_zvfh
3938template <> int repack<block_q4_0, 1, 16>(struct ggml_tensor * t, const void * data, size_t data_size) {
3939    return repack_q4_0_to_q4_0_16_bl(t, 1, data, data_size);
3940}
3941
3942template <> int repack<block_q4_K, 1, 16>(struct ggml_tensor * t, const void * data, size_t data_size) {
3943    return repack_q4_K_to_q4_K_16_bl(t, 1, data, data_size);
3944}
3945
3946template <> int repack<block_iq4_nl, 1, 16>(struct ggml_tensor * t, const void * data, size_t data_size) {
3947    return repack_iq4_nl_to_iq4_nl_16_bl(t, 1, data, data_size);
3948}
3949
3950template <> int repack<block_q8_0, 1, 16>(struct ggml_tensor * t, const void * data, size_t data_size) {
3951    return repack_q8_0_to_q8_0_16_bl(t, 1, data, data_size);
3952}
3953
3954template <> int repack<block_q2_K, 1, 16>(struct ggml_tensor * t, const void * data, size_t data_size) {
3955    return repack_q2_K_to_q2_K_16_bl(t, 1, data, data_size);
3956}
3957#endif
3958
3959// gemv
3960template <typename BLOC_TYPE, int64_t INTER_SIZE, int64_t NB_COLS, ggml_type PARAM_TYPE>
3961void gemv(int, float *, size_t, const void *, const void *, int, int);
3962
3963template <> void gemv<block_q4_0, 4, 4, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
3964    ggml_gemv_q4_0_4x4_q8_0(n, s, bs, vx, vy, nr, nc);
3965}
3966
3967template <> void gemv<block_q4_0, 8, 4, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
3968    ggml_gemv_q4_0_4x8_q8_0(n, s, bs, vx, vy, nr, nc);
3969}
3970
3971template <> void gemv<block_q4_0, 8, 8, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
3972    ggml_gemv_q4_0_8x8_q8_0(n, s, bs, vx, vy, nr, nc);
3973}
3974
3975template <>
3976void gemv<block_q2_K, 8, 8, GGML_TYPE_Q8_K>(int          n,
3977                                            float *      s,
3978                                            size_t       bs,
3979                                            const void * vx,
3980                                            const void * vy,
3981                                            int          nr,
3982                                            int          nc) {
3983    ggml_gemv_q2_K_8x8_q8_K(n, s, bs, vx, vy, nr, nc);
3984}
3985
3986template <> void gemv<block_q4_K, 4, 8, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
3987    ggml_gemv_q4_K_8x4_q8_K(n, s, bs, vx, vy, nr, nc);
3988}
3989
3990template <> void gemv<block_q4_K, 8, 8, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
3991    ggml_gemv_q4_K_8x8_q8_K(n, s, bs, vx, vy, nr, nc);
3992}
3993
3994template <> void gemv<block_q5_K, 4, 8, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
3995    ggml_gemv_q5_K_8x4_q8_K(n, s, bs, vx, vy, nr, nc);
3996}
3997
3998template <> void gemv<block_q5_K, 8, 8, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
3999    ggml_gemv_q5_K_8x8_q8_K(n, s, bs, vx, vy, nr, nc);
4000}
4001
4002template <> void gemv<block_q6_K, 4, 8, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4003    ggml_gemv_q6_K_8x4_q8_K(n, s, bs, vx, vy, nr, nc);
4004}
4005
4006template <> void gemv<block_q6_K, 8, 8, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4007    ggml_gemv_q6_K_8x8_q8_K(n, s, bs, vx, vy, nr, nc);
4008}
4009
4010template <> void gemv<block_iq4_nl, 4, 4, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4011    ggml_gemv_iq4_nl_4x4_q8_0(n, s, bs, vx, vy, nr, nc);
4012}
4013
4014template <> void gemv<block_iq4_nl, 8, 8, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4015    ggml_gemv_iq4_nl_8x8_q8_0(n, s, bs, vx, vy, nr, nc);
4016}
4017
4018template <> void gemv<block_mxfp4, 4, 4, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4019    ggml_gemv_mxfp4_4x4_q8_0(n, s, bs, vx, vy, nr, nc);
4020}
4021
4022template <> void gemv<block_mxfp4, 8, 8, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4023    ggml_gemv_mxfp4_8x8_q8_0(n, s, bs, vx, vy, nr, nc);
4024}
4025
4026template <> void gemv<block_q8_0, 4, 4, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4027    ggml_gemv_q8_0_4x4_q8_0(n, s, bs, vx, vy, nr, nc);
4028}
4029
4030template <> void gemv<block_q8_0, 8, 4, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4031    ggml_gemv_q8_0_4x8_q8_0(n, s, bs, vx, vy, nr, nc);
4032}
4033
4034#if defined __riscv_zvfh
4035template <> void gemv<block_q4_0, 1, 16, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4036    ggml_gemv_q4_0_16x1_q8_0(n, s, bs, vx, vy, nr, nc);
4037}
4038
4039template <> void gemv<block_q4_K, 1, 16, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4040    ggml_gemv_q4_K_16x1_q8_K(n, s, bs, vx, vy, nr, nc);
4041}
4042
4043template <> void gemv<block_iq4_nl, 1, 16, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4044    ggml_gemv_iq4_nl_16x1_q8_0(n, s, bs, vx, vy, nr, nc);
4045}
4046
4047template <> void gemv<block_q8_0, 1, 16, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4048    ggml_gemv_q8_0_16x1_q8_0(n, s, bs, vx, vy, nr, nc);
4049}
4050
4051template <> void gemv<block_q2_K, 1, 16, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4052    ggml_gemv_q2_K_16x1_q8_K(n, s, bs, vx, vy, nr, nc);
4053}
4054#endif
4055
4056// gemm
4057template <typename BLOC_TYPE, int64_t INTER_SIZE, int64_t NB_COLS, ggml_type PARAM_TYPE>
4058void gemm(int, float *, size_t, const void *, const void *, int, int);
4059
4060template <> void gemm<block_q4_0, 4, 4, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4061    ggml_gemm_q4_0_4x4_q8_0(n, s, bs, vx, vy, nr, nc);
4062}
4063
4064template <> void gemm<block_q4_0, 8, 4, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4065    ggml_gemm_q4_0_4x8_q8_0(n, s, bs, vx, vy, nr, nc);
4066}
4067
4068template <>
4069void gemm<block_q4_0, 8, 8, GGML_TYPE_Q8_0>(int          n,
4070                                            float *      s,
4071                                            size_t       bs,
4072                                            const void * vx,
4073                                            const void * vy,
4074                                            int          nr,
4075                                            int          nc) {
4076    ggml_gemm_q4_0_8x8_q8_0(n, s, bs, vx, vy, nr, nc);
4077}
4078
4079template <> void gemm<block_q2_K, 8, 8, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4080    ggml_gemm_q2_K_8x8_q8_K(n, s, bs, vx, vy, nr, nc);
4081}
4082
4083template <> void gemm<block_q4_K, 4, 8, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4084    ggml_gemm_q4_K_8x4_q8_K(n, s, bs, vx, vy, nr, nc);
4085}
4086
4087template <> void gemm<block_q4_K, 8, 8, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4088    ggml_gemm_q4_K_8x8_q8_K(n, s, bs, vx, vy, nr, nc);
4089}
4090
4091template <> void gemm<block_q5_K, 4, 8, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4092    ggml_gemm_q5_K_8x4_q8_K(n, s, bs, vx, vy, nr, nc);
4093}
4094
4095template <> void gemm<block_q5_K, 8, 8, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4096    ggml_gemm_q5_K_8x8_q8_K(n, s, bs, vx, vy, nr, nc);
4097}
4098
4099template <> void gemm<block_q6_K, 4, 8, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4100    ggml_gemm_q6_K_8x4_q8_K(n, s, bs, vx, vy, nr, nc);
4101}
4102
4103template <> void gemm<block_q6_K, 8, 8, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4104    ggml_gemm_q6_K_8x8_q8_K(n, s, bs, vx, vy, nr, nc);
4105}
4106
4107template <> void gemm<block_iq4_nl, 4, 4, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4108    ggml_gemm_iq4_nl_4x4_q8_0(n, s, bs, vx, vy, nr, nc);
4109}
4110
4111template <> void gemm<block_iq4_nl, 8, 8, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4112    ggml_gemm_iq4_nl_8x8_q8_0(n, s, bs, vx, vy, nr, nc);
4113}
4114
4115template <> void gemm<block_mxfp4, 4, 4, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4116    ggml_gemm_mxfp4_4x4_q8_0(n, s, bs, vx, vy, nr, nc);
4117}
4118
4119template <> void gemm<block_mxfp4, 8, 8, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4120    ggml_gemm_mxfp4_8x8_q8_0(n, s, bs, vx, vy, nr, nc);
4121}
4122
4123template <> void gemm<block_q8_0, 4, 4, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4124    ggml_gemm_q8_0_4x4_q8_0(n, s, bs, vx, vy, nr, nc);
4125}
4126
4127template <> void gemm<block_q8_0, 8, 4, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4128    ggml_gemm_q8_0_4x8_q8_0(n, s, bs, vx, vy, nr, nc);
4129}
4130
4131#if defined __riscv_zvfh
4132template <> void gemm<block_q4_0, 1, 16, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4133    ggml_gemm_q4_0_16x1_q8_0(n, s, bs, vx, vy, nr, nc);
4134}
4135
4136template <> void gemm<block_q4_K, 1, 16, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4137    ggml_gemm_q4_K_16x1_q8_K(n, s, bs, vx, vy, nr, nc);
4138}
4139
4140template <> void gemm<block_iq4_nl, 1, 16, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4141    ggml_gemm_iq4_nl_16x1_q8_0(n, s, bs, vx, vy, nr, nc);
4142}
4143
4144template <> void gemm<block_q8_0, 1, 16, GGML_TYPE_Q8_0>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4145    ggml_gemm_q8_0_16x1_q8_0(n, s, bs, vx, vy, nr, nc);
4146}
4147
4148template <> void gemm<block_q2_K, 1, 16, GGML_TYPE_Q8_K>(int n, float * s, size_t bs, const void * vx, const void * vy, int nr, int nc) {
4149    ggml_gemm_q2_K_16x1_q8_K(n, s, bs, vx, vy, nr, nc);
4150}
4151#endif
4152
4153class tensor_traits_base : public ggml::cpu::tensor_traits {
4154  public:
4155    virtual int repack(struct ggml_tensor * t, const void * data, size_t data_size) = 0;
4156};
4157
4158template <typename BLOC_TYPE, int64_t INTER_SIZE, int64_t NB_COLS, ggml_type PARAM_TYPE> class tensor_traits : public tensor_traits_base {
4159
4160    bool work_size(int /* n_threads */, const struct ggml_tensor * op, size_t & size) override {
4161        // not realy a GGML_TYPE_Q8_0 but same size.
4162        switch (op->op) {
4163            case GGML_OP_MUL_MAT:
4164                {
4165                    size = ggml_row_size(PARAM_TYPE, ggml_nelements(op->src[1]));
4166                    return true;
4167                }
4168            case GGML_OP_MUL_MAT_ID:
4169                {
4170                    size = ggml_row_size(PARAM_TYPE, ggml_nelements(op->src[1]));
4171                    size = GGML_PAD(size, sizeof(int64_t)); // + padding for next block.
4172
4173                    const int64_t ne02 = op->src[0]->ne[2]; // n_as, n_expert
4174                    const int64_t ne12 = op->src[1]->ne[2]; // n_tokens
4175
4176                    const size_t sizeof_mmid_row_mapping = sizeof(int64_t);
4177
4178                    size += sizeof_mmid_row_mapping*ne02*(ne12 + 1);
4179
4180                    return true;
4181                }
4182            default:
4183                // GGML_ABORT("fatal error");
4184                break;
4185        }
4186        return false;
4187    }
4188
4189    bool compute_forward(struct ggml_compute_params * params, struct ggml_tensor * op) override {
4190        switch (op->op) {
4191            case GGML_OP_MUL_MAT:
4192                forward_mul_mat(params, op);
4193                return true;
4194            case GGML_OP_MUL_MAT_ID:
4195                forward_mul_mat_id(params, op);
4196                return true;
4197            default:
4198                // GGML_ABORT("fatal error");
4199                break;
4200        }
4201        return false;
4202    }
4203
4204    void forward_mul_mat_one_chunk(ggml_compute_params * params,
4205                                   ggml_tensor *         op,
4206                                   int64_t               src0_start,
4207                                   int64_t               src0_end,
4208                                   int64_t               src1_start,
4209                                   int64_t               src1_end) {
4210        const ggml_tensor * src0 = op->src[0];
4211        const ggml_tensor * src1 = op->src[1];
4212        ggml_tensor *       dst  = op;
4213
4214        GGML_TENSOR_BINARY_OP_LOCALS
4215
4216        const size_t src1_col_stride = ggml_row_size(PARAM_TYPE, ne10);
4217
4218        GGML_ASSERT(ne03 == 1 && ne13 == 1);
4219        GGML_ASSERT(ne12 % ne02 == 0);
4220        const int64_t r2 = ne12 / ne02;
4221
4222        const int64_t i12 = src1_start / ne1;
4223        const int64_t i11 = src1_start - i12 * ne1;
4224
4225        // Determine batch index
4226        const int64_t i02 = i12 / r2;
4227
4228        const int64_t i1 = i11;
4229        const int64_t i2 = i12;
4230
4231        const char * src0_ptr = (const char *) src0->data + i02 * nb02;
4232        const char * src1_ptr = (const char *) params->wdata + (i11 + i12 * ne11) * src1_col_stride;
4233        char *       dst_ptr  = ((char *) dst->data + (i1 * nb1 + i2 * nb2));
4234
4235        const int64_t nrows = src1_end - src1_start;
4236        const int64_t ncols = src0_end - src0_start;
4237
4238        GGML_ASSERT(src1_ptr + src1_col_stride * nrows <= (const char *) params->wdata + params->wsize);
4239
4240        // If there are more than three rows in src1, use gemm; otherwise, use gemv.
4241        if (nrows > 3) {
4242            gemm<BLOC_TYPE, INTER_SIZE, NB_COLS, PARAM_TYPE>(ne00, (float *) (dst_ptr) + src0_start, nb1 / nb0,
4243                                                             src0_ptr + src0_start * nb01, src1_ptr,
4244                                                             nrows - (nrows % 4), ncols);
4245        }
4246        for (int iter = nrows - (nrows % 4); iter < nrows; iter++) {
4247            gemv<BLOC_TYPE, INTER_SIZE, NB_COLS, PARAM_TYPE>(ne00, (float *) (dst_ptr + (iter * nb1)) + src0_start,
4248                                                             ne01, src0_ptr + src0_start * nb01,
4249                                                             src1_ptr + (src1_col_stride * iter), 1 /* nrows */, ncols);
4250        }
4251    }
4252
4253    void forward_mul_mat(ggml_compute_params * params, ggml_tensor * op) {
4254        const ggml_tensor * src0 = op->src[0];
4255        const ggml_tensor * src1 = op->src[1];
4256        ggml_tensor *       dst  = op;
4257
4258        GGML_TENSOR_BINARY_OP_LOCALS
4259
4260        const int ith = params->ith;
4261        const int nth = params->nth;
4262
4263        GGML_ASSERT(ne0 == ne01);
4264        GGML_ASSERT(ne1 == ne11);
4265        GGML_ASSERT(ne2 == ne12);
4266        GGML_ASSERT(ne3 == ne13);
4267
4268        // dst cannot be transposed or permuted
4269        GGML_ASSERT(nb0 == sizeof(float));
4270        GGML_ASSERT(nb0 <= nb1);
4271        GGML_ASSERT(nb1 <= nb2);
4272        GGML_ASSERT(nb2 <= nb3);
4273
4274        // TODO: General batched mul mat for 4D tensors
4275        // Currently only supports 3D tensors
4276        GGML_ASSERT(ne03 == 1);
4277        GGML_ASSERT(ne13 == 1);
4278        GGML_ASSERT(ne3 == 1);
4279
4280        GGML_ASSERT(src1->type == GGML_TYPE_F32);
4281
4282        GGML_ASSERT(ggml_n_dims(op->src[0]) == 2);
4283        // GGML_ASSERT(ggml_n_dims(op->src[1]) == 2);
4284
4285        char *       wdata = static_cast<char *>(params->wdata);
4286        const size_t nbw1  = ggml_row_size(PARAM_TYPE, ne10);
4287        const size_t nbw2  = nbw1 * ne11;
4288
4289        assert(params->wsize >= nbw2 * ne12);
4290
4291        const ggml_from_float_t from_float = ggml_get_type_traits_cpu(PARAM_TYPE)->from_float;
4292
4293        // INFO: Quantization is done in planes to avoid extra complexity in chunking.
4294        // Flattening dimensions not multiple of INTER_SIZE would require extra handling depending on how
4295        // the planes are broadcast.
4296        for (int64_t i12 = 0; i12 < ne12; i12++) {
4297            char * data_ptr  = (char *) src1->data + i12 * nb12;
4298            char * wdata_ptr = wdata + i12 * nbw2;
4299
4300            for (int64_t i11 = ith * 4; i11 < ne11 - ne11 % 4; i11 += nth * 4) {
4301                ggml_quantize_mat_t<INTER_SIZE, PARAM_TYPE>((float *) (data_ptr + i11 * nb11),
4302                                                            (void *) (wdata_ptr + i11 * nbw1), 4, ne10);
4303            }
4304
4305            const int64_t i11_processed = ne11 - ne11 % 4;
4306            for (int64_t i11 = i11_processed + ith; i11 < ne11; i11 += nth) {
4307                from_float((float *) (data_ptr + i11 * nb11), (void *) (wdata_ptr + i11 * nbw1), ne10);
4308            }
4309        }
4310
4311        // disable for NUMA
4312        const bool disable_chunking = ggml_is_numa();
4313
4314        // 4x chunks per thread
4315        const int64_t nr0 = ggml_nrows(op->src[0]);
4316
4317        int     nth_scaled  = nth * 4;
4318        int64_t chunk_size0 = (nr0 + nth_scaled - 1) / nth_scaled;
4319        int64_t nchunk0     = (nr0 + chunk_size0 - 1) / chunk_size0;
4320
4321        // src1 is chunked only by full planes.
4322        // When we flatten we need to address dimensions not multiple of the q8 INTER_SIZE
4323        // to route them thorugh GEMV.
4324        // nchunk1 = ne12 also avoids messing the chunking for models with no 3d tensors
4325        // to avoid affecting their performance
4326        int64_t nchunk1 = ne12;
4327
4328        // Ensure minimum chunk size to avoid alignment issues with high thread counts
4329        // Minimum chunk size should be at least NB_COLS to prevent overlapping chunks after alignment
4330        const int64_t min_chunk_size = NB_COLS;
4331        if (nchunk0 > 0 && (nr0 / nchunk0) < min_chunk_size && nr0 >= min_chunk_size) {
4332            nchunk0 = (nr0 + min_chunk_size - 1) / min_chunk_size;
4333        }
4334
4335        int64_t dr0 = (nr0 + nchunk0 - 1) / nchunk0;
4336        // Only increase nchunk0 to nth if it won't make chunks too small
4337        if (nth == 1 || ((nchunk0 < nth || disable_chunking) && (nr0 + nth - 1) / nth >= min_chunk_size)) {
4338            nchunk0 = nth;
4339            dr0 = (nr0 + nchunk0 - 1) / nchunk0;
4340        }
4341
4342        // Ensure nchunk doesn't exceed the number of rows divided by minimum chunk size
4343        // This prevents creating too many tiny chunks that could overlap after alignment
4344        const int64_t max_nchunk = (nr0 + min_chunk_size - 1) / min_chunk_size;
4345        nchunk0                  = MIN(nchunk0, max_nchunk);
4346
4347        if (ith == 0) {
4348            // Every thread starts at ith, so the first unprocessed chunk is nth.  This save a bit of coordination right at the start.
4349            ggml_threadpool_chunk_set(params->threadpool, nth);
4350        }
4351
4352        ggml_barrier(params->threadpool);
4353
4354        // The first chunk comes from our thread_id, the rest will get auto-assigned.
4355        int current_chunk = ith;
4356
4357        while (current_chunk < nchunk0 * nchunk1) {
4358            const int64_t ith0 = current_chunk % nchunk0;
4359            const int64_t ith1 = current_chunk / nchunk0;
4360
4361            int64_t src0_start = dr0 * ith0;
4362            int64_t src0_end   = MIN(src0_start + dr0, nr0);
4363
4364            // full-plane range for src1
4365            int64_t src1_start = ith1 * ne11;
4366            int64_t src1_end = (ith1 + 1) * ne11;
4367
4368            // Align boundaries to NB_COLS - round up to ensure all data is included
4369            // The chunk size limiting above ensures chunks are large enough to prevent overlaps
4370            src0_start = (src0_start % NB_COLS) ? src0_start + NB_COLS - (src0_start % NB_COLS) : src0_start;
4371            src0_end   = (src0_end % NB_COLS) ? src0_end + NB_COLS - (src0_end % NB_COLS) : src0_end;
4372            src0_end   = MIN(src0_end, ne01);
4373
4374            // Make sure current plane is the last one before exiting
4375            if (src0_start >= src0_end) {
4376                current_chunk = ggml_threadpool_chunk_add(params->threadpool, 1);
4377                continue;
4378            }
4379
4380            forward_mul_mat_one_chunk(params, dst, src0_start, src0_end, src1_start, src1_end);
4381
4382            current_chunk = ggml_threadpool_chunk_add(params->threadpool, 1);
4383        }
4384    }
4385
4386    void forward_mul_mat_id(ggml_compute_params * params, ggml_tensor * op) {
4387        const ggml_tensor * src0 = op->src[0];
4388        const ggml_tensor * src1 = op->src[1];
4389        const ggml_tensor * ids  = op->src[2];
4390        ggml_tensor *       dst  = op;
4391
4392        GGML_TENSOR_BINARY_OP_LOCALS
4393
4394        const int ith = params->ith;
4395        const int nth = params->nth;
4396
4397        const ggml_from_float_t from_float = ggml_get_type_traits_cpu(PARAM_TYPE)->from_float;
4398
4399        // we don't support permuted src0 or src1
4400        GGML_ASSERT(nb00 == ggml_type_size(src0->type));
4401        GGML_ASSERT(nb10 == ggml_type_size(src1->type));
4402
4403        // dst cannot be transposed or permuted
4404        GGML_ASSERT(nb0 == sizeof(float));
4405        GGML_ASSERT(nb0 <= nb1);
4406        GGML_ASSERT(nb1 <= nb2);
4407        GGML_ASSERT(nb2 <= nb3);
4408
4409        GGML_ASSERT(ne03 == 1);
4410        GGML_ASSERT(ne13 == 1);
4411        GGML_ASSERT(ne3  == 1);
4412
4413        GGML_ASSERT(src1->type == GGML_TYPE_F32);
4414
4415        // row groups
4416        const int n_ids = ids->ne[0]; // n_expert_used
4417        const int n_as  = ne02;       // n_expert
4418
4419        const size_t nbw1 = ggml_row_size(PARAM_TYPE, ne10);
4420        const size_t nbw2 = nbw1*ne11;
4421        const size_t nbw3 = nbw2*ne12;
4422
4423        struct mmid_row_mapping {
4424            int32_t i1;
4425            int32_t i2;
4426        };
4427
4428        GGML_ASSERT(params->wsize >=
4429                (GGML_PAD(nbw3, sizeof(int64_t)) +
4430                 n_as*(ne12 + 1)*sizeof(mmid_row_mapping))
4431                );
4432
4433        auto * wdata          = (char *)params->wdata;
4434        auto * wdata_src1_end = (char *)wdata + GGML_PAD(nbw3, sizeof(int64_t));
4435
4436        // total of [n_as][ne12 + 1] elements of type mmid_row_mapping (2*int32_t = int64_t)
4437        auto * matrix_row_counts = (int64_t *) (wdata_src1_end);                                        // [n_as]
4438        struct mmid_row_mapping * matrix_rows = (struct mmid_row_mapping *) (matrix_row_counts + n_as); // [n_as][ne12]
4439
4440        // src1: float32 => param type
4441        for (int64_t i12 = 0; i12 < ne12; ++i12) {
4442            for (int64_t i11 = ith; i11 < ne11; i11 += nth) {
4443                from_float((float *)((char *) src1->data + i12 * nb12 + i11 * nb11),
4444                           (void *)               (wdata + i12 * nbw2 + i11 * nbw1),
4445                           ne10);
4446            }
4447        }
4448
4449#define MMID_MATRIX_ROW(row_id, i1) matrix_rows[(row_id) * ne12 + (i1)]
4450
4451        if (ith == 0) {
4452            // initialize matrix_row_counts
4453            memset(matrix_row_counts, 0, n_as * sizeof(int64_t));
4454
4455            // group rows by src0 matrix
4456            for (int32_t iid1 = 0; iid1 < ids->ne[1]; ++iid1) {
4457                for (int32_t id = 0; id < n_ids; ++id) {
4458                    const int32_t i02 =
4459                        *(const int32_t *) ((const char *) ids->data + iid1 * ids->nb[1] + id * ids->nb[0]);
4460
4461                    GGML_ASSERT(i02 >= 0 && i02 < n_as);
4462
4463                    MMID_MATRIX_ROW(i02, matrix_row_counts[i02]) = { id, iid1 };
4464                    matrix_row_counts[i02] += 1;
4465                }
4466            }
4467        }
4468
4469        ggml_barrier(params->threadpool);
4470
4471        // compute each matrix multiplication in sequence
4472        for (int cur_a = 0; cur_a < n_as; ++cur_a) {
4473            const int64_t cne1 = matrix_row_counts[cur_a];
4474
4475            if (cne1 == 0) {
4476                continue;
4477            }
4478
4479            const auto * src0_cur = (const char *) src0->data + cur_a*nb02;
4480
4481            //const int64_t nr0 = ne01; // src0 rows
4482            const int64_t nr1 = cne1; // src1 rows
4483
4484            int64_t src0_cur_start = (ith * ne01) / nth;
4485            int64_t src0_cur_end   = ((ith + 1) * ne01) / nth;
4486
4487            // Align boundaries to NB_COLS - round up to ensure all data is included
4488            src0_cur_start = (src0_cur_start % NB_COLS) ? src0_cur_start + NB_COLS - (src0_cur_start % NB_COLS) : src0_cur_start;
4489            src0_cur_end   = (src0_cur_end   % NB_COLS) ? src0_cur_end   + NB_COLS - (src0_cur_end   % NB_COLS) : src0_cur_end;
4490            if (src0_cur_end > ne01) {
4491                src0_cur_end = ne01;
4492            }
4493
4494            if (src0_cur_start >= src0_cur_end) {
4495                return;
4496            }
4497
4498            for (int ir1 = 0; ir1 < nr1; ir1++) {
4499                struct mmid_row_mapping row_mapping = MMID_MATRIX_ROW(cur_a, ir1);
4500
4501                const int id = row_mapping.i1;  // selected expert index
4502
4503                const int64_t i11 = id % ne11;
4504                const int64_t i12 = row_mapping.i2;  // row index in src1
4505
4506                const int64_t i1 = id;               // selected expert index
4507                const int64_t i2 = i12;              // row
4508
4509                const auto * src1_col = (const char *) wdata + (i11 * nbw1 + i12 * nbw2);
4510
4511                gemv<BLOC_TYPE, INTER_SIZE, NB_COLS, PARAM_TYPE>(
4512                    ne00, (float *) ((char *) dst->data + (i1 * nb1 + i2 * nb2)) + src0_cur_start, ne01,
4513                    src0_cur + src0_cur_start * nb01, src1_col, 1, src0_cur_end - src0_cur_start);
4514            }
4515        }
4516#undef MMID_MATRIX_ROW
4517    }
4518
4519    int repack(struct ggml_tensor * t, const void * data, size_t data_size) override {
4520        GGML_LOG_DEBUG("%s: repack tensor %s with %s_%dx%d\n", __func__, t->name, ggml_type_name(t->type),
4521                       (int) NB_COLS, (int) INTER_SIZE);
4522        return ggml::cpu::repack::repack<BLOC_TYPE, INTER_SIZE, NB_COLS>(t, data, data_size);
4523    }
4524};
4525
4526}  // namespace ggml::cpu::repack
4527
4528static const ggml::cpu::tensor_traits * ggml_repack_get_optimal_repack_type(const struct ggml_tensor * cur) {
4529    // instance for Q4
4530    static const ggml::cpu::repack::tensor_traits<block_q4_0, 4, 4, GGML_TYPE_Q8_0> q4_0_4x4_q8_0;
4531    static const ggml::cpu::repack::tensor_traits<block_q4_0, 8, 4, GGML_TYPE_Q8_0> q4_0_4x8_q8_0;
4532    static const ggml::cpu::repack::tensor_traits<block_q4_0, 8, 8, GGML_TYPE_Q8_0> q4_0_8x8_q8_0;
4533
4534    // instance for Q4_K
4535    static const ggml::cpu::repack::tensor_traits<block_q4_K, 4, 8, GGML_TYPE_Q8_K> q4_K_8x4_q8_K;
4536    static const ggml::cpu::repack::tensor_traits<block_q4_K, 8, 8, GGML_TYPE_Q8_K> q4_K_8x8_q8_K;
4537
4538    // instance for Q5_K
4539    static const ggml::cpu::repack::tensor_traits<block_q5_K, 4, 8, GGML_TYPE_Q8_K> q5_K_8x4_q8_K;
4540    static const ggml::cpu::repack::tensor_traits<block_q5_K, 8, 8, GGML_TYPE_Q8_K> q5_K_8x8_q8_K;
4541
4542    // instance for Q6_K
4543    static const ggml::cpu::repack::tensor_traits<block_q6_K, 4, 8, GGML_TYPE_Q8_K> q6_K_8x4_q8_K;
4544    static const ggml::cpu::repack::tensor_traits<block_q6_K, 8, 8, GGML_TYPE_Q8_K> q6_K_8x8_q8_K;
4545
4546    // instance for Q2
4547    static const ggml::cpu::repack::tensor_traits<block_q2_K, 8, 8, GGML_TYPE_Q8_K> q2_K_8x8_q8_K;
4548
4549    // instance for IQ4
4550    static const ggml::cpu::repack::tensor_traits<block_iq4_nl, 4, 4, GGML_TYPE_Q8_0> iq4_nl_4x4_q8_0;
4551    static const ggml::cpu::repack::tensor_traits<block_iq4_nl, 8, 8, GGML_TYPE_Q8_0> iq4_nl_8x8_q8_0;
4552
4553    // instance for MXFP4
4554    static const ggml::cpu::repack::tensor_traits<block_mxfp4, 4, 4, GGML_TYPE_Q8_0> mxfp4_4x4_q8_0;
4555    static const ggml::cpu::repack::tensor_traits<block_mxfp4, 8, 8, GGML_TYPE_Q8_0> mxfp4_8x8_q8_0;
4556
4557    // instance for Q8_0
4558    static const ggml::cpu::repack::tensor_traits<block_q8_0, 4, 4, GGML_TYPE_Q8_0> q8_0_4x4_q8_0;
4559    static const ggml::cpu::repack::tensor_traits<block_q8_0, 8, 4, GGML_TYPE_Q8_0> q8_0_4x8_q8_0;
4560
4561    // instances for RISC-V
4562    //
4563    // These implement outer-product style matrix multiplication kernels with
4564    // an interleave of 1.
4565#if defined __riscv_zvfh
4566    static const ggml::cpu::repack::tensor_traits<block_q4_0, 1, 16, GGML_TYPE_Q8_0> q4_0_16x1_q8_0;
4567    static const ggml::cpu::repack::tensor_traits<block_q4_K, 1, 16, GGML_TYPE_Q8_K> q4_K_16x1_q8_K;
4568    static const ggml::cpu::repack::tensor_traits<block_iq4_nl, 1, 16, GGML_TYPE_Q8_0> iq4_nl_16x1_q8_0;
4569    static const ggml::cpu::repack::tensor_traits<block_q8_0, 1, 16, GGML_TYPE_Q8_0> q8_0_16x1_q8_0;
4570    static const ggml::cpu::repack::tensor_traits<block_q2_K, 1, 16, GGML_TYPE_Q8_K> q2_K_16x1_q8_K;
4571#endif
4572
4573    if (cur->type == GGML_TYPE_Q4_0) {
4574        if (ggml_cpu_has_avx2() || (ggml_cpu_has_sve() && ggml_cpu_has_matmul_int8() && ggml_cpu_get_sve_cnt() == QK8_0)) {
4575            if (cur->ne[1] % 8 == 0) {
4576                return &q4_0_8x8_q8_0;
4577            }
4578        }
4579        if (ggml_cpu_has_neon() && ggml_cpu_has_matmul_int8()) {
4580            if (cur->ne[1] % 4 == 0) {
4581                return &q4_0_4x8_q8_0;
4582            }
4583        }
4584        if (ggml_cpu_has_neon() && ggml_cpu_has_dotprod()) {
4585            if (cur->ne[1] % 4 == 0) {
4586                return &q4_0_4x4_q8_0;
4587            }
4588        }
4589        if (ggml_cpu_has_vxe()) {
4590            if (cur->ne[1] % 4 == 0) {
4591                return &q4_0_4x4_q8_0;
4592            }
4593        }
4594        if (ggml_cpu_has_riscv_v()) {
4595            #if defined __riscv_zvfh
4596            switch (__riscv_vlenb() * 8) {
4597                case 128:  { break; } // TODO
4598                case 256:  { if (cur->ne[1] % 16 == 0) { return &q4_0_16x1_q8_0; } break; }
4599                case 512:  { break; } // TODO
4600                case 1024: { break; } // TODO
4601                default:   { return nullptr; }
4602            }
4603            #endif
4604        }
4605    } else if (cur->type == GGML_TYPE_Q4_K) {
4606        if (ggml_cpu_has_avx2()) {
4607            if (cur->ne[1] % 8 == 0) {
4608                return &q4_K_8x8_q8_K;
4609            }
4610        }
4611        if (ggml_cpu_has_neon() && ggml_cpu_has_matmul_int8()) {
4612            if (cur->ne[1] % 8 == 0) {
4613                return &q4_K_8x8_q8_K;
4614            }
4615        }
4616        if (ggml_cpu_has_neon() && ggml_cpu_has_dotprod()) {
4617            if (cur->ne[1] % 8 == 0) {
4618                return &q4_K_8x4_q8_K;
4619            }
4620        }
4621        if (ggml_cpu_has_riscv_v()) {
4622            #if defined __riscv_zvfh
4623            switch (__riscv_vlenb() * 8) {
4624                case 128:  { break; } // TODO
4625                case 256:  { if (cur->ne[1] % 16 == 0) { return &q4_K_16x1_q8_K; } break; }
4626                case 512:  { break; } // TODO
4627                case 1024: { break; } // TODO
4628                default:   { return nullptr; }
4629            }
4630            #endif
4631        }
4632    } else if (cur->type == GGML_TYPE_Q2_K) {
4633        if (ggml_cpu_has_avx512()) {
4634            if (cur->ne[1] % 8 == 0) {
4635                return &q2_K_8x8_q8_K;
4636            }
4637        }
4638        if (ggml_cpu_has_riscv_v()) {
4639            #if defined __riscv_zvfh
4640            switch (__riscv_vlenb() * 8) {
4641                case 128:  { break; } // TODO
4642                case 256:  { if (cur->ne[1] % 16 == 0) { return &q2_K_16x1_q8_K; } break; }
4643                case 512:  { break; } // TODO
4644                case 1024: { break; } // TODO
4645                default:   { return nullptr; }
4646            }
4647            #endif
4648        }
4649    } else if (cur->type == GGML_TYPE_Q5_K) {
4650        if (ggml_cpu_has_neon() && ggml_cpu_has_matmul_int8()) {
4651            if (cur->ne[1] % 8 == 0) {
4652                return &q5_K_8x8_q8_K;
4653            }
4654        }
4655        if (ggml_cpu_has_neon() && ggml_cpu_has_dotprod()) {
4656            if (cur->ne[1] % 8 == 0) {
4657                return &q5_K_8x4_q8_K;
4658            }
4659        }
4660    } else if (cur->type == GGML_TYPE_Q6_K) {
4661        if (ggml_cpu_has_neon() && ggml_cpu_has_matmul_int8()) {
4662            if (cur->ne[1] % 8 == 0) {
4663                return &q6_K_8x8_q8_K;
4664            }
4665        }
4666        if (ggml_cpu_has_neon() && ggml_cpu_has_dotprod()) {
4667            if (cur->ne[1] % 8 == 0) {
4668                return &q6_K_8x4_q8_K;
4669            }
4670        }
4671    } else if (cur->type == GGML_TYPE_IQ4_NL) {
4672        if (ggml_cpu_has_avx2()) {
4673            if (cur->ne[1] % 8 == 0) {
4674                return &iq4_nl_8x8_q8_0;
4675            }
4676        }
4677        if (ggml_cpu_has_neon() && ggml_cpu_has_dotprod()) {
4678            if (cur->ne[1] % 4 == 0) {
4679                return &iq4_nl_4x4_q8_0;
4680            }
4681        }
4682        if (ggml_cpu_has_riscv_v()) {
4683            #if defined __riscv_zvfh
4684            switch (__riscv_vlenb() * 8) {
4685                case 128:  { break; } // TODO
4686                case 256:  { if (cur->ne[1] % 16 == 0) { return &iq4_nl_16x1_q8_0; } break; }
4687                case 512:  { break; } // TODO
4688                case 1024: { break; } // TODO
4689                default:   { return nullptr; }
4690            }
4691            #endif
4692        }
4693    } else if (cur->type == GGML_TYPE_MXFP4) {
4694        if (ggml_cpu_has_avx2()) {
4695            if (cur->ne[1] % 8 == 0) {
4696                return &mxfp4_8x8_q8_0;
4697            }
4698        }
4699        if (ggml_cpu_has_neon() && ggml_cpu_has_dotprod()) {
4700            if (cur->ne[1] % 4 == 0) {
4701                return &mxfp4_4x4_q8_0;
4702            }
4703        }
4704    } else if (cur->type == GGML_TYPE_Q8_0) {
4705        if (ggml_cpu_has_neon() && ggml_cpu_has_matmul_int8()) {
4706            if (cur->ne[1] % 4 == 0) {
4707                return &q8_0_4x8_q8_0;
4708            }
4709        }
4710        if (ggml_cpu_has_neon() && ggml_cpu_has_dotprod()) {
4711            if (cur->ne[1] % 4 == 0) {
4712                return &q8_0_4x4_q8_0;
4713            }
4714        }
4715        if (ggml_cpu_has_riscv_v()) {
4716            #if defined __riscv_zvfh
4717            switch (__riscv_vlenb() * 8) {
4718                case 128:  { break; } // TODO
4719                case 256:  { if (cur->ne[1] % 16 == 0) { return &q8_0_16x1_q8_0; } break; }
4720                case 512:  { break; } // TODO
4721                case 1024: { break; } // TODO
4722                default:   { return nullptr; }
4723            }
4724            #endif
4725        }
4726    }
4727
4728    return nullptr;
4729}
4730
4731static enum ggml_status ggml_backend_cpu_repack_buffer_init_tensor(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor) {
4732    tensor->extra = (void *) const_cast<ggml::cpu::tensor_traits *>(ggml_repack_get_optimal_repack_type(tensor));
4733
4734    GGML_UNUSED(buffer);
4735    return GGML_STATUS_SUCCESS;
4736}
4737
4738static void ggml_backend_cpu_repack_buffer_set_tensor(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor,
4739                                                       const void * data, size_t offset, size_t size) {
4740    GGML_ASSERT(offset == 0);
4741    GGML_ASSERT(size == ggml_nbytes(tensor));
4742
4743    auto tensor_traits = (ggml::cpu::repack::tensor_traits_base *) tensor->extra;
4744    auto OK            = tensor_traits->repack(tensor, data, size);
4745
4746    GGML_ASSERT(OK == 0);
4747    GGML_UNUSED(buffer);
4748}
4749
4750static const char * ggml_backend_cpu_repack_buffer_type_get_name(ggml_backend_buffer_type_t buft) {
4751    return "CPU_REPACK";
4752
4753    GGML_UNUSED(buft);
4754}
4755
4756static ggml_backend_buffer_t ggml_backend_cpu_repack_buffer_type_alloc_buffer(ggml_backend_buffer_type_t buft, size_t size) {
4757    ggml_backend_buffer_t buffer = ggml_backend_buft_alloc_buffer(ggml_backend_cpu_buffer_type(), size);
4758
4759    if (buffer == nullptr) {
4760        return nullptr;
4761    }
4762
4763    buffer->buft              = buft;
4764    buffer->iface.init_tensor = ggml_backend_cpu_repack_buffer_init_tensor;
4765    buffer->iface.set_tensor  = ggml_backend_cpu_repack_buffer_set_tensor;
4766    buffer->iface.get_tensor  = nullptr;
4767    buffer->iface.cpy_tensor  = nullptr;
4768    return buffer;
4769}
4770
4771static size_t ggml_backend_cpu_repack_buffer_type_get_alignment(ggml_backend_buffer_type_t buft) {
4772    return TENSOR_ALIGNMENT;
4773
4774    GGML_UNUSED(buft);
4775}
4776
4777namespace ggml::cpu::repack {
4778class extra_buffer_type : ggml::cpu::extra_buffer_type {
4779    bool supports_op(ggml_backend_dev_t, const struct ggml_tensor * op) override {
4780        if (    op->op == GGML_OP_MUL_MAT &&
4781                op->src[0]->buffer &&
4782                (ggml_n_dims(op->src[0]) == 2) &&
4783                op->src[0]->buffer->buft == ggml_backend_cpu_repack_buffer_type() &&
4784                ggml_repack_get_optimal_repack_type(op->src[0])
4785                ) {
4786            if (op->src[1]->buffer && !ggml_backend_buft_is_host(op->src[1]->buffer->buft)) {
4787                return false;
4788            }
4789            if (op->src[1]->type == GGML_TYPE_F32) {
4790                return true;
4791            }
4792            //if (op->src[1]->type == GGML_TYPE_Q8_0) {
4793            //    return true;
4794            //}
4795            // may be possible if Q8_0 packed...
4796        } else if (op->op == GGML_OP_MUL_MAT_ID
4797                && op->src[0]->buffer
4798                && (ggml_n_dims(op->src[0]) == 3)
4799                && op->src[0]->buffer->buft == ggml_backend_cpu_repack_buffer_type()
4800                && ggml_repack_get_optimal_repack_type(op->src[0])
4801                ) {
4802            if (op->src[1]->buffer && !ggml_backend_buft_is_host(op->src[1]->buffer->buft)) {
4803                return false;
4804            }
4805            if (op->src[1]->type == GGML_TYPE_F32) {
4806                return true;
4807            }
4808            //if (op->src[1]->type == GGML_TYPE_Q8_0) {
4809            //    return true;
4810            //}
4811        }
4812        return false;
4813    }
4814
4815    ggml::cpu::tensor_traits * get_tensor_traits(const struct ggml_tensor * op) override {
4816        if (op->op == GGML_OP_MUL_MAT || op->op == GGML_OP_MUL_MAT_ID) {
4817            if (op->src[0]->buffer && op->src[0]->buffer->buft == ggml_backend_cpu_repack_buffer_type()) {
4818                return (ggml::cpu::tensor_traits *) op->src[0]->extra;
4819            }
4820        }
4821        return nullptr;
4822    }
4823};
4824}  // namespace ggml::cpu::repack
4825
4826ggml_backend_buffer_type_t ggml_backend_cpu_repack_buffer_type(void) {
4827    static struct ggml_backend_buffer_type ggml_backend_cpu_buffer_type_repack = {
4828        /* .iface    = */ {
4829                           /* .get_name         = */ ggml_backend_cpu_repack_buffer_type_get_name,
4830                           /* .alloc_buffer     = */ ggml_backend_cpu_repack_buffer_type_alloc_buffer,
4831                           /* .get_alignment    = */ ggml_backend_cpu_repack_buffer_type_get_alignment,
4832                           /* .get_max_size     = */ nullptr,  // defaults to SIZE_MAX
4833                           /* .get_alloc_size   = */ nullptr,  // defaults to ggml_nbytes
4834                           /* .is_host          = */ nullptr,
4835                           },
4836        /* .device  = */ ggml_backend_reg_dev_get(ggml_backend_cpu_reg(), 0),
4837        /* .context = */ new ggml::cpu::repack::extra_buffer_type(),
4838    };
4839
4840    return &ggml_backend_cpu_buffer_type_repack;
4841}