char-fork/llama.cpp

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

Sigbjørn Skjæretsycl : add Q2_K reordered MMVQ and ESIMD kernels (again) (#27490)867229003

char/aliceai-t5-moe
91.8 KiB2227 linesraw
1#include "convert.hpp"
2#include "dmmv.hpp"
3#include "dequantize.hpp"
4#include "presets.hpp"
5
6#if defined(__INTEL_LLVM_COMPILER)
7    #if __has_include(<sycl/ext/oneapi/bfloat16.hpp>)
8        #include <sycl/ext/oneapi/bfloat16.hpp>
9        #define GGML_SYCL_DMMV_HAS_BF16
10    #endif
11    #include <sycl/ext/intel/esimd.hpp>
12    #include "esimd.hpp"
13    #define GGML_SYCL_DMMV_HAS_ESIMD
14#endif
15
16static void convert_f16(const void * vx, const int64_t ib, const int iqs, dfloat2 & v){
17    const sycl::half *x = (const sycl::half *)vx;
18
19    // automatic half -> float type cast if dfloat == float
20    v.x() = x[ib + iqs + 0];
21    v.y() = x[ib + iqs + 1];
22}
23
24#ifdef GGML_SYCL_DMMV_HAS_BF16
25static void convert_bf16(const void * vx, const int64_t ib, const int iqs, dfloat2 & v){
26    const sycl::ext::oneapi::bfloat16 *x = (const sycl::ext::oneapi::bfloat16 *)vx;
27
28    // automatic bfloat16 -> float type cast if dfloat == float
29    v.x() = x[ib + iqs + 0];
30    v.y() = x[ib + iqs + 1];
31}
32#endif
33
34static void convert_f32(const void * vx, const int64_t ib, const int iqs, dfloat2 & v){
35    const float * x = (const float *) vx;
36
37    // automatic half -> float type cast if dfloat == float
38    v.x() = x[ib + iqs + 0];
39    v.y() = x[ib + iqs + 1];
40}
41
42template <int qk, int qr, dequantize_kernel_t dequantize_kernel>
43static void dequantize_mul_mat_vec(const void * __restrict__ vx, const dfloat * __restrict__ y, float * __restrict__ dst, const int ncols, const int nrows,
44                                   const sycl::nd_item<3> &item_ct1) {
45    // qk = quantized weights per x block
46    // qr = number of quantized weights per data value in x block
47    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
48                    item_ct1.get_local_id(1);
49
50    if (row >= nrows) {
51        return;
52    }
53
54    const int tid = item_ct1.get_local_id(2);
55
56    const int iter_stride = 2*GGML_SYCL_DMMV_X;
57    const int vals_per_iter = iter_stride / WARP_SIZE; // num quantized vals per thread and i iter
58    const int y_offset = qr == 1 ? 1 : qk/2;
59
60// partial sum for each thread
61#ifdef GGML_SYCL_F16
62    sycl::half2 tmp = {0.0f, 0.0f}; // two sums for f16 to take advantage of half2 intrinsics
63#else
64    float tmp = 0.0f;
65#endif // GGML_SYCL_F16
66
67    for (int i = 0; i < ncols; i += iter_stride) {
68        const int col = i + vals_per_iter*tid;
69        const int ib = (row*ncols + col)/qk; // x block index
70        const int iqs = (col%qk)/qr; // x quant index
71        const int iybs = col - col%qk; // y block start index
72
73// processing >2 values per i iter is faster for fast GPUs
74#pragma unroll
75        for (int j = 0; j < vals_per_iter; j += 2) {
76            // process 2 vals per j iter
77
78            // dequantize
79            // for qr = 2 the iqs needs to increase by 1 per j iter because 2 weights per data val
80            dfloat2 v;
81            dequantize_kernel(vx, ib, iqs + j/qr, v);
82
83            // matrix multiplication
84            // for qr = 2 the y index needs to increase by 1 per j iter because of y_offset = qk/2
85#ifdef GGML_SYCL_F16
86            dfloat2 t1{y[iybs + iqs + j / qr + 0],
87                        y[iybs + iqs + j / qr + y_offset]};
88
89            tmp += v * t1;
90#else
91            tmp += v.x() * y[iybs + iqs + j / qr + 0];
92            tmp += v.y() * y[iybs + iqs + j / qr + y_offset];
93#endif // GGML_SYCL_F16
94        }
95    }
96
97    // sum up partial sums and write back result
98    const int mask_start = ncols > GGML_SYCL_DMMV_X ? WARP_SIZE >> 1 : WARP_SIZE >> 2;
99    for (int mask = mask_start; mask > 0; mask >>= 1) {
100        tmp +=
101            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
102    }
103
104    if (tid == 0) {
105#ifdef GGML_SYCL_F16
106        dst[row] = tmp.x() + tmp.y();
107#else
108        dst[row] = tmp;
109#endif // GGML_SYCL_F16
110    }
111}
112
113template <int qk, int qr, dequantize_kernel_t_reorder dequantize_kernel_reorder>
114static void dequantize_mul_mat_vec_reorder(const void * __restrict__ vx, const dfloat * __restrict__ y, float * __restrict__ dst, const int ncols, const int nrows,
115                                   const sycl::nd_item<3> &item_ct1) {
116    // qk = quantized weights per x block
117    // qr = number of quantized weights per data value in x block
118    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
119                    item_ct1.get_local_id(1);
120
121    if (row >= nrows) {
122        return;
123    }
124
125    const int tid = item_ct1.get_local_id(2);
126
127
128    const int ncols_left = ncols % (QK4_0*WARP_SIZE);
129    const int ncols_align = ncols - ncols_left;
130    const int iter_stride = 8*2*GGML_SYCL_DMMV_X;
131    const int vals_per_iter = iter_stride / WARP_SIZE; // num quantized vals per thread and i iter //64/16=4, 512/16/2= 16
132    const int y_offset = qr == 1 ? 1 : qk/2;
133
134// partial sum for each thread
135#ifdef GGML_SYCL_F16
136    sycl::half2 tmp = {0.0f, 0.0f}; // two sums for f16 to take advantage of half2 intrinsics
137#else
138    float tmp = 0.0f;
139#endif // GGML_SYCL_F16
140    const char *d_ptr = (const char*)vx+ncols*nrows/2;
141    int i=0;
142    for (i = 0; i < ncols_align; i += iter_stride) {
143        const int col = i + vals_per_iter*tid;
144        const int ib = (row*ncols + col)/qk; // x block index
145        const int iqs = (col%qk)/qr; // x quant index
146        const int iybs = col - col%qk; // y block start index
147
148// processing >2 values per i iter is faster for fast GPUs
149#pragma unroll
150        for (int j = 0; j < vals_per_iter; j += 2) {
151            // process 2 vals per j iter
152
153            // dequantize
154            // for qr = 2 the iqs needs to increase by 1 per j iter because 2 weights per data val
155            dfloat2 v;
156            dequantize_kernel_reorder((const void *)d_ptr, ib, (const void *)vx, ib * QK4_0 / 2 +iqs+j/qr, v);
157
158            // matrix multiplication
159            // for qr = 2 the y index needs to increase by 1 per j iter because of y_offset = qk/2
160#ifdef GGML_SYCL_F16
161            dfloat2 t1{y[iybs + iqs + j / qr + 0],
162                        y[iybs + iqs + j / qr + y_offset]};
163
164            tmp += v * t1;
165#else
166            tmp += v.x() * y[iybs + iqs + j / qr + 0];
167            tmp += v.y() * y[iybs + iqs + j / qr + y_offset];
168#endif // GGML_SYCL_F16
169        }
170    }
171
172    for (; i < ncols; i += iter_stride) {
173        if (tid>=ncols_left/QK4_0) continue;
174        const int col = i + vals_per_iter*tid;
175        const int ib = (row*ncols + col)/qk; // x block index
176        const int iqs = (col%qk)/qr; // x quant index
177        const int iybs = col - col%qk; // y block start index
178
179// processing >2 values per i iter is faster for fast GPUs
180#pragma unroll
181        for (int j = 0; j < vals_per_iter; j += 2) {
182            // process 2 vals per j iter
183
184            // dequantize
185            // for qr = 2 the iqs needs to increase by 1 per j iter because 2 weights per data val
186            dfloat2 v;
187            dequantize_kernel_reorder((const void *)d_ptr, ib, (const void *)vx, ib * QK4_0 / 2 +iqs+j/qr, v);
188
189            // matrix multiplication
190            // for qr = 2 the y index needs to increase by 1 per j iter because of y_offset = qk/2
191#ifdef GGML_SYCL_F16
192            dfloat2 t1{y[iybs + iqs + j / qr + 0],
193                        y[iybs + iqs + j / qr + y_offset]};
194
195            tmp += v * t1;
196#else
197            tmp += v.x() * y[iybs + iqs + j / qr + 0];
198            tmp += v.y() * y[iybs + iqs + j / qr + y_offset];
199#endif // GGML_SYCL_F16
200        }
201    }
202
203    // sum up partial sums and write back result
204    const int mask_start = ncols > GGML_SYCL_DMMV_X ? WARP_SIZE >> 1 : WARP_SIZE >> 2;
205    for (int mask = mask_start; mask > 0; mask >>= 1) {
206        tmp +=
207            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
208    }
209
210    if (tid == 0) {
211#ifdef GGML_SYCL_F16
212        dst[row] = tmp.x() + tmp.y();
213#else
214        dst[row] = tmp;
215#endif // GGML_SYCL_F16
216    }
217}
218
219static void convert_mul_mat_vec_f16_sycl(const void *vx, const dfloat *y,
220                                         float *dst, const int ncols,
221                                         const int nrows,
222                                         dpct::queue_ptr stream) {
223    GGML_ASSERT(ncols % GGML_SYCL_DMMV_X == 0);
224    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
225    const sycl::range<3> block_nums(1, 1, block_num_y);
226    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
227    {
228        dpct::has_capability_or_fail(stream->get_device(),
229                                     {sycl::aspect::fp16});
230
231        stream->parallel_for(
232            sycl::nd_range<3>(block_nums * block_dims, block_dims),
233            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
234                dequantize_mul_mat_vec<1, 1, convert_f16>(vx, y, dst, ncols,
235                                                          nrows, item_ct1);
236            });
237    }
238}
239
240#ifdef GGML_SYCL_DMMV_HAS_BF16
241static void convert_mul_mat_vec_bf16_sycl(const void *vx, const dfloat *y,
242                                          float *dst, const int ncols,
243                                          const int nrows,
244                                          dpct::queue_ptr stream) {
245    // The qk=1 kernel iterates with stride 2*GGML_SYCL_DMMV_X, so ncols must be a
246    // multiple of that — not just GGML_SYCL_DMMV_X — to avoid out-of-bounds reads.
247    GGML_ASSERT(ncols % (2*GGML_SYCL_DMMV_X) == 0);
248    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
249    const sycl::range<3> block_nums(1, 1, block_num_y);
250    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
251    {
252        stream->parallel_for(
253            sycl::nd_range<3>(block_nums * block_dims, block_dims),
254            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
255                dequantize_mul_mat_vec<1, 1, convert_bf16>(vx, y, dst, ncols,
256                                                           nrows, item_ct1);
257            });
258    }
259}
260#endif
261
262static void dequantize_mul_mat_vec_q2_k(const void *__restrict__ vx,
263                                        const float *__restrict__ yy,
264                                        float *__restrict__ dst,
265                                        const int ncols, int nrows,
266                                        const sycl::nd_item<3> &item_ct1) {
267
268    static_assert(16%K_QUANTS_PER_ITERATION == 0, "16 must be divisible by K_QUANTS_PER_ITERATION");
269
270    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
271                    item_ct1.get_local_id(1);
272    if (row >= nrows) return;
273
274    const int num_blocks_per_row = ncols / QK_K;
275    const int ib0 = row*num_blocks_per_row;
276
277    const block_q2_K * x = (const block_q2_K *)vx + ib0;
278
279    float tmp = 0; // partial sum for thread in warp
280
281#if QK_K == 256
282    const int tid =
283        item_ct1.get_local_id(2) / K_QUANTS_PER_ITERATION; // 0...7 or 0...15
284    const int ix =
285        item_ct1.get_local_id(2) % K_QUANTS_PER_ITERATION; // 0 or 0,1
286
287    const int step = 16/K_QUANTS_PER_ITERATION;
288
289    const int in = tid % step;                           // 0...15 or 0...7
290
291    const int l0 = K_QUANTS_PER_ITERATION*in;            // 0...15 or 0...14 in steps of 2
292
293    uint32_t aux[4];
294    const uint8_t * d = (const uint8_t *)aux;
295    const uint8_t * m = (const uint8_t *)(aux + 2);
296
297    for (int i = ix; i < num_blocks_per_row; i += K_QUANTS_PER_ITERATION) {
298
299        const float dall = x[i].dm[0];
300        const float dmin = x[i].dm[1];
301
302        for (int im = 0; im < 2; ++im) {
303            const int q_offset = 32*im + l0;
304            const int s_offset = 8*im;
305            const int y_offset = 128*im + l0;
306
307            const float   * y = yy + i * QK_K + y_offset;
308            const uint8_t * q = x[i].qs + q_offset;
309
310            const uint32_t * a = (const uint32_t *)(x[i].scales + s_offset);
311            aux[0] = a[0] & 0x0f0f0f0f;
312            aux[1] = a[1] & 0x0f0f0f0f;
313            aux[2] = (a[0] >> 4) & 0x0f0f0f0f;
314            aux[3] = (a[1] >> 4) & 0x0f0f0f0f;
315
316            float sum1 = 0, sum2 = 0;
317            for (int l = 0; l < K_QUANTS_PER_ITERATION; ++l) {
318                sum1 += y[l+ 0] * d[0] * ((q[l+ 0] >> 0) & 3)
319                      + y[l+32] * d[2] * ((q[l+ 0] >> 2) & 3)
320                      + y[l+64] * d[4] * ((q[l+ 0] >> 4) & 3)
321                      + y[l+96] * d[6] * ((q[l+ 0] >> 6) & 3)
322                      + y[l+16] * d[1] * ((q[l+16] >> 0) & 3)
323                      + y[l+48] * d[3] * ((q[l+16] >> 2) & 3)
324                      + y[l+80] * d[5] * ((q[l+16] >> 4) & 3)
325                      +y[l+112] * d[7] * ((q[l+16] >> 6) & 3);
326                sum2 += y[l+ 0] * m[0] + y[l+32] * m[2] + y[l+64] * m[4] + y[ l+96] * m[6]
327                      + y[l+16] * m[1] + y[l+48] * m[3] + y[l+80] * m[5] + y[l+112] * m[7];
328
329            }
330            tmp += dall * sum1 - dmin * sum2;
331        }
332
333    }
334#else
335    const int tid = item_ct1.get_local_id(2) /
336                    (2 * K_QUANTS_PER_ITERATION); // 0...15 or 0...7
337    const int ix = item_ct1.get_local_id(2) %
338                   (2 * K_QUANTS_PER_ITERATION); // 0....1 or 0...3
339    const int offset = tid * K_QUANTS_PER_ITERATION;
340
341    uint32_t uaux[2];
342    const uint8_t * d = (const uint8_t *)uaux;
343
344
345    for (int i = ix; i < num_blocks_per_row; i += 2*K_QUANTS_PER_ITERATION) {
346
347        const float   * y = yy + i * QK_K + offset;
348        const uint8_t * q = x[i].qs + offset;
349        const uint32_t * s = (const uint32_t *)x[i].scales;
350
351        uaux[0] = s[0] & 0x0f0f0f0f;
352        uaux[1] = (s[0] >> 4) & 0x0f0f0f0f;
353
354        const sycl::float2 dall =
355            x[i].dm.convert<float, sycl::rounding_mode::automatic>();
356
357        float sum1 = 0, sum2 = 0;
358        for (int l = 0; l < K_QUANTS_PER_ITERATION; ++l) {
359            const uint8_t ql = q[l];
360            sum1 += y[l+ 0] * d[0] * ((ql >> 0) & 3)
361                  + y[l+16] * d[1] * ((ql >> 2) & 3)
362                  + y[l+32] * d[2] * ((ql >> 4) & 3)
363                  + y[l+48] * d[3] * ((ql >> 6) & 3);
364            sum2 += y[l+0] * d[4] + y[l+16] * d[5] + y[l+32] * d[6] + y[l+48] * d[7];
365        }
366        tmp += dall.x() * sum1 - dall.y() * sum2;
367    }
368
369#endif
370
371    // sum up partial sums and write back result
372#pragma unroll
373    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
374        tmp +=
375            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
376    }
377
378    if (item_ct1.get_local_id(2) == 0) {
379        dst[row] = tmp;
380    }
381}
382
383static void dequantize_mul_mat_vec_q2_k_reorder(const void *__restrict__ vx,
384                                                const float *__restrict__ yy,
385                                                float *__restrict__ dst,
386                                                const int ncols, int nrows,
387                                                const sycl::nd_item<3> &item_ct1) {
388
389    static_assert(16%K_QUANTS_PER_ITERATION == 0, "16 must be divisible by K_QUANTS_PER_ITERATION");
390
391    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
392                    item_ct1.get_local_id(1);
393    if (row >= nrows) return;
394
395    const int num_blocks_per_row = ncols / QK_K;
396    const int ib0 = row*num_blocks_per_row;
397
398    // SOA base pointers for the reordered layout:
399    //   [qs: nb * (QK_K/4)] [scales: nb * (QK_K/16)] [dm: nb * sizeof(half2)]
400    const int nb = nrows * num_blocks_per_row;
401    const uint8_t     * qs_base     = (const uint8_t *)vx;
402    const uint8_t     * scales_base = qs_base + (size_t)nb * (QK_K / 4);
403    const sycl::half2 * dm_base     = (const sycl::half2 *)(scales_base + (size_t)nb * (QK_K / 16));
404
405    float tmp = 0; // partial sum for thread in warp
406
407#if QK_K == 256
408    const int tid =
409        item_ct1.get_local_id(2) / K_QUANTS_PER_ITERATION; // 0...7 or 0...15
410    const int ix =
411        item_ct1.get_local_id(2) % K_QUANTS_PER_ITERATION; // 0 or 0,1
412
413    const int step = 16/K_QUANTS_PER_ITERATION;
414
415    const int in = tid % step;                           // 0...15 or 0...7
416
417    const int l0 = K_QUANTS_PER_ITERATION*in;            // 0...15 or 0...14 in steps of 2
418
419    uint32_t aux[4];
420    const uint8_t * d = (const uint8_t *)aux;
421    const uint8_t * m = (const uint8_t *)(aux + 2);
422
423    for (int i = ix; i < num_blocks_per_row; i += K_QUANTS_PER_ITERATION) {
424        const int bi = ib0 + i;
425
426        const sycl::half2 dm_val = dm_base[bi];
427        const float dall = dm_val[0];
428        const float dmin = dm_val[1];
429
430        for (int im = 0; im < 2; ++im) {
431            const int q_offset = 32*im + l0;
432            const int s_offset = 8*im;
433            const int y_offset = 128*im + l0;
434
435            const float   * y = yy + i * QK_K + y_offset;
436            const uint8_t * q = qs_base + bi * (QK_K / 4) + q_offset;
437
438            const uint32_t * a = (const uint32_t *)(scales_base + bi * (QK_K / 16) + s_offset);
439            aux[0] = a[0] & 0x0f0f0f0f;
440            aux[1] = a[1] & 0x0f0f0f0f;
441            aux[2] = (a[0] >> 4) & 0x0f0f0f0f;
442            aux[3] = (a[1] >> 4) & 0x0f0f0f0f;
443
444            float sum1 = 0, sum2 = 0;
445            for (int l = 0; l < K_QUANTS_PER_ITERATION; ++l) {
446                sum1 += y[l+ 0] * d[0] * ((q[l+ 0] >> 0) & 3)
447                      + y[l+32] * d[2] * ((q[l+ 0] >> 2) & 3)
448                      + y[l+64] * d[4] * ((q[l+ 0] >> 4) & 3)
449                      + y[l+96] * d[6] * ((q[l+ 0] >> 6) & 3)
450                      + y[l+16] * d[1] * ((q[l+16] >> 0) & 3)
451                      + y[l+48] * d[3] * ((q[l+16] >> 2) & 3)
452                      + y[l+80] * d[5] * ((q[l+16] >> 4) & 3)
453                      +y[l+112] * d[7] * ((q[l+16] >> 6) & 3);
454                sum2 += y[l+ 0] * m[0] + y[l+32] * m[2] + y[l+64] * m[4] + y[ l+96] * m[6]
455                      + y[l+16] * m[1] + y[l+48] * m[3] + y[l+80] * m[5] + y[l+112] * m[7];
456
457            }
458            tmp += dall * sum1 - dmin * sum2;
459        }
460    }
461#else
462    GGML_UNUSED(vx);
463    GGML_UNUSED(yy);
464    GGML_UNUSED(ncols);
465    GGML_UNUSED(item_ct1);
466    GGML_ABORT("Q2_K reorder DMMV not supported for QK_K != 256");
467#endif
468
469    // sum up partial sums and write back result
470#pragma unroll
471    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
472        tmp +=
473            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
474    }
475
476    if (item_ct1.get_local_id(2) == 0) {
477        dst[row] = tmp;
478    }
479}
480
481static void dequantize_mul_mat_vec_q3_k(const void *__restrict__ vx,
482                                        const float *__restrict__ yy,
483                                        float *__restrict__ dst,
484                                        const int ncols, int nrows,
485                                        const sycl::nd_item<3> &item_ct1) {
486
487    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
488                    item_ct1.get_local_id(1);
489    if (row >= nrows) return;
490
491    const int num_blocks_per_row = ncols / QK_K;
492    const int ib0 = row*num_blocks_per_row;
493
494    const block_q3_K * x = (const block_q3_K *)vx + ib0;
495
496    float tmp = 0; // partial sum for thread in warp
497
498#if QK_K == 256
499
500    const uint16_t kmask1 = 0x0303;
501    const uint16_t kmask2 = 0x0f0f;
502
503    const int tid =
504        item_ct1.get_local_id(2) / K_QUANTS_PER_ITERATION; // 0...7 or 0...15
505    const int ix =
506        item_ct1.get_local_id(2) % K_QUANTS_PER_ITERATION; // 0 or 0,1
507
508    const int n  = K_QUANTS_PER_ITERATION;               // iterations in the inner loop
509    const int step = 16/K_QUANTS_PER_ITERATION;
510    const int in = tid % step;                           // 0...15 or 0...7
511
512    const int l0 = n*in;                                 // 0...15 or 0...14 in steps of 2
513
514    uint16_t utmp[4];
515    const int8_t * s = (const int8_t *)utmp;
516
517    for (int i = ix; i < num_blocks_per_row; i += K_QUANTS_PER_ITERATION) {
518
519        const uint8_t * h = x[i].hmask + l0;
520        const float d = x[i].d;
521
522        for (int im = 0; im < 2; ++im) {
523            const int q_offset =  32*im + l0;
524            const int y_offset = 128*im + l0;
525            const uint16_t s_shift = 4*im;
526            const uint8_t m = 1 << (4*im);
527
528            const float   * y  = yy + i * QK_K + y_offset;
529            const uint8_t * q = x[i].qs + q_offset;
530
531            const uint16_t * a = (const uint16_t *)x[i].scales;
532            utmp[0] = ((a[0] >> s_shift) & kmask2) | (((a[4] >> (s_shift + 0)) & kmask1) << 4);
533            utmp[1] = ((a[1] >> s_shift) & kmask2) | (((a[5] >> (s_shift + 0)) & kmask1) << 4);
534            utmp[2] = ((a[2] >> s_shift) & kmask2) | (((a[4] >> (s_shift + 2)) & kmask1) << 4);
535            utmp[3] = ((a[3] >> s_shift) & kmask2) | (((a[5] >> (s_shift + 2)) & kmask1) << 4);
536
537            float sum = 0;
538            for (int l = 0; l < n; ++l) {
539                sum += y[l+ 0] * (s[0] - 32) * (((q[l] >> 0) & 3) - (h[l] & (m << 0) ? 0 : 4))
540                     + y[l+32] * (s[2] - 32) * (((q[l] >> 2) & 3) - (h[l] & (m << 1) ? 0 : 4))
541                     + y[l+64] * (s[4] - 32) * (((q[l] >> 4) & 3) - (h[l] & (m << 2) ? 0 : 4))
542                     + y[l+96] * (s[6] - 32) * (((q[l] >> 6) & 3) - (h[l] & (m << 3) ? 0 : 4));
543                sum += y[l+16] * (s[1] - 32) * (((q[l+16] >> 0) & 3) - (h[l+16] & (m << 0) ? 0 : 4))
544                     + y[l+48] * (s[3] - 32) * (((q[l+16] >> 2) & 3) - (h[l+16] & (m << 1) ? 0 : 4))
545                     + y[l+80] * (s[5] - 32) * (((q[l+16] >> 4) & 3) - (h[l+16] & (m << 2) ? 0 : 4))
546                    + y[l+112] * (s[7] - 32) * (((q[l+16] >> 6) & 3) - (h[l+16] & (m << 3) ? 0 : 4));
547            }
548            tmp += d * sum;
549        }
550
551    }
552#else
553
554    const int tid = item_ct1.get_local_id(2)/(2*K_QUANTS_PER_ITERATION);  // 0...15 or 0...7
555    const int ix  = item_ct1.get_local_id(2)%(2*K_QUANTS_PER_ITERATION);  // 0....1 or 0...3
556    const int offset = tid * K_QUANTS_PER_ITERATION;         // 0...15 or 0...14
557    const int in = offset/8;                                 // 0 or 1
558    const int im = offset%8;                                 // 0...7
559
560    for (int i = ix; i < num_blocks_per_row; i += 2*K_QUANTS_PER_ITERATION) {
561
562        const float   * y = yy + i * QK_K + offset;
563        const uint8_t * q = x[i].qs + offset;
564        const uint8_t * s = x[i].scales;
565
566        const float dall = (float)x[i].d;
567
568        float sum = 0;
569        for (int l = 0; l < K_QUANTS_PER_ITERATION; ++l) {
570            const uint8_t hl = x[i].hmask[im+l] >> in;
571            const uint8_t ql = q[l];
572            sum += y[l+ 0] * dall * ((s[0] & 0xF) - 8) * ((int8_t)((ql >> 0) & 3) - ((hl >> 0) & 1 ? 0 : 4))
573                 + y[l+16] * dall * ((s[0] >>  4) - 8) * ((int8_t)((ql >> 2) & 3) - ((hl >> 2) & 1 ? 0 : 4))
574                 + y[l+32] * dall * ((s[1] & 0xF) - 8) * ((int8_t)((ql >> 4) & 3) - ((hl >> 4) & 1 ? 0 : 4))
575                 + y[l+48] * dall * ((s[1] >>  4) - 8) * ((int8_t)((ql >> 6) & 3) - ((hl >> 6) & 1 ? 0 : 4));
576        }
577        tmp += sum;
578    }
579#endif
580
581    // sum up partial sums and write back result
582#pragma unroll
583    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
584        tmp +=
585            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
586    }
587
588    if (item_ct1.get_local_id(2) == 0) {
589        dst[row] = tmp;
590    }
591}
592
593static void dequantize_mul_mat_vec_q3_k_reorder(const void *__restrict__ vx,
594                                                const float *__restrict__ yy,
595                                                float *__restrict__ dst,
596                                                const int ncols, int nrows,
597                                                const sycl::nd_item<3> &item_ct1) {
598
599    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
600                    item_ct1.get_local_id(1);
601    if (row >= nrows) return;
602
603    const int num_blocks_per_row = ncols / QK_K;
604    const int ib0 = row*num_blocks_per_row;
605
606    // SOA base pointers for the reordered layout:
607    //   [qs: nb * (QK_K/4)] [hmask: nb * (QK_K/8)] [scales: nb * 12] [d: nb * sizeof(half)]
608    const int nb = nrows * num_blocks_per_row;
609    const uint8_t   * qs_base     = (const uint8_t *)vx;
610    const uint8_t   * hmask_base  = qs_base + (size_t)nb * (QK_K / 4);
611    const uint8_t   * scales_base = hmask_base + (size_t)nb * (QK_K / 8);
612    const sycl::half * d_base     = (const sycl::half *)(scales_base + (size_t)nb * 12);
613
614    float tmp = 0; // partial sum for thread in warp
615
616#if QK_K == 256
617
618    const uint16_t kmask1 = 0x0303;
619    const uint16_t kmask2 = 0x0f0f;
620
621    const int tid =
622        item_ct1.get_local_id(2) / K_QUANTS_PER_ITERATION; // 0...7 or 0...15
623    const int ix =
624        item_ct1.get_local_id(2) % K_QUANTS_PER_ITERATION; // 0 or 0,1
625
626    const int n  = K_QUANTS_PER_ITERATION;               // iterations in the inner loop
627    const int step = 16/K_QUANTS_PER_ITERATION;
628    const int in = tid % step;                           // 0...15 or 0...7
629
630    const int l0 = n*in;                                 // 0...15 or 0...14 in steps of 2
631
632    uint16_t utmp[4];
633    const int8_t * s = (const int8_t *)utmp;
634
635    for (int i = ix; i < num_blocks_per_row; i += K_QUANTS_PER_ITERATION) {
636        const int bi = ib0 + i;
637
638        const uint8_t * h  = hmask_base + bi * (QK_K / 8) + l0;
639
640        const float d = d_base[bi];
641
642        for (int im = 0; im < 2; ++im) {
643            const int q_offset =  32*im + l0;
644            const int y_offset = 128*im + l0;
645            const uint16_t s_shift = 4*im;
646            const uint8_t m = 1 << (4*im);
647
648            const float   * y  = yy + i * QK_K + y_offset;
649            const uint8_t * q  = qs_base + bi * (QK_K / 4) + q_offset;
650
651            const uint16_t * a = (const uint16_t *)(scales_base + bi * 12);
652            utmp[0] = ((a[0] >> s_shift) & kmask2) | (((a[4] >> (s_shift + 0)) & kmask1) << 4);
653            utmp[1] = ((a[1] >> s_shift) & kmask2) | (((a[5] >> (s_shift + 0)) & kmask1) << 4);
654            utmp[2] = ((a[2] >> s_shift) & kmask2) | (((a[4] >> (s_shift + 2)) & kmask1) << 4);
655            utmp[3] = ((a[3] >> s_shift) & kmask2) | (((a[5] >> (s_shift + 2)) & kmask1) << 4);
656
657            float sum = 0;
658            for (int l = 0; l < n; ++l) {
659                sum += y[l+ 0] * (s[0] - 32) * (((q[l] >> 0) & 3) - (h[l] & (m << 0) ? 0 : 4))
660                     + y[l+32] * (s[2] - 32) * (((q[l] >> 2) & 3) - (h[l] & (m << 1) ? 0 : 4))
661                     + y[l+64] * (s[4] - 32) * (((q[l] >> 4) & 3) - (h[l] & (m << 2) ? 0 : 4))
662                     + y[l+96] * (s[6] - 32) * (((q[l] >> 6) & 3) - (h[l] & (m << 3) ? 0 : 4));
663                sum += y[l+16] * (s[1] - 32) * (((q[l+16] >> 0) & 3) - (h[l+16] & (m << 0) ? 0 : 4))
664                     + y[l+48] * (s[3] - 32) * (((q[l+16] >> 2) & 3) - (h[l+16] & (m << 1) ? 0 : 4))
665                     + y[l+80] * (s[5] - 32) * (((q[l+16] >> 4) & 3) - (h[l+16] & (m << 2) ? 0 : 4))
666                    + y[l+112] * (s[7] - 32) * (((q[l+16] >> 6) & 3) - (h[l+16] & (m << 3) ? 0 : 4));
667            }
668            tmp += d * sum;
669        }
670    }
671#else
672    GGML_UNUSED(vx);
673    GGML_UNUSED(yy);
674    GGML_UNUSED(ncols);
675    GGML_UNUSED(item_ct1);
676    GGML_ABORT("Q3_K reorder DMMV not supported for QK_K != 256");
677#endif
678
679    // sum up partial sums and write back result
680#pragma unroll
681    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
682        tmp +=
683            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
684    }
685
686    if (item_ct1.get_local_id(2) == 0) {
687        dst[row] = tmp;
688    }
689}
690
691static void dequantize_mul_mat_vec_q4_k(const void *__restrict__ vx,
692                                        const float *__restrict__ yy,
693                                        float *__restrict__ dst,
694                                        const int ncols, int nrows,
695                                        const sycl::nd_item<3> &item_ct1) {
696
697    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
698                    item_ct1.get_local_id(1);
699    if (row >= nrows) return;
700    const int num_blocks_per_row = ncols / QK_K;
701    const int ib0 = row*num_blocks_per_row;
702
703    const block_q4_K * x = (const block_q4_K *)vx + ib0;
704
705#if QK_K == 256
706    const uint16_t kmask1 = 0x3f3f;
707    const uint16_t kmask2 = 0x0f0f;
708    const uint16_t kmask3 = 0xc0c0;
709
710    const int tid =
711        item_ct1.get_local_id(2) / K_QUANTS_PER_ITERATION; // 0...7 or 0...15
712    const int ix =
713        item_ct1.get_local_id(2) % K_QUANTS_PER_ITERATION; // 0 or 0,1
714
715    const int step = 8/K_QUANTS_PER_ITERATION;           // 8 or 4
716
717    const int il_base = tid/step;                        // 0 or 1 (was 0...3)
718    const int ir  = tid - step*il_base;                  // 0...7 or 0...3
719    const int n   = 2 * K_QUANTS_PER_ITERATION;          // 2 or 4
720
721    const int in = il_base%2;
722
723    const int l0 = n*(2*ir + in);
724
725    uint16_t aux[4];
726    const uint8_t * sc = (const uint8_t *)aux;
727
728#if K_QUANTS_PER_ITERATION == 2
729    uint32_t q32[4];
730    const uint8_t * q4 = (const uint8_t *)q32;
731#else
732    uint16_t q16[4];
733    const uint8_t * q4 = (const uint8_t *)q16;
734#endif
735
736    float tmp = 0; // partial sum for thread in warp
737
738    for (int i = ix; i < num_blocks_per_row; i += K_QUANTS_PER_ITERATION) {
739
740        const float dall = x[i].dm[0];
741        const float dmin = x[i].dm[1];
742
743        for (int im = 0; im < 2; ++im) {
744            const int q_offset = 32*im + l0;
745            const int y_offset = 64*im + l0;
746
747            const float   * y1 = yy + i*QK_K + y_offset;
748            const float   * y2 = y1 + 128;
749
750            const uint16_t * a = (const uint16_t *)x[i].scales;
751            aux[0] = a[im+0] & kmask1;
752            aux[1] = a[im+2] & kmask1;
753            aux[2] = ((a[im+4] >> 0) & kmask2) | ((a[im+0] & kmask3) >> 2);
754            aux[3] = ((a[im+4] >> 4) & kmask2) | ((a[im+2] & kmask3) >> 2);
755
756#if K_QUANTS_PER_ITERATION == 2
757            const uint32_t * q1 = (const uint32_t *)(x[i].qs + q_offset);
758            const uint32_t * q2 = q1 + 16;
759
760            q32[0] = q1[0] & 0x0f0f0f0f;
761            q32[1] = q1[0] & 0xf0f0f0f0;
762            q32[2] = q2[0] & 0x0f0f0f0f;
763            q32[3] = q2[0] & 0xf0f0f0f0;
764
765            sycl::float4 s = {0.f, 0.f, 0.f, 0.f};
766            float smin = 0;
767            for (int l = 0; l < 4; ++l) {
768                s.x() += y1[l] * q4[l + 0]; s.y() += y1[l + 32] * q4[l + 4];
769                s.z() += y2[l] * q4[l + 8]; s.w() += y2[l + 32] * q4[l + 12];
770                smin += y1[l] * sc[2] + y1[l+32] * sc[3] + y2[l] * sc[6] + y2[l+32] * sc[7];
771            }
772            tmp += dall * (s.x() * sc[0] + s.y() * sc[1] * 1.f / 16.f +
773                           s.z() * sc[4] + s.w() * sc[5] * 1.f / 16.f) -
774                   dmin * smin;
775#else
776            const uint16_t * q1 = (const uint16_t *)(x[i].qs + q_offset);
777            const uint16_t * q2 = q1 + 32;
778
779            q16[0] = q1[0] & 0x0f0f;
780            q16[1] = q1[0] & 0xf0f0;
781            q16[2] = q2[0] & 0x0f0f;
782            q16[3] = q2[0] & 0xf0f0;
783
784            sycl::float4 s = {0.f, 0.f, 0.f, 0.f};
785            float smin = 0;
786            for (int l = 0; l < 2; ++l) {
787                s.x() += y1[l] * q4[l+0]; s.y() += y1[l+32] * q4[l+2];
788                s.z() += y2[l] * q4[l+4]; s.w() += y2[l+32] * q4[l+6];
789                smin += y1[l] * sc[2] + y1[l+32] * sc[3] + y2[l] * sc[6] + y2[l+32] * sc[7];
790            }
791            tmp += dall * (s.x() * sc[0] + s.y() * sc[1] * 1.f/16.f + s.z() * sc[4] + s.w() * sc[5] * 1.f/16.f) - dmin * smin;
792#endif
793        }
794
795    }
796#else
797    const int tid = item_ct1.get_local_id(2)/(2*K_QUANTS_PER_ITERATION);  // 0...15
798    const int ix  = item_ct1.get_local_id(2)%(2*K_QUANTS_PER_ITERATION);
799
800    const int step = tid * K_QUANTS_PER_ITERATION;
801
802    uint16_t aux16[2];
803    const uint8_t * s = (const uint8_t *)aux16;
804
805    float tmp = 0;
806
807    for (int i = ix; i < num_blocks_per_row; i += 2*K_QUANTS_PER_ITERATION) {
808        const uint8_t * q = x[i].qs + step;
809        const float   * y = yy + i*QK_K + step;
810        const uint16_t * a = (const uint16_t *)x[i].scales;
811        aux16[0] = a[0] & 0x0f0f;
812        aux16[1] = (a[0] >> 4) & 0x0f0f;
813        const float d = (float)x[i].dm[0];
814        const float m = (float)x[i].dm[1];
815        float sum = 0.f;
816        for (int j = 0; j < K_QUANTS_PER_ITERATION; ++j) {
817            sum += y[j+ 0] * (d * s[0] * (q[j+ 0] & 0xF) - m * s[2])
818                 + y[j+16] * (d * s[0] * (q[j+16] & 0xF) - m * s[2])
819                 + y[j+32] * (d * s[1] * (q[j+ 0] >>  4) - m * s[3])
820                 + y[j+48] * (d * s[1] * (q[j+16] >>  4) - m * s[3]);
821        }
822        tmp += sum;
823    }
824
825#endif
826
827    // sum up partial sums and write back result
828#pragma unroll
829    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
830        tmp +=
831            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
832    }
833
834    if (tid == 0) {
835        dst[row] = tmp;
836    }
837}
838
839static void dequantize_mul_mat_vec_q4_k_reorder(const void *__restrict__ vx,
840                                                const float *__restrict__ yy,
841                                                float *__restrict__ dst,
842                                                const int ncols, int nrows,
843                                                const sycl::nd_item<3> &item_ct1) {
844
845    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
846                    item_ct1.get_local_id(1);
847    if (row >= nrows) return;
848    const int num_blocks_per_row = ncols / QK_K;
849    const int ib0 = row*num_blocks_per_row;
850
851    // SOA base pointers for the reordered layout:
852    //   [qs: nb * QK_K/2] [scales: nb * K_SCALE_SIZE] [dm: nb * sizeof(half2)]
853    const int nb = nrows * num_blocks_per_row;
854    const uint8_t     * qs_base     = (const uint8_t *)vx;
855    const uint8_t     * scales_base = qs_base + (size_t)nb * (QK_K / 2);
856    const sycl::half2 * dm_base     = (const sycl::half2 *)(scales_base + (size_t)nb * K_SCALE_SIZE);
857
858#if QK_K == 256
859    const uint16_t kmask1 = 0x3f3f;
860    const uint16_t kmask2 = 0x0f0f;
861    const uint16_t kmask3 = 0xc0c0;
862
863    const int tid =
864        item_ct1.get_local_id(2) / K_QUANTS_PER_ITERATION; // 0...7 or 0...15
865    const int ix =
866        item_ct1.get_local_id(2) % K_QUANTS_PER_ITERATION; // 0 or 0,1
867
868    const int step = 8/K_QUANTS_PER_ITERATION;           // 8 or 4
869
870    const int il_base = tid/step;                        // 0 or 1 (was 0...3)
871    const int ir  = tid - step*il_base;                  // 0...7 or 0...3
872    const int n   = 2 * K_QUANTS_PER_ITERATION;          // 2 or 4
873
874    const int in = il_base%2;
875
876    const int l0 = n*(2*ir + in);
877
878    uint16_t aux[4];
879    const uint8_t * sc = (const uint8_t *)aux;
880
881#if K_QUANTS_PER_ITERATION == 2
882    uint32_t q32[4];
883    const uint8_t * q4 = (const uint8_t *)q32;
884#else
885    uint16_t q16[4];
886    const uint8_t * q4 = (const uint8_t *)q16;
887#endif
888
889    float tmp = 0; // partial sum for thread in warp
890
891    for (int i = ix; i < num_blocks_per_row; i += K_QUANTS_PER_ITERATION) {
892        const int bi = ib0 + i;
893
894        const sycl::half2 dm_val = dm_base[bi];
895        const float dall = dm_val[0];
896        const float dmin = dm_val[1];
897
898        for (int im = 0; im < 2; ++im) {
899            const int q_offset = 32*im + l0;
900            const int y_offset = 64*im + l0;
901
902            const float   * y1 = yy + i*QK_K + y_offset;
903            const float   * y2 = y1 + 128;
904
905            const uint16_t * a = (const uint16_t *)(scales_base + bi * K_SCALE_SIZE);
906            aux[0] = a[im+0] & kmask1;
907            aux[1] = a[im+2] & kmask1;
908            aux[2] = ((a[im+4] >> 0) & kmask2) | ((a[im+0] & kmask3) >> 2);
909            aux[3] = ((a[im+4] >> 4) & kmask2) | ((a[im+2] & kmask3) >> 2);
910
911#if K_QUANTS_PER_ITERATION == 2
912            const uint32_t * q1 = (const uint32_t *)(qs_base + bi * (QK_K / 2) + q_offset);
913            const uint32_t * q2 = q1 + 16;
914
915            q32[0] = q1[0] & 0x0f0f0f0f;
916            q32[1] = q1[0] & 0xf0f0f0f0;
917            q32[2] = q2[0] & 0x0f0f0f0f;
918            q32[3] = q2[0] & 0xf0f0f0f0;
919
920            sycl::float4 s = {0.f, 0.f, 0.f, 0.f};
921            float smin = 0;
922            for (int l = 0; l < 4; ++l) {
923                s.x() += y1[l] * q4[l + 0]; s.y() += y1[l + 32] * q4[l + 4];
924                s.z() += y2[l] * q4[l + 8]; s.w() += y2[l + 32] * q4[l + 12];
925                smin += y1[l] * sc[2] + y1[l+32] * sc[3] + y2[l] * sc[6] + y2[l+32] * sc[7];
926            }
927            tmp += dall * (s.x() * sc[0] + s.y() * sc[1] * 1.f / 16.f +
928                           s.z() * sc[4] + s.w() * sc[5] * 1.f / 16.f) -
929                   dmin * smin;
930#else
931            const uint16_t * q1 = (const uint16_t *)(qs_base + bi * (QK_K / 2) + q_offset);
932            const uint16_t * q2 = q1 + 32;
933
934            q16[0] = q1[0] & 0x0f0f;
935            q16[1] = q1[0] & 0xf0f0;
936            q16[2] = q2[0] & 0x0f0f;
937            q16[3] = q2[0] & 0xf0f0;
938
939            sycl::float4 s = {0.f, 0.f, 0.f, 0.f};
940            float smin = 0;
941            for (int l = 0; l < 2; ++l) {
942                s.x() += y1[l] * q4[l+0]; s.y() += y1[l+32] * q4[l+2];
943                s.z() += y2[l] * q4[l+4]; s.w() += y2[l+32] * q4[l+6];
944                smin += y1[l] * sc[2] + y1[l+32] * sc[3] + y2[l] * sc[6] + y2[l+32] * sc[7];
945            }
946            tmp += dall * (s.x() * sc[0] + s.y() * sc[1] * 1.f/16.f + s.z() * sc[4] + s.w() * sc[5] * 1.f/16.f) - dmin * smin;
947#endif
948        }
949
950    }
951#else
952    const int tid = item_ct1.get_local_id(2)/(2*K_QUANTS_PER_ITERATION);  // 0...15
953    const int ix  = item_ct1.get_local_id(2)%(2*K_QUANTS_PER_ITERATION);
954
955    const int step = tid * K_QUANTS_PER_ITERATION;
956
957    uint16_t aux16[2];
958    const uint8_t * s = (const uint8_t *)aux16;
959
960    float tmp = 0;
961
962    for (int i = ix; i < num_blocks_per_row; i += 2*K_QUANTS_PER_ITERATION) {
963        const int bi = ib0 + i;
964
965        const uint8_t * q = qs_base + bi * (QK_K / 2) + step;
966        const float   * y = yy + i*QK_K + step;
967        const uint16_t * a = (const uint16_t *)(scales_base + bi * K_SCALE_SIZE);
968        aux16[0] = a[0] & 0x0f0f;
969        aux16[1] = (a[0] >> 4) & 0x0f0f;
970        const sycl::half2 dm_val = dm_base[bi];
971        const float d = (float)dm_val[0];
972        const float m = (float)dm_val[1];
973        float sum = 0.f;
974        for (int j = 0; j < K_QUANTS_PER_ITERATION; ++j) {
975            sum += y[j+ 0] * (d * s[0] * (q[j+ 0] & 0xF) - m * s[2])
976                 + y[j+16] * (d * s[0] * (q[j+16] & 0xF) - m * s[2])
977                 + y[j+32] * (d * s[1] * (q[j+ 0] >>  4) - m * s[3])
978                 + y[j+48] * (d * s[1] * (q[j+16] >>  4) - m * s[3]);
979        }
980        tmp += sum;
981    }
982
983#endif
984
985    // sum up partial sums and write back result
986#pragma unroll
987    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
988        tmp +=
989            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
990    }
991
992    if (tid == 0) {
993        dst[row] = tmp;
994    }
995}
996
997static void dequantize_mul_mat_vec_q5_k(const void *__restrict__ vx,
998                                        const float *__restrict__ yy,
999                                        float *__restrict__ dst,
1000                                        const int ncols, int nrows,
1001                                        const sycl::nd_item<3> &item_ct1) {
1002
1003    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
1004                    item_ct1.get_local_id(1);
1005    if (row >= nrows) return;
1006    const int num_blocks_per_row = ncols / QK_K;
1007    const int ib0 = row*num_blocks_per_row;
1008
1009    const block_q5_K * x = (const block_q5_K *)vx + ib0;
1010
1011    float tmp = 0; // partial sum for thread in warp
1012
1013#if QK_K == 256
1014    const uint16_t kmask1 = 0x3f3f;
1015    const uint16_t kmask2 = 0x0f0f;
1016    const uint16_t kmask3 = 0xc0c0;
1017
1018    const int tid = item_ct1.get_local_id(2) / 2; // 0...7
1019    const int ix = item_ct1.get_local_id(2) % 2;
1020
1021    const int il_base = tid/4;     // 0 or 1 (was 0...3)
1022    const int ir  = tid - 4*il_base;// 0...3
1023    const int n   = 2;
1024
1025    const int in = il_base%2;
1026
1027    const int l0 = n*(2*ir + in);
1028
1029    uint16_t aux[4];
1030    const uint8_t * sc = (const uint8_t *)aux;
1031
1032    uint16_t q16[8];
1033    const uint8_t * q4 = (const uint8_t *)q16;
1034
1035    for (int i = ix; i < num_blocks_per_row; i += 2) {
1036
1037        const uint8_t * qh  = x[i].qh + l0;
1038        const float dall = x[i].dm[0];
1039        const float dmin = x[i].dm[1];
1040
1041        for (int im = 0; im < 2; ++im) {
1042            const int q_offset = 32*im + l0;
1043            const int y_offset = 64*im + l0;
1044
1045            const uint8_t hm1  = 1 << (2*im);
1046            const uint8_t hm2  = hm1 << 4;
1047
1048            const uint8_t * ql1 = x[i].qs + q_offset;
1049            const float   * y1  = yy + i*QK_K + y_offset;
1050            const float   * y2  = y1 + 128;
1051
1052            const uint16_t * a = (const uint16_t *)x[i].scales;
1053            aux[0] = a[im+0] & kmask1;
1054            aux[1] = a[im+2] & kmask1;
1055            aux[2] = ((a[im+4] >> 0) & kmask2) | ((a[im+0] & kmask3) >> 2);
1056            aux[3] = ((a[im+4] >> 4) & kmask2) | ((a[im+2] & kmask3) >> 2);
1057
1058            sycl::float4 sum = {0.f, 0.f, 0.f, 0.f};
1059            float smin = 0;
1060            const uint16_t * q1 = (const uint16_t *)ql1;
1061            const uint16_t * q2 = q1 + 32;
1062            q16[0] = q1[0] & 0x0f0f;
1063            q16[1] = q1[8] & 0x0f0f;
1064            q16[2] = (q1[0] >> 4) & 0x0f0f;
1065            q16[3] = (q1[8] >> 4) & 0x0f0f;
1066            q16[4] = q2[0] & 0x0f0f;
1067            q16[5] = q2[8] & 0x0f0f;
1068            q16[6] = (q2[0] >> 4) & 0x0f0f;
1069            q16[7] = (q2[8] >> 4) & 0x0f0f;
1070            for (int l = 0; l < n; ++l) {
1071                sum.x() +=
1072                    y1[l + 0] * (q4[l + 0] + (qh[l + 0] & (hm1 << 0) ? 16 : 0)) +
1073                    y1[l + 16] * (q4[l + 2] + (qh[l + 16] & (hm1 << 0) ? 16 : 0));
1074                sum.y() +=
1075                    y1[l + 32] * (q4[l + 4] + (qh[l + 0] & (hm1 << 1) ? 16 : 0)) +
1076                    y1[l + 48] * (q4[l + 6] + (qh[l + 16] & (hm1 << 1) ? 16 : 0));
1077                sum.z() +=
1078                    y2[l + 0] * (q4[l + 8] + (qh[l + 0] & (hm2 << 0) ? 16 : 0)) +
1079                    y2[l + 16] * (q4[l + 10] + (qh[l + 16] & (hm2 << 0) ? 16 : 0));
1080                sum.w() +=
1081                    y2[l + 32] * (q4[l + 12] + (qh[l + 0] & (hm2 << 1) ? 16 : 0)) +
1082                    y2[l + 48] * (q4[l + 14] + (qh[l + 16] & (hm2 << 1) ? 16 : 0));
1083                smin += (y1[l] + y1[l+16]) * sc[2] + (y1[l+32] + y1[l+48]) * sc[3]
1084                      + (y2[l] + y2[l+16]) * sc[6] + (y2[l+32] + y2[l+48]) * sc[7];
1085            }
1086            tmp += dall * (sum.x() * sc[0] + sum.y() * sc[1] + sum.z() * sc[4] +
1087                           sum.w() * sc[5]) -
1088                   dmin * smin;
1089        }
1090    }
1091
1092#else
1093    const int tid = item_ct1.get_local_id(2)/(2*K_QUANTS_PER_ITERATION);  // 0...15
1094    const int ix  = item_ct1.get_local_id(2)%(2*K_QUANTS_PER_ITERATION);
1095    const int step = tid * K_QUANTS_PER_ITERATION;
1096    const int im = step/8;
1097    const int in = step%8;
1098
1099    for (int i = ix; i < num_blocks_per_row; i += 2*K_QUANTS_PER_ITERATION) {
1100        const uint8_t * q = x[i].qs + step;
1101        const int8_t  * s = x[i].scales;
1102        const float   * y = yy + i*QK_K + step;
1103        const float     d = x[i].d;
1104        float sum = 0.f;
1105        for (int j = 0; j < K_QUANTS_PER_ITERATION; ++j) {
1106            const uint8_t h = x[i].qh[in+j] >> im;
1107            sum += y[j+ 0] * d * s[0] * ((q[j+ 0] & 0xF) - ((h >> 0) & 1 ? 0 : 16))
1108                 + y[j+16] * d * s[1] * ((q[j+16] & 0xF) - ((h >> 2) & 1 ? 0 : 16))
1109                 + y[j+32] * d * s[2] * ((q[j+ 0] >>  4) - ((h >> 4) & 1 ? 0 : 16))
1110                 + y[j+48] * d * s[3] * ((q[j+16] >>  4) - ((h >> 6) & 1 ? 0 : 16));
1111        }
1112        tmp += sum;
1113    }
1114#endif
1115
1116    // sum up partial sums and write back result
1117#pragma unroll
1118    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
1119        tmp +=
1120            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
1121    }
1122
1123    if (item_ct1.get_local_id(2) == 0) {
1124        dst[row] = tmp;
1125    }
1126}
1127
1128static void dequantize_mul_mat_vec_q5_k_reorder(const void *__restrict__ vx,
1129                                                const float *__restrict__ yy,
1130                                                float *__restrict__ dst,
1131                                                const int ncols, int nrows,
1132                                                const sycl::nd_item<3> &item_ct1) {
1133
1134    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
1135                    item_ct1.get_local_id(1);
1136    if (row >= nrows) return;
1137    const int num_blocks_per_row = ncols / QK_K;
1138    const int ib0 = row*num_blocks_per_row;
1139
1140    // SOA base pointers for the reordered layout:
1141    //   [qs: nb * QK_K/2] [qh: nb * QK_K/8] [scales: nb * K_SCALE_SIZE] [dm: nb * sizeof(half2)]
1142    const int nb = nrows * num_blocks_per_row;
1143    const uint8_t     * qs_base     = (const uint8_t *)vx;
1144    const uint8_t     * qh_base     = qs_base + (size_t)nb * (QK_K / 2);
1145    const uint8_t     * scales_base = qh_base + (size_t)nb * (QK_K / 8);
1146    const sycl::half2 * dm_base     = (const sycl::half2 *)(scales_base + (size_t)nb * K_SCALE_SIZE);
1147
1148    float tmp = 0; // partial sum for thread in warp
1149
1150#if QK_K == 256
1151    const uint16_t kmask1 = 0x3f3f;
1152    const uint16_t kmask2 = 0x0f0f;
1153    const uint16_t kmask3 = 0xc0c0;
1154
1155    const int tid = item_ct1.get_local_id(2) / 2; // 0...15
1156    const int ix = item_ct1.get_local_id(2) % 2;
1157
1158    const int il_base = tid/4;      // 0...3
1159    const int ir  = tid - 4*il_base;// 0...3
1160    const int n   = 2;
1161
1162    const int in = il_base%2;
1163
1164    const int l0 = n*(2*ir + in);
1165
1166    uint16_t aux[4];
1167    const uint8_t * sc = (const uint8_t *)aux;
1168
1169    uint16_t q16[8];
1170    const uint8_t * q4 = (const uint8_t *)q16;
1171
1172    for (int i = ix; i < num_blocks_per_row; i += 2) {
1173        const int bi = ib0 + i;
1174
1175        const uint8_t * qh  = qh_base + bi * (QK_K / 8) + l0;
1176        const sycl::half2 dm_val = dm_base[bi];
1177        const float dall = dm_val[0];
1178        const float dmin = dm_val[1];
1179
1180        for (int im = 0; im < 2; ++im) {
1181            const int q_offset = 32*im + l0;
1182            const int y_offset = 64*im + l0;
1183
1184            const uint8_t hm1  = 1 << (2*im);
1185            const uint8_t hm2  = hm1 << 4;
1186
1187            const uint8_t * ql1 = qs_base + bi * (QK_K / 2) + q_offset;
1188            const float   * y1  = yy + i*QK_K + y_offset;
1189            const float   * y2  = y1 + 128;
1190
1191            const uint16_t * a = (const uint16_t *)(scales_base + bi * K_SCALE_SIZE);
1192            aux[0] = a[im+0] & kmask1;
1193            aux[1] = a[im+2] & kmask1;
1194            aux[2] = ((a[im+4] >> 0) & kmask2) | ((a[im+0] & kmask3) >> 2);
1195            aux[3] = ((a[im+4] >> 4) & kmask2) | ((a[im+2] & kmask3) >> 2);
1196
1197            sycl::float4 sum = {0.f, 0.f, 0.f, 0.f};
1198            float smin = 0;
1199            const uint16_t * q1 = (const uint16_t *)ql1;
1200            const uint16_t * q2 = q1 + 32;
1201            q16[0] = q1[0] & 0x0f0f;
1202            q16[1] = q1[8] & 0x0f0f;
1203            q16[2] = (q1[0] >> 4) & 0x0f0f;
1204            q16[3] = (q1[8] >> 4) & 0x0f0f;
1205            q16[4] = q2[0] & 0x0f0f;
1206            q16[5] = q2[8] & 0x0f0f;
1207            q16[6] = (q2[0] >> 4) & 0x0f0f;
1208            q16[7] = (q2[8] >> 4) & 0x0f0f;
1209            for (int l = 0; l < n; ++l) {
1210                sum.x() +=
1211                    y1[l + 0] * (q4[l + 0] + (qh[l + 0] & (hm1 << 0) ? 16 : 0)) +
1212                    y1[l + 16] * (q4[l + 2] + (qh[l + 16] & (hm1 << 0) ? 16 : 0));
1213                sum.y() +=
1214                    y1[l + 32] * (q4[l + 4] + (qh[l + 0] & (hm1 << 1) ? 16 : 0)) +
1215                    y1[l + 48] * (q4[l + 6] + (qh[l + 16] & (hm1 << 1) ? 16 : 0));
1216                sum.z() +=
1217                    y2[l + 0] * (q4[l + 8] + (qh[l + 0] & (hm2 << 0) ? 16 : 0)) +
1218                    y2[l + 16] * (q4[l + 10] + (qh[l + 16] & (hm2 << 0) ? 16 : 0));
1219                sum.w() +=
1220                    y2[l + 32] * (q4[l + 12] + (qh[l + 0] & (hm2 << 1) ? 16 : 0)) +
1221                    y2[l + 48] * (q4[l + 14] + (qh[l + 16] & (hm2 << 1) ? 16 : 0));
1222                smin += (y1[l] + y1[l+16]) * sc[2] + (y1[l+32] + y1[l+48]) * sc[3]
1223                      + (y2[l] + y2[l+16]) * sc[6] + (y2[l+32] + y2[l+48]) * sc[7];
1224            }
1225            tmp += dall * (sum.x() * sc[0] + sum.y() * sc[1] + sum.z() * sc[4] +
1226                           sum.w() * sc[5]) -
1227                   dmin * smin;
1228        }
1229    }
1230#else
1231    // The reordered Q5_K layout is only produced for QK_K == 256.
1232#endif
1233
1234    // sum up partial sums and write back result
1235#pragma unroll
1236    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
1237        tmp +=
1238            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
1239    }
1240
1241    if (item_ct1.get_local_id(2) == 0) {
1242        dst[row] = tmp;
1243    }
1244}
1245
1246static void dequantize_mul_mat_vec_q6_k(const void * __restrict__ vx, const float * __restrict__ yy, float * __restrict__ dst, const int ncols, int nrows,
1247                                        const sycl::nd_item<3> &item_ct1) {
1248
1249    static_assert(16%K_QUANTS_PER_ITERATION == 0, "16 must be divisible by K_QUANTS_PER_ITERATION");
1250
1251    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
1252                    item_ct1.get_local_id(1);
1253    if (row >= nrows) return;
1254
1255    const int num_blocks_per_row = ncols / QK_K;
1256    const int ib0 = row*num_blocks_per_row;
1257
1258    const block_q6_K * x = (const block_q6_K *)vx + ib0;
1259
1260#if QK_K == 256
1261
1262    const int tid =
1263        item_ct1.get_local_id(2) / K_QUANTS_PER_ITERATION; // 0...7 or 0...15
1264    const int ix =
1265        item_ct1.get_local_id(2) % K_QUANTS_PER_ITERATION; // 0 or 0, 1
1266
1267    const int step = 16/K_QUANTS_PER_ITERATION;          // 16 or 8
1268
1269    const int in = tid % step;                           // 0...15 or 0...7
1270
1271#if K_QUANTS_PER_ITERATION == 1
1272    const int l0 = K_QUANTS_PER_ITERATION*in;            // 0...15
1273    const int is = 0;
1274#else
1275    const int l0 = 4 * in;                               // 0, 4, 8, ..., 28
1276    const int is = in / 4;
1277#endif
1278
1279    float tmp = 0; // partial sum for thread in warp
1280
1281    for (int i = ix; i < num_blocks_per_row; i += K_QUANTS_PER_ITERATION) {
1282
1283        const float d = x[i].d;
1284
1285        for (int im = 0; im < 2; ++im) {
1286            const int ql_offset = 64*im + l0;
1287            const int qh_offset = 32*im + l0;
1288            const int s_offset  =  8*im + is;
1289            const int y_offset = 128*im + l0;
1290
1291            const float   * y  = yy + i * QK_K + y_offset;
1292            const uint8_t * ql = x[i].ql + ql_offset;
1293            const uint8_t * qh = x[i].qh + qh_offset;
1294            const int8_t  * s  = x[i].scales + s_offset;
1295
1296#if K_QUANTS_PER_ITERATION == 1
1297            float sum = y[ 0] * s[0] * d * ((int8_t)((ql[ 0] & 0xF) | ((qh[ 0] & 0x03) << 4)) - 32)
1298                      + y[16] * s[1] * d * ((int8_t)((ql[16] & 0xF) | ((qh[16] & 0x03) << 4)) - 32)
1299                      + y[32] * s[2] * d * ((int8_t)((ql[32] & 0xF) | ((qh[ 0] & 0x0c) << 2)) - 32)
1300                      + y[48] * s[3] * d * ((int8_t)((ql[48] & 0xF) | ((qh[16] & 0x0c) << 2)) - 32)
1301                      + y[64] * s[4] * d * ((int8_t)((ql[ 0]  >> 4) | ((qh[ 0] & 0x30) >> 0)) - 32)
1302                      + y[80] * s[5] * d * ((int8_t)((ql[16]  >> 4) | ((qh[16] & 0x30) >> 0)) - 32)
1303                      + y[96] * s[6] * d * ((int8_t)((ql[32]  >> 4) | ((qh[ 0] & 0xc0) >> 2)) - 32)
1304                      +y[112] * s[7] * d * ((int8_t)((ql[48]  >> 4) | ((qh[16] & 0xc0) >> 2)) - 32);
1305            tmp += sum;
1306#else
1307            float sum = 0;
1308            for (int l = 0; l < 4; ++l) {
1309                sum += y[l+ 0] * s[0] * d * ((int8_t)((ql[l+ 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32)
1310                     + y[l+32] * s[2] * d * ((int8_t)((ql[l+32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32)
1311                     + y[l+64] * s[4] * d * ((int8_t)((ql[l+ 0]  >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32)
1312                     + y[l+96] * s[6] * d * ((int8_t)((ql[l+32]  >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32);
1313            }
1314            tmp += sum;
1315#endif
1316        }
1317
1318    }
1319
1320#else
1321
1322    const int tid = item_ct1.get_local_id(2)/(2*K_QUANTS_PER_ITERATION);  // 0...7
1323    const int ix  = item_ct1.get_local_id(2)%(2*K_QUANTS_PER_ITERATION);  // 0...3
1324
1325    const int step = tid * K_QUANTS_PER_ITERATION;
1326
1327    float tmp = 0; // partial sum for thread in warp
1328
1329    for (int i = ix; i < num_blocks_per_row; i += 2*K_QUANTS_PER_ITERATION) {
1330
1331        const float   * y  = yy + i * QK_K + step;
1332        const uint8_t * ql = x[i].ql + step;
1333        const uint8_t * qh = x[i].qh + step;
1334        const int8_t  * s  = x[i].scales;
1335
1336        const float d = x[i+0].d;
1337
1338        float sum = 0;
1339        for (int j = 0; j < K_QUANTS_PER_ITERATION; ++j) {
1340            sum += y[j+ 0] * s[0] * d * ((int8_t)((ql[j+ 0] & 0xF) | ((qh[j] & 0x03) << 4)) - 32)
1341                 + y[j+16] * s[1] * d * ((int8_t)((ql[j+16] & 0xF) | ((qh[j] & 0x0c) << 2)) - 32)
1342                 + y[j+32] * s[2] * d * ((int8_t)((ql[j+ 0] >>  4) | ((qh[j] & 0x30) >> 0)) - 32)
1343                 + y[j+48] * s[3] * d * ((int8_t)((ql[j+16] >>  4) | ((qh[j] & 0xc0) >> 2)) - 32);
1344        }
1345        tmp += sum;
1346
1347    }
1348
1349#endif
1350
1351    // sum up partial sums and write back result
1352#pragma unroll
1353    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
1354        tmp +=
1355            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
1356    }
1357
1358    if (tid == 0) {
1359        dst[row] = tmp;
1360    }
1361}
1362
1363static void dequantize_mul_mat_vec_q6_k_reorder(const void * __restrict__ vx, const float * __restrict__ yy, float * __restrict__ dst, const int ncols, int nrows,
1364                                                const sycl::nd_item<3> &item_ct1) {
1365
1366    static_assert(16%K_QUANTS_PER_ITERATION == 0, "16 must be divisible by K_QUANTS_PER_ITERATION");
1367
1368    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
1369                    item_ct1.get_local_id(1);
1370    if (row >= nrows) return;
1371
1372    const int num_blocks_per_row = ncols / QK_K;
1373    const int ib0 = row*num_blocks_per_row;
1374
1375    // SOA base pointers for the reordered layout:
1376    //   [ql: nb * QK_K/2] [qh: nb * QK_K/4] [scales: nb * QK_K/16] [d: nb * sizeof(half)]
1377    const int nb = nrows * num_blocks_per_row;
1378    const uint8_t   * ql_base     = (const uint8_t *)vx;
1379    const uint8_t   * qh_base     = ql_base + (size_t)nb * (QK_K / 2);
1380    const int8_t    * scales_base = (const int8_t *)(qh_base + (size_t)nb * (QK_K / 4));
1381    const sycl::half * d_base     = (const sycl::half *)((const uint8_t *)scales_base + (size_t)nb * (QK_K / 16));
1382
1383#if QK_K == 256
1384
1385    const int tid =
1386        item_ct1.get_local_id(2) / K_QUANTS_PER_ITERATION; // 0...7 or 0...15
1387    const int ix =
1388        item_ct1.get_local_id(2) % K_QUANTS_PER_ITERATION; // 0 or 0, 1
1389
1390    const int step = 16/K_QUANTS_PER_ITERATION;          // 16 or 8
1391
1392    const int in = tid % step;                           // 0...15 or 0...7
1393
1394#if K_QUANTS_PER_ITERATION == 1
1395    const int l0 = K_QUANTS_PER_ITERATION*in;            // 0...15
1396    const int is = 0;
1397#else
1398    const int l0 = 4 * in;                               // 0, 4, 8, ..., 28
1399    const int is = in / 4;
1400#endif
1401
1402    float tmp = 0; // partial sum for thread in warp
1403
1404    for (int i = ix; i < num_blocks_per_row; i += K_QUANTS_PER_ITERATION) {
1405        const int bi = ib0 + i;
1406
1407        const float d = d_base[bi];
1408
1409        for (int im = 0; im < 2; ++im) {
1410            const int ql_offset = 64*im + l0;
1411            const int qh_offset = 32*im + l0;
1412            const int s_offset  =  8*im + is;
1413            const int y_offset = 128*im + l0;
1414
1415            const float   * y  = yy + i * QK_K + y_offset;
1416            const uint8_t * ql = ql_base + bi * (QK_K / 2) + ql_offset;
1417            const uint8_t * qh = qh_base + bi * (QK_K / 4) + qh_offset;
1418            const int8_t  * s  = scales_base + bi * (QK_K / 16) + s_offset;
1419
1420#if K_QUANTS_PER_ITERATION == 1
1421            float sum = y[ 0] * s[0] * d * ((int8_t)((ql[ 0] & 0xF) | ((qh[ 0] & 0x03) << 4)) - 32)
1422                      + y[16] * s[1] * d * ((int8_t)((ql[16] & 0xF) | ((qh[16] & 0x03) << 4)) - 32)
1423                      + y[32] * s[2] * d * ((int8_t)((ql[32] & 0xF) | ((qh[ 0] & 0x0c) << 2)) - 32)
1424                      + y[48] * s[3] * d * ((int8_t)((ql[48] & 0xF) | ((qh[16] & 0x0c) << 2)) - 32)
1425                      + y[64] * s[4] * d * ((int8_t)((ql[ 0]  >> 4) | ((qh[ 0] & 0x30) >> 0)) - 32)
1426                      + y[80] * s[5] * d * ((int8_t)((ql[16]  >> 4) | ((qh[16] & 0x30) >> 0)) - 32)
1427                      + y[96] * s[6] * d * ((int8_t)((ql[32]  >> 4) | ((qh[ 0] & 0xc0) >> 2)) - 32)
1428                      +y[112] * s[7] * d * ((int8_t)((ql[48]  >> 4) | ((qh[16] & 0xc0) >> 2)) - 32);
1429            tmp += sum;
1430#else
1431            float sum = 0;
1432            for (int l = 0; l < 4; ++l) {
1433                sum += y[l+ 0] * s[0] * d * ((int8_t)((ql[l+ 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32)
1434                     + y[l+32] * s[2] * d * ((int8_t)((ql[l+32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32)
1435                     + y[l+64] * s[4] * d * ((int8_t)((ql[l+ 0]  >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32)
1436                     + y[l+96] * s[6] * d * ((int8_t)((ql[l+32]  >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32);
1437            }
1438            tmp += sum;
1439#endif
1440        }
1441
1442    }
1443
1444#else
1445
1446    const int tid = item_ct1.get_local_id(2)/(2*K_QUANTS_PER_ITERATION);  // 0...7
1447    const int ix  = item_ct1.get_local_id(2)%(2*K_QUANTS_PER_ITERATION);  // 0...3
1448
1449    const int step = tid * K_QUANTS_PER_ITERATION;
1450
1451    float tmp = 0; // partial sum for thread in warp
1452
1453    for (int i = ix; i < num_blocks_per_row; i += 2*K_QUANTS_PER_ITERATION) {
1454        const int bi = ib0 + i;
1455
1456        const float   * y  = yy + i * QK_K + step;
1457        const uint8_t * ql = ql_base + bi * (QK_K / 2) + step;
1458        const uint8_t * qh = qh_base + bi * (QK_K / 4) + step;
1459        const int8_t  * s  = scales_base + bi * (QK_K / 16);
1460
1461        const float d = d_base[bi];
1462
1463        float sum = 0;
1464        for (int j = 0; j < K_QUANTS_PER_ITERATION; ++j) {
1465            sum += y[j+ 0] * s[0] * d * ((int8_t)((ql[j+ 0] & 0xF) | ((qh[j] & 0x03) << 4)) - 32)
1466                 + y[j+16] * s[1] * d * ((int8_t)((ql[j+16] & 0xF) | ((qh[j] & 0x0c) << 2)) - 32)
1467                 + y[j+32] * s[2] * d * ((int8_t)((ql[j+ 0] >>  4) | ((qh[j] & 0x30) >> 0)) - 32)
1468                 + y[j+48] * s[3] * d * ((int8_t)((ql[j+16] >>  4) | ((qh[j] & 0xc0) >> 2)) - 32);
1469        }
1470        tmp += sum;
1471
1472    }
1473
1474#endif
1475
1476    // sum up partial sums and write back result
1477#pragma unroll
1478    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
1479        tmp +=
1480            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
1481    }
1482
1483    if (tid == 0) {
1484        dst[row] = tmp;
1485    }
1486}
1487
1488static void dequantize_mul_mat_vec_q4_0_sycl_reorder(const void *vx, const dfloat *y,
1489                                             float *dst, const int ncols,
1490                                             const int nrows,
1491                                             dpct::queue_ptr stream) {
1492    GGML_ASSERT(ncols % GGML_SYCL_DMMV_X == 0);
1493    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1494    // the number of rows may exceed maximum grid size in the y or z dimensions, use the x dimension instead
1495    const sycl::range<3> block_nums(1, 1, block_num_y);
1496    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1497    {
1498        dpct::has_capability_or_fail(stream->get_device(),
1499                                     {sycl::aspect::fp16});
1500
1501        stream->parallel_for(
1502            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1503            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1504                dequantize_mul_mat_vec_reorder<QK4_0, QR4_0, dequantize_q4_0_reorder>(
1505                    vx, y, dst, ncols, nrows, item_ct1);
1506            });
1507    }
1508}
1509
1510
1511static void dequantize_mul_mat_vec_q4_0_sycl(const void *vx, const dfloat *y,
1512                                             float *dst, const int ncols,
1513                                             const int nrows,
1514                                             dpct::queue_ptr stream) {
1515    GGML_ASSERT(ncols % GGML_SYCL_DMMV_X == 0);
1516    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1517    // the number of rows may exceed maximum grid size in the y or z dimensions, use the x dimension instead
1518    const sycl::range<3> block_nums(1, 1, block_num_y);
1519    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1520    {
1521        dpct::has_capability_or_fail(stream->get_device(),
1522                                     {sycl::aspect::fp16});
1523
1524        stream->parallel_for(
1525            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1526            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1527                dequantize_mul_mat_vec<QK4_0, QR4_0, dequantize_q4_0>(
1528                    vx, y, dst, ncols, nrows, item_ct1);
1529            });
1530    }
1531}
1532
1533static void dequantize_mul_mat_vec_q1_0_sycl_reorder(const void *vx, const dfloat *y,
1534                                             float *dst, const int ncols,
1535                                             const int nrows,
1536                                             dpct::queue_ptr stream) {
1537    GGML_ASSERT(ncols % GGML_SYCL_DMMV_X == 0);
1538    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1539    // the number of rows may exceed maximum grid size in the y or z dimensions, use the x dimension instead
1540    const sycl::range<3> block_nums(1, 1, block_num_y);
1541    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1542    {
1543        dpct::has_capability_or_fail(stream->get_device(),
1544                                     {sycl::aspect::fp16});
1545
1546        stream->parallel_for(
1547            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1548            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1549                dequantize_mul_mat_vec_reorder<QK1_0, QR1_0, dequantize_q1_0_reorder>(
1550                    vx, y, dst, ncols, nrows, item_ct1);
1551            });
1552    }
1553}
1554
1555static void dequantize_mul_mat_vec_q1_0_sycl(const void *vx, const dfloat *y,
1556                                             float *dst, const int ncols,
1557                                             const int nrows,
1558                                             dpct::queue_ptr stream) {
1559    GGML_ASSERT(ncols % GGML_SYCL_DMMV_X == 0);
1560    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1561    // the number of rows may exceed maximum grid size in the y or z dimensions, use the x dimension instead
1562    const sycl::range<3> block_nums(1, 1, block_num_y);
1563    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1564    {
1565        dpct::has_capability_or_fail(stream->get_device(),
1566                                     {sycl::aspect::fp16});
1567
1568        stream->parallel_for(
1569            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1570            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1571                dequantize_mul_mat_vec<QK1_0, QR1_0, dequantize_q1_0>(
1572                    vx, y, dst, ncols, nrows, item_ct1);
1573            });
1574    }
1575}
1576
1577static void dequantize_mul_mat_vec_q4_1_sycl(const void *vx, const dfloat *y,
1578                                             float *dst, const int ncols,
1579                                             const int nrows,
1580                                             dpct::queue_ptr stream) {
1581    GGML_ASSERT(ncols % GGML_SYCL_DMMV_X == 0);
1582    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1583    const sycl::range<3> block_nums(1, 1, block_num_y);
1584    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1585    {
1586        dpct::has_capability_or_fail(stream->get_device(),
1587                                     {sycl::aspect::fp16});
1588
1589        stream->parallel_for(
1590            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1591            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1592                dequantize_mul_mat_vec<QK4_1, QR4_1, dequantize_q4_1>(
1593                    vx, y, dst, ncols, nrows, item_ct1);
1594            });
1595    }
1596}
1597
1598static void dequantize_mul_mat_vec_q5_0_sycl(const void *vx, const dfloat *y,
1599                                             float *dst, const int ncols,
1600                                             const int nrows,
1601                                             dpct::queue_ptr stream) {
1602    GGML_ASSERT(ncols % GGML_SYCL_DMMV_X == 0);
1603    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1604    const sycl::range<3> block_nums(1, 1, block_num_y);
1605    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1606    {
1607        dpct::has_capability_or_fail(stream->get_device(),
1608                                     {sycl::aspect::fp16});
1609
1610        stream->parallel_for(
1611            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1612            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1613                dequantize_mul_mat_vec<QK5_0, QR5_0, dequantize_q5_0>(
1614                    vx, y, dst, ncols, nrows, item_ct1);
1615            });
1616    }
1617}
1618
1619static void dequantize_mul_mat_vec_q5_1_sycl(const void *vx, const dfloat *y,
1620                                             float *dst, const int ncols,
1621                                             const int nrows,
1622                                             dpct::queue_ptr stream) {
1623    GGML_ASSERT(ncols % GGML_SYCL_DMMV_X == 0);
1624    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1625    const sycl::range<3> block_nums(1, 1, block_num_y);
1626    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1627    {
1628        dpct::has_capability_or_fail(stream->get_device(),
1629                                     {sycl::aspect::fp16});
1630
1631        stream->parallel_for(
1632            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1633            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1634                dequantize_mul_mat_vec<QK5_1, QR5_1, dequantize_q5_1>(
1635                    vx, y, dst, ncols, nrows, item_ct1);
1636            });
1637    }
1638}
1639
1640static void dequantize_mul_mat_vec_q8_0_sycl_reorder(const void *vx, const dfloat *y,
1641                                             float *dst, const int ncols,
1642                                             const int nrows,
1643                                             dpct::queue_ptr stream) {
1644    GGML_ASSERT(ncols % GGML_SYCL_DMMV_X == 0);
1645    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1646    const sycl::range<3> block_nums(1, 1, block_num_y);
1647    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1648    {
1649        dpct::has_capability_or_fail(stream->get_device(),
1650                                     {sycl::aspect::fp16});
1651
1652        stream->parallel_for(
1653            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1654            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1655                // Q8_0 reorder layout: [all qs (ncols*nrows bytes)][all d values]
1656                // Cannot reuse dequantize_mul_mat_vec_reorder template because it has
1657                // Q4_0-specific constants hardcoded (d_ptr offset and qs stride).
1658                const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
1659                    item_ct1.get_local_id(1);
1660                if (row >= nrows) return;
1661
1662                const int tid = item_ct1.get_local_id(2);
1663                const int iter_stride = 8*2*GGML_SYCL_DMMV_X;
1664                const int vals_per_iter = iter_stride / WARP_SIZE;
1665                const int ncols_left = ncols % (QK8_0*WARP_SIZE);
1666                const int ncols_align = ncols - ncols_left;
1667
1668#ifdef GGML_SYCL_F16
1669                sycl::half2 tmp = {0.0f, 0.0f};
1670#else
1671                float tmp = 0.0f;
1672#endif
1673                const char *d_ptr = (const char*)vx + ncols*nrows;  // d after all qs
1674
1675                int i = 0;
1676                for (i = 0; i < ncols_align; i += iter_stride) {
1677                    const int col = i + vals_per_iter*tid;
1678                    const int ib = (row*ncols + col)/QK8_0;
1679                    const int iqs = col % QK8_0;
1680
1681#pragma unroll
1682                    for (int j = 0; j < vals_per_iter; j += 2) {
1683                        dfloat2 v;
1684                        dequantize_q8_0_reorder((const void *)d_ptr, ib, (const void *)vx,
1685                                                ib * QK8_0 + iqs + j, v);
1686
1687#ifdef GGML_SYCL_F16
1688                        dfloat2 t1{y[col + j + 0], y[col + j + 1]};
1689                        tmp += v * t1;
1690#else
1691                        tmp += v.x() * y[col + j + 0];
1692                        tmp += v.y() * y[col + j + 1];
1693#endif
1694                    }
1695                }
1696
1697                // handle remaining columns
1698                for (; i < ncols; i += iter_stride) {
1699                    if (tid >= ncols_left/QK8_0) continue;
1700                    const int col = i + vals_per_iter*tid;
1701                    const int ib = (row*ncols + col)/QK8_0;
1702                    const int iqs = col % QK8_0;
1703
1704#pragma unroll
1705                    for (int j = 0; j < vals_per_iter; j += 2) {
1706                        dfloat2 v;
1707                        dequantize_q8_0_reorder((const void *)d_ptr, ib, (const void *)vx,
1708                                                ib * QK8_0 + iqs + j, v);
1709
1710#ifdef GGML_SYCL_F16
1711                        dfloat2 t1{y[col + j + 0], y[col + j + 1]};
1712                        tmp += v * t1;
1713#else
1714                        tmp += v.x() * y[col + j + 0];
1715                        tmp += v.y() * y[col + j + 1];
1716#endif
1717                    }
1718                }
1719
1720                // reduce
1721                const int mask_start = ncols > GGML_SYCL_DMMV_X ? WARP_SIZE >> 1 : WARP_SIZE >> 2;
1722                for (int mask = mask_start; mask > 0; mask >>= 1) {
1723                    tmp += dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
1724                }
1725
1726                if (tid == 0) {
1727#ifdef GGML_SYCL_F16
1728                    dst[row] = tmp.x() + tmp.y();
1729#else
1730                    dst[row] = tmp;
1731#endif
1732                }
1733            });
1734    }
1735}
1736
1737static void dequantize_mul_mat_vec_q8_0_sycl(const void *vx, const dfloat *y,
1738                                             float *dst, const int ncols,
1739                                             const int nrows,
1740                                             dpct::queue_ptr stream) {
1741    GGML_ASSERT(ncols % GGML_SYCL_DMMV_X == 0);
1742    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1743    const sycl::range<3> block_nums(1, 1, block_num_y);
1744    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1745    {
1746        dpct::has_capability_or_fail(stream->get_device(),
1747                                     {sycl::aspect::fp16});
1748
1749        stream->parallel_for(
1750            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1751            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1752                dequantize_mul_mat_vec<QK8_0, QR8_0, dequantize_q8_0>(
1753                    vx, y, dst, ncols, nrows, item_ct1);
1754            });
1755    }
1756}
1757
1758static void dequantize_mul_mat_vec_q2_K_sycl(const void *vx, const float *y,
1759                                             float *dst, const int ncols,
1760                                             const int nrows,
1761                                             dpct::queue_ptr stream) {
1762    GGML_ASSERT(ncols % QK_K == 0);
1763    const int ny = 2; // very slightly faster than 1 even when K_QUANTS_PER_ITERATION = 2
1764    const int block_num_y = (nrows + ny - 1) / ny;
1765    const sycl::range<3> block_nums(1, 1, block_num_y);
1766    const sycl::range<3> block_dims(1, ny, WARP_SIZE);
1767    stream->parallel_for(
1768        sycl::nd_range<3>(block_nums * block_dims, block_dims),
1769        [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1770            dequantize_mul_mat_vec_q2_k(vx, y, dst, ncols, nrows, item_ct1);
1771        });
1772}
1773
1774static void dequantize_mul_mat_vec_q2_K_sycl_reorder(const void *vx, const float *y,
1775                                                     float *dst, const int ncols,
1776                                                     const int nrows,
1777                                                     dpct::queue_ptr stream) {
1778    GGML_ASSERT(ncols % QK_K == 0);
1779    const int ny = 2 / K_QUANTS_PER_ITERATION;
1780    const int block_num_y = (nrows + ny - 1) / ny;
1781    const sycl::range<3> block_nums(1, 1, block_num_y);
1782    const sycl::range<3> block_dims(1, ny, WARP_SIZE);
1783    stream->parallel_for(
1784        sycl::nd_range<3>(block_nums * block_dims, block_dims),
1785        [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1786            dequantize_mul_mat_vec_q2_k_reorder(vx, y, dst, ncols, nrows, item_ct1);
1787        });
1788}
1789
1790static void dequantize_mul_mat_vec_q3_K_sycl(const void *vx, const float *y,
1791                                             float *dst, const int ncols,
1792                                             const int nrows,
1793                                             dpct::queue_ptr stream) {
1794    GGML_ASSERT(ncols % QK_K == 0);
1795    const int ny = 2 / K_QUANTS_PER_ITERATION;
1796    const int block_num_y = (nrows + ny - 1) / ny;
1797    const sycl::range<3> block_nums(1, 1, block_num_y);
1798    const sycl::range<3> block_dims(1, ny, WARP_SIZE);
1799    stream->parallel_for(
1800        sycl::nd_range<3>(block_nums * block_dims, block_dims),
1801        [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1802            dequantize_mul_mat_vec_q3_k(vx, y, dst, ncols, nrows, item_ct1);
1803        });
1804}
1805
1806static void dequantize_mul_mat_vec_q3_K_sycl_reorder(const void *vx, const float *y,
1807                                                     float *dst, const int ncols,
1808                                                     const int nrows,
1809                                                     dpct::queue_ptr stream) {
1810    GGML_ASSERT(ncols % QK_K == 0);
1811    const int ny = 2 / K_QUANTS_PER_ITERATION;
1812    const int block_num_y = (nrows + ny - 1) / ny;
1813    const sycl::range<3> block_nums(1, 1, block_num_y);
1814    const sycl::range<3> block_dims(1, ny, WARP_SIZE);
1815    stream->parallel_for(
1816        sycl::nd_range<3>(block_nums * block_dims, block_dims),
1817        [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1818            dequantize_mul_mat_vec_q3_k_reorder(vx, y, dst, ncols, nrows, item_ct1);
1819        });
1820}
1821
1822static void dequantize_mul_mat_vec_q4_K_sycl(const void *vx, const float *y,
1823                                             float *dst, const int ncols,
1824                                             const int nrows,
1825                                             dpct::queue_ptr stream) {
1826    GGML_ASSERT(ncols % QK_K == 0);
1827    const int ny = 2 / K_QUANTS_PER_ITERATION;
1828    const int block_num_y = (nrows + ny - 1) / ny;
1829    const sycl::range<3> block_nums(1, 1, block_num_y);
1830    const sycl::range<3> block_dims(1, ny, WARP_SIZE);
1831    stream->parallel_for(
1832        sycl::nd_range<3>(block_nums * block_dims, block_dims),
1833        [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1834            dequantize_mul_mat_vec_q4_k(vx, y, dst, ncols, nrows, item_ct1);
1835        });
1836}
1837
1838static void dequantize_mul_mat_vec_q5_K_sycl(const void *vx, const float *y,
1839                                             float *dst, const int ncols,
1840                                             const int nrows,
1841                                             dpct::queue_ptr stream) {
1842    GGML_ASSERT(ncols % QK_K == 0);
1843    const int ny = 2 / K_QUANTS_PER_ITERATION;
1844    const int block_num_y = (nrows + ny - 1) / ny;
1845    const sycl::range<3> block_nums(1, 1, block_num_y);
1846    const sycl::range<3> block_dims(1, ny, WARP_SIZE);
1847    stream->parallel_for(
1848        sycl::nd_range<3>(block_nums * block_dims, block_dims),
1849        [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1850            dequantize_mul_mat_vec_q5_k(vx, y, dst, ncols, nrows, item_ct1);
1851        });
1852}
1853
1854static void dequantize_mul_mat_vec_q6_K_sycl(const void *vx, const float *y,
1855                                             float *dst, const int ncols,
1856                                             const int nrows,
1857                                             dpct::queue_ptr stream) {
1858    GGML_ASSERT(ncols % QK_K == 0);
1859    const int ny = 2 / K_QUANTS_PER_ITERATION;
1860    const int block_num_y = (nrows + ny - 1) / ny;
1861    const sycl::range<3> block_nums(1, 1, block_num_y);
1862    const sycl::range<3> block_dims(1, ny, WARP_SIZE);
1863    stream->parallel_for(
1864        sycl::nd_range<3>(block_nums * block_dims, block_dims),
1865        [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1866            dequantize_mul_mat_vec_q6_k(vx, y, dst, ncols, nrows, item_ct1);
1867        });
1868}
1869
1870#ifdef GGML_SYCL_DMMV_HAS_ESIMD
1871using ggml_sycl_esimd::GGML_SYCL_DMMV_ESIMD_WG_SIZE;
1872
1873// generic reordered dequantize-matvec: each work-group owns a pair of
1874// consecutive output rows and updates one 32-wide accumulator per row
1875template <ggml_type T>
1876ESIMD_INLINE void dequantize_mul_mat_vec_reorder_esimd(
1877        const void * vx, const float * y, float * dst,
1878        const int ncols, const int nrows,
1879        sycl::local_accessor<float, 1> lmem,
1880        const sycl::nd_item<1> & it) {
1881    using namespace sycl::ext::intel::esimd;
1882    using traits = ggml_sycl_esimd::esimd_reorder_q_traits<T>;
1883
1884    const int    num_blocks_per_row = ncols / QK_K;
1885    const size_t nb = (size_t) nrows * num_blocks_per_row;
1886    const auto   ps = traits::make_ptrs(vx, nb);
1887
1888    const int  tid      = it.get_local_id(0);
1889    const int  row_pair = it.get_group(0);
1890    const int  row0     = row_pair * 2; // two consecutive output rows
1891    const bool has_row1 = row0 + 1 < nrows;
1892
1893    // one 32-wide accumulator per output row (small footprint, no spill)
1894    simd<float, 32> acc0 = 0.0f;
1895    simd<float, 32> acc1 = 0.0f;
1896
1897    for (int ib = tid; ib < num_blocks_per_row; ib += GGML_SYCL_DMMV_ESIMD_WG_SIZE) {
1898        simd<float, 256> y_vec = block_load<float, 256>(y + (size_t) ib * QK_K);
1899
1900        const size_t bi0 = (size_t) (row0 + 0) * num_blocks_per_row + ib;
1901        const size_t bi1 = (size_t) (row0 + 1) * num_blocks_per_row + ib;
1902
1903        traits::mac_pair(ps, bi0, ps, bi1, has_row1, y_vec, acc0, acc1);
1904    }
1905
1906    lmem[tid * 2 + 0] = reduce<float>(acc0, std::plus<>{});
1907    lmem[tid * 2 + 1] = reduce<float>(acc1, std::plus<>{});
1908    it.barrier(sycl::access::fence_space::local_space);
1909
1910    if (tid == 0) {
1911        float sum0 = 0.0f;
1912        float sum1 = 0.0f;
1913        for (int p = 0; p < GGML_SYCL_DMMV_ESIMD_WG_SIZE; ++p) {
1914            sum0 += lmem[p * 2 + 0];
1915            sum1 += lmem[p * 2 + 1];
1916        }
1917        dst[row0 + 0] = sum0;
1918        if (has_row1) {
1919            dst[row0 + 1] = sum1;
1920        }
1921    }
1922}
1923
1924static void dequantize_mul_mat_vec_q2_K_sycl_reorder_esimd(const void *vx, const float *y,
1925                                                           float *dst, const int ncols,
1926                                                           const int nrows,
1927                                                           dpct::queue_ptr stream) {
1928    GGML_ASSERT(ncols % QK_K == 0);
1929    const int workgroups = (nrows + 1) / 2;
1930    stream->submit([&](sycl::handler &h) {
1931        sycl::local_accessor<float, 1> lmem(sycl::range<1>(GGML_SYCL_DMMV_ESIMD_WG_SIZE * 2), h);
1932        h.parallel_for(
1933            sycl::nd_range<1>(sycl::range<1>((size_t)workgroups * GGML_SYCL_DMMV_ESIMD_WG_SIZE), sycl::range<1>(GGML_SYCL_DMMV_ESIMD_WG_SIZE)),
1934            [=](sycl::nd_item<1> it) [[intel::sycl_explicit_simd]] {
1935                dequantize_mul_mat_vec_reorder_esimd<GGML_TYPE_Q2_K>(
1936                    vx, y, dst, ncols, nrows, lmem, it);
1937            });
1938    });
1939}
1940
1941static void dequantize_mul_mat_vec_q3_K_sycl_reorder_esimd(const void *vx, const float *y,
1942                                                           float *dst, const int ncols,
1943                                                           const int nrows,
1944                                                           dpct::queue_ptr stream) {
1945    GGML_ASSERT(ncols % QK_K == 0);
1946    const int workgroups = (nrows + 1) / 2;
1947    stream->submit([&](sycl::handler &h) {
1948        sycl::local_accessor<float, 1> lmem(sycl::range<1>(GGML_SYCL_DMMV_ESIMD_WG_SIZE * 2), h);
1949        h.parallel_for(
1950            sycl::nd_range<1>(sycl::range<1>((size_t)workgroups * GGML_SYCL_DMMV_ESIMD_WG_SIZE), sycl::range<1>(GGML_SYCL_DMMV_ESIMD_WG_SIZE)),
1951            [=](sycl::nd_item<1> it) [[intel::sycl_explicit_simd]] {
1952                dequantize_mul_mat_vec_reorder_esimd<GGML_TYPE_Q3_K>(
1953                    vx, y, dst, ncols, nrows, lmem, it);
1954            });
1955    });
1956}
1957
1958static void dequantize_mul_mat_vec_q4_K_sycl_reorder_esimd(const void *vx, const float *y,
1959                                                           float *dst, const int ncols,
1960                                                           const int nrows,
1961                                                           dpct::queue_ptr stream) {
1962    GGML_ASSERT(ncols % QK_K == 0);
1963    const int workgroups = (nrows + 1) / 2;
1964    stream->submit([&](sycl::handler &h) {
1965        sycl::local_accessor<float, 1> lmem(sycl::range<1>(GGML_SYCL_DMMV_ESIMD_WG_SIZE * 2), h);
1966        h.parallel_for(
1967            sycl::nd_range<1>(sycl::range<1>((size_t)workgroups * GGML_SYCL_DMMV_ESIMD_WG_SIZE), sycl::range<1>(GGML_SYCL_DMMV_ESIMD_WG_SIZE)),
1968            [=](sycl::nd_item<1> it) [[intel::sycl_explicit_simd]] {
1969                dequantize_mul_mat_vec_reorder_esimd<GGML_TYPE_Q4_K>(
1970                    vx, y, dst, ncols, nrows, lmem, it);
1971            });
1972    });
1973}
1974
1975static void dequantize_mul_mat_vec_q5_K_sycl_reorder_esimd(const void *vx, const float *y,
1976                                                           float *dst, const int ncols,
1977                                                           const int nrows,
1978                                                           dpct::queue_ptr stream) {
1979    GGML_ASSERT(ncols % QK_K == 0);
1980    const int workgroups = (nrows + 1) / 2;
1981    stream->submit([&](sycl::handler &h) {
1982        sycl::local_accessor<float, 1> lmem(sycl::range<1>(GGML_SYCL_DMMV_ESIMD_WG_SIZE * 2), h);
1983        h.parallel_for(
1984            sycl::nd_range<1>(sycl::range<1>((size_t)workgroups * GGML_SYCL_DMMV_ESIMD_WG_SIZE), sycl::range<1>(GGML_SYCL_DMMV_ESIMD_WG_SIZE)),
1985            [=](sycl::nd_item<1> it) [[intel::sycl_explicit_simd]] {
1986                dequantize_mul_mat_vec_reorder_esimd<GGML_TYPE_Q5_K>(
1987                    vx, y, dst, ncols, nrows, lmem, it);
1988            });
1989    });
1990}
1991
1992static void dequantize_mul_mat_vec_q6_K_sycl_reorder_esimd(const void *vx, const float *y,
1993                                                           float *dst, const int ncols,
1994                                                           const int nrows,
1995                                                           dpct::queue_ptr stream) {
1996    GGML_ASSERT(ncols % QK_K == 0);
1997    const int workgroups = (nrows + 1) / 2;
1998    stream->submit([&](sycl::handler &h) {
1999        sycl::local_accessor<float, 1> lmem(sycl::range<1>(GGML_SYCL_DMMV_ESIMD_WG_SIZE * 2), h);
2000        h.parallel_for(
2001            sycl::nd_range<1>(sycl::range<1>((size_t)workgroups * GGML_SYCL_DMMV_ESIMD_WG_SIZE), sycl::range<1>(GGML_SYCL_DMMV_ESIMD_WG_SIZE)),
2002            [=](sycl::nd_item<1> it) [[intel::sycl_explicit_simd]] {
2003                dequantize_mul_mat_vec_reorder_esimd<GGML_TYPE_Q6_K>(
2004                    vx, y, dst, ncols, nrows, lmem, it);
2005            });
2006    });
2007}
2008
2009#endif // GGML_SYCL_DMMV_HAS_ESIMD
2010
2011static void dequantize_mul_mat_vec_q4_K_sycl_reorder(const void *vx, const float *y,
2012                                                     float *dst, const int ncols,
2013                                                     const int nrows,
2014                                                     dpct::queue_ptr stream) {
2015    GGML_ASSERT(ncols % QK_K == 0);
2016    const int ny = 2 / K_QUANTS_PER_ITERATION;
2017    const int block_num_y = (nrows + ny - 1) / ny;
2018    const sycl::range<3> block_nums(1, 1, block_num_y);
2019    const sycl::range<3> block_dims(1, ny, WARP_SIZE);
2020    stream->parallel_for(
2021        sycl::nd_range<3>(block_nums * block_dims, block_dims),
2022        [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2023            dequantize_mul_mat_vec_q4_k_reorder(vx, y, dst, ncols, nrows, item_ct1);
2024        });
2025}
2026
2027static void dequantize_mul_mat_vec_q5_K_sycl_reorder(const void *vx, const float *y,
2028                                                     float *dst, const int ncols,
2029                                                     const int nrows,
2030                                                     dpct::queue_ptr stream) {
2031    GGML_ASSERT(ncols % QK_K == 0);
2032    const int ny = 2 / K_QUANTS_PER_ITERATION;
2033    const int block_num_y = (nrows + ny - 1) / ny;
2034    const sycl::range<3> block_nums(1, 1, block_num_y);
2035    const sycl::range<3> block_dims(1, ny, WARP_SIZE);
2036    stream->parallel_for(
2037        sycl::nd_range<3>(block_nums * block_dims, block_dims),
2038        [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2039            dequantize_mul_mat_vec_q5_k_reorder(vx, y, dst, ncols, nrows, item_ct1);
2040        });
2041}
2042
2043static void dequantize_mul_mat_vec_q6_K_sycl_reorder(const void *vx, const float *y,
2044                                                     float *dst, const int ncols,
2045                                                     const int nrows,
2046                                                     dpct::queue_ptr stream) {
2047    GGML_ASSERT(ncols % QK_K == 0);
2048    const int ny = 2 / K_QUANTS_PER_ITERATION;
2049    const int block_num_y = (nrows + ny - 1) / ny;
2050    const sycl::range<3> block_nums(1, 1, block_num_y);
2051    const sycl::range<3> block_dims(1, ny, WARP_SIZE);
2052    stream->parallel_for(
2053        sycl::nd_range<3>(block_nums * block_dims, block_dims),
2054        [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2055            dequantize_mul_mat_vec_q6_k_reorder(vx, y, dst, ncols, nrows, item_ct1);
2056        });
2057}
2058
2059void ggml_sycl_op_dequantize_mul_mat_vec(
2060    ggml_backend_sycl_context & ctx,
2061    const ggml_tensor *src0, const ggml_tensor *src1, ggml_tensor *dst,
2062    const char *src0_dd_i, const float *src1_ddf_i, const char *src1_ddq_i,
2063    float *dst_dd_i, const int64_t row_low, const int64_t row_high,
2064    const int64_t src1_ncols, const int64_t src1_padded_row_size,
2065    const dpct::queue_ptr &stream) {
2066
2067    const int64_t ne00 = src0->ne[0];
2068    const int64_t row_diff = row_high - row_low;
2069    GGML_ASSERT(src1->type == GGML_TYPE_F32);
2070    // on some GPUs it is faster to convert src1 to half and to use half precision intrinsics
2071#ifdef GGML_SYCL_F16
2072    ggml_sycl_pool_alloc<sycl::half> src1_dfloat_a(ctx.pool());
2073    sycl::half *src1_dfloat = nullptr; // dfloat == half
2074
2075    bool src1_convert_f16 =
2076        src0->type == GGML_TYPE_Q1_0 ||
2077        src0->type == GGML_TYPE_Q4_0 || src0->type == GGML_TYPE_Q4_1 ||
2078        src0->type == GGML_TYPE_Q5_0 || src0->type == GGML_TYPE_Q5_1 ||
2079        src0->type == GGML_TYPE_Q8_0 || src0->type == GGML_TYPE_F16 ||
2080        src0->type == GGML_TYPE_BF16;
2081
2082    if (src1_convert_f16) {
2083        scope_op_debug_print scope_dbg_print(__func__, "/to_fp16_sycl", dst, /*num_src=*/2,
2084                                             " : converting src1 to fp16");
2085        src1_dfloat = src1_dfloat_a.alloc(ne00);
2086        const to_fp16_sycl_t to_fp16_sycl = ggml_get_to_fp16_sycl(src1->type, dst);
2087        GGML_ASSERT(to_fp16_sycl != nullptr);
2088        to_fp16_sycl(src1_ddf_i, src1_dfloat, ne00, stream);
2089    }
2090#else
2091    const dfloat * src1_dfloat = (const dfloat *) src1_ddf_i; // dfloat == float, no conversion
2092#endif // GGML_SYCL_F16
2093
2094    switch (src0->type) {
2095        case GGML_TYPE_Q1_0:
2096            if ((ggml_tensor_extra_gpu*)dst->src[0]->extra &&
2097                ((ggml_tensor_extra_gpu*)dst->src[0]->extra)->optimized_feature.reorder) {
2098                dequantize_mul_mat_vec_q1_0_sycl_reorder(src0_dd_i, src1_dfloat, dst_dd_i, ne00, row_diff, stream);
2099            } else {
2100                dequantize_mul_mat_vec_q1_0_sycl(src0_dd_i, src1_dfloat, dst_dd_i, ne00, row_diff, stream);
2101            }
2102            break;
2103        case GGML_TYPE_Q4_0:
2104            if ((ggml_tensor_extra_gpu*)dst->src[0]->extra &&
2105                ((ggml_tensor_extra_gpu*)dst->src[0]->extra)->optimized_feature.reorder) {
2106                dequantize_mul_mat_vec_q4_0_sycl_reorder(src0_dd_i, src1_dfloat, dst_dd_i, ne00, row_diff, stream);
2107            } else {
2108                dequantize_mul_mat_vec_q4_0_sycl(src0_dd_i, src1_dfloat, dst_dd_i, ne00, row_diff, stream);
2109            }
2110            break;
2111        case GGML_TYPE_Q4_1:
2112            dequantize_mul_mat_vec_q4_1_sycl(src0_dd_i, src1_dfloat, dst_dd_i, ne00, row_diff, stream);
2113            break;
2114        case GGML_TYPE_Q5_0:
2115            dequantize_mul_mat_vec_q5_0_sycl(src0_dd_i, src1_dfloat, dst_dd_i, ne00, row_diff, stream);
2116            break;
2117        case GGML_TYPE_Q5_1:
2118            dequantize_mul_mat_vec_q5_1_sycl(src0_dd_i, src1_dfloat, dst_dd_i, ne00, row_diff, stream);
2119            break;
2120        case GGML_TYPE_Q8_0:
2121            if ((ggml_tensor_extra_gpu *) dst->src[0]->extra &&
2122                ((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
2123                dequantize_mul_mat_vec_q8_0_sycl_reorder(src0_dd_i, src1_dfloat, dst_dd_i, ne00, row_diff, stream);
2124            } else {
2125                dequantize_mul_mat_vec_q8_0_sycl(src0_dd_i, src1_dfloat, dst_dd_i, ne00, row_diff, stream);
2126            }
2127            break;
2128        case GGML_TYPE_Q2_K:
2129            if ((ggml_tensor_extra_gpu *) dst->src[0]->extra &&
2130                ((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
2131#ifdef GGML_SYCL_DMMV_HAS_ESIMD
2132                if (g_ggml_sycl_enable_esimd) {
2133                    dequantize_mul_mat_vec_q2_K_sycl_reorder_esimd(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2134                }
2135                else
2136#endif
2137                {
2138                    dequantize_mul_mat_vec_q2_K_sycl_reorder(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2139                }
2140            } else {
2141                dequantize_mul_mat_vec_q2_K_sycl(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2142            }
2143            break;
2144        case GGML_TYPE_Q3_K:
2145            if ((ggml_tensor_extra_gpu *) dst->src[0]->extra &&
2146                ((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
2147#ifdef GGML_SYCL_DMMV_HAS_ESIMD
2148                if (g_ggml_sycl_enable_esimd) {
2149                    dequantize_mul_mat_vec_q3_K_sycl_reorder_esimd(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2150                }
2151                else
2152#endif
2153                {
2154                    dequantize_mul_mat_vec_q3_K_sycl_reorder(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2155                }
2156            } else {
2157                dequantize_mul_mat_vec_q3_K_sycl(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2158            }
2159            break;
2160        case GGML_TYPE_Q4_K:
2161            if ((ggml_tensor_extra_gpu *) dst->src[0]->extra &&
2162                ((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
2163#ifdef GGML_SYCL_DMMV_HAS_ESIMD
2164                if (g_ggml_sycl_enable_esimd) {
2165                    dequantize_mul_mat_vec_q4_K_sycl_reorder_esimd(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2166                }
2167                else
2168#endif
2169                {
2170                    dequantize_mul_mat_vec_q4_K_sycl_reorder(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2171                }
2172            } else {
2173                dequantize_mul_mat_vec_q4_K_sycl(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2174            }
2175            break;
2176        case GGML_TYPE_Q5_K:
2177            if ((ggml_tensor_extra_gpu *) dst->src[0]->extra &&
2178                ((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
2179#ifdef GGML_SYCL_DMMV_HAS_ESIMD
2180                if (g_ggml_sycl_enable_esimd) {
2181                    dequantize_mul_mat_vec_q5_K_sycl_reorder_esimd(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2182                }
2183                else
2184#endif
2185                {
2186                    dequantize_mul_mat_vec_q5_K_sycl_reorder(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2187                }
2188            } else {
2189                dequantize_mul_mat_vec_q5_K_sycl(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2190            }
2191            break;
2192        case GGML_TYPE_Q6_K:
2193            if ((ggml_tensor_extra_gpu *) dst->src[0]->extra &&
2194                ((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
2195#ifdef GGML_SYCL_DMMV_HAS_ESIMD
2196                if (g_ggml_sycl_enable_esimd) {
2197                    dequantize_mul_mat_vec_q6_K_sycl_reorder_esimd(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2198                }
2199                else
2200#endif
2201                {
2202                    dequantize_mul_mat_vec_q6_K_sycl_reorder(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2203                }
2204            } else {
2205                dequantize_mul_mat_vec_q6_K_sycl(src0_dd_i, src1_ddf_i, dst_dd_i, ne00, row_diff, stream);
2206            }
2207            break;
2208        case GGML_TYPE_F16:
2209            convert_mul_mat_vec_f16_sycl(src0_dd_i, src1_dfloat, dst_dd_i, ne00, row_diff, stream);
2210            break;
2211#ifdef GGML_SYCL_DMMV_HAS_BF16
2212        case GGML_TYPE_BF16:
2213            convert_mul_mat_vec_bf16_sycl(src0_dd_i, src1_dfloat, dst_dd_i, ne00, row_diff, stream);
2214            break;
2215#endif
2216        default:
2217            printf("ggml_sycl_op_dequantize_mul_mat_vec unsupported GGML_TYPE %d\n", src0->type);
2218            GGML_ABORT("fatal error");
2219    }
2220
2221    GGML_UNUSED(src1);
2222    GGML_UNUSED(dst);
2223    GGML_UNUSED(src1_ddq_i);
2224    GGML_UNUSED(src1_ncols);
2225    GGML_UNUSED(src1_padded_row_size);
2226    GGML_UNUSED(ctx);
2227}