char-fork/llama.cpp

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

alex-spacemitggml-cpu: Add IME2 Instruction Support for the SpacemiT Backend (#22863)81b0d882a

char/aliceai-t5-moe
73.2 KiB1795 linesraw
1#define GGML_COMMON_IMPL_CPP
2#define GGML_COMMON_DECL_CPP
3
4#include "repack.h"
5
6#include "ggml-common.h"
7#include "ggml-cpu.h"
8#include "ggml-impl.h"
9#include "ime_kernels.h"
10
11#include <algorithm>
12#include <cassert>
13#include <cmath>
14#include <cstring>
15
16// clang-format off
17#if defined(__riscv)
18
19#if !defined(__riscv_v) || !defined(__riscv_v_intrinsic)
20#error "riscv v extension or v_intrinsic not enabled"
21#else
22#include <riscv_vector.h>
23#endif
24
25#if !defined(__riscv_zfh)
26#error "riscv zfh extension not enabled"
27#endif
28
29#else
30#error "riscv not enabled in this build"
31#endif
32
33#if defined(__GNUC__)
34#pragma GCC diagnostic ignored "-Wcast-qual"
35#pragma GCC diagnostic ignored "-Wunused-parameter"
36#endif
37
38// clang-format on
39
40template <int K> constexpr int QK_0() {
41    if constexpr (K == 4) {
42        return QK4_0;
43    }
44    if constexpr (K == 8) {
45        return QK8_0;
46    }
47    return -1;
48}
49
50template <int K, int N> struct block {
51    ggml_half d[N];                         // deltas for N qK_0 blocks
52    uint8_t   qs[(QK_0<K>() * N * K) / 8];  // quants for N qK_0 blocks
53};
54
55template <int K, int N> struct block_with_zp {
56    ggml_half d[N];                         // deltas for N qK_1 blocks
57    uint8_t   zp[N];                        // zero points for N qK_1 blocks
58    uint8_t   qs[(QK_0<K>() * N * K) / 8];  // quants for N qK_1 blocks
59};
60
61// control size
62static_assert(sizeof(block<4, 16>) == 16 * sizeof(ggml_half) + QK4_0 * 8, "wrong block<4,16> size/padding");
63static_assert(sizeof(block_with_zp<4, 16>) == 16 * sizeof(ggml_half) + QK4_0 * 8 + 16 * sizeof(uint8_t),
64              "wrong block_with_zp<4,16> size/padding");
65
66static_assert(sizeof(block<8, 16>) == 16 * sizeof(ggml_half) + QK4_0 * 16, "wrong block<8,16> size/padding");
67
68static_assert(sizeof(block<4, 32>) == 32 * sizeof(ggml_half) + QK4_0 * 16, "wrong block<4,32> size/padding");
69static_assert(sizeof(block_with_zp<4, 32>) == 32 * sizeof(ggml_half) + QK4_0 * 16 + 32 * sizeof(uint8_t),
70              "wrong block_with_zp<4,32> size/padding");
71
72using block_q4_0x16 = block<4, 16>;
73using block_q4_1x16 = block_with_zp<4, 16>;
74using block_q8_0x16 = block<8, 16>;
75
76using block_q4_0x32 = block<4, 32>;
77using block_q4_1x32 = block_with_zp<4, 32>;
78using block_q8_0x32 = block<8, 32>;
79
80struct block_q4_0x32x256 {
81    block_q4_0x32 blocks[8];  // [f16 * 32 | i4 * 32 * 32] * 8
82};
83
84struct block_q4_1x32x256 {
85    block_q4_0x32 blocks[8];
86    uint8_t       zps[32 * 8];
87};
88
89static block_q4_0x16 make_block_q4_0x16(block_q4_0 * in, unsigned int blck_size_interleave) {
90    block_q4_0x16 out;
91    GGML_ASSERT(QK4_0 / blck_size_interleave == 2);
92
93    for (int i = 0; i < 16; i++) {
94        out.d[i] = in[i].d;
95    }
96
97    for (int i = 0; i < 16; i++) {
98        // [0, 15], in.d & 0x0F
99        for (int j = 0; j < QK4_0 / 4; j++) {
100            //src [b0 b16] ......... [b8 b24] ......... [b15 b31]
101            //dst [b0 b8] ......... [b7 b15]
102            out.qs[i * QK4_0 / 4 + j] = (in[i].qs[j] & 0x0F) | ((in[i].qs[j + QK4_0 / 4] & 0x0F) << 4);
103        }
104    }
105
106    for (int i = 0; i < 16; i++) {
107        // [16, 31], in.d & 0xF0
108        for (int j = 0; j < QK4_0 / 4; j++) {
109            //src [b0 b16] ......... [b8 b24] ......... [b15 b31]
110            //dst [b16 b24] ......... [b23 b31]
111            out.qs[4 * QK4_0 + i * QK4_0 / 4 + j] = ((in[i].qs[j] & 0xF0) >> 4) | (in[i].qs[j + QK4_0 / 4] & 0xF0);
112        }
113    }
114
115    return out;
116}
117
118static block_q4_1x16 make_block_q4_1x16(block_q4_1 * in, unsigned int blck_size_interleave) {
119    block_q4_1x16 out;
120    GGML_ASSERT(QK4_1 / blck_size_interleave == 2);
121
122    for (int i = 0; i < 16; i++) {
123        float d   = GGML_FP16_TO_FP32(in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d);
124        float m   = GGML_FP16_TO_FP32(in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.m);
125        float mid = -std::nearbyintf(m / d);
126        mid       = std::min(15.0f, std::max(0.0f, mid));
127        out.d[i]  = GGML_FP32_TO_FP16(d);
128        out.zp[i] = static_cast<uint8_t>(mid);
129    }
130
131    for (int i = 0; i < 16; i++) {
132        // [0, 15], in.d & 0x0F
133        for (int j = 0; j < QK4_1 / 4; j++) {
134            //src [b0 b16] ......... [b8 b24] ......... [b15 b31]
135            //dst [b0 b8] ......... [b7 b15]
136            out.qs[i * QK4_1 / 4 + j] = (in[i].qs[j] & 0x0F) | ((in[i].qs[j + QK4_1 / 4] & 0x0F) << 4);
137        }
138    }
139
140    for (int i = 0; i < 16; i++) {
141        // [16, 31], in.d & 0xF0
142        for (int j = 0; j < QK4_1 / 4; j++) {
143            //src [b0 b16] ......... [b8 b24] ......... [b15 b31]
144            //dst [b16 b24] ......... [b23 b31]
145            out.qs[4 * QK4_1 + i * QK4_1 / 4 + j] = ((in[i].qs[j] & 0xF0) >> 4) | (in[i].qs[j + QK4_1 / 4] & 0xF0);
146        }
147    }
148
149    return out;
150}
151
152static int repack_q4_0_to_q4_0_16_bl(ggml_tensor *              t,
153                                     int                        interleave_block,
154                                     const void * GGML_RESTRICT data,
155                                     size_t                     data_size) {
156    GGML_ASSERT(t->type == GGML_TYPE_Q4_0);
157    GGML_ASSERT(interleave_block == 16);
158
159    constexpr int nrows_interleaved = 16;
160
161    block_q4_0x16 *    dst = (block_q4_0x16 *) t->data;
162    const block_q4_0 * src = (const block_q4_0 *) data;
163    block_q4_0         dst_tmp[16];
164    int                nrow    = ggml_nrows(t);
165    int                nblocks = t->ne[0] / QK4_0;
166
167    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q4_0));
168
169    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK4_0 != 0) {
170        return -1;
171    }
172
173    for (int b = 0; b < nrow; b += nrows_interleaved) {
174        for (int64_t x = 0; x < nblocks; x++) {
175            for (int i = 0; i < nrows_interleaved; i++) {
176                dst_tmp[i] = src[x + i * nblocks];
177            }
178            *dst++ = make_block_q4_0x16(dst_tmp, interleave_block);
179        }
180        src += nrows_interleaved * nblocks;
181    }
182    return 0;
183
184    GGML_UNUSED(data_size);
185}
186
187static int repack_q4_1_to_q4_1_16_bl(ggml_tensor *              t,
188                                     int                        interleave_block,
189                                     const void * GGML_RESTRICT data,
190                                     size_t                     data_size) {
191    GGML_ASSERT(t->type == GGML_TYPE_Q4_1);
192    GGML_ASSERT(interleave_block == 16);
193
194    constexpr int nrows_interleaved = 16;
195
196    block_q4_1x16 *    dst = (block_q4_1x16 *) t->data;
197    const block_q4_1 * src = (const block_q4_1 *) data;
198    block_q4_1         dst_tmp[16];
199    int                nrow    = ggml_nrows(t);
200    int                nblocks = t->ne[0] / QK4_1;
201
202    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q4_1));
203
204    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK4_1 != 0) {
205        return -1;
206    }
207
208    for (int b = 0; b < nrow; b += nrows_interleaved) {
209        for (int64_t x = 0; x < nblocks; x++) {
210            for (int i = 0; i < nrows_interleaved; i++) {
211                dst_tmp[i] = src[x + i * nblocks];
212            }
213            *dst++ = make_block_q4_1x16(dst_tmp, interleave_block);
214        }
215        src += nrows_interleaved * nblocks;
216    }
217    return 0;
218
219    GGML_UNUSED(data_size);
220}
221
222static inline void get_scale_min_k4(int                           j,
223                                    const uint8_t * GGML_RESTRICT q,
224                                    uint8_t * GGML_RESTRICT       d,
225                                    uint8_t * GGML_RESTRICT       m) {
226    if (j < 4) {
227        *d = q[j] & 63;
228        *m = q[j + 4] & 63;
229    } else {
230        *d = (q[j + 4] & 0xF) | ((q[j - 4] >> 6) << 4);
231        *m = (q[j + 4] >> 4) | ((q[j - 0] >> 6) << 4);
232    }
233}
234
235static int repack_q4_k_to_q4_1_16_bl(ggml_tensor *              t,
236                                     int                        interleave_block,
237                                     const void * GGML_RESTRICT data,
238                                     size_t                     data_size) {
239    GGML_ASSERT(t->type == GGML_TYPE_Q4_K);
240    GGML_ASSERT(interleave_block == 16);
241    GGML_ASSERT(QK_K / QK4_1 == 8);
242
243    constexpr int nrows_interleaved = 16;
244
245    block_q4_1x16 *    dst = (block_q4_1x16 *) t->data;
246    const block_q4_K * src = (const block_q4_K *) data;
247    block_q4_1         dst_tmp[16];
248    int                nrow    = ggml_nrows(t);
249    int                nblocks = t->ne[0] / QK_K;
250
251    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK_K != 0) {
252        return -1;
253    }
254
255    for (int b = 0; b < nrow; b += nrows_interleaved) {
256        for (int64_t x = 0; x < nblocks; x++) {
257            for (int j = 0; j < 8; j++) {
258                for (int i = 0; i < nrows_interleaved; i++) {
259                    uint8_t     sc, m;
260                    const float d = GGML_FP16_TO_FP32(src[x + i * nblocks].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d);
261                    const float min =
262                        GGML_FP16_TO_FP32(src[x + i * nblocks].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.dmin);
263                    get_scale_min_k4(j, src[x + i * nblocks].scales, &sc, &m);
264                    const float d1 = d * sc;
265                    const float m1 = min * m;
266
267                    dst_tmp[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d = GGML_FP32_TO_FP16(d1);
268                    dst_tmp[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.m = GGML_FP32_TO_FP16(-m1);
269                    // src -> [b0, b32] [b1, b33] ... [b31, b63]
270                    // dst -> [b0, b16] [b1, b17] ... [b15, b31] [b32, b48] [b33, b49] ... [b47, b63]
271                    const uint8_t * q                                  = src[x + i * nblocks].qs + (j / 2) * QK4_1;
272                    if (j % 2 == 0) {
273                        for (int ii = 0; ii < 16; ii++) {
274                            dst_tmp[i].qs[ii] = (q[ii] & 0x0F) | ((q[ii + 16] & 0x0F) << 4);
275                        }
276                    } else {
277                        for (int ii = 0; ii < 16; ii++) {
278                            dst_tmp[i].qs[ii] = ((q[ii] & 0xF0) >> 4) | (q[ii + 16] & 0xF0);
279                        }
280                    }
281                }
282                *dst++ = make_block_q4_1x16(dst_tmp, interleave_block);
283            }
284        }
285        src += nrows_interleaved * nblocks;
286    }
287    return 0;
288
289    GGML_UNUSED(data_size);
290}
291
292static block_q4_0x32 make_block_q4_0x32(block_q4_0 * in, unsigned int blck_size_interleave) {
293    block_q4_0x32 out;
294    assert(QK4_0 / blck_size_interleave == 1);
295    GGML_UNUSED(blck_size_interleave);
296
297    for (int i = 0; i < 32; i++) {
298        out.d[i] = in[i].d;
299    }
300
301    for (int i = 0; i < 32; i++) {
302        // [0, 15], in.d & 0x0F
303        for (int j = 0; j < QK4_0 / 4; j++) {
304            //src [b0 b16] ......... [b8 b24] ......... [b15 b31]
305            //dst [b0 b1] .........  [b14 b15]
306            out.qs[i * QK4_0 / 2 + j] = (in[i].qs[j * 2] & 0x0F) | ((in[i].qs[j * 2 + 1] & 0x0F) << 4);
307        }
308    }
309
310    for (int i = 0; i < 32; i++) {
311        // [16, 31], in.d & 0xF0
312        for (int j = 0; j < QK4_0 / 4; j++) {
313            //src [b0 b16] ......... [b8 b24] ......... [b15 b31]
314            //dst [b16 b17] ......... [b30 b31]
315            out.qs[i * QK4_0 / 2 + QK4_0 / 4 + j] = ((in[i].qs[j * 2] & 0xF0) >> 4) | (in[i].qs[j * 2 + 1] & 0xF0);
316        }
317    }
318
319    return out;
320}
321
322static block_q4_1x32 make_block_q4_1x32(block_q4_1 * in, unsigned int blck_size_interleave) {
323    block_q4_1x32 out;
324    GGML_ASSERT(QK4_1 / blck_size_interleave == 1);
325    GGML_UNUSED(blck_size_interleave);
326
327    for (int i = 0; i < 32; i++) {
328        float d   = GGML_FP16_TO_FP32(in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d);
329        float m   = GGML_FP16_TO_FP32(in[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.m);
330        float mid = -std::nearbyintf(m / d);
331        mid       = std::min(15.0f, std::max(0.0f, mid));
332        out.d[i]  = GGML_FP32_TO_FP16(d);
333        out.zp[i] = static_cast<uint8_t>(mid);
334    }
335
336    for (int i = 0; i < 32; i++) {
337        // [0, 15], in.d & 0x0F
338        for (int j = 0; j < QK4_1 / 4; j++) {
339            //src [b0 b16] ......... [b8 b24] ......... [b15 b31]
340            //dst [b0 b1] ......... [b14 b15]
341            out.qs[i * QK4_1 / 2 + j] = (in[i].qs[j * 2] & 0x0F) | ((in[i].qs[j * 2 + 1] & 0x0F) << 4);
342        }
343    }
344
345    for (int i = 0; i < 32; i++) {
346        // [16, 31], in.d & 0xF0
347        for (int j = 0; j < QK4_1 / 4; j++) {
348            //src [b0 b16] ......... [b8 b24] ......... [b15 b31]
349            //dst [b16 b24] ......... [b23 b31]
350            out.qs[i * QK4_1 / 2 + QK4_1 / 4 + j] = ((in[i].qs[j * 2] & 0xF0) >> 4) | (in[i].qs[j * 2 + 1] & 0xF0);
351        }
352    }
353
354    return out;
355}
356
357static block_q8_0x32 make_block_q8_0x32(block_q8_0 * in, unsigned int blck_size_interleave) {
358    block_q8_0x32 out;
359    GGML_ASSERT(QK8_0 / blck_size_interleave == 1);
360    GGML_UNUSED(blck_size_interleave);
361
362    for (int i = 0; i < 32; i++) {
363        out.d[i] = in[i].d;
364    }
365
366    for (int i = 0; i < 32; i++) {
367        memcpy(out.qs + i * QK8_0, in[i].qs, QK8_0);
368    }
369
370    return out;
371}
372
373static int repack_q2_k_to_q2_k_32_bl(ggml_tensor *              t,
374                                     int                        interleave_block,
375                                     const void * GGML_RESTRICT data,
376                                     size_t                     data_size) {
377    GGML_ASSERT(t->type == GGML_TYPE_Q2_K);
378    GGML_ASSERT(interleave_block == 32);
379    GGML_ASSERT(QK_K == 256);
380
381    constexpr int nrows_interleaved = 32;
382
383    const block_q2_K * src = (const block_q2_K *) data;
384
385    auto * dst = (spacemit_kernels::nrow_block_q2_k<32> *) t->data;
386
387    int nrow    = ggml_nrows(t);
388    int nblocks = t->ne[0] / QK_K;
389
390    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q2_K));
391
392    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK_K != 0) {
393        return -1;
394    }
395
396    uint8_t qs_aux[256] = { 0 };
397    for (int b = 0; b < nrow; b += nrows_interleaved) {
398        for (int64_t x = 0; x < nblocks; x++) {
399            for (int i = 0; i < nrows_interleaved; i++) {
400                const block_q2_K * src_block = &src[(b + i) * nblocks + x];
401
402                // scale for [16, N]
403                for (int j = 0; j < 16; j++) {
404                    auto zp_aux = (dst->scales[j * nrows_interleaved + i]) & 0xF0;
405
406                    dst->scales[j * nrows_interleaved + i] = (src_block->scales[j] & 0x0F) | zp_aux;
407                }
408
409                // zp for [N, 16]
410                for (int j = 0; j < 16; j++) {
411                    auto scale_aux = (dst->scales[16 * i + j]) & 0x0F;
412
413                    dst->scales[16 * i + j] = (src_block->scales[j] & 0xF0) | scale_aux;
414                }
415
416                for (int k = 0; k < 4; k++) {
417                    for (int j = 0; j < 32; j++) {
418                        qs_aux[k * 32 + j] = (src_block->qs[j] >> (2 * k)) & 0x03;
419                    }
420                }
421
422                for (int k = 0; k < 4; k++) {
423                    for (int j = 0; j < 32; j++) {
424                        qs_aux[k * 32 + j + 128] = (src_block->qs[j + 32] >> (2 * k)) & 0x03;
425                    }
426                }
427
428                // from nrows_interleaved * [2 * 32byte]
429                // to 4 * [nrows_interleaved * 16byte]
430                for (int k = 0; k < 4; k++) {
431                    for (int j = 0; j < 16; j++) {
432                        uint8_t qs0  = qs_aux[j + k * 64];
433                        uint8_t qs16 = qs_aux[j + 16 + k * 64];
434                        uint8_t qs32 = qs_aux[j + 32 + k * 64];
435                        uint8_t qs48 = qs_aux[j + 48 + k * 64];
436
437                        dst->qs[(k * nrows_interleaved + i) * 16 + j] =
438                            (qs0 & 0x03) | ((qs16 & 0x03) << 2) | ((qs32 & 0x03) << 4) | ((qs48 & 0x03) << 6);
439                    }
440                }
441
442                dst->scales16[i] = src_block->GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d;
443                dst->zeros16[i]  = src_block->GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.dmin;
444            }
445            dst++;
446        }
447    }
448
449    return 0;
450}
451
452static int repack_q3_k_to_q3_k_32_bl(ggml_tensor *              t,
453                                     int                        interleave_block,
454                                     const void * GGML_RESTRICT data,
455                                     size_t                     data_size) {
456    GGML_ASSERT(t->type == GGML_TYPE_Q3_K);
457    GGML_ASSERT(interleave_block == 32);
458    GGML_ASSERT(QK_K == 256);
459
460    constexpr int nrows_interleaved = 32;
461
462    const uint32_t kmask1 = 0x03030303;
463    const uint32_t kmask2 = 0x0f0f0f0f;
464
465    const block_q3_K * src = (const block_q3_K *) data;
466
467    auto * dst = (spacemit_kernels::nrow_block_q3_k<32> *) t->data;
468
469    int nrow    = ggml_nrows(t);
470    int nblocks = t->ne[0] / QK_K;
471
472    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q3_K));
473
474    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK_K != 0) {
475        return -1;
476    }
477
478    uint32_t b_scale_aux[4] = { 0 };
479    uint8_t  qs_aux[256]    = { 0 };
480
481    for (int b = 0; b < nrow; b += nrows_interleaved) {
482        for (int64_t x = 0; x < nblocks; x++) {
483            for (int i = 0; i < nrows_interleaved; i++) {
484                const block_q3_K * src_block = &src[(b + i) * nblocks + x];
485
486                uint32_t * auxs  = b_scale_aux;
487                int8_t *   scale = (int8_t *) auxs;
488                memcpy(auxs, src_block->scales, 12);
489
490                uint32_t tmp = auxs[2];
491                auxs[2]      = ((auxs[0] >> 4) & kmask2) | (((tmp >> 4) & kmask1) << 4);
492                auxs[3]      = ((auxs[1] >> 4) & kmask2) | (((tmp >> 6) & kmask1) << 4);
493                auxs[0]      = (auxs[0] & kmask2) | (((tmp >> 0) & kmask1) << 4);
494                auxs[1]      = (auxs[1] & kmask2) | (((tmp >> 2) & kmask1) << 4);
495
496                for (int j = 0; j < 16; j++) {
497                    dst->scales[j * nrows_interleaved + i] = scale[j] - 32;
498                }
499
500                for (int k = 0; k < 4; k++) {
501                    for (int j = 0; j < 32; j++) {
502                        qs_aux[k * 32 + j] = (src_block->qs[j] >> (2 * k)) & 0x03;
503                    }
504                }
505
506                for (int k = 0; k < 4; k++) {
507                    for (int j = 0; j < 32; j++) {
508                        qs_aux[k * 32 + j + 128] = (src_block->qs[j + 32] >> (2 * k)) & 0x03;
509                    }
510                }
511
512                // from nrows_interleaved * [2 * 32byte]
513                // to 4 * [nrows_interleaved * 16byte]
514                for (int k = 0; k < 4; k++) {
515                    for (int j = 0; j < 16; j++) {
516                        uint8_t qs0  = qs_aux[j + k * 64];
517                        uint8_t qs16 = qs_aux[j + 16 + k * 64];
518                        uint8_t qs32 = qs_aux[j + 32 + k * 64];
519                        uint8_t qs48 = qs_aux[j + 48 + k * 64];
520
521                        dst->qs[(k * nrows_interleaved + i) * 16 + j] =
522                            (qs0 & 0x03) | ((qs16 & 0x03) << 2) | ((qs32 & 0x03) << 4) | ((qs48 & 0x03) << 6);
523                    }
524                }
525
526                //memcpy(dst->hmask + i * 32, src_block->hmask, 32);
527
528                // from nrows_interleaved * [32byte]
529                // to 16 * [nrows_interleaved * uint16_t]
530                uint16_t * dst_mask = ((uint16_t *) dst->hmask) + i;
531                for (int j = 0; j < 16; j++, dst_mask += nrows_interleaved) {
532                    uint8_t   b_shift    = j / 2;
533                    uint8_t * b_mask_col = (uint8_t *) (src_block->hmask + (j % 2) * 16);
534                    // b0 - b15
535                    uint16_t  msk_out_0  = 0;
536
537                    for (int k = 0; k < 8; k++) {
538                        msk_out_0 |= (uint16_t) ((b_mask_col[k] >> b_shift) & 0x01) << k;
539                    }
540                    for (int k = 8; k < 16; k++) {
541                        msk_out_0 |= (uint16_t) ((b_mask_col[k] >> b_shift) & 0x01) << k;
542                    }
543
544                    dst_mask[0] = msk_out_0;
545                }
546
547                dst->scales16[i] = src_block->d;
548            }
549
550            dst++;
551        }
552    }
553
554    return 0;
555}
556
557static int repack_q4_0_to_q4_0_32_bl_ref(ggml_tensor *              t,
558                                         int                        interleave_block,
559                                         const void * GGML_RESTRICT data,
560                                         size_t                     data_size) {
561    GGML_ASSERT(t->type == GGML_TYPE_Q4_0);
562    GGML_ASSERT(interleave_block == 32);  // unused
563
564    constexpr int nrows_interleaved = 32;
565
566    block_q4_0x32 *    dst = (block_q4_0x32 *) t->data;
567    const block_q4_0 * src = (const block_q4_0 *) data;
568    block_q4_0         dst_tmp[32];
569    int                nrow    = ggml_nrows(t);
570    int                nblocks = t->ne[0] / QK4_0;
571
572    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q4_0));
573
574    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK4_0 != 0) {
575        return -1;
576    }
577
578    for (int b = 0; b < nrow; b += nrows_interleaved) {
579        for (int64_t x = 0; x < nblocks; x++) {
580            for (int i = 0; i < nrows_interleaved; i++) {
581                dst_tmp[i] = src[x + i * nblocks];
582            }
583            *dst++ = make_block_q4_0x32(dst_tmp, interleave_block);
584        }
585        src += nrows_interleaved * nblocks;
586    }
587    return 0;
588
589    GGML_UNUSED(data_size);
590}
591
592static int repack_q4_0_to_q4_0_256_32_bl_ref(ggml_tensor *              t,
593                                             int                        interleave_block,
594                                             const void * GGML_RESTRICT data,
595                                             size_t                     data_size) {
596    GGML_ASSERT(t->type == GGML_TYPE_Q4_0);
597    GGML_ASSERT(interleave_block == 32);  // unused
598
599    constexpr int nrows_interleaved = 32;
600
601    block_q4_0x32x256 * dst = (block_q4_0x32x256 *) t->data;
602    const block_q4_0 *  src = (const block_q4_0 *) data;
603    block_q4_0          dst_tmp[32];
604    int                 nrow    = ggml_nrows(t);
605    int                 nblocks = t->ne[0] / QK4_0;
606
607    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q4_0));
608    GGML_ASSERT(nblocks % 8 == 0);  // for 256-block interleaving
609    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK4_0 != 0) {
610        return -1;
611    }
612
613    for (int b = 0; b < nrow; b += nrows_interleaved) {
614        for (int64_t x = 0; x < nblocks; x += 8) {
615            for (int j = 0; j < 8; j++) {
616                for (int i = 0; i < nrows_interleaved; i++) {
617                    dst_tmp[i] = src[x + j + i * nblocks];
618                }
619                dst->blocks[j] = make_block_q4_0x32(dst_tmp, interleave_block);
620            }
621            dst++;
622        }
623        src += nrows_interleaved * nblocks;
624    }
625    return 0;
626
627    GGML_UNUSED(data_size);
628}
629
630static int repack_q4_0_to_q4_1_256_32_bl_ref(ggml_tensor *              t,
631                                             int                        interleave_block,
632                                             const void * GGML_RESTRICT data,
633                                             size_t                     data_size) {
634    GGML_ASSERT(t->type == GGML_TYPE_Q4_1);
635    GGML_ASSERT(interleave_block == 32);  // unused
636
637    constexpr int nrows_interleaved = 32;
638
639    block_q4_1x32x256 * dst = (block_q4_1x32x256 *) t->data;
640    const block_q4_1 *  src = (const block_q4_1 *) data;
641    block_q4_1          dst_tmp[32];
642    int                 nrow    = ggml_nrows(t);
643    int                 nblocks = t->ne[0] / QK4_0;
644
645    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q4_1));
646    GGML_ASSERT(nblocks % 8 == 0);  // for 256-block interleaving
647    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK4_0 != 0) {
648        return -1;
649    }
650
651    for (int b = 0; b < nrow; b += nrows_interleaved) {
652        for (int64_t x = 0; x < nblocks; x += 8) {
653            for (int j = 0; j < 8; j++) {
654                for (int i = 0; i < nrows_interleaved; i++) {
655                    dst_tmp[i] = src[x + j + i * nblocks];
656                }
657
658                block_q4_0x32 * dst_block = &dst->blocks[j];
659                uint8_t *       dst_zp    = dst->zps + j * nrows_interleaved;
660
661                for (int i = 0; i < nrows_interleaved; i++) {
662                    float d   = GGML_FP16_TO_FP32(dst_tmp[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d);
663                    float m   = GGML_FP16_TO_FP32(dst_tmp[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.m);
664                    float mid = -std::nearbyintf(m / d);
665                    mid       = std::min(15.0f, std::max(0.0f, mid));
666
667                    dst_block->d[i] = GGML_FP32_TO_FP16(d);
668                    dst_zp[i]       = static_cast<uint8_t>(mid);
669                }
670
671                for (int i = 0; i < nrows_interleaved; i++) {
672                    for (int k = 0; k < QK4_1 / 4; k++) {
673                        dst_block->qs[i * QK4_1 / 2 + k] =
674                            (dst_tmp[i].qs[k * 2] & 0x0F) | ((dst_tmp[i].qs[k * 2 + 1] & 0x0F) << 4);
675                    }
676                }
677
678                for (int i = 0; i < nrows_interleaved; i++) {
679                    for (int k = 0; k < QK4_1 / 4; k++) {
680                        dst_block->qs[i * QK4_1 / 2 + QK4_1 / 4 + k] =
681                            ((dst_tmp[i].qs[k * 2] & 0xF0) >> 4) | (dst_tmp[i].qs[k * 2 + 1] & 0xF0);
682                    }
683                }
684            }
685            dst++;
686        }
687        src += nrows_interleaved * nblocks;
688    }
689    return 0;
690
691    GGML_UNUSED(data_size);
692}
693
694// RVV optimized version of repack_q4_0_to_q4_0_32_bl
695// Eliminates the intermediate dst_tmp buffer and vectorizes nibble repack.
696static int repack_q4_0_to_q4_0_32_bl(ggml_tensor *              t,
697                                     int                        interleave_block,
698                                     const void * GGML_RESTRICT data,
699                                     size_t                     data_size) {
700    GGML_ASSERT(t->type == GGML_TYPE_Q4_0);
701    GGML_ASSERT(interleave_block == 32);
702
703    constexpr int nrows_interleaved = 32;
704    constexpr int qs_bytes          = QK4_0 / 2;  // 16
705
706    block_q4_0x32 *    dst     = (block_q4_0x32 *) t->data;
707    const block_q4_0 * src     = (const block_q4_0 *) data;
708    int                nrow    = ggml_nrows(t);
709    int                nblocks = t->ne[0] / QK4_0;
710
711    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q4_0));
712
713    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK4_0 != 0) {
714        return -1;
715    }
716
717    const ptrdiff_t row_stride = (ptrdiff_t) nblocks * sizeof(block_q4_0);
718
719    for (int b = 0; b < nrow; b += nrows_interleaved) {
720        for (int64_t x = 0; x < nblocks; x++) {
721            const block_q4_0 * col_src = src + x;
722
723            // --- 1) Gather 32 scale values (ggml_half d) with stride load ---
724            // d is at offset 0 of each block_q4_0, stride between rows = row_stride
725            {
726                const uint8_t * d_base    = (const uint8_t *) &col_src->d;
727                ggml_half *     d_dst     = dst->d;
728                size_t          remaining = 32;
729                size_t          offset    = 0;
730                while (remaining > 0) {
731                    size_t      vl = __riscv_vsetvl_e16m1(remaining);
732                    vuint16m1_t vd =
733                        __riscv_vlse16_v_u16m1((const uint16_t *) (d_base + offset * row_stride), row_stride, vl);
734                    __riscv_vse16_v_u16m1((uint16_t *) (d_dst + offset), vd, vl);
735                    offset += vl;
736                    remaining -= vl;
737                }
738            }
739
740            // --- 2) Nibble repack qs for each of the 32 rows ---
741            // For each row i:
742            //   src qs[16]: [b0|b16] [b1|b17] ... [b15|b31]  (lo nibble = b_j, hi nibble = b_{j+16})
743            //   dst qs low  8B: (qs[2j] & 0x0F) | ((qs[2j+1] & 0x0F) << 4)  for j=0..7
744            //   dst qs high 8B: ((qs[2j] >> 4))  | (qs[2j+1] & 0xF0)         for j=0..7
745            {
746                const size_t vl8 = __riscv_vsetvl_e8m1(8);
747                for (int i = 0; i < 32; i++) {
748                    const uint8_t * sq = col_src[i * nblocks].qs;
749                    uint8_t *       dq = dst->qs + i * qs_bytes;
750
751                    // stride-2 load to separate even/odd bytes
752                    vuint8m1_t v_even = __riscv_vlse8_v_u8m1(sq, 2, vl8);      // qs[0], qs[2], ..., qs[14]
753                    vuint8m1_t v_odd  = __riscv_vlse8_v_u8m1(sq + 1, 2, vl8);  // qs[1], qs[3], ..., qs[15]
754
755                    // low nibble part: (even & 0x0F) | ((odd & 0x0F) << 4)
756                    vuint8m1_t v_even_lo = __riscv_vand_vx_u8m1(v_even, 0x0F, vl8);
757                    vuint8m1_t v_odd_lo  = __riscv_vand_vx_u8m1(v_odd, 0x0F, vl8);
758                    vuint8m1_t v_lo      = __riscv_vor_vv_u8m1(v_even_lo, __riscv_vsll_vx_u8m1(v_odd_lo, 4, vl8), vl8);
759
760                    // high nibble part: (even >> 4) | (odd & 0xF0)
761                    vuint8m1_t v_even_hi = __riscv_vsrl_vx_u8m1(v_even, 4, vl8);
762                    vuint8m1_t v_odd_hi  = __riscv_vand_vx_u8m1(v_odd, 0xF0, vl8);
763                    vuint8m1_t v_hi      = __riscv_vor_vv_u8m1(v_even_hi, v_odd_hi, vl8);
764
765                    __riscv_vse8_v_u8m1(dq, v_lo, vl8);
766                    __riscv_vse8_v_u8m1(dq + 8, v_hi, vl8);
767                }
768            }
769
770            dst++;
771        }
772        src += nrows_interleaved * nblocks;
773    }
774    return 0;
775
776    GGML_UNUSED(data_size);
777}
778
779static int repack_q4_1_to_q4_1_32_bl_ref(ggml_tensor *              t,
780                                         int                        interleave_block,
781                                         const void * GGML_RESTRICT data,
782                                         size_t                     data_size) {
783    GGML_ASSERT(t->type == GGML_TYPE_Q4_1);
784    GGML_ASSERT(interleave_block == 32);  // unused
785
786    constexpr int nrows_interleaved = 32;
787
788    block_q4_1x32 *    dst = (block_q4_1x32 *) t->data;
789    const block_q4_1 * src = (const block_q4_1 *) data;
790    block_q4_1         dst_tmp[32];
791    int                nrow    = ggml_nrows(t);
792    int                nblocks = t->ne[0] / QK4_1;
793
794    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q4_1));
795
796    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK4_1 != 0) {
797        return -1;
798    }
799
800    for (int b = 0; b < nrow; b += nrows_interleaved) {
801        for (int64_t x = 0; x < nblocks; x++) {
802            for (int i = 0; i < nrows_interleaved; i++) {
803                dst_tmp[i] = src[x + i * nblocks];
804            }
805            *dst++ = make_block_q4_1x32(dst_tmp, interleave_block);
806        }
807        src += nrows_interleaved * nblocks;
808    }
809    return 0;
810
811    GGML_UNUSED(data_size);
812}
813
814// RVV optimized version of repack_q4_1_to_q4_1_32_bl
815// Eliminates the intermediate dst_tmp buffer and vectorizes nibble repack + zp computation.
816static int repack_q4_1_to_q4_1_32_bl(ggml_tensor *              t,
817                                     int                        interleave_block,
818                                     const void * GGML_RESTRICT data,
819                                     size_t                     data_size) {
820    GGML_ASSERT(t->type == GGML_TYPE_Q4_1);
821    GGML_ASSERT(interleave_block == 32);
822
823    constexpr int nrows_interleaved = 32;
824    constexpr int qs_bytes          = QK4_1 / 2;  // 16
825
826    block_q4_1x32 *    dst     = (block_q4_1x32 *) t->data;
827    const block_q4_1 * src     = (const block_q4_1 *) data;
828    int                nrow    = ggml_nrows(t);
829    int                nblocks = t->ne[0] / QK4_1;
830
831    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q4_1));
832
833    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK4_1 != 0) {
834        return -1;
835    }
836
837    const ptrdiff_t row_stride = (ptrdiff_t) nblocks * sizeof(block_q4_1);
838
839    for (int b = 0; b < nrow; b += nrows_interleaved) {
840        for (int64_t x = 0; x < nblocks; x++) {
841            const block_q4_1 * col_src = src + x;
842
843            // --- 1) Gather d and m, compute zp = clamp(nearbyint(-m/d), 0, 15) ---
844            // block_q4_1 layout: [d(f16), m(f16), qs[16]]
845            // d is at byte offset 0, m is at byte offset 2 from each block start
846            {
847                const uint8_t * dm_base   = (const uint8_t *) &col_src->GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d;
848                ggml_half *     d_dst     = dst->d;
849                uint8_t *       zp_dst    = dst->zp;
850                size_t          remaining = 32;
851                size_t          offset    = 0;
852                while (remaining > 0) {
853                    size_t vl = __riscv_vsetvl_e16m1(remaining);
854
855                    // stride load d (f16) from each row
856                    vuint16m1_t vd_raw =
857                        __riscv_vlse16_v_u16m1((const uint16_t *) (dm_base + offset * row_stride), row_stride, vl);
858                    __riscv_vse16_v_u16m1((uint16_t *) (d_dst + offset), vd_raw, vl);
859
860                    // stride load m (f16) from each row (offset +2 bytes from d)
861                    vuint16m1_t vm_raw =
862                        __riscv_vlse16_v_u16m1((const uint16_t *) (dm_base + 2 + offset * row_stride), row_stride, vl);
863
864                    // convert to f32 for zp computation: zp = nearbyint(-m / d)
865                    vfloat16m1_t vd_f16 = __riscv_vreinterpret_v_u16m1_f16m1(vd_raw);
866                    vfloat16m1_t vm_f16 = __riscv_vreinterpret_v_u16m1_f16m1(vm_raw);
867
868                    // -m / d in f16 directly (SpaceMIT X60 supports f16 arithmetic)
869                    vfloat16m1_t v_neg_m = __riscv_vfneg_v_f16m1(vm_f16, vl);
870                    vfloat16m1_t v_ratio = __riscv_vfdiv_vv_f16m1(v_neg_m, vd_f16, vl);
871
872                    // Convert to f32 for nearbyint, then clamp
873                    vfloat32m2_t v_ratio_f32 = __riscv_vfwcvt_f_f_v_f32m2(v_ratio, vl);
874
875                    // Use integer rounding: convert f32 -> int (rounds to nearest)
876                    vint32m2_t v_zp_i32 = __riscv_vfcvt_x_f_v_i32m2(v_ratio_f32, vl);
877
878                    // clamp to [0, 15]
879                    v_zp_i32 = __riscv_vmax_vx_i32m2(v_zp_i32, 0, vl);
880                    v_zp_i32 = __riscv_vmin_vx_i32m2(v_zp_i32, 15, vl);
881
882                    // narrow i32 -> u8
883                    vint16m1_t  v_zp_i16 = __riscv_vncvt_x_x_w_i16m1(v_zp_i32, vl);
884                    vint8mf2_t  v_zp_i8  = __riscv_vncvt_x_x_w_i8mf2(v_zp_i16, vl);
885                    vuint8mf2_t v_zp_u8  = __riscv_vreinterpret_v_i8mf2_u8mf2(v_zp_i8);
886                    __riscv_vse8_v_u8mf2(zp_dst + offset, v_zp_u8, vl);
887
888                    offset += vl;
889                    remaining -= vl;
890                }
891            }
892
893            // --- 2) Nibble repack qs for each of the 32 rows ---
894            {
895                const size_t vl8 = __riscv_vsetvl_e8m1(8);
896                for (int i = 0; i < 32; i++) {
897                    const uint8_t * sq = col_src[i * nblocks].qs;
898                    uint8_t *       dq = dst->qs + i * qs_bytes;
899
900                    // stride-2 load to separate even/odd bytes
901                    vuint8m1_t v_even = __riscv_vlse8_v_u8m1(sq, 2, vl8);
902                    vuint8m1_t v_odd  = __riscv_vlse8_v_u8m1(sq + 1, 2, vl8);
903
904                    // low nibble part: (even & 0x0F) | ((odd & 0x0F) << 4)
905                    vuint8m1_t v_even_lo = __riscv_vand_vx_u8m1(v_even, 0x0F, vl8);
906                    vuint8m1_t v_odd_lo  = __riscv_vand_vx_u8m1(v_odd, 0x0F, vl8);
907                    vuint8m1_t v_lo      = __riscv_vor_vv_u8m1(v_even_lo, __riscv_vsll_vx_u8m1(v_odd_lo, 4, vl8), vl8);
908
909                    // high nibble part: (even >> 4) | (odd & 0xF0)
910                    vuint8m1_t v_even_hi = __riscv_vsrl_vx_u8m1(v_even, 4, vl8);
911                    vuint8m1_t v_odd_hi  = __riscv_vand_vx_u8m1(v_odd, 0xF0, vl8);
912                    vuint8m1_t v_hi      = __riscv_vor_vv_u8m1(v_even_hi, v_odd_hi, vl8);
913
914                    __riscv_vse8_v_u8m1(dq, v_lo, vl8);
915                    __riscv_vse8_v_u8m1(dq + 8, v_hi, vl8);
916                }
917            }
918
919            dst++;
920        }
921        src += nrows_interleaved * nblocks;
922    }
923    return 0;
924
925    GGML_UNUSED(data_size);
926}
927
928static int repack_q4_k_to_q4_1_32_bl(ggml_tensor *              t,
929                                     int                        interleave_block,
930                                     const void * GGML_RESTRICT data,
931                                     size_t                     data_size) {
932    GGML_ASSERT(t->type == GGML_TYPE_Q4_K);
933    GGML_ASSERT(interleave_block == 32);
934    GGML_ASSERT(QK_K / QK4_1 == 8);
935
936    constexpr int nrows_interleaved = 32;
937
938    block_q4_1x32 *    dst = (block_q4_1x32 *) t->data;
939    const block_q4_K * src = (const block_q4_K *) data;
940    block_q4_1         dst_tmp[32];
941    int                nrow    = ggml_nrows(t);
942    int                nblocks = t->ne[0] / QK_K;
943
944    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK_K != 0) {
945        return -1;
946    }
947
948    for (int b = 0; b < nrow; b += nrows_interleaved) {
949        for (int64_t x = 0; x < nblocks; x++) {
950            for (int j = 0; j < 8; j++) {
951                for (int i = 0; i < nrows_interleaved; i++) {
952                    uint8_t     sc, m;
953                    const float d = GGML_FP16_TO_FP32(src[x + i * nblocks].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d);
954                    const float min =
955                        GGML_FP16_TO_FP32(src[x + i * nblocks].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.dmin);
956                    get_scale_min_k4(j, src[x + i * nblocks].scales, &sc, &m);
957                    const float d1 = d * sc;
958                    const float m1 = min * m;
959
960                    dst_tmp[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d = GGML_FP32_TO_FP16(d1);
961                    dst_tmp[i].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.m = GGML_FP32_TO_FP16(-m1);
962                    // src -> [b0, b32] [b1, b33] ... [b31, b63]
963                    // dst -> [b0, b16] [b1, b17] ... [b15, b31] [b32, b48] [b33, b49] ... [b47, b63]
964                    const uint8_t * q                                  = src[x + i * nblocks].qs + (j / 2) * QK4_1;
965                    if (j % 2 == 0) {
966                        for (int ii = 0; ii < 16; ii++) {
967                            dst_tmp[i].qs[ii] = (q[ii] & 0x0F) | ((q[ii + 16] & 0x0F) << 4);
968                        }
969                    } else {
970                        for (int ii = 0; ii < 16; ii++) {
971                            dst_tmp[i].qs[ii] = ((q[ii] & 0xF0) >> 4) | (q[ii + 16] & 0xF0);
972                        }
973                    }
974                }
975                *dst++ = make_block_q4_1x32(dst_tmp, interleave_block);
976            }
977        }
978        src += nrows_interleaved * nblocks;
979    }
980    return 0;
981
982    GGML_UNUSED(data_size);
983}
984
985static int repack_q6_k_to_q8_0_32_bl_ref(ggml_tensor *              t,
986                                         int                        interleave_block,
987                                         const void * GGML_RESTRICT data,
988                                         size_t                     data_size) {
989    GGML_ASSERT(t->type == GGML_TYPE_Q6_K);
990    GGML_ASSERT(interleave_block == 32);
991    GGML_ASSERT(QK_K / QK4_1 == 8);
992
993    constexpr int nrows_interleaved = 32;
994
995    block_q8_0x32 *    dst = (block_q8_0x32 *) t->data;
996    const block_q6_K * src = (const block_q6_K *) data;
997    block_q8_0         dst_tmp[32];
998    int8_t             aux8[QK4_1];
999    int                nrow    = ggml_nrows(t);
1000    int                nblocks = t->ne[0] / QK_K;
1001
1002    if (t->ne[0] % QK_K != 0) {
1003        return -1;
1004    }
1005
1006    for (int b = 0; b < nrow; b += nrows_interleaved) {
1007        int64_t nrow_real = std::min((int64_t) nrow - b, (int64_t) nrows_interleaved);
1008        for (int64_t x = 0; x < nblocks; x++) {
1009            for (int bi = 0; bi < 8; bi++) {
1010                int i = 0;
1011                for (; i < nrow_real; i++) {
1012                    const uint8_t * q4     = src[x + i * nblocks].ql;
1013                    const uint8_t * qh     = src[x + i * nblocks].qh;
1014                    const int8_t *  scales = src[x + i * nblocks].scales;
1015                    float           d      = GGML_FP16_TO_FP32(src[x + i * nblocks].d);
1016
1017                    q4 += 64 * (bi / 4);
1018                    qh += 32 * (bi / 4);
1019                    int8_t * GGML_RESTRICT a = aux8;
1020
1021                    int8_t bi_idx = bi % 4;
1022
1023                    if (bi_idx == 0) {
1024                        for (int l = 0; l < 32; ++l) {
1025                            a[l] = (int8_t) ((q4[l] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32;
1026                        }
1027                    } else if (bi_idx == 1) {
1028                        for (int l = 0; l < 32; ++l) {
1029                            a[l] = (int8_t) ((q4[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32;
1030                        }
1031                    } else if (bi_idx == 2) {
1032                        for (int l = 0; l < 32; ++l) {
1033                            a[l] = (int8_t) ((q4[l + 0] >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32;
1034                        }
1035                    } else if (bi_idx == 3) {
1036                        for (int l = 0; l < 32; ++l) {
1037                            a[l] = (int8_t) ((q4[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32;
1038                        }
1039                    }
1040                    a = aux8;
1041
1042                    float a_max_abs = 0.0f;
1043                    float scale_0   = scales[bi * 2 + 0] * d;
1044                    float scale_1   = scales[bi * 2 + 1] * d;
1045                    for (int l = 0; l < 16; ++l) {
1046                        a_max_abs = std::max(a_max_abs, std::abs(a[l] * scale_0));
1047                    }
1048
1049                    for (int l = 16; l < 32; ++l) {
1050                        a_max_abs = std::max(a_max_abs, std::abs(a[l] * scale_1));
1051                    }
1052
1053                    float reflect_scale   = a_max_abs / ((1 << 7) - 1);
1054                    float reflect_scale_0 = scale_0 / reflect_scale;
1055                    float reflect_scale_1 = scale_1 / reflect_scale;
1056
1057                    for (int l = 0; l < 16; ++l) {
1058                        float a_temp = std::clamp(std::nearbyintf(a[l] * reflect_scale_0), -128.0f, 127.0f);
1059                        a[l]         = (int8_t) (a_temp);
1060                    }
1061
1062                    for (int l = 16; l < 32; ++l) {
1063                        float a_temp = std::clamp(std::nearbyintf(a[l] * reflect_scale_1), -128.0f, 127.0f);
1064                        a[l]         = (int8_t) (a_temp);
1065                    }
1066
1067                    dst_tmp[i].d = GGML_FP32_TO_FP16(reflect_scale);
1068
1069                    memcpy(dst_tmp[i].qs, a, 32 * sizeof(int8_t));
1070                }
1071
1072                for (; i < nrows_interleaved; i++) {
1073                    memset(&dst_tmp[i], 0, sizeof(block_q8_0));
1074                }
1075
1076                *dst++ = make_block_q8_0x32(dst_tmp, interleave_block);
1077            }
1078        }
1079        src += nrows_interleaved * nblocks;
1080    }
1081    return 0;
1082
1083    GGML_UNUSED(data_size);
1084}
1085
1086// RVV optimized version of repack_q6_k_to_q8_0_32_bl
1087// Vectorizes the Q6_K dequant -> requant pipeline using RVV intrinsics.
1088// For each sub-block (bi), dequant 32 Q6_K values to int6 -> apply two sub-block scales ->
1089// find max abs -> compute reflect_scale -> requant to int8 -> gather d with stride load.
1090static int repack_q6_k_to_q8_0_32_bl(ggml_tensor *              t,
1091                                     int                        interleave_block,
1092                                     const void * GGML_RESTRICT data,
1093                                     size_t                     data_size) {
1094    GGML_ASSERT(t->type == GGML_TYPE_Q6_K);
1095    GGML_ASSERT(interleave_block == 32);
1096    GGML_ASSERT(QK_K / QK4_1 == 8);
1097
1098    constexpr int nrows_interleaved = 32;
1099
1100    block_q8_0x32 *    dst     = (block_q8_0x32 *) t->data;
1101    const block_q6_K * src     = (const block_q6_K *) data;
1102    int                nrow    = ggml_nrows(t);
1103    int                nblocks = t->ne[0] / QK_K;
1104
1105    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK_K != 0) {
1106        return -1;
1107    }
1108
1109    const ptrdiff_t row_stride = (ptrdiff_t) nblocks * sizeof(block_q6_K);
1110
1111    for (int b = 0; b < nrow; b += nrows_interleaved) {
1112        for (int64_t x = 0; x < nblocks; x++) {
1113            for (int bi = 0; bi < 8; bi++) {
1114                // --- 1) Gather 32 d values with stride load ---
1115                // We need to compute reflect_scale per row first, so gather d later.
1116                // Process each row: dequant Q6_K sub-block -> requant to Q8_0
1117                for (int i = 0; i < nrows_interleaved; i++) {
1118                    const block_q6_K * src_blk = &src[x + i * nblocks];
1119                    const uint8_t *    q4      = src_blk->ql + 64 * (bi / 4);
1120                    const uint8_t *    qh      = src_blk->qh + 32 * (bi / 4);
1121                    const int8_t *     scales  = src_blk->scales;
1122                    float              d       = GGML_FP16_TO_FP32(src_blk->d);
1123
1124                    int8_t bi_idx = bi % 4;
1125
1126                    // --- Dequant 32 Q6_K values to int6 (range [-32, 31]) using RVV ---
1127                    // vl = 32 for e8m2 (VLEN=256) or loop for smaller VLEN
1128                    const size_t vl16 = __riscv_vsetvl_e8m1(16);
1129
1130                    vint8m1_t va_lo, va_hi;  // 16 elements each
1131
1132                    if (bi_idx == 0) {
1133                        // a[l] = (q4[l] & 0xF) | (((qh[l] >> 0) & 3) << 4) - 32
1134                        vuint8m1_t vq4_lo = __riscv_vle8_v_u8m1(q4, vl16);
1135                        vuint8m1_t vq4_hi = __riscv_vle8_v_u8m1(q4 + 16, vl16);
1136                        vuint8m1_t vqh_lo = __riscv_vle8_v_u8m1(qh, vl16);
1137                        vuint8m1_t vqh_hi = __riscv_vle8_v_u8m1(qh + 16, vl16);
1138
1139                        vuint8m1_t vlo4_lo = __riscv_vand_vx_u8m1(vq4_lo, 0x0F, vl16);
1140                        vuint8m1_t vlo4_hi = __riscv_vand_vx_u8m1(vq4_hi, 0x0F, vl16);
1141                        vuint8m1_t vh_lo   = __riscv_vsll_vx_u8m1(__riscv_vand_vx_u8m1(vqh_lo, 0x03, vl16), 4, vl16);
1142                        vuint8m1_t vh_hi   = __riscv_vsll_vx_u8m1(__riscv_vand_vx_u8m1(vqh_hi, 0x03, vl16), 4, vl16);
1143
1144                        vuint8m1_t vcomb_lo = __riscv_vor_vv_u8m1(vlo4_lo, vh_lo, vl16);
1145                        vuint8m1_t vcomb_hi = __riscv_vor_vv_u8m1(vlo4_hi, vh_hi, vl16);
1146
1147                        va_lo = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(vcomb_lo), 32, vl16);
1148                        va_hi = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(vcomb_hi), 32, vl16);
1149                    } else if (bi_idx == 1) {
1150                        // a[l] = (q4[l+32] & 0xF) | (((qh[l] >> 2) & 3) << 4) - 32
1151                        vuint8m1_t vq4_lo = __riscv_vle8_v_u8m1(q4 + 32, vl16);
1152                        vuint8m1_t vq4_hi = __riscv_vle8_v_u8m1(q4 + 48, vl16);
1153                        vuint8m1_t vqh_lo = __riscv_vle8_v_u8m1(qh, vl16);
1154                        vuint8m1_t vqh_hi = __riscv_vle8_v_u8m1(qh + 16, vl16);
1155
1156                        vuint8m1_t vlo4_lo = __riscv_vand_vx_u8m1(vq4_lo, 0x0F, vl16);
1157                        vuint8m1_t vlo4_hi = __riscv_vand_vx_u8m1(vq4_hi, 0x0F, vl16);
1158                        vuint8m1_t vh_lo   = __riscv_vsll_vx_u8m1(
1159                            __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(vqh_lo, 2, vl16), 0x03, vl16), 4, vl16);
1160                        vuint8m1_t vh_hi = __riscv_vsll_vx_u8m1(
1161                            __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(vqh_hi, 2, vl16), 0x03, vl16), 4, vl16);
1162
1163                        vuint8m1_t vcomb_lo = __riscv_vor_vv_u8m1(vlo4_lo, vh_lo, vl16);
1164                        vuint8m1_t vcomb_hi = __riscv_vor_vv_u8m1(vlo4_hi, vh_hi, vl16);
1165
1166                        va_lo = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(vcomb_lo), 32, vl16);
1167                        va_hi = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(vcomb_hi), 32, vl16);
1168                    } else if (bi_idx == 2) {
1169                        // a[l] = (q4[l] >> 4) | (((qh[l] >> 4) & 3) << 4) - 32
1170                        vuint8m1_t vq4_lo = __riscv_vle8_v_u8m1(q4, vl16);
1171                        vuint8m1_t vq4_hi = __riscv_vle8_v_u8m1(q4 + 16, vl16);
1172                        vuint8m1_t vqh_lo = __riscv_vle8_v_u8m1(qh, vl16);
1173                        vuint8m1_t vqh_hi = __riscv_vle8_v_u8m1(qh + 16, vl16);
1174
1175                        vuint8m1_t vhi4_lo = __riscv_vsrl_vx_u8m1(vq4_lo, 4, vl16);
1176                        vuint8m1_t vhi4_hi = __riscv_vsrl_vx_u8m1(vq4_hi, 4, vl16);
1177                        vuint8m1_t vh_lo   = __riscv_vsll_vx_u8m1(
1178                            __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(vqh_lo, 4, vl16), 0x03, vl16), 4, vl16);
1179                        vuint8m1_t vh_hi = __riscv_vsll_vx_u8m1(
1180                            __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(vqh_hi, 4, vl16), 0x03, vl16), 4, vl16);
1181
1182                        vuint8m1_t vcomb_lo = __riscv_vor_vv_u8m1(vhi4_lo, vh_lo, vl16);
1183                        vuint8m1_t vcomb_hi = __riscv_vor_vv_u8m1(vhi4_hi, vh_hi, vl16);
1184
1185                        va_lo = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(vcomb_lo), 32, vl16);
1186                        va_hi = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(vcomb_hi), 32, vl16);
1187                    } else {  // bi_idx == 3
1188                        // a[l] = (q4[l+32] >> 4) | (((qh[l] >> 6) & 3) << 4) - 32
1189                        vuint8m1_t vq4_lo = __riscv_vle8_v_u8m1(q4 + 32, vl16);
1190                        vuint8m1_t vq4_hi = __riscv_vle8_v_u8m1(q4 + 48, vl16);
1191                        vuint8m1_t vqh_lo = __riscv_vle8_v_u8m1(qh, vl16);
1192                        vuint8m1_t vqh_hi = __riscv_vle8_v_u8m1(qh + 16, vl16);
1193
1194                        vuint8m1_t vhi4_lo = __riscv_vsrl_vx_u8m1(vq4_lo, 4, vl16);
1195                        vuint8m1_t vhi4_hi = __riscv_vsrl_vx_u8m1(vq4_hi, 4, vl16);
1196                        vuint8m1_t vh_lo   = __riscv_vsll_vx_u8m1(
1197                            __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(vqh_lo, 6, vl16), 0x03, vl16), 4, vl16);
1198                        vuint8m1_t vh_hi = __riscv_vsll_vx_u8m1(
1199                            __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(vqh_hi, 6, vl16), 0x03, vl16), 4, vl16);
1200
1201                        vuint8m1_t vcomb_lo = __riscv_vor_vv_u8m1(vhi4_lo, vh_lo, vl16);
1202                        vuint8m1_t vcomb_hi = __riscv_vor_vv_u8m1(vhi4_hi, vh_hi, vl16);
1203
1204                        va_lo = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(vcomb_lo), 32, vl16);
1205                        va_hi = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(vcomb_hi), 32, vl16);
1206                    }
1207
1208                    // --- Widen to i16 for scaled abs computation ---
1209                    float scale_0 = scales[bi * 2 + 0] * d;
1210                    float scale_1 = scales[bi * 2 + 1] * d;
1211
1212                    // Widen i8 -> i16 -> f32 for abs*scale computation
1213                    vint16m2_t va_lo_w = __riscv_vsext_vf2_i16m2(va_lo, vl16);
1214                    vint16m2_t va_hi_w = __riscv_vsext_vf2_i16m2(va_hi, vl16);
1215
1216                    // Compute |a[l] * scale_0| for lo half, |a[l] * scale_1| for hi half
1217                    vfloat32m4_t vf_lo = __riscv_vfcvt_f_x_v_f32m4(__riscv_vsext_vf2_i32m4(va_lo_w, vl16), vl16);
1218                    vfloat32m4_t vf_hi = __riscv_vfcvt_f_x_v_f32m4(__riscv_vsext_vf2_i32m4(va_hi_w, vl16), vl16);
1219
1220                    vfloat32m4_t vabs_lo = __riscv_vfabs_v_f32m4(__riscv_vfmul_vf_f32m4(vf_lo, scale_0, vl16), vl16);
1221                    vfloat32m4_t vabs_hi = __riscv_vfabs_v_f32m4(__riscv_vfmul_vf_f32m4(vf_hi, scale_1, vl16), vl16);
1222
1223                    // Find max abs across both halves
1224                    vfloat32m4_t vabs_max = __riscv_vfmax_vv_f32m4(vabs_lo, vabs_hi, vl16);
1225
1226                    // Reduce to scalar max
1227                    vfloat32m1_t vzero     = __riscv_vfmv_v_f_f32m1(0.0f, 1);
1228                    vfloat32m1_t vmax_red  = __riscv_vfredmax_vs_f32m4_f32m1(vabs_max, vzero, vl16);
1229                    float        a_max_abs = __riscv_vfmv_f_s_f32m1_f32(vmax_red);
1230
1231                    float reflect_scale   = a_max_abs / 127.0f;
1232                    float reflect_scale_0 = scale_0 / reflect_scale;
1233                    float reflect_scale_1 = scale_1 / reflect_scale;
1234
1235                    // --- Requant: a[l] = clamp(nearbyint(a[l] * reflect_scale_x), -128, 127) ---
1236                    vfloat32m4_t vscaled_lo = __riscv_vfmul_vf_f32m4(vf_lo, reflect_scale_0, vl16);
1237                    vfloat32m4_t vscaled_hi = __riscv_vfmul_vf_f32m4(vf_hi, reflect_scale_1, vl16);
1238
1239                    // fcvt.x rounds to nearest (using current rounding mode)
1240                    vint32m4_t vi_lo = __riscv_vfcvt_x_f_v_i32m4(vscaled_lo, vl16);
1241                    vint32m4_t vi_hi = __riscv_vfcvt_x_f_v_i32m4(vscaled_hi, vl16);
1242
1243                    // Clamp to [-128, 127]
1244                    vi_lo = __riscv_vmax_vx_i32m4(vi_lo, -128, vl16);
1245                    vi_lo = __riscv_vmin_vx_i32m4(vi_lo, 127, vl16);
1246                    vi_hi = __riscv_vmax_vx_i32m4(vi_hi, -128, vl16);
1247                    vi_hi = __riscv_vmin_vx_i32m4(vi_hi, 127, vl16);
1248
1249                    // Narrow i32 -> i16 -> i8
1250                    vint16m2_t vi16_lo = __riscv_vncvt_x_x_w_i16m2(vi_lo, vl16);
1251                    vint16m2_t vi16_hi = __riscv_vncvt_x_x_w_i16m2(vi_hi, vl16);
1252                    vint8m1_t  vi8_lo  = __riscv_vncvt_x_x_w_i8m1(vi16_lo, vl16);
1253                    vint8m1_t  vi8_hi  = __riscv_vncvt_x_x_w_i8m1(vi16_hi, vl16);
1254
1255                    // Store d and qs directly into dst block
1256                    dst->d[i]   = GGML_FP32_TO_FP16(reflect_scale);
1257                    int8_t * dq = (int8_t *) dst->qs + i * QK8_0;
1258                    __riscv_vse8_v_i8m1(dq, vi8_lo, vl16);
1259                    __riscv_vse8_v_i8m1(dq + 16, vi8_hi, vl16);
1260                }
1261                dst++;
1262            }
1263        }
1264        src += nrows_interleaved * nblocks;
1265    }
1266    return 0;
1267
1268    GGML_UNUSED(data_size);
1269}
1270
1271static int repack_q8_0_to_q8_0_32_bl_ref(ggml_tensor *              t,
1272                                         int                        interleave_block,
1273                                         const void * GGML_RESTRICT data,
1274                                         size_t                     data_size) {
1275    GGML_ASSERT(t->type == GGML_TYPE_Q8_0);
1276    GGML_ASSERT(interleave_block == 32);  // unused
1277
1278    constexpr int nrows_interleaved = 32;
1279
1280    block_q8_0x32 *    dst = (block_q8_0x32 *) t->data;
1281    const block_q8_0 * src = (const block_q8_0 *) data;
1282    block_q8_0         dst_tmp[32];
1283    int                nrow    = ggml_nrows(t);
1284    int                nblocks = t->ne[0] / QK8_0;
1285
1286    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q8_0));
1287
1288    if (t->ne[0] % QK8_0 != 0) {
1289        return -1;
1290    }
1291
1292    for (int b = 0; b < nrow; b += nrows_interleaved) {
1293        int64_t nrows_real = std::min((int64_t) nrow - b, (int64_t) nrows_interleaved);
1294        for (int64_t x = 0; x < nblocks; x++) {
1295            int i = 0;
1296            for (; i < nrows_real; i++) {
1297                dst_tmp[i] = src[x + i * nblocks];
1298            }
1299            for (; i < nrows_interleaved; i++) {
1300                memset(&dst_tmp[i], 0, sizeof(block_q8_0));
1301            }
1302            *dst++ = make_block_q8_0x32(dst_tmp, interleave_block);
1303        }
1304        src += nrows_interleaved * nblocks;
1305    }
1306    return 0;
1307
1308    GGML_UNUSED(data_size);
1309}
1310
1311// RVV optimized version of repack_q8_0_to_q8_0_32_bl
1312// Eliminates the intermediate dst_tmp buffer and vectorizes scale gather + qs copy.
1313static int repack_q8_0_to_q8_0_32_bl(ggml_tensor *              t,
1314                                     int                        interleave_block,
1315                                     const void * GGML_RESTRICT data,
1316                                     size_t                     data_size) {
1317    GGML_ASSERT(t->type == GGML_TYPE_Q8_0);
1318    GGML_ASSERT(interleave_block == 32);
1319
1320    constexpr int nrows_interleaved = 32;
1321
1322    block_q8_0x32 *    dst     = (block_q8_0x32 *) t->data;
1323    const block_q8_0 * src     = (const block_q8_0 *) data;
1324    int                nrow    = ggml_nrows(t);
1325    int                nblocks = t->ne[0] / QK8_0;
1326
1327    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q8_0));
1328
1329    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK8_0 != 0) {
1330        return -1;
1331    }
1332
1333    const ptrdiff_t row_stride = (ptrdiff_t) nblocks * sizeof(block_q8_0);
1334
1335    for (int b = 0; b < nrow; b += nrows_interleaved) {
1336        for (int64_t x = 0; x < nblocks; x++) {
1337            const block_q8_0 * col_src = src + x;
1338
1339            // --- 1) Gather 32 scale values (ggml_half d) with stride load ---
1340            {
1341                const uint8_t * d_base    = (const uint8_t *) &col_src->d;
1342                ggml_half *     d_dst     = dst->d;
1343                size_t          remaining = 32;
1344                size_t          offset    = 0;
1345                while (remaining > 0) {
1346                    size_t      vl = __riscv_vsetvl_e16m1(remaining);
1347                    vuint16m1_t vd =
1348                        __riscv_vlse16_v_u16m1((const uint16_t *) (d_base + offset * row_stride), row_stride, vl);
1349                    __riscv_vse16_v_u16m1((uint16_t *) (d_dst + offset), vd, vl);
1350                    offset += vl;
1351                    remaining -= vl;
1352                }
1353            }
1354
1355            // --- 2) Copy qs for each of the 32 rows (32 bytes per row) ---
1356            {
1357                for (int i = 0; i < 32; i++) {
1358                    const int8_t * sq = col_src[i * nblocks].qs;
1359                    int8_t *       dq = (int8_t *) dst->qs + i * QK8_0;
1360
1361                    size_t len = QK8_0;
1362                    size_t idx = 0;
1363                    while (len > 0) {
1364                        size_t    vl = __riscv_vsetvl_e8m2(len);
1365                        vint8m2_t vs = __riscv_vle8_v_i8m2(sq + idx, vl);
1366                        __riscv_vse8_v_i8m2(dq + idx, vs, vl);
1367                        idx += vl;
1368                        len -= vl;
1369                    }
1370                }
1371            }
1372
1373            dst++;
1374        }
1375        src += nrows_interleaved * nblocks;
1376    }
1377    return 0;
1378
1379    GGML_UNUSED(data_size);
1380}
1381
1382static void convert_mxfp4_to_5bit(const block_mxfp4 & src, spacemit_kernels::nrow_block_mxfp4<1> & dst) {
1383    dst.e[0] = src.e;
1384
1385    // Decode all 32 mxfp4 values to signed integers via kvalues_mxfp4
1386    int8_t vals[32];
1387    for (int j = 0; j < QK_MXFP4 / 2; j++) {
1388        vals[j]                = kvalues_mxfp4[src.qs[j] & 0xF];
1389        vals[j + QK_MXFP4 / 2] = kvalues_mxfp4[src.qs[j] >> 4];
1390    }
1391
1392    // vals [b0, b1, b2, b3, ..., b30, b31]
1393    // Pack abs into qs with reorder: [b0,b1]..[b14,b15]..[b30,b31]
1394    for (int j = 0; j < QK_MXFP4 / 2; j++) {
1395        uint8_t lo0 = static_cast<uint8_t>(std::abs(vals[j * 2]));
1396        uint8_t lo1 = static_cast<uint8_t>(std::abs(vals[j * 2 + 1]));
1397        dst.qs[j]   = (lo0 & 0x0F) | ((lo1 & 0x0F) << 4);
1398    }
1399
1400    // Pack sign bits into qh[4] (32 bits total, 1 bit per weight)
1401    // reorder: [0,1,2,...,15,16,17,...,31] after the qs reorder above
1402    uint32_t sign_bits = 0;
1403    for (int j = 0; j < 32; j++) {
1404        if (vals[j] < 0) {
1405            sign_bits |= (1u << j);
1406        }
1407    }
1408    memcpy(dst.qh, &sign_bits, 4);
1409}
1410
1411static spacemit_kernels::nrow_block_mxfp4<32> make_block_mxfp4x32(spacemit_kernels::nrow_block_mxfp4<1> * in,
1412                                                                  unsigned int blck_size_interleave) {
1413    spacemit_kernels::nrow_block_mxfp4<32> out;
1414    GGML_ASSERT(QK_MXFP4 / blck_size_interleave == 1);
1415    GGML_UNUSED(blck_size_interleave);
1416
1417    for (int i = 0; i < 32; i++) {
1418        out.e[i] = in[i].e[0];
1419    }
1420
1421    // qs: copy per-row 16 bytes
1422    for (int i = 0; i < 32; i++) {
1423        memcpy(out.qs + i * 16, in[i].qs, 16);
1424    }
1425
1426    // qh: copy per-row 4 bytes
1427    for (int i = 0; i < 32; i++) {
1428        memcpy(out.qh + i * 4, in[i].qh, 4);
1429    }
1430
1431    return out;
1432}
1433
1434static int repack_mxfp4_to_mxfp4_32_bl(ggml_tensor *              t,
1435                                       int                        interleave_block,
1436                                       const void * GGML_RESTRICT data,
1437                                       size_t                     data_size) {
1438    GGML_ASSERT(t->type == GGML_TYPE_MXFP4);
1439    GGML_ASSERT(interleave_block == 32);
1440
1441    constexpr int nrows_interleaved = 32;
1442
1443    spacemit_kernels::nrow_block_mxfp4<32> * dst = (spacemit_kernels::nrow_block_mxfp4<32> *) t->data;
1444    const block_mxfp4 *                      src = (const block_mxfp4 *) data;
1445    spacemit_kernels::nrow_block_mxfp4<1>    dst_tmp[32];
1446    int                                      nrow    = ggml_nrows(t);
1447    int                                      nblocks = t->ne[0] / QK_MXFP4;
1448
1449    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_mxfp4));
1450
1451    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK_MXFP4 != 0) {
1452        return -1;
1453    }
1454
1455    for (int b = 0; b < nrow; b += nrows_interleaved) {
1456        for (int64_t x = 0; x < nblocks; x++) {
1457            for (int i = 0; i < nrows_interleaved; i++) {
1458                convert_mxfp4_to_5bit(src[x + i * nblocks], dst_tmp[i]);
1459            }
1460            *dst++ = make_block_mxfp4x32(dst_tmp, interleave_block);
1461        }
1462        src += nrows_interleaved * nblocks;
1463    }
1464    return 0;
1465}
1466
1467static spacemit_kernels::nrow_block_q5_1<32> make_block_q5_1x32(spacemit_kernels::nrow_block_q5_1<1> * in,
1468                                                                unsigned int blck_size_interleave) {
1469    spacemit_kernels::nrow_block_q5_1<32> out;
1470    GGML_ASSERT(QK5_1 / blck_size_interleave == 1);
1471    GGML_UNUSED(blck_size_interleave);
1472
1473    for (int i = 0; i < 32; i++) {
1474        out.scales16[i] = in[i].scales16[0];
1475        out.zp[i]       = in[i].zp[0];
1476    }
1477
1478    // qs: low 4 bits, reorder from [b0,b16],[b1,b17]... to [b0,b1]...[b14,b15] and [b16,b17]...[b30,b31]
1479    for (int i = 0; i < 32; i++) {
1480        // low half [0..15]
1481        for (int j = 0; j < QK5_1 / 4; j++) {
1482            out.qs[i * QK5_1 / 2 + j] = (in[i].qs[j * 2] & 0x0F) | ((in[i].qs[j * 2 + 1] & 0x0F) << 4);
1483        }
1484        // high half [16..31]
1485        for (int j = 0; j < QK5_1 / 4; j++) {
1486            out.qs[i * QK5_1 / 2 + QK5_1 / 4 + j] = ((in[i].qs[j * 2] & 0xF0) >> 4) | (in[i].qs[j * 2 + 1] & 0xF0);
1487        }
1488    }
1489
1490    // qh: 5th bit, copy directly
1491    for (int i = 0; i < 32; i++) {
1492        for (int j = 0; j < 4; j++) {
1493            out.qh[i * 4 + j] = in[i].qh[j];
1494        }
1495    }
1496
1497    return out;
1498}
1499
1500static spacemit_kernels::nrow_block_q5_0<32> make_block_q5_0x32(spacemit_kernels::nrow_block_q5_0<1> * in,
1501                                                                unsigned int blck_size_interleave) {
1502    spacemit_kernels::nrow_block_q5_0<32> out;
1503    GGML_ASSERT(QK5_0 / blck_size_interleave == 1);
1504    GGML_UNUSED(blck_size_interleave);
1505
1506    for (int i = 0; i < 32; i++) {
1507        out.scales16[i] = in[i].scales16[0];
1508    }
1509
1510    // qs: low 4 bits, reorder from [b0,b16],[b1,b17]... to [b0,b1]...[b14,b15] and [b16,b17]...[b30,b31]
1511    for (int i = 0; i < 32; i++) {
1512        // low half [0..15]
1513        for (int j = 0; j < QK5_0 / 4; j++) {
1514            out.qs[i * QK5_0 / 2 + j] = (in[i].qs[j * 2] & 0x0F) | ((in[i].qs[j * 2 + 1] & 0x0F) << 4);
1515        }
1516        // high half [16..31]
1517        for (int j = 0; j < QK5_0 / 4; j++) {
1518            out.qs[i * QK5_0 / 2 + QK5_0 / 4 + j] = ((in[i].qs[j * 2] & 0xF0) >> 4) | (in[i].qs[j * 2 + 1] & 0xF0);
1519        }
1520    }
1521
1522    // qh: 5th bit, copy directly
1523    for (int i = 0; i < 32; i++) {
1524        for (int j = 0; j < 4; j++) {
1525            out.qh[i * 4 + j] = in[i].qh[j];
1526        }
1527    }
1528
1529    return out;
1530}
1531
1532static int repack_q5_0_to_q5_0_32_bl(ggml_tensor *              t,
1533                                     int                        interleave_block,
1534                                     const void * GGML_RESTRICT data,
1535                                     size_t                     data_size) {
1536    GGML_ASSERT(t->type == GGML_TYPE_Q5_0);
1537    GGML_ASSERT(interleave_block == 32);  // unused
1538
1539    constexpr int nrows_interleaved = 32;
1540
1541    spacemit_kernels::nrow_block_q5_0<32> * dst = (spacemit_kernels::nrow_block_q5_0<32> *) t->data;
1542    const block_q5_0 *                      src = (const block_q5_0 *) data;
1543    spacemit_kernels::nrow_block_q5_0<1>    dst_tmp[32];
1544    int                                     nrow    = ggml_nrows(t);
1545    int                                     nblocks = t->ne[0] / QK5_0;
1546
1547    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q5_0));
1548
1549    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK5_0 != 0) {
1550        return -1;
1551    }
1552
1553    for (int b = 0; b < nrow; b += nrows_interleaved) {
1554        for (int64_t x = 0; x < nblocks; x++) {
1555            for (int i = 0; i < nrows_interleaved; i++) {
1556                const block_q5_0 & s = src[x + i * nblocks];
1557
1558                dst_tmp[i].scales16[0] = s.d;
1559                memcpy(dst_tmp[i].qs, s.qs, sizeof(dst_tmp[i].qs));
1560                memcpy(dst_tmp[i].qh, s.qh, sizeof(dst_tmp[i].qh));
1561            }
1562            *dst++ = make_block_q5_0x32(dst_tmp, interleave_block);
1563        }
1564        src += nrows_interleaved * nblocks;
1565    }
1566    return 0;
1567}
1568
1569static int repack_q5_1_to_q5_1_32_bl(ggml_tensor *              t,
1570                                     int                        interleave_block,
1571                                     const void * GGML_RESTRICT data,
1572                                     size_t                     data_size) {
1573    GGML_ASSERT(t->type == GGML_TYPE_Q5_1);
1574    GGML_ASSERT(interleave_block == 32);  // unused
1575
1576    constexpr int nrows_interleaved = 32;
1577
1578    spacemit_kernels::nrow_block_q5_1<32> * dst = (spacemit_kernels::nrow_block_q5_1<32> *) t->data;
1579    const block_q5_1 *                      src = (const block_q5_1 *) data;
1580    spacemit_kernels::nrow_block_q5_1<1>    dst_tmp[32];
1581    int                                     nrow    = ggml_nrows(t);
1582    int                                     nblocks = t->ne[0] / QK5_1;
1583
1584    GGML_ASSERT(data_size == nrow * nblocks * sizeof(block_q5_1));
1585
1586    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK5_1 != 0) {
1587        return -1;
1588    }
1589
1590    for (int b = 0; b < nrow; b += nrows_interleaved) {
1591        for (int64_t x = 0; x < nblocks; x++) {
1592            for (int i = 0; i < nrows_interleaved; i++) {
1593                const block_q5_1 & s = src[x + i * nblocks];
1594
1595                float d = GGML_FP16_TO_FP32(s.GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d);
1596                float m = GGML_FP16_TO_FP32(s.GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.m);
1597
1598                if (d == 0.0f) {
1599                    dst_tmp[i].scales16[0] = GGML_FP32_TO_FP16(std::fabs(m));
1600                    dst_tmp[i].zp[0]       = m < 0.0f ? 1 : 0;
1601                    memset(dst_tmp[i].qh, 0, sizeof(dst_tmp[i].qh));
1602                    memset(dst_tmp[i].qs, m > 0.0f ? 0x11 : 0x00, sizeof(dst_tmp[i].qs));
1603                    continue;
1604                }
1605
1606                float mid = std::nearbyintf(-m / d);
1607                mid       = std::min(31.0f, std::max(0.0f, mid));
1608
1609                dst_tmp[i].scales16[0] = GGML_FP32_TO_FP16(d);
1610                dst_tmp[i].zp[0]       = static_cast<uint8_t>(mid);
1611
1612                // qs: copy low 4 bits directly (same nibble packing)
1613                memcpy(dst_tmp[i].qs, s.qs, QK5_1 / 2);
1614
1615                // qh: copy 5th bit directly
1616                memcpy(dst_tmp[i].qh, s.qh, 4);
1617            }
1618            *dst++ = make_block_q5_1x32(dst_tmp, interleave_block);
1619        }
1620        src += nrows_interleaved * nblocks;
1621    }
1622    return 0;
1623}
1624
1625static int repack_q5_k_to_q5_1_32_bl(ggml_tensor *              t,
1626                                     int                        interleave_block,
1627                                     const void * GGML_RESTRICT data,
1628                                     size_t                     data_size) {
1629    GGML_ASSERT(t->type == GGML_TYPE_Q5_K);
1630    GGML_ASSERT(interleave_block == 32);
1631    GGML_ASSERT(QK_K / QK5_1 == 8);
1632
1633    constexpr int nrows_interleaved = 32;
1634
1635    spacemit_kernels::nrow_block_q5_1<32> * dst = (spacemit_kernels::nrow_block_q5_1<32> *) t->data;
1636    const block_q5_K *                      src = (const block_q5_K *) data;
1637    spacemit_kernels::nrow_block_q5_1<1>    dst_tmp[32];
1638    int                                     nrow    = ggml_nrows(t);
1639    int                                     nblocks = t->ne[0] / QK_K;
1640
1641    if (t->ne[1] % nrows_interleaved != 0 || t->ne[0] % QK_K != 0) {
1642        return -1;
1643    }
1644
1645    for (int b = 0; b < nrow; b += nrows_interleaved) {
1646        for (int64_t x = 0; x < nblocks; x++) {
1647            for (int j = 0; j < 8; j++) {
1648                for (int i = 0; i < nrows_interleaved; i++) {
1649                    uint8_t     sc, m;
1650                    const float d = GGML_FP16_TO_FP32(src[x + i * nblocks].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.d);
1651                    const float min =
1652                        GGML_FP16_TO_FP32(src[x + i * nblocks].GGML_COMMON_AGGR_U.GGML_COMMON_AGGR_S.dmin);
1653                    get_scale_min_k4(j, src[x + i * nblocks].scales, &sc, &m);
1654
1655                    float d1 = d * sc;
1656                    float m1 = min * m;
1657
1658                    float mid              = std::nearbyintf(m1 / d1);
1659                    mid                    = std::min(31.0f, std::max(0.0f, mid));
1660                    dst_tmp[i].scales16[0] = GGML_FP32_TO_FP16(d1);
1661                    dst_tmp[i].zp[0]       = static_cast<uint8_t>(mid);
1662
1663                    // src -> [b0, b32] [b1, b33] ... [b31, b63]
1664                    // dst -> [b0, b16] [b1, b17] ... [b15, b31] [b32, b48] [b33, b49] ... [b47, b63]
1665                    const uint8_t * q = src[x + i * nblocks].qs + (j / 2) * QK5_1;
1666                    if (j % 2 == 0) {
1667                        for (int ii = 0; ii < 16; ii++) {
1668                            dst_tmp[i].qs[ii] = (q[ii] & 0x0F) | ((q[ii + 16] & 0x0F) << 4);
1669                        }
1670                    } else {
1671                        for (int ii = 0; ii < 16; ii++) {
1672                            dst_tmp[i].qs[ii] = ((q[ii] & 0xF0) >> 4) | (q[ii + 16] & 0xF0);
1673                        }
1674                    }
1675
1676                    // Extract the 5th bit (qh) for this sub-block
1677                    // block_q5_K.qh[32]: for sub-block j, the 5th bit is at bit position j in qh[l]
1678                    // qs was reordered: dst_qs maps to src weights [0,16,1,17,...,15,31]
1679                    // So qh must follow the same reorder to stay aligned with qs
1680                    // dst qh[4] = 32 bits for 32 weights in the reordered layout:
1681                    //   byte 0: weights 0..7   (from src_qh[0..7])
1682                    //   byte 1: weights 8..15  (from src_qh[8..15])
1683                    //   byte 2: weights 16..23 (from src_qh[16..23])
1684                    //   byte 3: weights 24..31 (from src_qh[24..31])
1685                    const uint8_t * src_qh = src[x + i * nblocks].qh;
1686                    for (int bi = 0; bi < 4; bi++) {
1687                        uint8_t qh_byte = 0;
1688                        for (int k = 0; k < 8; k++) {
1689                            int src_idx = bi * 8 + k;
1690                            qh_byte |= ((src_qh[src_idx] >> j) & 1) << k;
1691                        }
1692                        dst_tmp[i].qh[bi] = qh_byte;
1693                    }
1694                }
1695                *dst++ = make_block_q5_1x32(dst_tmp, interleave_block);
1696            }
1697        }
1698        src += nrows_interleaved * nblocks;
1699    }
1700    return 0;
1701}
1702
1703namespace ggml::cpu::riscv64_spacemit {
1704
1705template <typename BLOC_TYPE, int64_t INTER_SIZE, int64_t NB_COLS> int repack(ggml_tensor *, const void *, size_t);
1706
1707template <> int repack<block_q4_0, 32, 16>(ggml_tensor * t, const void * data, size_t data_size) {
1708    return repack_q4_0_to_q4_0_16_bl(t, 16, data, data_size);
1709}
1710
1711template <> int repack<block_q4_1, 32, 16>(ggml_tensor * t, const void * data, size_t data_size) {
1712    return repack_q4_1_to_q4_1_16_bl(t, 16, data, data_size);
1713}
1714
1715template <> int repack<block_q4_K, 32, 16>(ggml_tensor * t, const void * data, size_t data_size) {
1716    return repack_q4_k_to_q4_1_16_bl(t, 16, data, data_size);
1717}
1718
1719template <> int repack<block_q2_K, 256, 32>(ggml_tensor * t, const void * data, size_t data_size) {
1720    return repack_q2_k_to_q2_k_32_bl(t, 32, data, data_size);
1721}
1722
1723template <> int repack<block_q3_K, 256, 32>(ggml_tensor * t, const void * data, size_t data_size) {
1724    return repack_q3_k_to_q3_k_32_bl(t, 32, data, data_size);
1725}
1726
1727template <> int repack<block_q4_0, 32, 32>(ggml_tensor * t, const void * data, size_t data_size) {
1728#if 0
1729    return repack_q4_0_to_q4_0_32_bl_ref(t, 32, data, data_size);
1730#else
1731    return repack_q4_0_to_q4_0_32_bl(t, 32, data, data_size);
1732#endif
1733}
1734
1735template <> int repack<block_q4_0, 256, 32>(ggml_tensor * t, const void * data, size_t data_size) {
1736#if 1
1737    return repack_q4_0_to_q4_0_256_32_bl_ref(t, 32, data, data_size);
1738#else
1739    //return repack_q4_0_to_q4_0_256_32_bl(t, 32, data, data_size);
1740#endif
1741}
1742
1743template <> int repack<block_q4_1, 32, 32>(ggml_tensor * t, const void * data, size_t data_size) {
1744#if 0
1745    return repack_q4_1_to_q4_1_32_bl_ref(t, 32, data, data_size);
1746#else
1747    return repack_q4_1_to_q4_1_32_bl(t, 32, data, data_size);
1748#endif
1749}
1750
1751template <> int repack<block_q4_1, 256, 32>(ggml_tensor * t, const void * data, size_t data_size) {
1752#if 1
1753    return repack_q4_0_to_q4_1_256_32_bl_ref(t, 32, data, data_size);
1754#else
1755    return repack_q4_1_to_q4_1_256_32_bl(t, 32, data, data_size);
1756#endif
1757}
1758
1759template <> int repack<block_q4_K, 32, 32>(ggml_tensor * t, const void * data, size_t data_size) {
1760    return repack_q4_k_to_q4_1_32_bl(t, 32, data, data_size);
1761}
1762
1763template <> int repack<block_q6_K, 32, 32>(ggml_tensor * t, const void * data, size_t data_size) {
1764#if 1
1765    return repack_q6_k_to_q8_0_32_bl_ref(t, 32, data, data_size);
1766#else
1767    return repack_q6_k_to_q8_0_32_bl(t, 32, data, data_size);
1768#endif
1769}
1770
1771template <> int repack<block_q8_0, 32, 32>(ggml_tensor * t, const void * data, size_t data_size) {
1772#if 1
1773    return repack_q8_0_to_q8_0_32_bl_ref(t, 32, data, data_size);
1774#else
1775    return repack_q8_0_to_q8_0_32_bl(t, 32, data, data_size);
1776#endif
1777}
1778
1779template <> int repack<block_mxfp4, 32, 32>(ggml_tensor * t, const void * data, size_t data_size) {
1780    return repack_mxfp4_to_mxfp4_32_bl(t, 32, data, data_size);
1781}
1782
1783template <> int repack<block_q5_0, 32, 32>(ggml_tensor * t, const void * data, size_t data_size) {
1784    return repack_q5_0_to_q5_0_32_bl(t, 32, data, data_size);
1785}
1786
1787template <> int repack<block_q5_1, 32, 32>(ggml_tensor * t, const void * data, size_t data_size) {
1788    return repack_q5_1_to_q5_1_32_bl(t, 32, data, data_size);
1789}
1790
1791template <> int repack<block_q5_K, 32, 32>(ggml_tensor * t, const void * data, size_t data_size) {
1792    return repack_q5_k_to_q5_1_32_bl(t, 32, data, data_size);
1793}
1794
1795}  // namespace ggml::cpu::riscv64_spacemit