char-fork/llama.cpp

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

Hongqiang Wangopencl: quant lm_head / decode GEMV and medium-batch GEMM optimizations (speculative decoding/MTP) (#26477)95ef7fc16

char/aliceai-t5-moe
89.5 KiB2663 linesraw
1//------------------------------------------------------------------------------
2// This file is contains kernels for data conversion.
3// These kernels are used when loading the model, so its performance is less
4// important.
5//------------------------------------------------------------------------------
6#pragma OPENCL EXTENSION cl_khr_fp16 : enable
7
8#ifdef cl_intel_required_subgroup_size
9#pragma OPENCL EXTENSION cl_intel_required_subgroup_size : enable
10#define INTEL_GPU 1
11#define REQD_SUBGROUP_SIZE_16 __attribute__((intel_reqd_sub_group_size(16)))
12#define REQD_SUBGROUP_SIZE_32 __attribute__((intel_reqd_sub_group_size(32)))
13#elif defined(cl_qcom_reqd_sub_group_size)
14#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size : enable
15#define ADRENO_GPU 1
16#define REQD_SUBGROUP_SIZE_64  __attribute__((qcom_reqd_sub_group_size("half")))
17#define REQD_SUBGROUP_SIZE_128 __attribute__((qcom_reqd_sub_group_size("full")))
18#endif
19
20#define QK4_0                   32
21#define QR4_0                   2
22#define QK4_1                   32
23#define QR4_1                   2
24#define QK5_0                   32
25#define QR5_0                   2
26#define QK5_1                   32
27#define QR5_1                   2
28#define QK8_0                   32
29#define QR8_0                   1
30#define QK1_0                   128
31#define QR1_0                   1
32#define QK_K                    256
33#define K_SCALE_SIZE            (3 * QK_K / 64)
34#define K_QUANTS_PER_ITERATION  2
35
36typedef char int8_t;
37typedef uchar uint8_t;
38typedef short int16_t;
39typedef ushort uint16_t;
40typedef int int32_t;
41typedef uint uint32_t;
42
43//------------------------------------------------------------------------------
44// block_q1_0
45//------------------------------------------------------------------------------
46typedef struct {
47    half d;             // delta
48    uchar qs[QK1_0/8];  // 1-bit signs (16 bytes)
49} block_q1_0;
50
51//------------------------------------------------------------------------------
52// block_q4_0
53//------------------------------------------------------------------------------
54struct block_q4_0
55{
56    half d;
57    uint8_t qs[QK4_0 / 2];
58};
59
60//------------------------------------------------------------------------------
61// block_q4_1
62//------------------------------------------------------------------------------
63struct block_q4_1 {
64    half d; // delta
65    half m; // min
66    uchar qs[QK4_1 / 2]; // nibbles / quants
67};
68
69//------------------------------------------------------------------------------
70// block_q5_0
71//------------------------------------------------------------------------------
72struct block_q5_0 {
73    half d; // delta
74    uchar qh[4]; // 5-th bit of quants
75    uchar qs[QK5_0 / 2]; // nibbles / quants
76};
77
78//------------------------------------------------------------------------------
79// block_q5_1
80//------------------------------------------------------------------------------
81struct block_q5_1 {
82    half d; // delta
83    half m; // min
84    uchar qh[4]; // 5-th bit of quants
85    uchar qs[QK5_1 / 2]; // nibbles / quants
86};
87
88//------------------------------------------------------------------------------
89// block_q4_k
90//------------------------------------------------------------------------------
91struct block_q4_K {
92    half d; // delta
93    half dm; // min
94    uchar s[K_SCALE_SIZE];
95    uchar q[QK_K / 2]; // nibbles / quants
96};
97
98//------------------------------------------------------------------------------
99// block_q5_k
100//------------------------------------------------------------------------------
101struct block_q5_K {
102    half d; // delta
103    half dm; // min
104    uchar s[K_SCALE_SIZE];
105    uchar qh[QK_K / 8];
106    uchar qs[QK_K / 2]; // nibbles / quants
107};
108
109//------------------------------------------------------------------------------
110// block_q6_K
111//------------------------------------------------------------------------------
112struct block_q6_K {
113    uint8_t ql[QK_K/2];      // quants, lower 4 bits
114    uint8_t qh[QK_K/4];      // quants, upper 2 bits
115    int8_t  scales[QK_K/16]; // scales, quantized with 8 bits
116    half d;                  // super-block scale
117};
118
119//------------------------------------------------------------------------------
120// block_iq4_nl
121//------------------------------------------------------------------------------
122#define QK4_NL 32
123
124struct block_iq4_nl
125{
126    half d;
127    uint8_t qs[QK4_NL / 2];
128};
129
130//------------------------------------------------------------------------------
131// bf16 to f16
132//------------------------------------------------------------------------------
133kernel void kernel_convert_bf16_to_f16(
134    global const ushort * src,
135    global half * dst,
136    ulong off_dst,
137    ulong n
138) {
139    uint i = get_global_id(0);
140    if (i >= n) {
141        return;
142    }
143
144    dst[i + off_dst] = (half) as_float((uint) src[i] << 16);
145}
146
147//------------------------------------------------------------------------------
148// f16 to bf16
149//------------------------------------------------------------------------------
150kernel void kernel_convert_f16_to_bf16(
151    global const half * src,
152    ulong off_src,
153    global ushort * dst,
154    ulong n
155) {
156    uint i = get_global_id(0);
157    if (i >= n) {
158        return;
159    }
160
161    float f = (float) src[i + off_src];
162    uint bits = as_uint(f);
163    if ((bits & 0x7fffffffu) > 0x7f800000u) {
164        // nan to quiet nan
165        dst[i] = (ushort)((bits >> 16) | 0x40u);
166    } else {
167        uint rounded = bits + 0x7fffu + ((bits >> 16) & 1u);
168        dst[i] = (ushort)(rounded >> 16);
169    }
170}
171
172//------------------------------------------------------------------------------
173// kernel_convert_block_q1_0
174// Convert block_q1_0 (AOS) to 2 separate arrays (SOA): quant bytes + scales.
175// q1_0 bits are stored in natural order (bit j of byte i -> weight 8*i + j)
176//------------------------------------------------------------------------------
177kernel void kernel_convert_block_q1_0(
178    global block_q1_0 * src0,
179    global uchar * dst_q,
180    global half  * dst_d
181) {
182    global block_q1_0 * b = (global block_q1_0 *) src0 + get_global_id(0);
183    global uchar      * q = (global uchar *) dst_q + (QK1_0/8)*get_global_id(0);
184    global half       * d = (global half *) dst_d + get_global_id(0);
185
186    *d = b->d;
187
188    for (int i = 0; i < QK1_0/8; ++i) {
189        q[i] = b->qs[i];
190    }
191}
192
193kernel void kernel_restore_block_q1_0(
194    global uchar * src_q,
195    global half  * src_d,
196    global block_q1_0 * dst
197) {
198    global block_q1_0 * b = (global block_q1_0 *) dst + get_global_id(0);
199    global uchar      * q = (global uchar *) src_q + (QK1_0/8)*get_global_id(0);
200    global half       * d = (global half *) src_d + get_global_id(0);
201
202    b->d = *d;
203    for (int i = 0; i < QK1_0/8; ++i) {
204        b->qs[i] = q[i];
205    }
206}
207
208//------------------------------------------------------------------------------
209// kernel_convert_block_q4_0
210// Convert the block_q4_0 format to 2 separate arrays (AOS -> SOA).
211// This kernel does not deshuffle the bits.
212//------------------------------------------------------------------------------
213kernel void kernel_convert_block_q4_0(
214    global struct block_q4_0 * src0,
215    global uchar * dst_q,
216    global half  * dst_d
217) {
218    global struct block_q4_0 * b = (global struct block_q4_0 *) src0 + get_global_id(0);
219    global uchar * q = (global uchar *) dst_q + QK4_0/2*get_global_id(0);
220    global half  * d = (global half *) dst_d + get_global_id(0);
221
222    *d = b->d;
223
224    for (int i = 0; i < QK4_0/2; ++i) {
225        q[i] = b->qs[i];
226    }
227}
228
229kernel void kernel_restore_block_q4_0(
230    global uchar * src_q,
231    global half  * src_d,
232    global struct block_q4_0 * dst
233) {
234    global struct block_q4_0 * b = (global struct block_q4_0 *) dst + get_global_id(0);
235    global uchar * q = (global uchar *) src_q + QK4_0/2*get_global_id(0);
236    global half  * d = (global half *) src_d + get_global_id(0);
237
238    b->d = *d;
239    for (int i = 0; i < QK4_0/2; ++i) {
240        b->qs[i] = q[i];
241    }
242}
243
244//------------------------------------------------------------------------------
245// kernel_convert_block_q4_0_noshuffle
246// Flatten q4_0 weights and unshuffle the bits
247//------------------------------------------------------------------------------
248
249kernel void kernel_convert_block_q4_0_noshuffle(
250    global struct block_q4_0 * src0,
251    global uchar * dst_q,
252    global half  * dst_d
253) {
254    global struct block_q4_0 * b = (global struct block_q4_0 *) src0 + get_global_id(0);
255    global uchar * q = (global uchar *) dst_q + QK4_0/2*get_global_id(0);
256    global half  * d = (global half *) dst_d + get_global_id(0);
257
258    *d = b->d;
259    for (int i = 0; i < QK4_0/4; ++i) {
260        uchar x0 = b->qs[2*i + 0];
261        uchar x1 = b->qs[2*i + 1];
262
263        q[i + 0      ] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
264        q[i + QK4_0/4] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
265
266#ifdef ADRENO_GPU
267        // Workaround for adreno - must have the following printf statement for
268        // the kernel to work properly. Otherwise it produces incorrect result.
269        // convert_uchar above also seems necessary.
270        // Compare against a large number so that it does not print anything.
271        // get_sub_group_local_id() also works.
272        if (get_global_id(0) == 65536*4096) {
273            printf("%04x - %02x\n", *(global ushort*)d, ((x0 & 0xF0) >> 4) | (x1 & 0xF0));
274        }
275#endif
276    }
277}
278
279kernel void kernel_restore_block_q4_0_noshuffle(
280    global uchar * src_q,
281    global half  * src_d,
282    global struct block_q4_0 * dst,
283    uchar mask_0F,
284    uchar mask_F0
285) {
286    global struct block_q4_0 * b = (global struct block_q4_0 *) dst + get_global_id(0);
287    global uchar * q = (global uchar *) src_q + QK4_0/2*get_global_id(0);
288    global half  * d = (global half *) src_d + get_global_id(0);
289
290    b->d = *d;
291    for (int i = 0; i < QK4_0/4; ++i) {
292        uchar x0 = q[i + 0      ] ;
293        uchar x1 = q[i + QK4_0/4];
294
295        b->qs[2*i + 0] = convert_uchar((x0 & mask_0F) | ((x1 & mask_0F) << 4));
296        b->qs[2*i + 1] = convert_uchar(((x0 & mask_F0) >> 4) | (x1 & mask_F0));
297    }
298}
299
300kernel void kernel_convert_block_q4_0_trans4_ns(
301    global struct block_q4_0 * src0,
302    __global uint * dst_q,
303    __global half * dst_d,
304    uint ne00,
305    uint ne01
306) {
307    uint i00 = get_global_id(1);
308    uint i01 = get_global_id(0);
309    uint i02 = get_global_id(2);
310
311    if (i01 >= ne01) {
312        return;
313    }
314
315    uint ne00_blk = ne00 / QK4_0;
316    uint src_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
317    uint dst_blk_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
318
319    global struct block_q4_0 * b = src0 + src_blk_offset;
320    dst_d[dst_blk_offset] = b->d;
321
322    // extract quantization and unshuffle
323    ushort8 pre_block = ((global ushort8 *)(&(b->qs[0])))[0];
324
325    ushort8 post_block = (ushort8)(0);
326
327    uchar * pre_block_ptr = (uchar *)(&pre_block);
328    uchar * post_block_ptr = (uchar *)(&post_block);
329
330    for (int i = 0; i < QK4_0 / 4; ++i) {
331        uchar x0 = pre_block_ptr[2*i + 0];
332        uchar x1 = pre_block_ptr[2*i + 1];
333
334        post_block_ptr[i + 0        ] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
335        post_block_ptr[i + QK4_0 / 4] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
336    }
337
338    uint4 q_block = as_uint4(post_block);
339
340    uint offset = i02 * ne00_blk * ne01 * 4 + i00 * ne01 * 4 + i01;
341    dst_q[offset] = q_block.x;
342    dst_q[offset + ne01] = q_block.y;
343    dst_q[offset + ne01 * 2] = q_block.z;
344    dst_q[offset + ne01 * 3] = q_block.w;
345}
346
347kernel void kernel_restore_block_q4_0_trans4_ns(
348    __global uint * src_q,
349    __global half * src_d,
350    __global struct block_q4_0 * dst0,
351    uint ne00,
352    uint ne01
353) {
354    uint i00 = get_global_id(1);
355    uint i01 = get_global_id(0);
356    uint i02 = get_global_id(2);
357
358    if (i01 >= ne01) {
359        return;
360    }
361
362    uint ne00_blk = ne00 / QK4_0;
363    uint dst_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
364    uint src_d_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
365
366    __global struct block_q4_0 * b = dst0 + dst_blk_offset;
367    b->d = src_d[src_d_offset];
368
369    // collect transposed quantization parts for a block
370    uint src_q_offset = i02 * ne00_blk * ne01 * 4 + i00 * ne01 * 4 + i01;
371    uint4 q_block;
372    q_block.x = src_q[src_q_offset];
373    q_block.y = src_q[src_q_offset + ne01];
374    q_block.z = src_q[src_q_offset + ne01 * 2];
375    q_block.w = src_q[src_q_offset + ne01 * 3];
376
377    ushort8 post_block = as_ushort8(q_block);
378    ushort8 pre_block = (ushort8)(0);
379
380    uchar * pre_block_ptr = (uchar *)(&pre_block);
381    uchar * post_block_ptr = (uchar *)(&post_block);
382
383    for (int i = 0; i < QK4_0 / 4; ++i) {
384        uchar x0 = post_block_ptr[i + 0];
385        uchar x1 = post_block_ptr[i + QK4_0 / 4];
386
387        pre_block_ptr[2 * i + 0] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
388        pre_block_ptr[2 * i + 1] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
389    }
390
391    ((__global ushort8 *)(&(b->qs[0])))[0] = pre_block;
392}
393
394//------------------------------------------------------------------------------
395// kernel_convert_block_q4_1
396// Convert the block_q4_1 format to 2 separate arrays (AOS -> SOA).
397// This kernel does not deshuffle the bits.
398//------------------------------------------------------------------------------
399kernel void kernel_convert_block_q4_1(
400    global struct block_q4_1 * src0,
401    global uchar * dst_q,
402    global half  * dst_d,
403    global half  * dst_m
404) {
405    global struct block_q4_1 * b = (global struct block_q4_1 *) src0 + get_global_id(0);
406    global uchar * q = (global uchar *) dst_q + QK4_1/2*get_global_id(0);
407    global half  * d = (global half *) dst_d + get_global_id(0);
408    global half  * m = (global half *) dst_m + get_global_id(0);
409
410    *d = b->d;
411    *m = b->m;
412
413    for (int i = 0; i < QK4_1/2; ++i) {
414        q[i] = b->qs[i];
415    }
416}
417
418kernel void kernel_restore_block_q4_1(
419    global uchar * src_q,
420    global half  * src_d,
421    global half  * src_m,
422    global struct block_q4_1 * dst
423) {
424    global struct block_q4_1 * b = (global struct block_q4_1 *) dst + get_global_id(0);
425    global uchar * q = (global uchar *) src_q + QK4_1/2*get_global_id(0);
426    global half  * d = (global half *) src_d + get_global_id(0);
427    global half  * m = (global half *) src_m + get_global_id(0);
428
429    b->d = *d;
430    b->m = *m;
431    for (int i = 0; i < QK4_1/2; ++i) {
432        b->qs[i] = q[i];
433    }
434}
435
436kernel void kernel_convert_block_q4_1_noshuffle(
437    global struct block_q4_1 * src0,
438    global uchar * dst_q,
439    global half  * dst_d,
440    global half  * dst_m
441) {
442    global struct block_q4_1 * b = (global struct block_q4_1 *) src0 + get_global_id(0);
443    global uchar * q = (global uchar *) dst_q + QK4_1/2*get_global_id(0);
444    global half  * d = (global half *) dst_d + get_global_id(0);
445    global half  * m = (global half *) dst_m + get_global_id(0);
446
447    *d = b->d;
448    *m = b->m;
449    for (int i = 0; i < QK4_1/4; ++i) {
450        uchar x0 = b->qs[2*i + 0];
451        uchar x1 = b->qs[2*i + 1];
452
453        q[i + 0      ] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
454        q[i + QK4_1/4] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
455
456#ifdef ADRENO_GPU
457        if (get_global_id(0) == 65536*4096) {
458            printf("%04x - %02x\n", *(global ushort*)d, ((x0 & 0xF0) >> 4) | (x1 & 0xF0));
459        }
460#endif
461    }
462}
463
464kernel void kernel_restore_block_q4_1_noshuffle(
465    global uchar * src_q,
466    global half  * src_d,
467    global half  * src_m,
468    global struct block_q4_1 * dst,
469    uchar mask_0F,
470    uchar mask_F0
471) {
472    global struct block_q4_1 * b = (global struct block_q4_1 *) dst + get_global_id(0);
473    global uchar * q = (global uchar *) src_q + QK4_1/2*get_global_id(0);
474    global half  * d = (global half *) src_d + get_global_id(0);
475    global half  * m = (global half *) src_m + get_global_id(0);
476
477    b->d = *d;
478    b->m = *m;
479    for (int i = 0; i < QK4_1/4; ++i) {
480        uchar x0 = q[i + 0      ] ;
481        uchar x1 = q[i + QK4_1/4];
482
483        b->qs[2*i + 0] = convert_uchar((x0 & mask_0F) | ((x1 & mask_0F) << 4));
484        b->qs[2*i + 1] = convert_uchar(((x0 & mask_F0) >> 4) | (x1 & mask_F0));
485    }
486}
487
488kernel void kernel_convert_block_q4_1_trans4_ns(
489    __global struct block_q4_1 * src0,
490    __global uint * dst_q,
491    __global half * dst_d,
492    __global half * dst_m,
493    uint ne00,
494    uint ne01
495) {
496    uint i00 = get_global_id(1);
497    uint i01 = get_global_id(0);
498    uint i02 = get_global_id(2);
499
500    if (i01 >= ne01) {
501        return;
502    }
503
504    uint ne00_blk = ne00 / QK4_1;
505    uint src_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
506    uint dst_blk_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
507
508    global struct block_q4_1 * b = src0 + src_blk_offset;
509    dst_d[dst_blk_offset] = b->d;
510    dst_m[dst_blk_offset] = b->m;
511
512    // extract quantization and unshuffle
513    ushort8 pre_block = ((global ushort8 *)(&(b->qs[0])))[0];
514
515    ushort8 post_block = (ushort8)(0);
516
517    uchar * pre_block_ptr = (uchar *)(&pre_block);
518    uchar * post_block_ptr = (uchar *)(&post_block);
519
520    for (int i = 0; i < QK4_1 / 4; ++i) {
521        uchar x0 = pre_block_ptr[2*i + 0];
522        uchar x1 = pre_block_ptr[2*i + 1];
523
524        post_block_ptr[i + 0        ] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
525        post_block_ptr[i + QK4_1 / 4] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
526    }
527
528    uint4 q_block = as_uint4(post_block);
529
530    uint offset = i02 * ne00_blk * ne01 * 4 + i00 * ne01 * 4 + i01;
531    dst_q[offset] = q_block.x;
532    dst_q[offset + ne01] = q_block.y;
533    dst_q[offset + ne01 * 2] = q_block.z;
534    dst_q[offset + ne01 * 3] = q_block.w;
535}
536
537kernel void kernel_restore_block_q4_1_trans4_ns(
538    __global uint * src_q,
539    __global half * src_d,
540    __global half * src_m,
541    __global struct block_q4_1 * dst0,
542    uint ne00,
543    uint ne01
544) {
545    int i00 = get_global_id(1);
546    uint i01 = get_global_id(0);
547    uint i02 = get_global_id(2);
548
549    if (i01 >= ne01) {
550        return;
551    }
552
553    uint ne00_blk = ne00 / QK4_1;
554    uint dst_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
555    uint src_dm_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
556
557    __global struct block_q4_1 * b = dst0 + dst_blk_offset;
558    b->d = src_d[src_dm_offset];
559    b->m = src_m[src_dm_offset];
560
561    // collect transposed quantization parts for a block
562    uint src_q_offset = i02 * ne00_blk * ne01 * 4 + i00 * ne01 * 4 + i01;
563    uint4 q_block;
564    q_block.x = src_q[src_q_offset];
565    q_block.y = src_q[src_q_offset + ne01];
566    q_block.z = src_q[src_q_offset + ne01 * 2];
567    q_block.w = src_q[src_q_offset + ne01 * 3];
568
569    ushort8 post_block = as_ushort8(q_block);
570    ushort8 pre_block = (ushort8)(0);
571
572    uchar * pre_block_ptr = (uchar *)(&pre_block);
573    uchar * post_block_ptr = (uchar *)(&post_block);
574
575    for (int i = 0; i < QK4_0 / 4; ++i) {
576        uchar x0 = post_block_ptr[i + 0];
577        uchar x1 = post_block_ptr[i + QK4_0 / 4];
578
579        pre_block_ptr[2 * i + 0] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
580        pre_block_ptr[2 * i + 1] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
581    }
582
583    ((__global ushort8 *)(&(b->qs[0])))[0] = pre_block;
584}
585
586//------------------------------------------------------------------------------
587// kernel_convert_block_q5_0
588// Convert the block_q5_0 format to 3 separate arrays (AOS -> SOA).
589// This kernel does not deshuffle the bits.
590//------------------------------------------------------------------------------
591kernel void kernel_convert_block_q5_0(
592    global struct block_q5_0 * src0,
593    global uchar * dst_qs,
594    global uint  * dst_qh,
595    global half  * dst_d,
596    ulong n_blk
597) {
598    if (get_global_id(0) >= n_blk) {
599        return;
600    }
601
602    global struct block_q5_0 * b = (global struct block_q5_0 *) src0 + get_global_id(0);
603    global uchar * qs = (global uchar *) dst_qs + (QK5_0/2)*get_global_id(0);
604    global uint  * qh = (global uint  *) dst_qh + get_global_id(0);
605    global half  * d  = (global half  *) dst_d  + get_global_id(0);
606
607    *d = b->d;
608    *qh = *((global uint *)(b->qh));
609
610    for (int i = 0; i < QK5_0/2; ++i) {
611        qs[i] = b->qs[i];
612    }
613}
614
615kernel void kernel_restore_block_q5_0(
616    global uchar * src_qs,
617    global uint  * src_qh,
618    global half  * src_d,
619    global struct block_q5_0 * dst
620) {
621    global struct block_q5_0 * b = (global struct block_q5_0 *) dst + get_global_id(0);
622    global uchar * qs = (global uchar *) src_qs + (QK5_0/2)*get_global_id(0);
623    global uint  * qh = (global uint  *) src_qh + get_global_id(0);
624    global half  * d  = (global half  *) src_d  + get_global_id(0);
625
626    b->d = *d;
627    *((global uint *)(b->qh)) = *qh;
628    for (int i = 0; i < QK5_0/2; ++i) {
629        b->qs[i] = qs[i];
630    }
631}
632
633kernel void kernel_convert_block_q5_0_noshuffle(
634    global struct block_q5_0 * src0,
635    global uchar * dst_q,
636    global uint  * dst_qh,
637    global half  * dst_d
638) {
639    global struct block_q5_0 * b = (global struct block_q5_0 *) src0 + get_global_id(0);
640    global uchar * q  = (global uchar *) dst_q + QK5_0/2*get_global_id(0);
641    global uint  * qh = (global uint  *) dst_qh + get_global_id(0);
642    global half  * d  = (global half  *) dst_d  + get_global_id(0);
643
644    *d = b->d;
645    *qh = *((global uint *)(b->qh));
646
647    for (int i = 0; i < QK5_0/4; ++i) {
648        uchar x0 = b->qs[2*i + 0];
649        uchar x1 = b->qs[2*i + 1];
650
651        q[i + 0      ] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
652        q[i + QK5_0/4] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
653
654#ifdef ADRENO_GPU
655        if (get_global_id(0) == 65536*4096) {
656            printf("%04x - %02x\n", *(global ushort*)d, ((x0 & 0xF0) >> 4) | (x1 & 0xF0));
657        }
658#endif
659    }
660}
661
662kernel void kernel_restore_block_q5_0_noshuffle(
663    global uchar * src_q,
664    global uint  * src_qh,
665    global half  * src_d,
666    global struct block_q5_0 * dst,
667    uchar mask_0F,
668    uchar mask_F0
669) {
670    global struct block_q5_0 * b = (global struct block_q5_0 *) dst + get_global_id(0);
671    global uchar * q  = (global uchar *) src_q + QK5_0/2*get_global_id(0);
672    global uint  * qh = (global uint  *) src_qh + get_global_id(0);
673    global half  * d  = (global half  *) src_d  + get_global_id(0);
674
675    b->d = *d;
676    *((global uint *)(b->qh)) = *qh;
677
678    for (int i = 0; i < QK5_0/4; ++i) {
679        uchar x0 = q[i + 0      ];
680        uchar x1 = q[i + QK5_0/4];
681
682        b->qs[2*i + 0] = convert_uchar((x0 & mask_0F) | ((x1 & mask_0F) << 4));
683        b->qs[2*i + 1] = convert_uchar(((x0 & mask_F0) >> 4) | (x1 & mask_F0));
684    }
685}
686
687kernel void kernel_convert_block_q5_0_trans4_ns(
688    __global struct block_q5_0 * src0,
689    __global uint * dst_qs,
690    __global uint * dst_qh,
691    __global half * dst_d,
692    uint ne00,
693    uint ne01
694) {
695    uint i00 = get_global_id(1);
696    uint i01 = get_global_id(0);
697    uint i02 = get_global_id(2);
698
699    if (i01 >= ne01) {
700        return;
701    }
702
703    uint ne00_blk = ne00 / QK5_0;
704    uint src_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
705    uint dst_blk_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
706
707    global struct block_q5_0 * b = src0 + src_blk_offset;
708    dst_d[dst_blk_offset] = b->d;
709
710    dst_qh[dst_blk_offset] = ((global uint *)(&(b->qh[0])))[0];
711
712    // extract quantization and unshuffle
713    ushort8 pre_block = ((global ushort8 *)(&(b->qs[0])))[0];
714    ushort8 post_block = (ushort8)(0);
715
716    uchar * pre_block_ptr = (uchar *)(&pre_block);
717    uchar * post_block_ptr = (uchar *)(&post_block);
718
719    for (int i = 0; i < QK5_0 / 4; ++i) {
720        uchar x0 = pre_block_ptr[2*i + 0];
721        uchar x1 = pre_block_ptr[2*i + 1];
722
723        post_block_ptr[i + 0        ] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
724        post_block_ptr[i + QK5_0 / 4] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
725    }
726
727    uint4 q_block = as_uint4(post_block);
728
729    uint offset = i02 * ne00_blk * ne01 * 4 + i00 * ne01 * 4 + i01;
730    dst_qs[offset] = q_block.x;
731    dst_qs[offset + ne01] = q_block.y;
732    dst_qs[offset + ne01 * 2] = q_block.z;
733    dst_qs[offset + ne01 * 3] = q_block.w;
734}
735
736kernel void kernel_restore_block_q5_0_trans4_ns(
737    __global uint * src_qs,
738    __global uint * src_qh,
739    __global half * src_d,
740    __global struct block_q5_0 * dst0,
741    uint ne00,
742    uint ne01
743) {
744    int i00 = get_global_id(1);
745    uint i01 = get_global_id(0);
746    uint i02 = get_global_id(2);
747
748    if (i01 >= ne01) {
749        return;
750    }
751
752    uint ne00_blk = ne00 / QK5_0;
753    uint dst_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
754    uint src_blk_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
755
756    __global struct block_q5_0 * b = dst0 + dst_blk_offset;
757    b->d = src_d[src_blk_offset];
758
759    ((__global uint *)(&(b->qh[0])))[0] = src_qh[src_blk_offset];
760
761    // collect transposed quantization parts for a block
762    uint src_q_offset = i02 * ne00_blk * ne01 * 4 + i00 * ne01 * 4 + i01;
763    uint4 q_block;
764    q_block.x = src_qs[src_q_offset];
765    q_block.y = src_qs[src_q_offset + ne01];
766    q_block.z = src_qs[src_q_offset + ne01 * 2];
767    q_block.w = src_qs[src_q_offset + ne01 * 3];
768
769    ushort8 post_block = as_ushort8(q_block);
770    ushort8 pre_block = (ushort8)(0);
771
772    uchar * pre_block_ptr = (uchar *)(&pre_block);
773    uchar * post_block_ptr = (uchar *)(&post_block);
774
775    for (int i = 0; i < QK5_0 / 4; ++i) {
776        uchar x0 = post_block_ptr[i + 0];
777        uchar x1 = post_block_ptr[i + QK5_0 / 4];
778
779        pre_block_ptr[2 * i + 0] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
780        pre_block_ptr[2 * i + 1] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
781    }
782
783    ((__global ushort8 *)(&(b->qs[0])))[0] = pre_block;
784}
785
786//------------------------------------------------------------------------------
787// kernel_convert_block_q5_1
788// Convert the block_q5_1 format to 4 separate arrays (AOS -> SOA).
789// This kernel does not deshuffle the bits.
790//------------------------------------------------------------------------------
791kernel void kernel_convert_block_q5_1(
792    global struct block_q5_1 * src0,
793    global uchar * dst_qs,
794    global uint  * dst_qh,
795    global half  * dst_d,
796    global half  * dst_m,
797    ulong n_blk
798) {
799    if (get_global_id(0) >= n_blk) {
800        return;
801    }
802
803    global struct block_q5_1 * b = (global struct block_q5_1 *) src0 + get_global_id(0);
804    global uchar * qs = (global uchar *) dst_qs + (QK5_1/2)*get_global_id(0);
805    global uint  * qh = (global uint  *) dst_qh + get_global_id(0);
806    global half  * d  = (global half  *) dst_d  + get_global_id(0);
807    global half  * m  = (global half  *) dst_m  + get_global_id(0);
808
809    *d = b->d;
810    *m = b->m;
811    *qh = *((global uint *)(b->qh));
812
813    for (int i = 0; i < QK5_1/2; ++i) {
814        qs[i] = b->qs[i];
815    }
816}
817
818kernel void kernel_restore_block_q5_1(
819    global uchar * src_qs,
820    global uint  * src_qh,
821    global half  * src_d,
822    global half  * src_m,
823    global struct block_q5_1 * dst
824) {
825    global struct block_q5_1 * b = (global struct block_q5_1 *) dst + get_global_id(0);
826    global uchar * qs = (global uchar *) src_qs + (QK5_1/2)*get_global_id(0);
827    global uint  * qh = (global uint  *) src_qh + get_global_id(0);
828    global half  * d  = (global half  *) src_d  + get_global_id(0);
829    global half  * m  = (global half  *) src_m  + get_global_id(0);
830
831    b->d = *d;
832    b->m = *m;
833    *((global uint *)(b->qh)) = *qh;
834    for (int i = 0; i < QK5_1/2; ++i) {
835        b->qs[i] = qs[i];
836    }
837}
838
839kernel void kernel_convert_block_q5_1_noshuffle(
840    global struct block_q5_1 * src0,
841    global uchar * dst_q,
842    global uint  * dst_qh,
843    global half  * dst_d,
844    global half  * dst_m
845) {
846    global struct block_q5_1 * b = (global struct block_q5_1 *) src0 + get_global_id(0);
847    global uchar * q  = (global uchar *) dst_q + QK5_1/2*get_global_id(0);
848    global uint  * qh = (global uint  *) dst_qh + get_global_id(0);
849    global half  * d  = (global half  *) dst_d  + get_global_id(0);
850    global half  * m  = (global half  *) dst_m  + get_global_id(0);
851
852    *d = b->d;
853    *m = b->m;
854    *qh = *((global uint *)(b->qh));
855
856    for (int i = 0; i < QK5_1/4; ++i) {
857        uchar x0 = b->qs[2*i + 0];
858        uchar x1 = b->qs[2*i + 1];
859
860        q[i + 0      ] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
861        q[i + QK5_1/4] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
862
863#ifdef ADRENO_GPU
864        if (get_global_id(0) == 65536*4096) {
865            printf("%04x - %02x\n", *(global ushort*)d, ((x0 & 0xF0) >> 4) | (x1 & 0xF0));
866        }
867#endif
868    }
869}
870
871kernel void kernel_restore_block_q5_1_noshuffle(
872    global uchar * src_q,
873    global uint  * src_qh,
874    global half  * src_d,
875    global half  * src_m,
876    global struct block_q5_1 * dst,
877    uchar mask_0F,
878    uchar mask_F0
879) {
880    global struct block_q5_1 * b = (global struct block_q5_1 *) dst + get_global_id(0);
881    global uchar * q  = (global uchar *) src_q + QK5_1/2*get_global_id(0);
882    global uint  * qh = (global uint  *) src_qh + get_global_id(0);
883    global half  * d  = (global half  *) src_d  + get_global_id(0);
884    global half  * m  = (global half  *) src_m  + get_global_id(0);
885
886    b->d = *d;
887    b->m = *m;
888    *((global uint *)(b->qh)) = *qh;
889
890    for (int i = 0; i < QK5_1/4; ++i) {
891        uchar x0 = q[i + 0      ];
892        uchar x1 = q[i + QK5_1/4];
893
894        b->qs[2*i + 0] = convert_uchar((x0 & mask_0F) | ((x1 & mask_0F) << 4));
895        b->qs[2*i + 1] = convert_uchar(((x0 & mask_F0) >> 4) | (x1 & mask_F0));
896    }
897}
898
899kernel void kernel_convert_block_q5_1_trans4_ns(
900    __global struct block_q5_1 * src0,
901    __global uint * dst_qs,
902    __global uint * dst_qh,
903    __global half * dst_d,
904    __global half * dst_m,
905    uint ne00,
906    uint ne01
907) {
908    uint i00 = get_global_id(1);
909    uint i01 = get_global_id(0);
910    uint i02 = get_global_id(2);
911
912    if (i01 >= ne01) {
913        return;
914    }
915
916    uint ne00_blk = ne00 / QK5_1;
917    uint src_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
918    uint dst_blk_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
919
920    global struct block_q5_1 * b = src0 + src_blk_offset;
921    dst_d[dst_blk_offset] = b->d;
922    dst_m[dst_blk_offset] = b->m;
923
924    dst_qh[dst_blk_offset] = ((global uint *)(&(b->qh[0])))[0];
925
926    // extract quantization and unshuffle
927    ushort8 pre_block = ((global ushort8 *)(&(b->qs[0])))[0];
928    ushort8 post_block = (ushort8)(0);
929
930    uchar * pre_block_ptr = (uchar *)(&pre_block);
931    uchar * post_block_ptr = (uchar *)(&post_block);
932
933    for (int i = 0; i < QK5_1 / 4; ++i) {
934        uchar x0 = pre_block_ptr[2*i + 0];
935        uchar x1 = pre_block_ptr[2*i + 1];
936
937        post_block_ptr[i + 0        ] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
938        post_block_ptr[i + QK5_1 / 4] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
939    }
940
941    uint4 q_block = as_uint4(post_block);
942
943    uint offset = i02 * ne00_blk * ne01 * 4 + i00 * ne01 * 4 + i01;
944    dst_qs[offset] = q_block.x;
945    dst_qs[offset + ne01] = q_block.y;
946    dst_qs[offset + ne01 * 2] = q_block.z;
947    dst_qs[offset + ne01 * 3] = q_block.w;
948}
949
950kernel void kernel_restore_block_q5_1_trans4_ns(
951    __global uint * src_qs,
952    __global uint * src_qh,
953    __global half * src_d,
954    __global half * src_m,
955    __global struct block_q5_1 * dst0,
956    uint ne00,
957    uint ne01
958) {
959    int i00 = get_global_id(1);
960    uint i01 = get_global_id(0);
961    uint i02 = get_global_id(2);
962
963    if (i01 >= ne01) {
964        return;
965    }
966
967    uint ne00_blk = ne00 / QK5_1;
968    uint dst_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
969    uint src_blk_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
970
971    __global struct block_q5_1 * b = dst0 + dst_blk_offset;
972    b->d = src_d[src_blk_offset];
973    b->m = src_m[src_blk_offset];
974
975    ((__global uint *)(&(b->qh[0])))[0] = src_qh[src_blk_offset];
976
977    // collect transposed quantization parts for a block
978    uint src_q_offset = i02 * ne00_blk * ne01 * 4 + i00 * ne01 * 4 + i01;
979    uint4 q_block;
980    q_block.x = src_qs[src_q_offset];
981    q_block.y = src_qs[src_q_offset + ne01];
982    q_block.z = src_qs[src_q_offset + ne01 * 2];
983    q_block.w = src_qs[src_q_offset + ne01 * 3];
984
985    ushort8 post_block = as_ushort8(q_block);
986    ushort8 pre_block = (ushort8)(0);
987
988    uchar * pre_block_ptr = (uchar *)(&pre_block);
989    uchar * post_block_ptr = (uchar *)(&post_block);
990
991    for (int i = 0; i < QK5_1 / 4; ++i) {
992        uchar x0 = post_block_ptr[i + 0];
993        uchar x1 = post_block_ptr[i + QK5_1 / 4];
994
995        pre_block_ptr[2 * i + 0] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
996        pre_block_ptr[2 * i + 1] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
997    }
998    ((__global ushort8 *)(&(b->qs[0])))[0] = pre_block;
999}
1000
1001kernel void kernel_convert_block_q4_k_trans4_ns(
1002    __global struct block_q4_K * src0,
1003    __global uint  * dst_q,
1004    __global half  * dst_d,
1005    __global half  * dst_dm,
1006    __global uchar * dst_s,
1007    uint ne00,
1008    uint ne01,
1009    uchar mask_0F,
1010    uchar mask_F0
1011) {
1012    uint i00 = get_global_id(1);
1013    uint i01 = get_global_id(0);
1014    uint i02 = get_global_id(2);
1015
1016    if (i01 >= ne01) {
1017        return;
1018    }
1019
1020    uint ne00_blk = ne00 / QK_K;
1021    uint src_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
1022    uint dst_blk_offset = i01 + i00 * ne01     + i02 * ne00_blk * ne01;
1023
1024    __global struct block_q4_K * b = src0 + src_blk_offset;
1025
1026    dst_d [dst_blk_offset] = b->d;
1027    dst_dm[dst_blk_offset] = b->dm;
1028
1029    uint4 qv[8];
1030    uchar * qv_bytes = (uchar *)qv;
1031    for (int i = 0; i < QK_K / 64; ++i) {
1032        for (int j = 0; j < 16; ++j) {
1033            uchar x0 = b->q[i*32 + 2*j];
1034            uchar x1 = b->q[i*32 + 2*j + 1];
1035
1036            qv_bytes[i*32 + j     ] = convert_uchar(x0 & mask_0F) | convert_uchar((x1 & mask_0F) << 4);
1037            qv_bytes[i*32 + j + 16] = convert_uchar((x0 & mask_F0) >> 4) | convert_uchar(x1 & mask_F0);
1038        }
1039    }
1040
1041    uint base = i02 * ne00_blk * ne01 * 32 + i00 * ne01 * 32 + i01;
1042    #pragma unroll
1043    for (int p = 0; p < 8; ++p) {
1044        uint4 v = qv[p];
1045        dst_q[base + (p * 4 + 0) * ne01] = v.x;
1046        dst_q[base + (p * 4 + 1) * ne01] = v.y;
1047        dst_q[base + (p * 4 + 2) * ne01] = v.z;
1048        dst_q[base + (p * 4 + 3) * ne01] = v.w;
1049    }
1050
1051    __global uchar * s_dst = dst_s + (i02 * ne01 + i01) * ne00_blk * K_SCALE_SIZE + i00 * K_SCALE_SIZE;
1052    #pragma unroll
1053    for (int i = 0; i < K_SCALE_SIZE; ++i) {
1054        s_dst[i] = b->s[i];
1055    }
1056}
1057
1058kernel void kernel_restore_block_q4_k_trans4_ns(
1059    __global uint  * src_q,
1060    __global half  * src_d,
1061    __global half  * src_dm,
1062    __global uchar * src_s,
1063    __global struct block_q4_K * dst0,
1064    uint ne00,
1065    uint ne01,
1066    uchar mask_0F,
1067    uchar mask_F0
1068) {
1069    uint i00 = get_global_id(1);  // block index along K
1070    uint i01 = get_global_id(0);  // row index
1071    uint i02 = get_global_id(2);  // batch index
1072
1073    if (i01 >= ne01) {
1074        return;
1075    }
1076
1077    uint ne00_blk = ne00 / QK_K;
1078
1079    uint src_blk_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
1080    uint dst_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
1081
1082    __global struct block_q4_K * b = dst0 + dst_blk_offset;
1083
1084    b->d  = src_d[src_blk_offset];
1085    b->dm = src_dm[src_blk_offset];
1086
1087    __global uchar * s_src = src_s + (i02 * ne01 + i01) * ne00_blk * K_SCALE_SIZE + i00 * K_SCALE_SIZE;
1088    for (int i = 0; i < K_SCALE_SIZE; ++i) {
1089        b->s[i] = s_src[i];
1090    }
1091
1092    uint base = i02 * ne00_blk * ne01 * 32 + i00 * ne01 * 32 + i01;
1093
1094    uint4 qv[8];
1095    for (int p = 0; p < 8; ++p) {
1096        qv[p].x = src_q[base + (p * 4 + 0) * ne01];
1097        qv[p].y = src_q[base + (p * 4 + 1) * ne01];
1098        qv[p].z = src_q[base + (p * 4 + 2) * ne01];
1099        qv[p].w = src_q[base + (p * 4 + 3) * ne01];
1100    }
1101
1102    uchar * qv_bytes = (uchar *)qv;
1103    for (int i = 0; i < QK_K / 64; ++i) {
1104        for (int j = 0; j < 16; ++j) {
1105            uchar lo = qv_bytes[i*32 + j];
1106            uchar hi = qv_bytes[i*32 + j + 16];
1107            b->q[i*32 + 2*j]     = convert_uchar((lo & mask_0F) | ((hi & mask_0F) << 4));
1108            b->q[i*32 + 2*j + 1] = convert_uchar(((lo & mask_F0) >> 4) | (hi & mask_F0));
1109        }
1110    }
1111}
1112
1113//------------------------------------------------------------------------------
1114// kernel_convert_block_q4_k_tiled_ns
1115//
1116// Tiled-wide layout for the long-vocab q4_K lm_head/embed GEMV (decode path).
1117// Mirror of kernel_convert_block_q6_k_tiled_ns: recovers each weight's 4-bit
1118// code in CANONICAL ggml element order (e in [0,256)) and re-packs into 32 uints
1119// (8 codes/uint), stored TILED by 64 output rows so the matching GEMV
1120// (gemv_noshuffle_q4_k_f32_tiled) coalesces every weight load. The 12-byte
1121// packed scale block `s` and d/dm are stored per (row, K-block) tiled; the GEMV
1122// re-derives the 8 (scale,min) pairs via get_scale_min_k4, exactly like the o4
1123// kernel. Both ends owned here -> correct by construction vs the reference q4_K
1124// dequant. Requires ne01 % 64 == 0 (gated host-side). Buffer sizes identical to
1125// the trans4_ns layout.
1126//
1127//   q  uint4 granule g of (row r, K-block sb): idx = ((rt*ne00_blk+sb)*8 + g)*64 + rit
1128//   s  (12 bytes) of (r, sb):                  idx = (rt*ne00_blk+sb)*64 + rit, *12
1129//   d/dm (half)  of (r, sb):                   idx = (rt*ne00_blk+sb)*64 + rit
1130//   where rt = r/64, rit = r%64.
1131//------------------------------------------------------------------------------
1132kernel void kernel_convert_block_q4_k_tiled_ns(
1133    __global struct block_q4_K * src0,
1134    __global uint  * dst_q,    // 32 uints / superblock (4-bit codes, 8 codes/uint)
1135    __global half  * dst_d,    // 1 half  / superblock
1136    __global half  * dst_dm,   // 1 half  / superblock
1137    __global uchar * dst_s,    // K_SCALE_SIZE (12) bytes / superblock
1138    uint ne00,
1139    uint ne01
1140) {
1141    uint i00 = get_global_id(1);   // K-block index (superblock along ne00)
1142    uint i01 = get_global_id(0);   // output row index (along ne01)
1143    uint i02 = get_global_id(2);   // batch
1144
1145    uint ne00_blk = ne00 / QK_K;
1146
1147    uint src_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
1148    __global struct block_q4_K * b = src0 + src_blk_offset;
1149
1150    uint rt  = i01 / 64;
1151    uint rit = i01 % 64;
1152    uint tile_blk = (i02 * (ne01 / 64) + rt) * ne00_blk + i00;
1153
1154    // --- recover canonical 4-bit codes in e-order, pack 8 codes/uint ---
1155    uint qw[32] = {0};
1156    for (uint e = 0; e < 256; ++e) {
1157        uint g    = e >> 6;           // group 0..3 (q advances 32 bytes/group)
1158        uint within = e & 63u;
1159        uint hlf  = within >> 5;      // 0 = low nibble, 1 = high nibble
1160        uint l    = within & 31u;     // 0..31
1161        uchar byte = b->q[g * 32u + l];
1162        uint code = (hlf == 0u) ? (uint)(byte & 0x0F) : (uint)(byte >> 4);
1163        qw[e >> 3] |= code << ((e & 7u) * 4u);
1164    }
1165
1166    for (uint gr = 0; gr < 8; ++gr) {
1167        uint base = (tile_blk * 8u + gr) * 64u + rit;   // uint4 index
1168        dst_q[base * 4u + 0u] = qw[gr * 4u + 0u];
1169        dst_q[base * 4u + 1u] = qw[gr * 4u + 1u];
1170        dst_q[base * 4u + 2u] = qw[gr * 4u + 2u];
1171        dst_q[base * 4u + 3u] = qw[gr * 4u + 3u];
1172    }
1173
1174    // packed scales (12 bytes), tiled per (row, block)
1175    __global uchar * s_dst = dst_s + (tile_blk * 64u + rit) * K_SCALE_SIZE;
1176    #pragma unroll
1177    for (int i = 0; i < K_SCALE_SIZE; ++i) {
1178        s_dst[i] = b->s[i];
1179    }
1180
1181    dst_d [tile_blk * 64u + rit] = b->d;
1182    dst_dm[tile_blk * 64u + rit] = b->dm;
1183}
1184
1185kernel void kernel_convert_block_q5_k_trans4_ns(
1186    __global struct block_q5_K * src0,
1187    __global uint  * dst_qs,
1188    __global uint  * dst_qh,
1189    __global half  * dst_d,
1190    __global half  * dst_dm,
1191    __global uchar * dst_s,
1192    uint ne00,
1193    uint ne01,
1194    uchar mask_0F,
1195    uchar mask_F0
1196) {
1197    uint i00 = get_global_id(1);
1198    uint i01 = get_global_id(0);
1199    uint i02 = get_global_id(2);
1200
1201    if (i01 >= ne01) {
1202        return;
1203    }
1204
1205    uint ne00_blk = ne00 / QK_K;
1206    uint src_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
1207    uint dst_blk_offset = i01 + i00 * ne01     + i02 * ne00_blk * ne01;
1208
1209    __global struct block_q5_K * b = src0 + src_blk_offset;
1210
1211    dst_d [dst_blk_offset] = b->d;
1212    dst_dm[dst_blk_offset] = b->dm;
1213
1214    for (int k = 0; k < 8; k++) {
1215        uchar b0 = 0, b1 = 0, b2 = 0, b3 = 0;
1216        for (int bit = 0; bit < 8; bit++) {
1217            b0 |= (uchar)(((b->qh[bit]      >> k) & 1) << bit);
1218            b1 |= (uchar)(((b->qh[8  + bit] >> k) & 1) << bit);
1219            b2 |= (uchar)(((b->qh[16 + bit] >> k) & 1) << bit);
1220            b3 |= (uchar)(((b->qh[24 + bit] >> k) & 1) << bit);
1221        }
1222        uint packed = (uint)b0 | ((uint)b1 << 8) | ((uint)b2 << 16) | ((uint)b3 << 24);
1223        dst_qh[i01 + (i00 * 8 + k) * ne01 + i02 * ne00_blk * 8 * ne01] = packed;
1224    }
1225
1226    uint4 qv[8];
1227    uchar * qv_bytes = (uchar *)qv;
1228    for (int i = 0; i < QK_K / 64; ++i) {
1229        for (int j = 0; j < 16; ++j) {
1230            uchar x0 = b->qs[i*32 + 2*j];
1231            uchar x1 = b->qs[i*32 + 2*j + 1];
1232
1233            qv_bytes[i*32 + j     ] = convert_uchar(x0 & mask_0F) | convert_uchar((x1 & mask_0F) << 4);
1234            qv_bytes[i*32 + j + 16] = convert_uchar((x0 & mask_F0) >> 4) | convert_uchar(x1 & mask_F0);
1235        }
1236    }
1237
1238    uint base = i02 * ne00_blk * ne01 * 32 + i00 * ne01 * 32 + i01;
1239    #pragma unroll
1240    for (int p = 0; p < 8; ++p) {
1241        uint4 v = qv[p];
1242        dst_qs[base + (p * 4 + 0) * ne01] = v.x;
1243        dst_qs[base + (p * 4 + 1) * ne01] = v.y;
1244        dst_qs[base + (p * 4 + 2) * ne01] = v.z;
1245        dst_qs[base + (p * 4 + 3) * ne01] = v.w;
1246    }
1247
1248    __global uchar * s_dst = dst_s + (i02 * ne01 + i01) * ne00_blk * K_SCALE_SIZE + i00 * K_SCALE_SIZE;
1249    #pragma unroll
1250    for (int i = 0; i < K_SCALE_SIZE; ++i) {
1251        s_dst[i] = b->s[i];
1252    }
1253}
1254
1255kernel void kernel_restore_block_q5_k_trans4_ns(
1256    __global uint  * src_qs,
1257    __global uint  * src_qh,
1258    __global half  * src_d,
1259    __global half  * src_dm,
1260    __global uchar * src_s,
1261    __global struct block_q5_K * dst0,
1262    uint ne00,
1263    uint ne01,
1264    uchar mask_0F,
1265    uchar mask_F0
1266) {
1267    uint i00 = get_global_id(1);  // block index along K
1268    uint i01 = get_global_id(0);  // row index
1269    uint i02 = get_global_id(2);  // batch index
1270
1271    if (i01 >= ne01) {
1272        return;
1273    }
1274
1275    uint ne00_blk = ne00 / QK_K;
1276
1277    uint src_blk_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
1278    uint dst_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
1279
1280    __global struct block_q5_K * b = dst0 + dst_blk_offset;
1281
1282    b->d  = src_d[src_blk_offset];
1283    b->dm = src_dm[src_blk_offset];
1284
1285    for (int j = 0; j < 32; j++) b->qh[j] = 0;
1286    for (int k = 0; k < 8; k++) {
1287        uint packed = src_qh[i01 + (i00 * 8 + k) * ne01 + i02 * ne00_blk * 8 * ne01];
1288        uchar b0 = (uchar)(packed & 0xFF);
1289        uchar b1 = (uchar)((packed >> 8) & 0xFF);
1290        uchar b2 = (uchar)((packed >> 16) & 0xFF);
1291        uchar b3 = (uchar)((packed >> 24) & 0xFF);
1292        for (int bit = 0; bit < 8; bit++) {
1293            b->qh[bit]      |= (uchar)(((b0 >> bit) & 1) << k);
1294            b->qh[8  + bit] |= (uchar)(((b1 >> bit) & 1) << k);
1295            b->qh[16 + bit] |= (uchar)(((b2 >> bit) & 1) << k);
1296            b->qh[24 + bit] |= (uchar)(((b3 >> bit) & 1) << k);
1297        }
1298    }
1299
1300    __global uchar * s_src = src_s + (i02 * ne01 + i01) * ne00_blk * K_SCALE_SIZE + i00 * K_SCALE_SIZE;
1301    for (int i = 0; i < K_SCALE_SIZE; ++i) {
1302        b->s[i] = s_src[i];
1303    }
1304
1305    uint base = i02 * ne00_blk * ne01 * 32 + i00 * ne01 * 32 + i01;
1306
1307    uint4 qv[8];
1308    for (int p = 0; p < 8; ++p) {
1309        qv[p].x = src_qs[base + (p * 4 + 0) * ne01];
1310        qv[p].y = src_qs[base + (p * 4 + 1) * ne01];
1311        qv[p].z = src_qs[base + (p * 4 + 2) * ne01];
1312        qv[p].w = src_qs[base + (p * 4 + 3) * ne01];
1313    }
1314
1315    uchar * qv_bytes = (uchar *)qv;
1316    for (int i = 0; i < QK_K / 64; ++i) {
1317        for (int j = 0; j < 16; ++j) {
1318            uchar lo = qv_bytes[i*32 + j];
1319            uchar hi = qv_bytes[i*32 + j + 16];
1320            b->qs[i*32 + 2*j]     = convert_uchar((lo & mask_0F) | ((hi & mask_0F) << 4));
1321            b->qs[i*32 + 2*j + 1] = convert_uchar(((lo & mask_F0) >> 4) | (hi & mask_F0));
1322        }
1323    }
1324}
1325
1326kernel void kernel_convert_block_q6_k_trans4_ns(
1327    __global struct block_q6_K * src0,
1328    __global uint  * dst_ql,
1329    __global uint  * dst_qh,
1330    __global half  * dst_d,
1331    __global char  * dst_s,
1332    uint ne00,
1333    uint ne01,
1334    uchar mask_0F,
1335    uchar mask_F0
1336) {
1337    uint i00 = get_global_id(1);
1338    uint i01 = get_global_id(0);
1339    uint i02 = get_global_id(2);
1340
1341    if (i01 >= ne01) {
1342        return;
1343    }
1344
1345    uint ne00_blk = ne00 / QK_K;
1346
1347    uint src_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
1348    uint dst_blk_offset = i01 + i00 * ne01     + i02 * ne00_blk * ne01;
1349
1350    __global struct block_q6_K * b = src0 + src_blk_offset;
1351
1352    dst_d[dst_blk_offset] = b->d;
1353
1354    uint4 qlv[8];
1355    uchar * qlv_bytes = (uchar *)qlv;
1356    for (int i = 0; i < 2; ++i) {
1357        for (int j = 0; j < 16; ++j) {
1358            uchar x0 = b->ql[i*64 + 2*j];
1359            uchar x1 = b->ql[i*64 + 2*j + 1];
1360            uchar x2 = b->ql[i*64 + 32 + 2*j];
1361            uchar x3 = b->ql[i*64 + 32 + 2*j + 1];
1362            qlv_bytes[i*64 + j     ] = convert_uchar(x0 & mask_0F) | convert_uchar((x1 & mask_0F) << 4);
1363            qlv_bytes[i*64 + j + 16] = convert_uchar(x2 & mask_0F) | convert_uchar((x3 & mask_0F) << 4);
1364            qlv_bytes[i*64 + j + 32] = convert_uchar((x0 & mask_F0) >> 4) | convert_uchar(x1 & mask_F0);
1365            qlv_bytes[i*64 + j + 48] = convert_uchar((x2 & mask_F0) >> 4) | convert_uchar(x3 & mask_F0);
1366        }
1367    }
1368
1369    uint ql_base = i02 * ne00_blk * ne01 * 32 + i00 * ne01 * 32 + i01;
1370
1371    #pragma unroll
1372    for (int p = 0; p < 8; ++p) {
1373        uint4 v = qlv[p];
1374        dst_ql[ql_base + (p * 4 + 0) * ne01] = v.x;
1375        dst_ql[ql_base + (p * 4 + 1) * ne01] = v.y;
1376        dst_ql[ql_base + (p * 4 + 2) * ne01] = v.z;
1377        dst_ql[ql_base + (p * 4 + 3) * ne01] = v.w;
1378    }
1379
1380    uint qhv[16] = {0};
1381
1382    for (int n = 0; n < 2; ++n) {
1383        for (int l = 0; l < 32; ++l) {
1384            uchar h = b->qh[n*32 + l];
1385            int u = l / 16;
1386            int bit_pos = (l % 16) * 2;
1387            qhv[(n*4 + 0)*2 + u] |= ((uint)((h >> 0) & 0x03)) << bit_pos;
1388            qhv[(n*4 + 1)*2 + u] |= ((uint)((h >> 2) & 0x03)) << bit_pos;
1389            qhv[(n*4 + 2)*2 + u] |= ((uint)((h >> 4) & 0x03)) << bit_pos;
1390            qhv[(n*4 + 3)*2 + u] |= ((uint)((h >> 6) & 0x03)) << bit_pos;
1391        }
1392    }
1393
1394    uint qh_base = i02 * ne00_blk * ne01 * 16 + i00 * ne01 * 16 + i01;
1395
1396    for (int p = 0; p < 16; ++p) {
1397        dst_qh[qh_base + p * ne01] = qhv[p];
1398    }
1399
1400    __global char * s_dst = dst_s + (i02 * ne01 + i01) * ne00_blk * 16 + i00 * 16;
1401    #pragma unroll
1402    for (int i = 0; i < 16; ++i) {
1403        s_dst[i] = b->scales[i];
1404    }
1405}
1406
1407kernel void kernel_restore_block_q6_k_trans4_ns(
1408    __global uint  * src_ql,
1409    __global uint  * src_qh,
1410    __global half  * src_d,
1411    __global char  * src_s,
1412    __global struct block_q6_K * dst0,
1413    uint ne00,
1414    uint ne01,
1415    uchar mask_0F,
1416    uchar mask_F0
1417) {
1418    uint i00 = get_global_id(1);  // block index along K
1419    uint i01 = get_global_id(0);  // row index
1420    uint i02 = get_global_id(2);  // batch index
1421
1422    if (i01 >= ne01) {
1423        return;
1424    }
1425
1426    uint ne00_blk = ne00 / QK_K;
1427
1428    uint src_blk_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
1429    uint dst_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
1430
1431    __global struct block_q6_K * b = dst0 + dst_blk_offset;
1432
1433    b->d = src_d[src_blk_offset];
1434
1435    uint ql_base = i02 * ne00_blk * ne01 * 32 + i00 * ne01 * 32 + i01;
1436    uint4 qlv[8];
1437    for (int p = 0; p < 8; ++p) {
1438        qlv[p].x = src_ql[ql_base + (p * 4 + 0) * ne01];
1439        qlv[p].y = src_ql[ql_base + (p * 4 + 1) * ne01];
1440        qlv[p].z = src_ql[ql_base + (p * 4 + 2) * ne01];
1441        qlv[p].w = src_ql[ql_base + (p * 4 + 3) * ne01];
1442    }
1443
1444    uchar * qlv_bytes = (uchar *)qlv;
1445    for (int i = 0; i < 2; ++i) {
1446        for (int j = 0; j < 16; ++j) {
1447            uchar lo_02 = qlv_bytes[i*64 + j];
1448            uchar lo_13 = qlv_bytes[i*64 + j + 16];
1449            uchar hi_02 = qlv_bytes[i*64 + j + 32];
1450            uchar hi_13 = qlv_bytes[i*64 + j + 48];
1451            b->ql[i*64 + 2*j]          = convert_uchar((lo_02 & mask_0F) | ((hi_02 & mask_0F) << 4));
1452            b->ql[i*64 + 2*j + 1]      = convert_uchar(((lo_02 & mask_F0) >> 4) | (hi_02 & mask_F0));
1453            b->ql[i*64 + 32 + 2*j]     = convert_uchar((lo_13 & mask_0F) | ((hi_13 & mask_0F) << 4));
1454            b->ql[i*64 + 32 + 2*j + 1] = convert_uchar(((lo_13 & mask_F0) >> 4) | (hi_13 & mask_F0));
1455        }
1456    }
1457
1458    uint qh_base = i02 * ne00_blk * ne01 * 16 + i00 * ne01 * 16 + i01;
1459    uint qhv[16];
1460    for (int p = 0; p < 16; ++p) {
1461        qhv[p] = src_qh[qh_base + p * ne01];
1462    }
1463
1464    for (int n = 0; n < 2; ++n) {
1465        for (int l = 0; l < 32; ++l) {
1466            int u = l / 16;
1467            int bit_pos = (l % 16) * 2;
1468            uchar v0 = (uchar)((qhv[(n*4 + 0)*2 + u] >> bit_pos) & 0x03);
1469            uchar v1 = (uchar)((qhv[(n*4 + 1)*2 + u] >> bit_pos) & 0x03);
1470            uchar v2 = (uchar)((qhv[(n*4 + 2)*2 + u] >> bit_pos) & 0x03);
1471            uchar v3 = (uchar)((qhv[(n*4 + 3)*2 + u] >> bit_pos) & 0x03);
1472            b->qh[n*32 + l] = v0 | (v1 << 2) | (v2 << 4) | (v3 << 6);
1473        }
1474    }
1475
1476    __global char * s_src = src_s + (i02 * ne01 + i01) * ne00_blk * 16 + i00 * 16;
1477    for (int i = 0; i < 16; ++i) {
1478        b->scales[i] = s_src[i];
1479    }
1480}
1481
1482//------------------------------------------------------------------------------
1483// block_mxfp4
1484//------------------------------------------------------------------------------
1485#define QK_MXFP4 32
1486struct block_mxfp4 {
1487    uchar e; // E8M0
1488    uchar qs[QK_MXFP4 / 2];
1489};
1490
1491//------------------------------------------------------------------------------
1492// kernel_convert_block_mxfp4
1493// Convert the block_mxfp4 format to 2 separate arrays (AOS -> SOA).
1494// This kernel does not deshuffle the bits.
1495//------------------------------------------------------------------------------
1496kernel void kernel_convert_block_mxfp4(
1497    global struct block_mxfp4 * src0,
1498    global uchar * dst_q,
1499    global uchar * dst_e
1500) {
1501    global struct block_mxfp4 * b = (global struct block_mxfp4 *) src0 + get_global_id(0);
1502    global uchar * q = (global uchar *) dst_q + QK_MXFP4 / 2 * get_global_id(0);
1503    global uchar * e = (global uchar *) dst_e + get_global_id(0);
1504
1505    *e = b->e;
1506
1507    for (int i = 0; i < QK_MXFP4 / 2; ++i) {
1508        q[i] = b->qs[i];
1509    }
1510}
1511
1512kernel void kernel_convert_block_mxfp4_trans(
1513    global struct block_mxfp4 * src0,
1514    __global uint4 * dst_q,
1515    __global uchar * dst_e,
1516    uint ne00,
1517    uint ne01
1518) {
1519    int i00 = get_global_id(1);
1520    uint i01 = get_global_id(0);
1521    uint i02 = get_global_id(2);
1522
1523    uint ne00_blk = ne00 / QK_MXFP4;
1524    uint src_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
1525    uint dst_blk_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
1526
1527    global struct block_mxfp4 * b = src0 + src_blk_offset;
1528
1529    dst_q[dst_blk_offset] = ((global uint4 *)(&(b->qs[0])))[0];
1530    dst_e[dst_blk_offset] = b->e;
1531}
1532
1533kernel void kernel_restore_block_mxfp4(
1534    global uchar * src_q,
1535    global half  * src_e,
1536    global struct block_mxfp4 * dst
1537) {
1538    global struct block_mxfp4 * b = (global struct block_mxfp4 *) dst + get_global_id(0);
1539    global uchar * q = (global uchar *) src_q + QK_MXFP4 / 2 * get_global_id(0);
1540    global uchar * e = (global uchar *) src_e + get_global_id(0);
1541
1542    b->e = *e;
1543    for (int i = 0; i < QK_MXFP4 / 2; ++i) {
1544        b->qs[i] = q[i];
1545    }
1546}
1547
1548kernel void kernel_restore_block_mxfp4_trans(
1549    __global uint4 * src_q,
1550    __global uchar * src_e,
1551    global struct block_mxfp4 * dst,
1552    uint ne00,
1553    uint ne01
1554) {
1555    int i00 = get_global_id(1);
1556    uint i01 = get_global_id(0);
1557    uint i02 = get_global_id(2);
1558
1559    uint ne00_blk = ne00 / QK_MXFP4;
1560    uint src_blk_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
1561    uint dst_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
1562
1563    global struct block_mxfp4 * b = dst + dst_blk_offset;
1564
1565    ((global uint4 *)(&(b->qs[0])))[0] = src_q[src_blk_offset];
1566    b->e = src_e[src_blk_offset];
1567}
1568
1569//------------------------------------------------------------------------------
1570// kernel_convert_block_q6_k_tiled_ns
1571//
1572// Tiled-wide layout for the long-vocab q6_K lm_head/embed GEMV (decode path).
1573// Unlike *_trans4_ns (which mirrors the bit-interleave the legacy 2-output GEMV
1574// consumes), this kernel is correct-by-construction against the CANONICAL ggml
1575// q6_K dequant: it recovers each weight's 6-bit code in element order e in
1576// [0,256), then re-packs low-4-bits into 32 uints (8 codes/uint) and high-2-bits
1577// into 16 uints (16 codes/uint). The matching GEMV (gemv_noshuffle_q6_k_f32_tiled)
1578// unpacks the same order, so both ends are owned here.
1579//
1580// Storage is TILED by 64 output rows so the GEMV's 64-thread tile coalesces:
1581//   ql uint4 granule g of (row r, K-block sb): idx = ((rt*ne00_blk + sb)*8 + g)*64 + rit
1582//   qh uint4 granule g:                         idx = ((rt*ne00_blk + sb)*4 + g)*64 + rit
1583//   scales (char16) of (r, sb):                 idx = (rt*ne00_blk + sb)*64 + rit
1584//   d (half) of (r, sb):                        idx = (rt*ne00_blk + sb)*64 + rit
1585// where rt = r/64, rit = r%64. Requires ne01 % 64 == 0 (gated host-side).
1586// Buffer sizes are byte-identical to the trans4_ns layout.
1587//------------------------------------------------------------------------------
1588kernel void kernel_convert_block_q6_k_tiled_ns(
1589    __global struct block_q6_K * src0,
1590    __global uint  * dst_ql,   // 32 uints / superblock (low 4 bits, 8 codes/uint)
1591    __global uint  * dst_qh,   // 16 uints / superblock (high 2 bits, 16 codes/uint)
1592    __global half  * dst_d,    // 1 half  / superblock
1593    __global char  * dst_s,    // 16 chars/ superblock
1594    uint ne00,
1595    uint ne01
1596) {
1597    uint i00 = get_global_id(1);   // K-block index (superblock along ne00)
1598    uint i01 = get_global_id(0);   // output row index (along ne01)
1599    uint i02 = get_global_id(2);   // batch
1600
1601    uint ne00_blk = ne00 / QK_K;
1602
1603    // Source block: row-major over (i02, i01, i00).
1604    uint src_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
1605    __global struct block_q6_K * b = src0 + src_blk_offset;
1606
1607    uint rt  = i01 / 64;
1608    uint rit = i01 % 64;
1609    uint tile_blk = (i02 * (ne01 / 64) + rt) * ne00_blk + i00;  // tile-major (row-tile, K-block)
1610
1611    // --- recover canonical 6-bit codes, pack into ql (4b) + qh (2b) in e-order ---
1612    // 32 ql-uints (8 low-nibbles each) + 16 qh-uints (16 2-bit slots each).
1613    uint qlw[32] = {0};
1614    uint qhw[16] = {0};
1615
1616    for (uint e = 0; e < 256; ++e) {
1617        uint n   = (e >= 128) ? 1u : 0u;       // which 128-half
1618        uint within = e - n * 128u;
1619        uint q   = within / 32u;               // quadrant 0..3
1620        uint l   = within % 32u;               // 0..31
1621
1622        uint off_ql = n * 64u;                 // raw ql byte base for this half
1623        uint off_qh = n * 32u;                 // raw qh byte base for this half
1624
1625        uchar low4;
1626        uchar qlb0 = b->ql[off_ql + l];
1627        uchar qlb1 = b->ql[off_ql + l + 32];
1628        if (q == 0)      low4 = qlb0 & 0x0F;
1629        else if (q == 1) low4 = qlb1 & 0x0F;
1630        else if (q == 2) low4 = (qlb0 >> 4) & 0x0F;
1631        else             low4 = (qlb1 >> 4) & 0x0F;
1632
1633        uchar hi2 = (b->qh[off_qh + l] >> (q * 2u)) & 0x03;
1634
1635        // pack low4 (e-order): uint e/8, nibble (e%8)
1636        qlw[e >> 3] |= ((uint)low4) << ((e & 7u) * 4u);
1637        // pack hi2 (e-order): uint e/16, 2-bit slot (e%16)
1638        qhw[e >> 4] |= ((uint)hi2)  << ((e & 15u) * 2u);
1639    }
1640
1641    // --- write tiled ---
1642    for (uint g = 0; g < 8; ++g) {
1643        uint base = (tile_blk * 8u + g) * 64u + rit;   // uint4 index
1644        dst_ql[base * 4u + 0u] = qlw[g * 4u + 0u];
1645        dst_ql[base * 4u + 1u] = qlw[g * 4u + 1u];
1646        dst_ql[base * 4u + 2u] = qlw[g * 4u + 2u];
1647        dst_ql[base * 4u + 3u] = qlw[g * 4u + 3u];
1648    }
1649    for (uint g = 0; g < 4; ++g) {
1650        uint base = (tile_blk * 4u + g) * 64u + rit;   // uint4 index
1651        dst_qh[base * 4u + 0u] = qhw[g * 4u + 0u];
1652        dst_qh[base * 4u + 1u] = qhw[g * 4u + 1u];
1653        dst_qh[base * 4u + 2u] = qhw[g * 4u + 2u];
1654        dst_qh[base * 4u + 3u] = qhw[g * 4u + 3u];
1655    }
1656
1657    // scales: 16 chars contiguous per (row, block), tiled
1658    __global char * s_dst = dst_s + (tile_blk * 64u + rit) * 16u;
1659    #pragma unroll
1660    for (int i = 0; i < 16; ++i) {
1661        s_dst[i] = b->scales[i];
1662    }
1663
1664    // super-block scale
1665    dst_d[tile_blk * 64u + rit] = b->d;
1666}
1667
1668kernel void kernel_convert_block_mxfp4_trans4_ns(
1669    global struct block_mxfp4 * src0,
1670    __global uint * dst_q,
1671    __global uchar * dst_e,
1672    uint ne00,
1673    uint ne01
1674) {
1675    uint i00 = get_global_id(1);
1676    uint i01 = get_global_id(0);
1677    uint i02 = get_global_id(2);
1678
1679    if (i01 >= ne01) {
1680        return;
1681    }
1682
1683    uint ne00_blk = ne00 / QK_MXFP4;
1684    uint src_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
1685    uint dst_blk_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
1686
1687    global struct block_mxfp4 * b = src0 + src_blk_offset;
1688    dst_e[dst_blk_offset] = b->e;
1689
1690    // extract quantization and unshuffle
1691    ushort8 pre_block = ((global ushort8 *)(&(b->qs[0])))[0];
1692
1693    ushort8 post_block = (ushort8)(0);
1694
1695    uchar * pre_block_ptr = (uchar *)(&pre_block);
1696    uchar * post_block_ptr = (uchar *)(&post_block);
1697
1698    for (int i = 0; i < QK_MXFP4 / 4; ++i) {
1699        uchar x0 = pre_block_ptr[2*i + 0];
1700        uchar x1 = pre_block_ptr[2*i + 1];
1701
1702        post_block_ptr[i + 0        ] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
1703        post_block_ptr[i + QK_MXFP4 / 4] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
1704    }
1705
1706    uint4 q_block = as_uint4(post_block);
1707
1708    uint offset = i02 * ne00_blk * ne01 * 4 + i00 * ne01 * 4 + i01;
1709    dst_q[offset] = q_block.x;
1710    dst_q[offset + ne01] = q_block.y;
1711    dst_q[offset + ne01 * 2] = q_block.z;
1712    dst_q[offset + ne01 * 3] = q_block.w;
1713}
1714
1715kernel void kernel_restore_block_mxfp4_trans4_ns(
1716    __global uint * src_q,
1717    __global uchar * src_e,
1718    __global struct block_mxfp4 * dst0,
1719    uint ne00,
1720    uint ne01
1721) {
1722    uint i00 = get_global_id(1);
1723    uint i01 = get_global_id(0);
1724    uint i02 = get_global_id(2);
1725
1726    if (i01 >= ne01) {
1727        return;
1728    }
1729
1730    uint ne00_blk = ne00 / QK_MXFP4;
1731    uint dst_blk_offset = i00 + i01 * ne00_blk + i02 * ne00_blk * ne01;
1732    uint src_d_offset = i01 + i00 * ne01 + i02 * ne00_blk * ne01;
1733
1734    __global struct block_mxfp4 * b = dst0 + dst_blk_offset;
1735    b->e = src_e[src_d_offset];
1736
1737    // collect transposed quantization parts for a block
1738    uint src_q_offset = i02 * ne00_blk * ne01 * 4 + i00 * ne01 * 4 + i01;
1739    uint4 q_block;
1740    q_block.x = src_q[src_q_offset];
1741    q_block.y = src_q[src_q_offset + ne01];
1742    q_block.z = src_q[src_q_offset + ne01 * 2];
1743    q_block.w = src_q[src_q_offset + ne01 * 3];
1744
1745    ushort8 post_block = as_ushort8(q_block);
1746    ushort8 pre_block = (ushort8)(0);
1747
1748    uchar * pre_block_ptr = (uchar *)(&pre_block);
1749    uchar * post_block_ptr = (uchar *)(&post_block);
1750
1751    for (int i = 0; i < QK_MXFP4 / 4; ++i) {
1752        uchar x0 = post_block_ptr[i + 0];
1753        uchar x1 = post_block_ptr[i + QK_MXFP4 / 4];
1754
1755        pre_block_ptr[2 * i + 0] = convert_uchar(x0 & 0x0F) | convert_uchar((x1 & 0x0F) << 4);
1756        pre_block_ptr[2 * i + 1] = convert_uchar((x0 & 0xF0) >> 4) | convert_uchar(x1 & 0xF0);
1757    }
1758
1759    ((__global ushort8 *)(&(b->qs[0])))[0] = pre_block;
1760}
1761
1762
1763//------------------------------------------------------------------------------
1764// block_q8_0
1765//------------------------------------------------------------------------------
1766typedef struct {
1767    half d;       // delta
1768    char qs[QK8_0]; // quants
1769} block_q8_0;
1770
1771kernel void kernel_convert_block_q8_0(
1772    global block_q8_0 * src0,
1773    global uchar * dst_q,
1774    global half  * dst_d
1775) {
1776    global block_q8_0 * b = (global block_q8_0 *) src0 + get_global_id(0);
1777    global uchar      * q = (global uchar *) dst_q + QK8_0*get_global_id(0);
1778    global half       * d = (global half *) dst_d + get_global_id(0);
1779
1780    *d = b->d;
1781
1782    for (int i = 0; i < QK8_0; ++i) {
1783        q[i] = b->qs[i];
1784    }
1785}
1786
1787kernel void kernel_restore_block_q8_0(
1788    global uchar * src_q,
1789    global half  * src_d,
1790    global block_q8_0 * dst
1791) {
1792    global block_q8_0 * b = (global block_q8_0 *) dst + get_global_id(0);
1793    global uchar      * q = (global uchar *) src_q + QK8_0*get_global_id(0);
1794    global half       * d = (global half *) src_d + get_global_id(0);
1795
1796    b->d = *d;
1797    for (int i = 0; i < QK8_0; ++i) {
1798        b->qs[i] = q[i];
1799    }
1800}
1801
1802// View-aware AoS q8_0 -> f32 dequant (f32/f32 FA path).
1803kernel void kernel_dequant_q8_0_f32_view_aos(
1804    global char * src,
1805    ulong         src_offset,
1806    ulong         src_nb1,
1807    ulong         src_nb2,
1808    ulong         src_nb3,
1809    int           nblk0,
1810    int           ne1,
1811    int           ne2,
1812    int           ne3,
1813    global float * dst
1814) {
1815    int blk_i0 = get_global_id(0);
1816    int i1     = get_global_id(1);
1817    int batch  = get_global_id(2);
1818
1819    if (blk_i0 >= nblk0) return;
1820    if (i1     >= ne1)   return;
1821
1822    int i2 = batch % ne2;
1823    int i3 = batch / ne2;
1824    if (i3 >= ne3) return;
1825
1826    global char * block = src + src_offset + (ulong)i3*src_nb3 + (ulong)i2*src_nb2 + (ulong)i1*src_nb1 + (ulong)blk_i0 * (2 + QK8_0);
1827    float d = vload_half(0, (global half *)block);
1828    global char * qs = block + 2;
1829
1830    ulong dst_row_base = ((ulong)i3 * ne2 * ne1 + (ulong)i2 * ne1 + (ulong)i1) * nblk0;
1831    global float * out = dst + (dst_row_base + blk_i0) * QK8_0;
1832
1833    for (int i = 0; i < QK8_0; ++i) {
1834        out[i] = d * (float)qs[i];
1835    }
1836}
1837
1838// View-aware AoS q8_0 -> f16 dequant. Rows tight, batch strides may be gapped.
1839kernel void kernel_dequant_q8_0_f16_view_aos(
1840    global char * src,
1841    ulong         src_offset,
1842    ulong         src_nb1,
1843    ulong         src_nb2,
1844    ulong         src_nb3,
1845    int           nblk0,
1846    int           ne1,
1847    int           ne2,
1848    int           ne3,
1849    global half * dst
1850) {
1851    int blk_i0 = get_global_id(0);
1852    int i1     = get_global_id(1);
1853    int batch  = get_global_id(2);
1854
1855    if (blk_i0 >= nblk0) return;
1856    if (i1     >= ne1)   return;
1857
1858    int i2 = batch % ne2;
1859    int i3 = batch / ne2;
1860    if (i3 >= ne3) return;
1861
1862    global char * block = src + src_offset + (ulong)i3*src_nb3 + (ulong)i2*src_nb2 + (ulong)i1*src_nb1 + (ulong)blk_i0 * (2 + QK8_0);
1863    float d = vload_half(0, (global half *)block);
1864    global char * qs = block + 2;
1865
1866    ulong dst_row_base = ((ulong)i3 * ne2 * ne1 + (ulong)i2 * ne1 + (ulong)i1) * nblk0;
1867    global half * out = dst + (dst_row_base + blk_i0) * QK8_0;
1868
1869    for (int i = 0; i < QK8_0; ++i) {
1870        out[i] = (half)(d * (float)qs[i]);
1871    }
1872}
1873
1874// View-aware AoS q4_0 -> f32 dequant (mirrors the q8_0 view variant).
1875kernel void kernel_dequant_q4_0_f32_view_aos(
1876    global char * src,
1877    ulong         src_offset,
1878    ulong         src_nb1,
1879    ulong         src_nb2,
1880    ulong         src_nb3,
1881    int           nblk0,
1882    int           ne1,
1883    int           ne2,
1884    int           ne3,
1885    global float * dst
1886) {
1887    int blk_i0 = get_global_id(0);
1888    int i1     = get_global_id(1);
1889    int batch  = get_global_id(2);
1890
1891    if (blk_i0 >= nblk0) return;
1892    if (i1     >= ne1)   return;
1893
1894    int i2 = batch % ne2;
1895    int i3 = batch / ne2;
1896    if (i3 >= ne3) return;
1897
1898    global char * block = src + src_offset + (ulong)i3*src_nb3 + (ulong)i2*src_nb2 + (ulong)i1*src_nb1 + (ulong)blk_i0 * (2 + QK4_0/2);
1899    float d = vload_half(0, (global half *)block);
1900    global uchar * qs = (global uchar *)(block + 2);
1901
1902    ulong dst_row_base = ((ulong)i3 * ne2 * ne1 + (ulong)i2 * ne1 + (ulong)i1) * nblk0;
1903    global float * out = dst + (dst_row_base + blk_i0) * QK4_0;
1904
1905    for (int i = 0; i < QK4_0/2; ++i) {
1906        uchar byte = qs[i];
1907        int q0 = (int)(byte & 0x0F) - 8;
1908        int q1 = (int)(byte >> 4)   - 8;
1909        out[i]            = d * (float)q0;
1910        out[i + QK4_0/2]  = d * (float)q1;
1911    }
1912}
1913
1914// View-aware AoS q4_0 -> f16 dequant (mirrors the q8_0 view variant).
1915kernel void kernel_dequant_q4_0_f16_view_aos(
1916    global char * src,
1917    ulong         src_offset,
1918    ulong         src_nb1,
1919    ulong         src_nb2,
1920    ulong         src_nb3,
1921    int           nblk0,
1922    int           ne1,
1923    int           ne2,
1924    int           ne3,
1925    global half * dst
1926) {
1927    int blk_i0 = get_global_id(0);
1928    int i1     = get_global_id(1);
1929    int batch  = get_global_id(2);
1930
1931    if (blk_i0 >= nblk0) return;
1932    if (i1     >= ne1)   return;
1933
1934    int i2 = batch % ne2;
1935    int i3 = batch / ne2;
1936    if (i3 >= ne3) return;
1937
1938    global char * block = src + src_offset + (ulong)i3*src_nb3 + (ulong)i2*src_nb2 + (ulong)i1*src_nb1 + (ulong)blk_i0 * (2 + QK4_0/2);
1939    float d = vload_half(0, (global half *)block);
1940    global uchar * qs = (global uchar *)(block + 2);
1941
1942    ulong dst_row_base = ((ulong)i3 * ne2 * ne1 + (ulong)i2 * ne1 + (ulong)i1) * nblk0;
1943    global half * out = dst + (dst_row_base + blk_i0) * QK4_0;
1944
1945    for (int i = 0; i < QK4_0/2; ++i) {
1946        uchar byte = qs[i];
1947        int q0 = (int)(byte & 0x0F) - 8;
1948        int q1 = (int)(byte >> 4)   - 8;
1949        out[i]          = (half)(d * (float)q0);
1950        out[i + QK4_0/2] = (half)(d * (float)q1);
1951    }
1952}
1953
1954kernel void kernel_restore_block_q8_0_trans(
1955    global uchar * src_q,
1956    global half  * src_d,
1957    global block_q8_0 * dst,
1958    uint ne00,
1959    uint ne01
1960){
1961    uint num_blk_per_row = ne00 / QK8_0;
1962
1963    global block_q8_0 * b = (global block_q8_0 *) dst + get_global_id(0) * num_blk_per_row;
1964    global uchar      * q = (global uchar *) src_q + get_global_id(0) * 4; // 4 8-bit packed
1965    global half       * d = (global half *) src_d + get_global_id(0);
1966
1967    for (uint blk = 0; blk < num_blk_per_row; blk++) {
1968        b->d = *d;
1969
1970        for (uint i = 0; i < QK8_0; i+=4) {
1971            b->qs[i]   = q[0];
1972            b->qs[i+1] = q[1];
1973            b->qs[i+2] = q[2];
1974            b->qs[i+3] = q[3];
1975
1976            q += 4 * ne01; // M stride
1977        }
1978
1979        d += ne01;
1980
1981        b++;
1982    }
1983}
1984
1985//------------------------------------------------------------------------------
1986// kernel_convert_block_q4_K
1987// Convert the block_q4_K format to 4 separate arrays (AOS -> SOA).
1988// This kernel does not deshuffle the bits.
1989// Each thread processes a super block.
1990// Mask args are just to keep the signature consistent with the no-shuffle
1991// version and they are not used in this kernel.
1992//------------------------------------------------------------------------------
1993kernel void kernel_convert_block_q4_K(
1994    global struct block_q4_K * src0,
1995    global uchar * dst_q,
1996    global uchar * dst_s,
1997    global half  * dst_d,
1998    global half  * dst_dm,
1999    uchar mask_0F,
2000    uchar mask_F0
2001) {
2002    global struct block_q4_K * b = (global struct block_q4_K *) src0 + get_global_id(0);
2003    global uchar * q  = (global uchar *) dst_q  + QK_K/2*get_global_id(0);
2004    global uchar * s  = (global uchar *) dst_s  + K_SCALE_SIZE*get_global_id(0);
2005    global half  * d  = (global half  *) dst_d  + get_global_id(0);
2006    global half  * dm = (global half  *) dst_dm + get_global_id(0);
2007
2008    *d  = b->d;
2009    *dm = b->dm;
2010
2011    for (int i = 0; i < QK_K/2; ++i) {
2012        q[i] = b->q[i];
2013    }
2014    for (int i = 0; i < K_SCALE_SIZE; ++i) {
2015        s[i] = b->s[i];
2016    }
2017}
2018
2019// Restore block_q4_K from flattened arrays.
2020// Each thread processes a super block.
2021// Mask args are just to keep the signature consistent with the no-shuffle ones.
2022kernel void kernel_restore_block_q4_K(
2023    global uchar * src_q,
2024    global uchar * src_s,
2025    global half  * src_d,
2026    global half  * src_dm,
2027    global struct block_q4_K * dst,
2028    uchar mask_0F,
2029    uchar mask_F0
2030) {
2031    global struct block_q4_K * b = (global struct block_q4_K *) dst + get_global_id(0);
2032    global uchar * q  = (global uchar *) src_q  + QK_K/2*get_global_id(0);
2033    global uchar * s  = (global uchar *) src_s + K_SCALE_SIZE*get_global_id(0);
2034    global half  * d  = (global half  *) src_d  + get_global_id(0);
2035    global half  * dm = (global half  *) src_dm  + get_global_id(0);
2036
2037    b->d  = *d;
2038    b->dm = *dm;
2039
2040    for (int i = 0; i < QK_K/2; ++i) {
2041        b->q[i] = q[i];
2042    }
2043    for (int i = 0; i < K_SCALE_SIZE; ++i) {
2044        b->s[i] = s[i];
2045    }
2046}
2047
2048kernel void kernel_convert_block_q4_K_noshuffle(
2049    global struct block_q4_K * src0,
2050    global uchar * dst_q,
2051    global uchar * dst_s,
2052    global half  * dst_d,
2053    global half  * dst_dm,
2054    uchar mask_0F,
2055    uchar mask_F0
2056) {
2057    global struct block_q4_K * b = (global struct block_q4_K *) src0 + get_global_id(0);
2058    global uchar * q  = (global uchar *) dst_q  + QK_K/2 * get_global_id(0);
2059    global uchar * s  = (global uchar *) dst_s  + K_SCALE_SIZE * get_global_id(0);
2060    global half  * d  = (global half  *) dst_d  + get_global_id(0);
2061    global half  * dm = (global half  *) dst_dm + get_global_id(0);
2062
2063    *d  = b->d;
2064    *dm = b->dm;
2065
2066    for (int i = 0; i < QK_K / 64; ++i) {
2067        for (int j = 0; j < 16; ++j) {
2068            uchar x0 = b->q[i*32 + 2*j];
2069            uchar x1 = b->q[i*32 + 2*j + 1];
2070            q[i*32 + j]      = convert_uchar(x0 & mask_0F) | convert_uchar((x1 & mask_0F) << 4);
2071            q[i*32 + j + 16] = convert_uchar((x0 & mask_F0) >> 4)   | convert_uchar(x1 & mask_F0);
2072        }
2073    }
2074
2075    for (int i = 0; i < K_SCALE_SIZE; ++i) {
2076        s[i] = b->s[i];
2077    }
2078}
2079
2080kernel void kernel_restore_block_q4_K_noshuffle(
2081    global uchar * src_q,
2082    global uchar * src_s,
2083    global half  * src_d,
2084    global half  * src_dm,
2085    global struct block_q4_K * dst,
2086    uchar mask_0F,
2087    uchar mask_F0
2088) {
2089    global struct block_q4_K * b = (global struct block_q4_K *) dst + get_global_id(0);
2090    global uchar * q  = (global uchar *) src_q  + QK_K/2 * get_global_id(0);
2091    global uchar * s  = (global uchar *) src_s  + K_SCALE_SIZE * get_global_id(0);
2092    global half  * d  = (global half  *) src_d  + get_global_id(0);
2093    global half  * dm = (global half  *) src_dm + get_global_id(0);
2094
2095    b->d  = *d;
2096    b->dm = *dm;
2097
2098    for (int i = 0; i < QK_K / 64; ++i) {
2099        for (int j = 0; j < 16; ++j) {
2100            uchar lo = q[i*32 + j];
2101            uchar hi = q[i*32 + j + 16];
2102            b->q[i*32 + 2*j]     = convert_uchar((lo & mask_0F) | ((hi & mask_0F) << 4));
2103            b->q[i*32 + 2*j + 1] = convert_uchar(((lo & mask_F0) >> 4) | (hi & mask_F0));
2104        }
2105    }
2106
2107    for (int i = 0; i < K_SCALE_SIZE; ++i) {
2108        b->s[i] = s[i];
2109    }
2110}
2111
2112//------------------------------------------------------------------------------
2113// kernel_convert_block_q5_K
2114// Convert the block_q5_K format to 5 separate arrays (AOS -> SOA).
2115// Each thread processes a super block.
2116//------------------------------------------------------------------------------
2117kernel void kernel_convert_block_q5_K(
2118    global struct block_q5_K * src0,
2119    global uchar * dst_q,
2120    global uchar * dst_qh,
2121    global uchar * dst_s,
2122    global half  * dst_d,
2123    global half  * dst_dm,
2124    uchar mask_0F,
2125    uchar mask_F0
2126) {
2127    global struct block_q5_K * b  = (global struct block_q5_K *) src0 + get_global_id(0);
2128    global uchar * q  = (global uchar *) dst_q  + QK_K/2*get_global_id(0);
2129    global uchar * qh = (global uchar *) dst_qh + QK_K/8*get_global_id(0);
2130    global uchar * s  = (global uchar *) dst_s  + K_SCALE_SIZE*get_global_id(0);
2131    global half  * d  = (global half  *) dst_d  + get_global_id(0);
2132    global half  * dm = (global half  *) dst_dm + get_global_id(0);
2133
2134    *d  = b->d;
2135    *dm = b->dm;
2136
2137    for (int i = 0; i < QK_K/2; ++i) {
2138        q[i] = b->qs[i];
2139    }
2140    for (int i = 0; i < QK_K/8; ++i) {
2141        qh[i] = b->qh[i];
2142    }
2143    for (int i = 0; i < K_SCALE_SIZE; ++i) {
2144        s[i] = b->s[i];
2145    }
2146}
2147
2148// Restore block_q5_K from flattened arrays.
2149// Each thread processes a super block.
2150kernel void kernel_restore_block_q5_K(
2151    global uchar * src_q,
2152    global uchar * src_qh,
2153    global uchar * src_s,
2154    global half  * src_d,
2155    global half  * src_dm,
2156    global struct block_q5_K * dst,
2157    uchar mask_0F,
2158    uchar mask_F0
2159) {
2160    global struct block_q5_K * b  = (global struct block_q5_K *) dst + get_global_id(0);
2161    global uchar * q  = (global uchar *) src_q  + QK_K/2*get_global_id(0);
2162    global uchar * qh = (global uchar *) src_qh + QK_K/8*get_global_id(0);
2163    global uchar * s  = (global uchar *) src_s  + K_SCALE_SIZE*get_global_id(0);
2164    global half  * d  = (global half  *) src_d  + get_global_id(0);
2165    global half  * dm = (global half  *) src_dm + get_global_id(0);
2166
2167    b->d    = *d;
2168    b->dm = *dm;
2169
2170    for (int i = 0; i < QK_K/2; ++i) {
2171        b->qs[i] = q[i];
2172    }
2173    for (int i = 0; i < QK_K/8; ++i) {
2174        b->qh[i] = qh[i];
2175    }
2176    for (int i = 0; i < K_SCALE_SIZE; ++i) {
2177        b->s[i] = s[i];
2178    }
2179}
2180
2181kernel void kernel_convert_block_q5_K_noshuffle(
2182    global struct block_q5_K * src0,
2183    global uchar * dst_q,
2184    global uchar * dst_qh,
2185    global uchar * dst_s,
2186    global half  * dst_d,
2187    global half  * dst_dm,
2188    uchar mask_0F,
2189    uchar mask_F0
2190) {
2191    global struct block_q5_K * b  = (global struct block_q5_K *) src0 + get_global_id(0);
2192    global uchar * q  = (global uchar *) dst_q  + QK_K/2       * get_global_id(0);
2193    global uchar * qh = (global uchar *) dst_qh + QK_K/8       * get_global_id(0);
2194    global uchar * s  = (global uchar *) dst_s  + K_SCALE_SIZE * get_global_id(0);
2195    global half  * d  = (global half  *) dst_d  + get_global_id(0);
2196    global half  * dm = (global half  *) dst_dm + get_global_id(0);
2197
2198    *d  = b->d;
2199    *dm = b->dm;
2200
2201    for (int i = 0; i < QK_K / 64; ++i) {
2202        for (int j = 0; j < 16; ++j) {
2203            uchar x0 = b->qs[i*32 + 2*j];
2204            uchar x1 = b->qs[i*32 + 2*j + 1];
2205            q[i*32 + j]      = convert_uchar(x0 & mask_0F) | convert_uchar((x1 & mask_0F) << 4);
2206            q[i*32 + j + 16] = convert_uchar((x0 & mask_F0) >> 4) | convert_uchar(x1 & mask_F0);
2207        }
2208    }
2209
2210    for (int l = 0; l < QK_K/8; ++l) {
2211        uchar x0 = 0;
2212        for (int i = 0; i < 8; ++i) {
2213            x0 |= ((b->qh[(l%4)*8+i] >> (l/4)) & 0x01) << i;
2214        }
2215        qh[l] = x0;
2216    }
2217
2218    for (int i = 0; i < K_SCALE_SIZE; ++i) {
2219        s[i] = b->s[i];
2220    }
2221}
2222
2223kernel void kernel_restore_block_q5_K_noshuffle(
2224    global uchar * src_q,
2225    global uchar * src_qh,
2226    global uchar * src_s,
2227    global half  * src_d,
2228    global half  * src_dm,
2229    global struct block_q5_K * dst,
2230    uchar mask_0F,
2231    uchar mask_F0
2232) {
2233    global struct block_q5_K * b  = (global struct block_q5_K *) dst + get_global_id(0);
2234    global uchar * q  = (global uchar *) src_q  + QK_K/2       * get_global_id(0);
2235    global uchar * qh = (global uchar *) src_qh + QK_K/8       * get_global_id(0);
2236    global uchar * s  = (global uchar *) src_s  + K_SCALE_SIZE * get_global_id(0);
2237    global half  * d  = (global half  *) src_d  + get_global_id(0);
2238    global half  * dm = (global half  *) src_dm + get_global_id(0);
2239
2240    b->d  = *d;
2241    b->dm = *dm;
2242
2243    for (int i = 0; i < QK_K / 64; ++i) {
2244        for (int j = 0; j < 16; ++j) {
2245            uchar lo = q[i*32 + j];
2246            uchar hi = q[i*32 + j + 16];
2247            b->qs[i*32 + 2*j]     = convert_uchar((lo & mask_0F) | ((hi & mask_0F) << 4));
2248            b->qs[i*32 + 2*j + 1] = convert_uchar(((lo & mask_F0) >> 4) | (hi & mask_F0));
2249        }
2250    }
2251
2252    for (int g = 0; g < 4; ++g) {
2253        for (int i = 0; i < 8; ++i) {
2254            uchar x0 = 0;
2255            for (int k = 0; k < 8; ++k) {
2256                x0 |= ((qh[4*k+g] >> i) & 0x01) << k;
2257            }
2258            b->qh[g*8+i] = x0;
2259        }
2260    }
2261
2262    for (int i = 0; i < K_SCALE_SIZE; ++i) {
2263        b->s[i] = s[i];
2264    }
2265}
2266
2267//------------------------------------------------------------------------------
2268// kernel_convert_block_q6_K
2269// Convert the block_q6_K format to 3 separate arrays (AOS -> SOA).
2270// This kernel does not deshuffle the bits.
2271// Each thread processes a super block.
2272//------------------------------------------------------------------------------
2273kernel void kernel_convert_block_q6_K(
2274    global struct block_q6_K * src0,
2275    global uchar * dst_ql,
2276    global uchar * dst_qh,
2277    global char  * dst_s,
2278    global half  * dst_d,
2279    uchar          mask_lsb_8,
2280    ulong          n_blk
2281) {
2282    if (get_global_id(0) >= n_blk) {
2283        return;
2284    }
2285    global struct block_q6_K * b = (global struct block_q6_K *) src0 + get_global_id(0);
2286    global uchar * ql = (global uchar *) dst_ql + QK_K/2*get_global_id(0);
2287    global uchar * qh = (global uchar *) dst_qh + QK_K/4*get_global_id(0);
2288    global char  * s  = (global char  *) dst_s  + QK_K/16*get_global_id(0);
2289    global half  * d  = (global half  *) dst_d  + get_global_id(0);
2290
2291    *d = b->d;
2292
2293    for (int i = 0; i < QK_K/2; ++i) {
2294        ql[i] = b->ql[i];
2295    }
2296    for (int i = 0; i < QK_K/4; ++i) {
2297        qh[i] = b->qh[i];
2298    }
2299    for (int i = 0; i < QK_K/16; ++i) {
2300        s[i] = b->scales[i];
2301    }
2302}
2303
2304// Restore block_q6_K from flattened arrays.
2305// Each thread processes a super block.
2306kernel void kernel_restore_block_q6_K(
2307    global uchar * dst_ql,
2308    global uchar * dst_qh,
2309    global char  * dst_s,
2310    global half  * dst_d,
2311    global struct block_q6_K * dst,
2312    uchar mask_lsb_8,
2313    ulong n_blk
2314) {
2315    if (get_global_id(0) >= n_blk) {
2316        return;
2317    }
2318    global struct block_q6_K * b = (global struct block_q6_K *) dst + get_global_id(0);
2319    global uchar * ql = (global uchar *) dst_ql + QK_K/2*get_global_id(0);
2320    global uchar * qh = (global uchar *) dst_qh + QK_K/4*get_global_id(0);
2321    global char  * s  = (global char  *) dst_s  + QK_K/16*get_global_id(0);
2322    global half  * d  = (global half  *) dst_d  + get_global_id(0);
2323
2324    b->d = *d;
2325
2326    for (int i = 0; i < QK_K/2; ++i) {
2327        b->ql[i] = ql[i];
2328    }
2329    for (int i = 0; i < QK_K/4; ++i) {
2330        b->qh[i] = qh[i];
2331    }
2332    for (int i = 0; i < QK_K/16; ++i) {
2333        b->scales[i] = s[i];
2334    }
2335}
2336
2337kernel void kernel_convert_block_q6_K_noshuffle(
2338    global struct block_q6_K * src0,
2339    global uchar * dst_ql,
2340    global uchar * dst_qh,
2341    global char  * dst_s,
2342    global half  * dst_d,
2343    uchar          mask_lsb_8,
2344    ulong          n_blk
2345) {
2346    if (get_global_id(0) >= n_blk) {
2347        return;
2348    }
2349    global struct block_q6_K * b = (global struct block_q6_K *) src0 + get_global_id(0);
2350    global uchar * ql = (global uchar *) dst_ql + QK_K/2*get_global_id(0);
2351    global uchar * qh = (global uchar *) dst_qh + QK_K/4*get_global_id(0);
2352    global char  * s  = (global char  *) dst_s  + QK_K/16*get_global_id(0);
2353    global half  * d  = (global half  *) dst_d  + get_global_id(0);
2354
2355    *d = b->d;
2356
2357    for (int i = 0; i < QK_K/2/4; ++i) {
2358        uchar x0 = b->ql[i*2 + 0] & mask_lsb_8;
2359        uchar x1 = b->ql[i*2 + 1] & mask_lsb_8;
2360        ql[i +  0] = (x0 & 0x0F)        | ((x1 & 0x0F) << 4);
2361        ql[i + 32] = ((x0 & 0xF0) >> 4) | (x1 & 0xF0);
2362
2363        uchar x2 = b->ql[i*2 + 0 + 64] & mask_lsb_8;
2364        uchar x3 = b->ql[i*2 + 1 + 64] & mask_lsb_8;
2365        ql[i + 64] = (x2 & 0x0F)        | ((x3 & 0x0F) << 4);
2366        ql[i + 96] = ((x2 & 0xF0) >> 4) | (x3 & 0xF0);
2367    }
2368
2369    for (int i = 0; i < QK_K/4/8; ++i) {
2370        uchar x0 = b->qh[i*4 + 0] & mask_lsb_8;
2371        uchar x1 = b->qh[i*4 + 1] & mask_lsb_8;
2372        uchar x2 = b->qh[i*4 + 2] & mask_lsb_8;
2373        uchar x3 = b->qh[i*4 + 3] & mask_lsb_8;
2374        qh[i +  0] = (x0 & 0x03)        | ((x1 & 0x03) << 2) | ((x2 & 0x03) << 4) | ((x3 & 0x03) << 6);
2375        qh[i +  8] = ((x0 & 0x0C) >> 2) | (x1 & 0x0C)        | ((x2 & 0x0C) << 2) | ((x3 & 0x0C) << 4);
2376        qh[i + 16] = ((x0 & 0x30) >> 4) | ((x1 & 0x30) >> 2) | (x2 & 0x30)        | ((x3 & 0x30) << 2);
2377        qh[i + 24] = ((x0 & 0xC0) >> 6) | ((x1 & 0xC0) >> 4) | ((x2 & 0xC0) >> 2) | (x3 & 0xC0);
2378
2379        uchar x4 = b->qh[i*4 + 0 + 32] & mask_lsb_8;
2380        uchar x5 = b->qh[i*4 + 1 + 32] & mask_lsb_8;
2381        uchar x6 = b->qh[i*4 + 2 + 32] & mask_lsb_8;
2382        uchar x7 = b->qh[i*4 + 3 + 32] & mask_lsb_8;
2383        qh[i + 32] = (x4 & 0x03)        | ((x5 & 0x03) << 2) | ((x6 & 0x03) << 4) | ((x7 & 0x03) << 6);
2384        qh[i + 40] = ((x4 & 0x0C) >> 2) | (x5 & 0x0C)        | ((x6 & 0x0C) << 2) | ((x7 & 0x0C) << 4);
2385        qh[i + 48] = ((x4 & 0x30) >> 4) | ((x5 & 0x30) >> 2) | (x6 & 0x30)        | ((x7 & 0x30) << 2);
2386        qh[i + 56] = ((x4 & 0xC0) >> 6) | ((x5 & 0xC0) >> 4) | ((x6 & 0xC0) >> 2) | (x7 & 0xC0);
2387    }
2388
2389    for (int i = 0; i < QK_K/16; ++i) {
2390        s[i] = b->scales[i];
2391    }
2392}
2393
2394kernel void kernel_restore_block_q6_K_noshuffle(
2395    global uchar * src_ql,
2396    global uchar * src_qh,
2397    global char  * src_s,
2398    global half  * src_d,
2399    global struct block_q6_K * dst,
2400    uchar          mask_lsb_8,
2401    ulong          n_blk
2402) {
2403    if (get_global_id(0) >= n_blk) {
2404        return;
2405    }
2406    global struct block_q6_K * b = (global struct block_q6_K *) dst + get_global_id(0);
2407    global uchar * ql = (global uchar *) src_ql + QK_K/2*get_global_id(0);
2408    global uchar * qh = (global uchar *) src_qh + QK_K/4*get_global_id(0);
2409    global char  * s  = (global char  *) src_s  + QK_K/16*get_global_id(0);
2410    global half  * d  = (global half  *) src_d  + get_global_id(0);
2411
2412    b->d = *d;
2413
2414    for (int i = 0; i < QK_K/2/4; ++i) {
2415        uchar x0   = ql[i +  0] & mask_lsb_8;
2416        uchar x1   = ql[i + 32] & mask_lsb_8;
2417        b->ql[i*2 + 0] = (x0 & 0x0F)        | ((x1 & 0x0F) << 4);
2418        b->ql[i*2 + 1] = ((x0 & 0xF0) >> 4) | (x1 & 0xF0);
2419
2420        uchar x2   = ql[i + 64] & mask_lsb_8;
2421        uchar x3   = ql[i + 96] & mask_lsb_8;
2422        b->ql[i*2 + 0 + 64] = (x2 & 0x0F)        | ((x3 & 0x0F) << 4);
2423        b->ql[i*2 + 1 + 64] = ((x2 & 0xF0) >> 4) | (x3 & 0xF0);
2424    }
2425
2426    for (int i = 0; i < QK_K/4/8; ++i) {
2427        uchar x0 = qh[i +  0] & mask_lsb_8;
2428        uchar x1 = qh[i +  8] & mask_lsb_8;
2429        uchar x2 = qh[i + 16] & mask_lsb_8;
2430        uchar x3 = qh[i + 24] & mask_lsb_8;
2431        b->qh[i*4 + 0] = (x0 & 0x03)        | ((x1 & 0x03) << 2) | ((x2 & 0x03) << 4) | ((x3 & 0x03) << 6);
2432        b->qh[i*4 + 1] = ((x0 & 0x0C) >> 2) | (x1 & 0x0C)        | ((x2 & 0x0C) << 2) | ((x3 & 0x0C) << 4);
2433        b->qh[i*4 + 2] = ((x0 & 0x30) >> 4) | ((x1 & 0x30) >> 2) | (x2 & 0x30)        | ((x3 & 0x30) << 2);
2434        b->qh[i*4 + 3] = ((x0 & 0xC0) >> 6) | ((x1 & 0xC0) >> 4) | ((x2 & 0xC0) >> 2) | (x3 & 0xC0);
2435
2436        uchar x4 = qh[i +  0 + 32] & mask_lsb_8;
2437        uchar x5 = qh[i +  8 + 32] & mask_lsb_8;
2438        uchar x6 = qh[i + 16 + 32] & mask_lsb_8;
2439        uchar x7 = qh[i + 24 + 32] & mask_lsb_8;
2440        b->qh[i*4 + 0 + 32] = (x4 & 0x03)        | ((x5 & 0x03) << 2) | ((x6 & 0x03) << 4) | ((x7 & 0x03) << 6);
2441        b->qh[i*4 + 1 + 32] = ((x4 & 0x0C) >> 2) | (x5 & 0x0C)        | ((x6 & 0x0C) << 2) | ((x7 & 0x0C) << 4);
2442        b->qh[i*4 + 2 + 32] = ((x4 & 0x30) >> 4) | ((x5 & 0x30) >> 2) | (x6 & 0x30)        | ((x7 & 0x30) << 2);
2443        b->qh[i*4 + 3 + 32] = ((x4 & 0xC0) >> 6) | ((x5 & 0xC0) >> 4) | ((x6 & 0xC0) >> 2) | (x7 & 0xC0);
2444    }
2445
2446    for (int i = 0; i < QK_K/16; ++i) {
2447        b->scales[i] = s[i];
2448    }
2449}
2450
2451//------------------------------------------------------------------------------
2452// kernel_convert_block_iq4_nl
2453// Convert the block_iq4_nl format to 2 separate arrays (AOS -> SOA).
2454//------------------------------------------------------------------------------
2455kernel void kernel_convert_block_iq4_nl(
2456    global struct block_iq4_nl * src0,
2457    global uchar * dst_q,
2458    global half  * dst_d,
2459    uchar          mask_0F,
2460    uchar          mask_F0,
2461    ulong          n_blk
2462) {
2463    if (get_global_id(0) >= n_blk) {
2464        return;
2465    }
2466    global struct block_iq4_nl * b = (global struct block_iq4_nl *) src0 + get_global_id(0);
2467    global uchar * q = (global uchar *) dst_q + QK4_NL/2*get_global_id(0);
2468    global half  * d = (global half *) dst_d + get_global_id(0);
2469
2470    *d = b->d;
2471
2472    for (int i = 0; i < QK4_NL/2; ++i) {
2473        q[i] = b->qs[i];
2474    }
2475}
2476
2477kernel void kernel_restore_block_iq4_nl(
2478    global uchar * src_q,
2479    global half  * src_d,
2480    global struct block_iq4_nl * dst,
2481    ulong          n_blk
2482) {
2483    if (get_global_id(0) >= n_blk) {
2484        return;
2485    }
2486    global struct block_iq4_nl * b = (global struct block_iq4_nl *) dst + get_global_id(0);
2487    global uchar * q = (global uchar *) src_q + QK4_NL/2*get_global_id(0);
2488    global half  * d = (global half *) src_d + get_global_id(0);
2489
2490    b->d = *d;
2491
2492    for (int i = 0; i < QK4_NL/2; ++i) {
2493        b->qs[i] = q[i];
2494    }
2495}
2496
2497kernel void kernel_convert_block_iq4_nl_noshuffle(
2498    global struct block_iq4_nl * src0,
2499    global uchar * dst_q,
2500    global half  * dst_d,
2501    uchar          mask_0F,
2502    uchar          mask_F0,
2503    ulong          n_blk
2504) {
2505    if (get_global_id(0) >= n_blk) {
2506        return;
2507    }
2508    global struct block_iq4_nl * b = (global struct block_iq4_nl *) src0 + get_global_id(0);
2509    global uchar * q = (global uchar *) dst_q + QK4_NL/2*get_global_id(0);
2510    global half  * d = (global half *) dst_d + get_global_id(0);
2511
2512    *d = b->d;
2513    for (int i = 0; i < QK4_NL/4; ++i) {
2514        uchar x0 = b->qs[2*i + 0];
2515        uchar x1 = b->qs[2*i + 1];
2516
2517        q[i + 0       ] = convert_uchar(x0 & mask_0F) | convert_uchar((x1 & mask_0F) << 4);
2518        q[i + QK4_NL/4] = convert_uchar((x0 & mask_F0) >> 4) | convert_uchar(x1 & mask_F0);
2519    }
2520}
2521
2522kernel void kernel_restore_block_iq4_nl_noshuffle(
2523    global uchar * src_q,
2524    global half  * src_d,
2525    global struct block_iq4_nl * dst,
2526    uchar mask_0F,
2527    uchar mask_F0,
2528    ulong n_blk
2529) {
2530    if (get_global_id(0) >= n_blk) {
2531        return;
2532    }
2533    global struct block_iq4_nl * b = (global struct block_iq4_nl *) dst + get_global_id(0);
2534    global uchar * q = (global uchar *) src_q + QK4_NL/2*get_global_id(0);
2535    global half  * d = (global half *) src_d + get_global_id(0);
2536
2537    b->d = *d;
2538    for (int i = 0; i < QK4_NL/4; ++i) {
2539        uchar x0 = q[i + 0       ];
2540        uchar x1 = q[i + QK4_NL/4];
2541
2542        b->qs[2*i + 0] = convert_uchar((x0 & mask_0F) | ((x1 & mask_0F) << 4));
2543        b->qs[2*i + 1] = convert_uchar(((x0 & mask_F0) >> 4) | (x1 & mask_F0));
2544    }
2545}
2546
2547// ---------------------------------------------------------------------------
2548// kernel_moe_expand_scale_q8_0
2549//
2550// Expand the q8_0 per-32-block scale d (one half/block, [expert][row][block]) into
2551// the UNIFORM scale[16] format the generic dp4a MoE GEMM (kernel_gemm_moe_q8_1_dp4a,
2552// MOE_QT=80) consumes: 16 f16 per 256-superblock (per-16-element segment), where the
2553// two segments of each 32-block share the block's d. q8_0 is symmetric -> no min
2554// buffer (the GEMM runs with has_min=0). The int8 weight codes are reused verbatim
2555// from the existing flat q8_0 weight buffer (extra0_q8_0->q), so only the scale is
2556// rebuilt here. One work-item per (row, superblock, expert).
2557// ---------------------------------------------------------------------------
2558kernel void kernel_moe_expand_scale_q8_0(
2559    global const half * src_d,      // [expert][row][block], one scale per 32-block
2560    global       half * dst_scale,  // [expert][row][block][2] (FLAT per-32-block)
2561    int ne00,
2562    int ne01
2563) {
2564    int row = get_global_id(0);
2565    int blk = get_global_id(1);   // 32-block index along K
2566    int e   = get_global_id(2);
2567    if (row >= ne01) { return; }
2568
2569    long nb = ne00 / 32;          // 32-blocks per row (K only needs % 32 == 0)
2570    half d  = src_d[((long)e*ne01 + row)*nb + blk];
2571    long b  = (((long)e*ne01 + row)*nb + blk) * 2;
2572    dst_scale[b + 0] = d;
2573    dst_scale[b + 1] = d;
2574}
2575
2576// ---------------------------------------------------------------------------
2577// kernel_moe_expand_scale_q5_0
2578//
2579// q5_0 = symmetric, value = d*(code-16), code = nibble | (hi<<4) in 0..31. The
2580// generic dp4a MoE GEMM keeps the unsigned code and centers via the min term:
2581//   scale*dp4a(code,a) - min*sum(a),  scale = d,  min = d*16.
2582// Reads the existing q5_0 d ([expert][block][row], one half/32-block, from the
2583// trans4 convert) and writes the FLAT per-32-block uniform scale[2]/min[1] in
2584// [expert][row][block] order (a transpose). One work-item per (row, block, expert).
2585// ---------------------------------------------------------------------------
2586kernel void kernel_moe_expand_scale_q5_0(
2587    global const half * src_d,      // [expert][block][row]
2588    global       half * dst_scale,  // [expert][row][block][2]
2589    global       half * dst_min,    // [expert][row][block]
2590    int ne00,
2591    int ne01
2592) {
2593    int row = get_global_id(0);
2594    int blk = get_global_id(1);
2595    int e   = get_global_id(2);
2596    if (row >= ne01) { return; }
2597
2598    long nb = ne00 / 32;
2599    half d  = src_d[(long)e*nb*ne01 + (long)blk*ne01 + row];   // [expert][block][row]
2600    long sb = (((long)e*ne01 + row)*nb + blk) * 2;
2601    long mb = ((long)e*ne01 + row)*nb + blk;
2602    dst_scale[sb + 0] = d;
2603    dst_scale[sb + 1] = d;
2604    dst_min[mb] = (half)((float)d * 16.0f);
2605}
2606
2607// ---------------------------------------------------------------------------
2608// kernel_moe_expand_scale_q5_K
2609//
2610// q5_K value = d*sv*code + (-dm*mn), with the 6-bit packed per-sub-block scale sv
2611// and min mn (8 sub-blocks of 32 per 256-superblock, decoded by get_scale_min_k4
2612// from the 12-byte s[]). The generic dp4a MoE GEMM (kernel_gemm_moe_q8_1_dp4a,
2613// MOE_QT=5) keeps the unsigned 5-bit code and applies scale/min via the uniform
2614// per-32-block buffers:
2615//   acc += sc0*a_d*raw1 + sc1*a_d*raw2 - mn_u*a_s,
2616//   sc0 = sc1 = d*sv (both per-16 segments of a 32-block share the sub-block scale),
2617//   mn_u = dm*mn (positive; the GEMM subtracts it -> the -dm*mn min term).
2618// q5_K's q_img (low nibbles) + qh (hi-bit plane) are already in the layout the GEMM
2619// reads (same trans4_ns convert that feeds gemm_moe_q5_k_f32_ns), so only the scale
2620// is rebuilt here.
2621//
2622// One work-item per (row, superblock, expert); each emits 8 sub-blocks.
2623// ---------------------------------------------------------------------------
2624kernel void kernel_moe_expand_scale_q5_K(
2625    global const uchar * src_s,     // [expert][row][superblock][12]
2626    global const half  * src_d,     // [expert][superblock][row]
2627    global const half  * src_dm,    // [expert][superblock][row]
2628    global       half  * dst_scale, // [expert][row][32block][2]
2629    global       half  * dst_min,   // [expert][row][32block]
2630    int ne00,
2631    int ne01
2632) {
2633    int row = get_global_id(0);
2634    int sb  = get_global_id(1);   // superblock index along K
2635    int e   = get_global_id(2);
2636    if (row >= ne01) { return; }
2637
2638    long nsb    = ne00 / 256;     // superblocks per row
2639    long nblk32 = ne00 / 32;      // 32-blocks per row
2640
2641    float d  = (float)src_d [((long)e*nsb + sb)*ne01 + row];
2642    float dm = (float)src_dm[((long)e*nsb + sb)*ne01 + row];
2643
2644    __global const uchar * sc = src_s + ((long)e*ne01 + row)*nsb*12 + (long)sb*12;
2645
2646    for (int j = 0; j < 8; ++j) {
2647        uchar sv, mn;
2648        // get_scale_min_k4 (6-bit packed scale/min for sub-block j of 8)
2649        if (j < 4) {
2650            sv = sc[j]   & 63;
2651            mn = sc[j+4] & 63;
2652        } else {
2653            sv = (sc[j+4] & 0x0F) | ((sc[j-4] & 0xC0) >> 2);
2654            mn = ((sc[j+4] >> 4) & 0x0F) | ((sc[j]   & 0xC0) >> 2);
2655        }
2656        long sub   = (long)sb*8 + j;
2657        long sbase = (((long)e*ne01 + row)*nblk32 + sub) * 2;
2658        half s_val = (half)(d  * (float)sv);
2659        dst_scale[sbase + 0] = s_val;
2660        dst_scale[sbase + 1] = s_val;
2661        dst_min[((long)e*ne01 + row)*nblk32 + sub] = (half)(dm * (float)mn);
2662    }
2663}