char-fork/llama.cpp

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

cwriterAdd IQ type handling for MoE (#28476)304665fe7

char/aliceai-t5-moe
157.7 KiB3106 linesraw
1#include "mmvq.hpp"
2
3#include "ggml.h"
4#include "common.hpp"
5#include "element_wise.hpp"
6#include "quants.hpp"
7#include "vecdotq.hpp"
8
9// Minimum weight-row count at which the Q4_K multi-column MMVQ kernel handles two output rows per
10// subgroup (rows_per_sg == 2) instead of one, when ncols_dst == 2.
11//
12// Pairing rows lets a subgroup load each activation block once and apply it to two rows, at the cost
13// of halving the number of subgroups in the launch. With only two destination columns there is too
14// little work per row to hide that loss of parallelism, so pairing only pays off once there are
15// enough rows to keep the device occupied. This is a measured performance crossover, not a
16// correctness or hardware limit - both variants compute the same result for any nrows.
17//
18// Derived on Intel Arc Pro B70 with `test-backend-ops perf -o MUL_MAT` (Q4_K, ncols_dst == 2),
19// sweeping nrows over 5120..6912 at ncols 17408 and 19968: one row per subgroup was up to 9% faster
20// below the crossover, two rows per subgroup 8-15% faster above it, and the crossover fell inside
21// (6144, 6272] for both ncols with no measurable ncols dependence. A later 32-row granularity sweep
22// narrowed it to (6144, 6176], so 6272 is a conservative gate rather than the exact crossover.
23// ncols_dst >= 3 amortizes the activation loads over more columns and is faster with two rows at
24// every row count, so it does not consult this threshold.
25static constexpr int Q4_K_MMVQ_ROW_PAIR_MIN_NROWS = 6272;
26
27template <typename reorder_vec_dot_q_sycl>
28static void mul_mat_vec_q_reorder(const void * __restrict__ vx, const void * __restrict__ vy, float * __restrict__ dst,
29                                  const int ncols, const int nrows, const sycl::nd_item<3> & nd_item) {
30    using block_type   = ggml_sycl_reordered::block_q_t<reorder_vec_dot_q_sycl::gtype>;
31    using block_traits = typename block_type::traits;
32
33    const auto sg           = nd_item.get_sub_group();
34    const int  sg_range     = sg.get_group_linear_range();
35    const int  workgroup_id = nd_item.get_group_linear_id();
36    const int  sg_id        = sg.get_group_linear_id();
37    const int  row          = workgroup_id * sg_range + sg_id;
38
39    if (row >= nrows) {
40        return;
41    }
42
43    const int     blocks_per_row              = ncols / block_traits::qk;
44    constexpr int blocks_per_subgroup         = ceil_div(block_traits::vdr_mmvq * WARP_SIZE, block_traits::qi);
45    constexpr int block_elements_per_subgroup = block_traits::qi / block_traits::vdr_mmvq;
46    const int     nblocks                     = nrows * (ncols / block_traits::qk);
47
48    static_assert(blocks_per_subgroup > 0);
49    static_assert(block_elements_per_subgroup > 0);
50
51    float partial_sum = 0.0f;
52    for (int i = sg.get_local_linear_id() / block_elements_per_subgroup; i < blocks_per_row; i += blocks_per_subgroup) {
53        const int ibx = row * blocks_per_row + i;  // x block index
54
55        const auto         bx_offset      = block_type::get_block_offset(ibx, nblocks);
56        const auto         d_offset       = block_type::get_d_offset(nrows, ncols, ibx);
57        // Y block index that aligns with ibx
58        const int iby = i * block_type::block_to_q8_1_ratio();
59        const int8_t* q8_1_quant_ptr = (const int8_t*)vy + iby * QK8_1;
60        const sycl::half2* q8_1_ds_ptr = (const sycl::half2*)((const char*)vy + ncols + iby * sizeof(sycl::half2));
61
62#pragma unroll
63        for (int elem = 0; elem < block_elements_per_subgroup; elem += WARP_SIZE) {
64            // x block quant index when casting the quants to int
65            const int iqs = elem + block_traits::vdr_mmvq * (sg.get_local_linear_id() % block_elements_per_subgroup);
66
67            partial_sum += reorder_vec_dot_q_sycl()(vx, bx_offset, d_offset, q8_1_quant_ptr, q8_1_ds_ptr, iqs);
68        }
69    }
70
71    auto sum = sycl::reduce_over_group(nd_item.get_sub_group(), partial_sum, std::plus<>());
72
73    if (sg.leader()) {
74        dst[row] = sum;
75    }
76}
77
78// With has_fusion, `vgate` is a second weight matrix sharing vx's shape, stride and reorder
79// layout: one pass computes both row dot products and the epilogue writes glu(gate, up).
80template <typename reorder_vec_dot_q_sycl, int ncols_dst, bool has_fusion = false, int rows_per_sg = 1>
81static void mul_mat_vec_q_reorder_ncols(const void * __restrict__ vx, const void * __restrict__ vgate,
82                                        const void * __restrict__ vy, float * __restrict__ dst, const int ncols,
83                                        const int nrows, const int stride_col_y_bytes, const int stride_col_dst,
84                                        const ggml_glu_op glu_op, const sycl::nd_item<3> & nd_item) {
85    using block_type   = ggml_sycl_reordered::block_q_t<reorder_vec_dot_q_sycl::gtype>;
86    using block_traits = typename block_type::traits;
87
88    const auto sg           = nd_item.get_sub_group();
89    const int  sg_range     = sg.get_group_linear_range();
90    const int  workgroup_id = nd_item.get_group_linear_id();
91    const int  sg_id        = sg.get_group_linear_id();
92    const int  row0         = (workgroup_id * sg_range + sg_id) * rows_per_sg;
93
94    // row is sub-group uniform, so this retires whole sub-groups and the collectives below
95    // stay convergent
96    if (row0 >= nrows) {
97        return;
98    }
99
100    static_assert(rows_per_sg == 1 ||
101                  reorder_vec_dot_shared_activations<reorder_vec_dot_q_sycl::gtype>::value);
102
103    const int     blocks_per_row              = ncols / block_traits::qk;
104    constexpr int blocks_per_subgroup         = ceil_div(block_traits::vdr_mmvq * WARP_SIZE, block_traits::qi);
105    constexpr int block_elements_per_subgroup = block_traits::qi / block_traits::vdr_mmvq;
106    const int     nblocks                     = nrows * (ncols / block_traits::qk);
107
108    static_assert(blocks_per_subgroup > 0);
109    static_assert(block_elements_per_subgroup > 0);
110
111    float partial_sum[ncols_dst][rows_per_sg] = {};
112    // sized 1 rather than 0 when unused: zero-length arrays are not standard C++, and the
113    // array is dead and eliminated in that case
114    [[maybe_unused]] float partial_gate[has_fusion ? ncols_dst : 1][has_fusion ? rows_per_sg : 1] = {};
115    for (int i = sg.get_local_linear_id() / block_elements_per_subgroup; i < blocks_per_row; i += blocks_per_subgroup) {
116        const int  iby       = i * block_type::block_to_q8_1_ratio();
117
118#pragma unroll
119        for (int elem = 0; elem < block_elements_per_subgroup; elem += WARP_SIZE) {
120            const int iqs = elem + block_traits::vdr_mmvq * (sg.get_local_linear_id() % block_elements_per_subgroup);
121
122            if constexpr (rows_per_sg > 1) {
123                typename reorder_vec_dot_q_sycl::weights wx[rows_per_sg];
124                [[maybe_unused]] typename reorder_vec_dot_q_sycl::weights wg[rows_per_sg];
125#pragma unroll
126                for (int r = 0; r < rows_per_sg; ++r) {
127                    const int row = sycl::min(row0 + r, nrows - 1);
128                    const int ibx = row * blocks_per_row + i;
129                    const auto bx_offset = block_type::get_block_offset(ibx, nblocks);
130                    const auto d_offset  = block_type::get_d_offset(nrows, ncols, ibx);
131                    wx[r] = reorder_vec_dot_q_sycl::load(vx, bx_offset, d_offset, iqs);
132                    if constexpr (has_fusion) {
133                        wg[r] = reorder_vec_dot_q_sycl::load(vgate, bx_offset, d_offset, iqs);
134                    }
135                }
136#pragma unroll
137                for (int j = 0; j < ncols_dst; ++j) {
138                    const char        * vy_j           = (const char *) vy + j * stride_col_y_bytes;
139                    const int8_t      * q8_1_quant_ptr = (const int8_t *) vy_j + iby * QK8_1;
140                    const sycl::half2 * q8_1_ds_ptr =
141                        (const sycl::half2 *) (vy_j + ncols + iby * sizeof(sycl::half2));
142                    const auto a = reorder_vec_dot_q_sycl::load_activations(q8_1_quant_ptr, q8_1_ds_ptr, iqs);
143#pragma unroll
144                    for (int r = 0; r < rows_per_sg; ++r) {
145                        partial_sum[j][r] += reorder_vec_dot_q_sycl::apply(wx[r], a);
146                        if constexpr (has_fusion) {
147                            partial_gate[j][r] += reorder_vec_dot_q_sycl::apply(wg[r], a);
148                        }
149                    }
150                }
151            } else if constexpr (reorder_vec_dot_shared_weights<reorder_vec_dot_q_sycl::gtype>::value) {
152                const int ibx = row0 * blocks_per_row + i;
153                const auto bx_offset = block_type::get_block_offset(ibx, nblocks);
154                const auto d_offset  = block_type::get_d_offset(nrows, ncols, ibx);
155                const auto wx = reorder_vec_dot_q_sycl::load(vx, bx_offset, d_offset, iqs);
156                if constexpr (has_fusion) {
157                    const auto wg = reorder_vec_dot_q_sycl::load(vgate, bx_offset, d_offset, iqs);
158
159#pragma unroll
160                    for (int j = 0; j < ncols_dst; ++j) {
161                        const char        * vy_j           = (const char *) vy + j * stride_col_y_bytes;
162                        const int8_t      * q8_1_quant_ptr = (const int8_t *) vy_j + iby * QK8_1;
163                        const sycl::half2 * q8_1_ds_ptr =
164                            (const sycl::half2 *) (vy_j + ncols + iby * sizeof(sycl::half2));
165
166                        // up and gate share the activation, so load it once and apply it twice
167                        const auto a = reorder_vec_dot_q_sycl::load_activations(q8_1_quant_ptr, q8_1_ds_ptr, iqs);
168
169                        partial_sum[j][0] += reorder_vec_dot_q_sycl::apply(wx, a);
170                        partial_gate[j][0] += reorder_vec_dot_q_sycl::apply(wg, a);
171                    }
172                } else {
173#pragma unroll
174                    for (int j = 0; j < ncols_dst; ++j) {
175                        const char        * vy_j           = (const char *) vy + j * stride_col_y_bytes;
176                        const int8_t      * q8_1_quant_ptr = (const int8_t *) vy_j + iby * QK8_1;
177                        const sycl::half2 * q8_1_ds_ptr =
178                            (const sycl::half2 *) (vy_j + ncols + iby * sizeof(sycl::half2));
179
180                        partial_sum[j][0] += reorder_vec_dot_q_sycl::dot(wx, q8_1_quant_ptr, q8_1_ds_ptr, iqs);
181                    }
182                }
183            } else {
184                const int ibx = row0 * blocks_per_row + i;
185                const auto bx_offset = block_type::get_block_offset(ibx, nblocks);
186                const auto d_offset  = block_type::get_d_offset(nrows, ncols, ibx);
187#pragma unroll
188                for (int j = 0; j < ncols_dst; ++j) {
189                    const char        * vy_j           = (const char *) vy + j * stride_col_y_bytes;
190                    const int8_t      * q8_1_quant_ptr = (const int8_t *) vy_j + iby * QK8_1;
191                    const sycl::half2 * q8_1_ds_ptr =
192                        (const sycl::half2 *) (vy_j + ncols + iby * sizeof(sycl::half2));
193
194                    partial_sum[j][0] +=
195                        reorder_vec_dot_q_sycl()(vx, bx_offset, d_offset, q8_1_quant_ptr, q8_1_ds_ptr, iqs);
196
197                    if constexpr (has_fusion) {
198                        partial_gate[j][0] +=
199                            reorder_vec_dot_q_sycl()(vgate, bx_offset, d_offset, q8_1_quant_ptr, q8_1_ds_ptr, iqs);
200                    }
201                }
202            }
203        }
204    }
205
206#pragma unroll
207    for (int j = 0; j < ncols_dst; ++j) {
208#pragma unroll
209        for (int r = 0; r < rows_per_sg; ++r) {
210            float sum = sycl::reduce_over_group(nd_item.get_sub_group(), partial_sum[j][r], std::plus<>());
211
212            if constexpr (has_fusion) {
213                const float gate = sycl::reduce_over_group(nd_item.get_sub_group(), partial_gate[j][r], std::plus<>());
214
215                // uniform across the launch; the launcher only instantiates SWIGLU and GEGLU
216                sum *= glu_op == GGML_GLU_OP_SWIGLU ? op_silu(gate) : op_gelu(gate);
217            }
218
219            if (sg.leader() && row0 + r < nrows) {
220                dst[j * stride_col_dst + row0 + r] = sum;
221            }
222        }
223    }
224}
225
226template <int qk, int qi, typename block_q_t, int vdr, vec_dot_q_sycl_t vec_dot_q_sycl>
227static void mul_mat_vec_q(const void * __restrict__ vx, const void * __restrict__ vy, float * __restrict__ dst,
228                          const int ncols, const int nrows, const sycl::nd_item<3> & item_ct1) {
229    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) + item_ct1.get_local_id(1);
230
231    if (row >= nrows) {
232        return;
233    }
234
235    const int     blocks_per_row  = ncols / qk;
236    constexpr int blocks_per_warp = (vdr * WARP_SIZE + qi - 1) / qi;  // Ensuring blocks_per_warp > 0
237
238    assert(blocks_per_warp > 0);
239
240    // partial sum for each thread
241    float tmp = 0.0f;
242
243    const block_q_t *  x = (const block_q_t *) vx;
244    const block_q8_1 * y = (const block_q8_1 *) vy;
245
246    for (int i = item_ct1.get_local_id(2) / (qi / vdr); i < blocks_per_row; i += blocks_per_warp) {
247        const int ibx = row * blocks_per_row + i;  // x block index
248
249        const int iby = i * (qk / QK8_1);          // y block index that aligns with ibx
250
251        for (size_t elem = 0; elem < qi / vdr; elem += WARP_SIZE) {
252            const int iqs = elem + vdr * (item_ct1.get_local_id(2) %
253                                          (qi / vdr));  // x block quant index when casting the quants to int
254
255            tmp += vec_dot_q_sycl(&x[ibx], &y[iby], iqs);
256        }
257    }
258
259    // sum up partial sums and write back result
260#pragma unroll
261    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
262        tmp += dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
263    }
264
265    if (item_ct1.get_local_id(2) == 0) {
266        dst[row] = tmp;
267    }
268}
269
270template <int qk, int qi, typename block_q_t, int vdr,
271          vec_dot_q_sycl_t vec_dot_q_sycl, int ncols_dst>
272static void mul_mat_vec_q_ncols(
273        const void * __restrict__ vx,
274        const void * __restrict__ vy,
275        float * __restrict__ dst,
276        const int ncols,
277        const int nrows,
278        const int stride_col_y,
279        const int stride_col_dst,
280        const sycl::nd_item<3> & item_ct1) {
281
282    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1)
283                  + item_ct1.get_local_id(1);
284
285    if (row >= nrows) {
286        return;
287    }
288
289    const int blocks_per_row = ncols / qk;
290    constexpr int blocks_per_warp = (vdr * WARP_SIZE + qi - 1) / qi;
291
292    // partial sums: one per output column
293    float tmp[ncols_dst] = {0.0f};
294
295    const block_q_t  * x = (const block_q_t *) vx;
296    const block_q8_1 * y = (const block_q8_1 *) vy;
297
298    for (int i = item_ct1.get_local_id(2) / (qi / vdr);
299         i < blocks_per_row;
300         i += blocks_per_warp) {
301
302        const int ibx = row * blocks_per_row + i;
303        const int iby = i * (qk / QK8_1);
304
305        // read weight block once, dot against all columns
306        for (size_t elem = 0; elem < qi / vdr; elem += WARP_SIZE) {
307            const int iqs = elem + vdr * (item_ct1.get_local_id(2) % (qi / vdr));
308
309#pragma unroll
310            for (int j = 0; j < ncols_dst; ++j) {
311                tmp[j] += vec_dot_q_sycl(&x[ibx], &y[j * stride_col_y + iby], iqs);
312            }
313        }
314    }
315
316    // reduce within subgroup
317#pragma unroll
318    for (int j = 0; j < ncols_dst; ++j) {
319#pragma unroll
320        for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
321            tmp[j] += dpct::permute_sub_group_by_xor(
322                item_ct1.get_sub_group(), tmp[j], mask);
323        }
324    }
325
326    if (item_ct1.get_local_id(2) == 0) {
327#pragma unroll
328        for (int j = 0; j < ncols_dst; ++j) {
329            dst[j * stride_col_dst + row] = tmp[j];
330        }
331    }
332}
333
334template <int qk, int qi, typename block_q_t, int vdr>
335static void mul_mat_vec_q_iq2_xxs_q8_1(const void *__restrict__ vx,
336                                       const void *__restrict__ vy,
337                                       float *__restrict__ dst, const int ncols,
338                                       const int nrows,
339                                       const sycl::nd_item<3> &item_ct1) {
340    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
341                    item_ct1.get_local_id(1);
342
343    if (row >= nrows) {
344        return;
345    }
346
347    const int blocks_per_row = ncols / qk;
348    const int blocks_per_warp = vdr * WARP_SIZE / qi;
349    assert(blocks_per_warp>0);
350
351// partial sum for each thread
352    float tmp = 0.0f;
353
354    const block_q_t  * x = (const block_q_t  *) vx;
355    const block_q8_1 * y = (const block_q8_1 *) vy;
356
357    for (int i = item_ct1.get_local_id(2) / (qi / vdr); i < blocks_per_row;
358         i += blocks_per_warp) {
359        const int ibx = row*blocks_per_row + i; // x block index
360
361        const int iby = i * (qk/QK8_1); // y block index that aligns with ibx
362
363        const int iqs =
364            vdr *
365            (item_ct1.get_local_id(2) %
366             (qi / vdr)); // x block quant index when casting the quants to int
367
368        tmp += vec_dot_iq2_xxs_q8_1(&x[ibx], &y[iby], iqs, iq2xxs_grid, ksigns_iq2xs, kmask_iq2xs);
369    }
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
383template <int qk, int qi, typename block_q_t, int vdr>
384static void mul_mat_vec_q_iq2_xs_q8_1(const void *__restrict__ vx,
385                                      const void *__restrict__ vy,
386                                      float *__restrict__ dst, const int ncols,
387                                      const int nrows,
388                                      const sycl::nd_item<3> &item_ct1) {
389    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
390                    item_ct1.get_local_id(1);
391
392    if (row >= nrows) {
393        return;
394    }
395
396    const int blocks_per_row = ncols / qk;
397    const int blocks_per_warp = vdr * WARP_SIZE / qi;
398    assert(blocks_per_warp>0);
399// partial sum for each thread
400    float tmp = 0.0f;
401
402    const block_q_t  * x = (const block_q_t  *) vx;
403    const block_q8_1 * y = (const block_q8_1 *) vy;
404
405    for (int i = item_ct1.get_local_id(2) / (qi / vdr); i < blocks_per_row;
406         i += blocks_per_warp) {
407        const int ibx = row*blocks_per_row + i; // x block index
408
409        const int iby = i * (qk/QK8_1); // y block index that aligns with ibx
410
411        const int iqs =
412            vdr *
413            (item_ct1.get_local_id(2) %
414             (qi / vdr)); // x block quant index when casting the quants to int
415
416        tmp += vec_dot_iq2_xs_q8_1(&x[ibx], &y[iby], iqs, iq2xs_grid, ksigns64);
417    }
418
419    // sum up partial sums and write back result
420#pragma unroll
421    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
422        tmp +=
423            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
424    }
425
426    if (item_ct1.get_local_id(2) == 0) {
427        dst[row] = tmp;
428    }
429}
430
431template <int qk, int qi, typename block_q_t, int vdr>
432static void mul_mat_vec_q_iq2_s_q8_1(const void *__restrict__ vx,
433                                     const void *__restrict__ vy,
434                                     float *__restrict__ dst, const int ncols,
435                                     const int nrows,
436                                     const sycl::nd_item<3> &item_ct1) {
437    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
438                    item_ct1.get_local_id(1);
439
440    if (row >= nrows) {
441        return;
442    }
443
444    const int blocks_per_row = ncols / qk;
445    const int blocks_per_warp = vdr * WARP_SIZE / qi;
446    assert(blocks_per_warp>0);
447// partial sum for each thread
448    float tmp = 0.0f;
449
450    const block_q_t  * x = (const block_q_t  *) vx;
451    const block_q8_1 * y = (const block_q8_1 *) vy;
452
453    for (int i = item_ct1.get_local_id(2) / (qi / vdr); i < blocks_per_row;
454         i += blocks_per_warp) {
455        const int ibx = row*blocks_per_row + i; // x block index
456
457        const int iby = i * (qk/QK8_1); // y block index that aligns with ibx
458
459        const int iqs =
460            vdr *
461            (item_ct1.get_local_id(2) %
462             (qi / vdr)); // x block quant index when casting the quants to int
463
464        tmp += vec_dot_iq2_s_q8_1(&x[ibx], &y[iby], iqs);
465    }
466
467    // sum up partial sums and write back result
468#pragma unroll
469    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
470        tmp +=
471            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
472    }
473
474    if (item_ct1.get_local_id(2) == 0) {
475        dst[row] = tmp;
476    }
477}
478
479template <int qk, int qi, typename block_q_t, int vdr>
480static void mul_mat_vec_q_iq3_xxs_q8_1(const void *__restrict__ vx,
481                                       const void *__restrict__ vy,
482                                       float *__restrict__ dst, const int ncols,
483                                       const int nrows,
484                                       const sycl::nd_item<3> &item_ct1) {
485    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
486                    item_ct1.get_local_id(1);
487
488    if (row >= nrows) {
489        return;
490    }
491
492    const int blocks_per_row = ncols / qk;
493    const int blocks_per_warp = vdr * WARP_SIZE / qi;
494    assert(blocks_per_warp>0);
495// partial sum for each thread
496    float tmp = 0.0f;
497
498    const block_q_t  * x = (const block_q_t  *) vx;
499    const block_q8_1 * y = (const block_q8_1 *) vy;
500
501    for (int i = item_ct1.get_local_id(2) / (qi / vdr); i < blocks_per_row;
502         i += blocks_per_warp) {
503        const int ibx = row*blocks_per_row + i; // x block index
504
505        const int iby = i * (qk/QK8_1); // y block index that aligns with ibx
506
507        const int iqs =
508            vdr *
509            (item_ct1.get_local_id(2) %
510             (qi / vdr)); // x block quant index when casting the quants to int
511
512        tmp += vec_dot_iq3_xxs_q8_1(&x[ibx], &y[iby], iqs, iq3xxs_grid, ksigns64);
513    }
514
515    // sum up partial sums and write back result
516#pragma unroll
517    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
518        tmp +=
519            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
520    }
521
522    if (item_ct1.get_local_id(2) == 0) {
523        dst[row] = tmp;
524    }
525}
526
527template <int qk, int qi, typename block_q_t, int vdr>
528static void mul_mat_vec_q_iq3_s_q8_1(const void *__restrict__ vx,
529                                     const void *__restrict__ vy,
530                                     float *__restrict__ dst, const int ncols,
531                                     const int nrows,
532                                     const sycl::nd_item<3> &item_ct1) {
533    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
534                    item_ct1.get_local_id(1);
535
536    if (row >= nrows) {
537        return;
538    }
539
540    const int blocks_per_row = ncols / qk;
541    const int blocks_per_warp = vdr * WARP_SIZE / qi;
542    assert(blocks_per_warp>0);
543// partial sum for each thread
544    float tmp = 0.0f;
545
546    const block_q_t  * x = (const block_q_t  *) vx;
547    const block_q8_1 * y = (const block_q8_1 *) vy;
548
549    for (int i = item_ct1.get_local_id(2) / (qi / vdr); i < blocks_per_row;
550         i += blocks_per_warp) {
551        const int ibx = row*blocks_per_row + i; // x block index
552
553        const int iby = i * (qk/QK8_1); // y block index that aligns with ibx
554
555        const int iqs =
556            vdr *
557            (item_ct1.get_local_id(2) %
558             (qi / vdr)); // x block quant index when casting the quants to int
559
560        tmp += vec_dot_iq3_s_q8_1(&x[ibx], &y[iby], iqs, iq3s_grid);
561    }
562
563    // sum up partial sums and write back result
564#pragma unroll
565    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
566        tmp +=
567            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
568    }
569
570    if (item_ct1.get_local_id(2) == 0) {
571        dst[row] = tmp;
572    }
573}
574
575template <int qk, int qi, typename block_q_t, int vdr>
576static void mul_mat_vec_q_iq1_s_q8_1(const void *__restrict__ vx,
577                                     const void *__restrict__ vy,
578                                     float *__restrict__ dst, const int ncols,
579                                     const int nrows,
580                                     const sycl::nd_item<3> &item_ct1) {
581    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
582                    item_ct1.get_local_id(1);
583
584    if (row >= nrows) {
585        return;
586    }
587
588    const int blocks_per_row = ncols / qk;
589    const int blocks_per_warp = vdr * WARP_SIZE / qi;
590    assert(blocks_per_warp>0);
591// partial sum for each thread
592    float tmp = 0.0f;
593
594    const block_q_t  * x = (const block_q_t  *) vx;
595    const block_q8_1 * y = (const block_q8_1 *) vy;
596
597    for (int i = item_ct1.get_local_id(2) / (qi / vdr); i < blocks_per_row;
598         i += blocks_per_warp) {
599        const int ibx = row*blocks_per_row + i; // x block index
600
601        const int iby = i * (qk/QK8_1); // y block index that aligns with ibx
602
603        const int iqs =
604            vdr *
605            (item_ct1.get_local_id(2) %
606             (qi / vdr)); // x block quant index when casting the quants to int
607
608        tmp += vec_dot_iq1_s_q8_1(&x[ibx], &y[iby], iqs, iq1s_grid_gpu);
609    }
610
611    // sum up partial sums and write back result
612#pragma unroll
613    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
614        tmp +=
615            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
616    }
617
618    if (item_ct1.get_local_id(2) == 0) {
619        dst[row] = tmp;
620    }
621}
622
623template <int qk, int qi, typename block_q_t, int vdr>
624static void mul_mat_vec_q_iq1_m_q8_1(const void *__restrict__ vx,
625                                     const void *__restrict__ vy,
626                                     float *__restrict__ dst, const int ncols,
627                                     const int nrows,
628                                     const sycl::nd_item<3> &item_ct1) {
629    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
630                    item_ct1.get_local_id(1);
631
632    if (row >= nrows) {
633        return;
634    }
635
636    const int blocks_per_row = ncols / qk;
637    const int blocks_per_warp = vdr * WARP_SIZE / qi;
638    assert(blocks_per_warp>0);
639// partial sum for each thread
640    float tmp = 0.0f;
641
642    const block_q_t  * x = (const block_q_t  *) vx;
643    const block_q8_1 * y = (const block_q8_1 *) vy;
644
645    for (int i = item_ct1.get_local_id(2) / (qi / vdr); i < blocks_per_row;
646         i += blocks_per_warp) {
647        const int ibx = row*blocks_per_row + i; // x block index
648
649        const int iby = i * (qk/QK8_1); // y block index that aligns with ibx
650
651        const int iqs =
652            vdr *
653            (item_ct1.get_local_id(2) %
654             (qi / vdr)); // x block quant index when casting the quants to int
655
656        tmp += vec_dot_iq1_m_q8_1(&x[ibx], &y[iby], iqs);
657    }
658
659    // sum up partial sums and write back result
660#pragma unroll
661    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
662        tmp +=
663            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
664    }
665
666    if (item_ct1.get_local_id(2) == 0) {
667        dst[row] = tmp;
668    }
669}
670
671template <int qk, int qi, typename block_q_t, int vdr>
672static void mul_mat_vec_q_iq4_nl_q8_1(const void *__restrict__ vx,
673                                      const void *__restrict__ vy,
674                                      float *__restrict__ dst, const int ncols,
675                                      const int nrows,
676                                      const sycl::nd_item<3> &item_ct1) {
677    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
678                    item_ct1.get_local_id(1);
679
680    if (row >= nrows) {
681        return;
682    }
683
684    const int blocks_per_row = ncols / qk;
685    const int blocks_per_warp = vdr * WARP_SIZE / qi;
686    assert(blocks_per_warp>0);
687// partial sum for each thread
688    float tmp = 0.0f;
689
690    const block_q_t  * x = (const block_q_t  *) vx;
691    const block_q8_1 * y = (const block_q8_1 *) vy;
692
693    for (int i = item_ct1.get_local_id(2) / (qi / vdr); i < blocks_per_row;
694         i += blocks_per_warp) {
695        const int ibx = row*blocks_per_row + i; // x block index
696
697        const int iby = i * (qk/QK8_1); // y block index that aligns with ibx
698
699        const int iqs =
700            vdr *
701            (item_ct1.get_local_id(2) %
702             (qi / vdr)); // x block quant index when casting the quants to int
703
704        tmp += vec_dot_iq4_nl_q8_1(&x[ibx], &y[iby], iqs);
705    }
706
707    // sum up partial sums and write back result
708#pragma unroll
709    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
710        tmp +=
711            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
712    }
713
714    if (item_ct1.get_local_id(2) == 0) {
715        dst[row] = tmp;
716    }
717}
718
719
720template <int qk, int qi, typename block_q_t, int vdr>
721static void mul_mat_vec_q_iq4_xs_q8_1(const void *__restrict__ vx,
722                                      const void *__restrict__ vy,
723                                      float *__restrict__ dst, const int ncols,
724                                      const int nrows,
725                                      const sycl::nd_item<3> &item_ct1) {
726    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
727                    item_ct1.get_local_id(1);
728
729    if (row >= nrows) {
730        return;
731    }
732
733    const int blocks_per_row = ncols / qk;
734    const int blocks_per_warp = vdr * WARP_SIZE / qi;
735    assert(blocks_per_warp>0);
736// partial sum for each thread
737    float tmp = 0.0f;
738
739    const block_q_t  * x = (const block_q_t  *) vx;
740    const block_q8_1 * y = (const block_q8_1 *) vy;
741
742    for (int i = item_ct1.get_local_id(2) / (qi / vdr); i < blocks_per_row;
743         i += blocks_per_warp) {
744        const int ibx = row*blocks_per_row + i; // x block index
745
746        const int iby = i * (qk/QK8_1); // y block index that aligns with ibx
747
748        const int iqs =
749            vdr *
750            (item_ct1.get_local_id(2) %
751             (qi / vdr)); // x block quant index when casting the quants to int
752
753        tmp += vec_dot_iq4_xs_q8_1(&x[ibx], &y[iby], iqs);
754    }
755
756    // sum up partial sums and write back result
757#pragma unroll
758    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
759        tmp +=
760            dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
761    }
762
763    if (item_ct1.get_local_id(2) == 0) {
764        dst[row] = tmp;
765    }
766}
767
768static void reorder_mul_mat_vec_q4_0_q8_1_sycl(const void * vx, const void * vy, float * dst, const int ncols,
769                                                    const int nrows, dpct::queue_ptr stream) {
770    GGML_ASSERT(ncols % QK4_0 == 0);
771    // Round up to a whole number of subgroup-sized workgroups; out-of-range rows are skipped inside the kernel.
772    constexpr size_t num_subgroups = WARP_SIZE;
773    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups);
774    const sycl::range<3> block_nums(1, 1, block_num_y);
775    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
776
777    stream->submit([&](sycl::handler & cgh) {
778        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
779                         [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
780                             mul_mat_vec_q_reorder<reorder_vec_dot_q_sycl<GGML_TYPE_Q4_0>>(vx, vy, dst, ncols, nrows,
781                                                                                           nd_item);
782                         });
783    });
784}
785
786template <int ncols_dst>
787static void reorder_mul_mat_vec_q4_0_q8_1_sycl_ncols(
788        const void * vx, const void * vy, float * dst,
789        const int ncols, const int nrows,
790        const int stride_col_y_bytes, const int stride_col_dst,
791        dpct::queue_ptr stream) {
792    GGML_ASSERT(ncols % QK4_0 == 0);
793    constexpr size_t num_subgroups = WARP_SIZE;
794    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups);
795    const sycl::range<3> block_nums(1, 1, block_num_y);
796    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
797
798    stream->submit([&](sycl::handler & cgh) {
799        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
800                         [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
801                             mul_mat_vec_q_reorder_ncols<reorder_vec_dot_q_sycl<GGML_TYPE_Q4_0>, ncols_dst>(
802                                 vx, /*vgate=*/ nullptr, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst,
803                                 /*glu_op=*/ GGML_GLU_OP_SWIGLU, nd_item);
804                         });
805    });
806}
807
808static void reorder_mul_mat_vec_q4_0_q8_1_sycl_switch_ncols(
809        const void * vx, const void * vy, float * dst,
810        const int ncols, const int nrows, const int ncols_dst,
811        const int stride_col_y_bytes, const int stride_col_dst,
812        dpct::queue_ptr stream) {
813    switch (ncols_dst) {
814        case 1: reorder_mul_mat_vec_q4_0_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
815        case 2: reorder_mul_mat_vec_q4_0_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
816        case 3: reorder_mul_mat_vec_q4_0_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
817        case 4: reorder_mul_mat_vec_q4_0_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
818        case 5: reorder_mul_mat_vec_q4_0_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
819        case 6: reorder_mul_mat_vec_q4_0_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
820        case 7: reorder_mul_mat_vec_q4_0_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
821        case 8: reorder_mul_mat_vec_q4_0_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
822        default: GGML_ABORT("unsupported ncols_dst=%d for Q4_0 reorder multi-col MMVQ", ncols_dst);
823    }
824}
825
826static void mul_mat_vec_q4_0_q8_1_sycl(const void * vx, const void * vy, float * dst, const int ncols, const int nrows,
827                                       dpct::queue_ptr stream) {
828    GGML_ASSERT(ncols % QK4_0 == 0);
829    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
830    const sycl::range<3> block_nums(1, 1, block_num_y);
831    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
832
833    {
834        stream->submit([&](sycl::handler & cgh) {
835            cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
836                             [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
837                                 mul_mat_vec_q<QK4_0, QI4_0, block_q4_0, VDR_Q4_0_Q8_1_MMVQ, vec_dot_q4_0_q8_1>(
838                                     vx, vy, dst, ncols, nrows, item_ct1);
839                             });
840        });
841    }
842}
843
844template <int ncols_dst>
845static void mul_mat_vec_q4_0_q8_1_sycl_ncols(
846        const void * vx, const void * vy, float * dst,
847        const int ncols, const int nrows,
848        const int stride_col_y, const int stride_col_dst,
849        dpct::queue_ptr stream) {
850    GGML_ASSERT(ncols % QK4_0 == 0);
851    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
852    const sycl::range<3> block_nums(1, 1, block_num_y);
853    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
854    stream->submit([&](sycl::handler & cgh) {
855        cgh.parallel_for(
856            sycl::nd_range<3>(block_nums * block_dims, block_dims),
857            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
858                mul_mat_vec_q_ncols<QK4_0, QI4_0, block_q4_0,
859                                    VDR_Q4_0_Q8_1_MMVQ, vec_dot_q4_0_q8_1, ncols_dst>(
860                    vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, item_ct1);
861            });
862    });
863}
864
865static void mul_mat_vec_q4_0_q8_1_sycl_switch_ncols(
866        const void * vx, const void * vy, float * dst,
867        const int ncols, const int nrows, const int ncols_dst,
868        const int stride_col_y, const int stride_col_dst,
869        dpct::queue_ptr stream) {
870    switch (ncols_dst) {
871        case 1: mul_mat_vec_q4_0_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
872        case 2: mul_mat_vec_q4_0_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
873        case 3: mul_mat_vec_q4_0_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
874        case 4: mul_mat_vec_q4_0_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
875        case 5: mul_mat_vec_q4_0_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
876        case 6: mul_mat_vec_q4_0_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
877        case 7: mul_mat_vec_q4_0_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
878        case 8: mul_mat_vec_q4_0_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
879        default: GGML_ABORT("unsupported ncols_dst=%d for Q4_0 multi-col MMVQ", ncols_dst);
880    }
881}
882
883static void mul_mat_vec_q4_1_q8_1_sycl(const void *vx, const void *vy,
884                                       float *dst, const int ncols,
885                                       const int nrows,
886                                       dpct::queue_ptr stream) {
887    GGML_ASSERT(ncols % QK4_1 == 0);
888    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
889    const sycl::range<3> block_nums(1, 1, block_num_y);
890    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
891    {
892
893        stream->submit([&](sycl::handler &cgh) {
894
895            cgh.parallel_for(
896                sycl::nd_range<3>(block_nums * block_dims, block_dims),
897                [=](sycl::nd_item<3> item_ct1)
898                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
899                        mul_mat_vec_q<QK4_0, QI4_1, block_q4_1,
900                                      VDR_Q4_1_Q8_1_MMVQ, vec_dot_q4_1_q8_1>(
901                            vx, vy, dst, ncols, nrows, item_ct1);
902                    });
903        });
904    }
905}
906
907template <int ncols_dst>
908static void mul_mat_vec_q4_1_q8_1_sycl_ncols(
909        const void * vx, const void * vy, float * dst,
910        const int ncols, const int nrows,
911        const int stride_col_y, const int stride_col_dst,
912        dpct::queue_ptr stream) {
913    GGML_ASSERT(ncols % QK4_1 == 0);
914    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
915    const sycl::range<3> block_nums(1, 1, block_num_y);
916    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
917    stream->submit([&](sycl::handler & cgh) {
918        cgh.parallel_for(
919            sycl::nd_range<3>(block_nums * block_dims, block_dims),
920            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
921                mul_mat_vec_q_ncols<QK4_0, QI4_1, block_q4_1,
922                                    VDR_Q4_1_Q8_1_MMVQ, vec_dot_q4_1_q8_1, ncols_dst>(
923                    vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, item_ct1);
924            });
925    });
926}
927
928static void mul_mat_vec_q4_1_q8_1_sycl_switch_ncols(
929        const void * vx, const void * vy, float * dst,
930        const int ncols, const int nrows, const int ncols_dst,
931        const int stride_col_y, const int stride_col_dst,
932        dpct::queue_ptr stream) {
933    switch (ncols_dst) {
934        case 1: mul_mat_vec_q4_1_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
935        case 2: mul_mat_vec_q4_1_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
936        case 3: mul_mat_vec_q4_1_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
937        case 4: mul_mat_vec_q4_1_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
938        case 5: mul_mat_vec_q4_1_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
939        case 6: mul_mat_vec_q4_1_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
940        case 7: mul_mat_vec_q4_1_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
941        case 8: mul_mat_vec_q4_1_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
942        default: GGML_ABORT("unsupported ncols_dst=%d for Q4_1 multi-col MMVQ", ncols_dst);
943    }
944}
945
946static void mul_mat_vec_mxfp4_q8_1_sycl(const void * vx, const void * vy, float * dst, const int ncols, const int nrows,
947                                        dpct::queue_ptr stream) {
948    GGML_ASSERT(ncols % QK_MXFP4 == 0);
949    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
950    const sycl::range<3> block_nums(1, 1, block_num_y);
951    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
952
953    {
954        stream->submit([&](sycl::handler & cgh) {
955            cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
956                             [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
957                                 mul_mat_vec_q<QK_MXFP4, QI_MXFP4, block_mxfp4, VDR_MXFP4_Q8_1_MMVQ, vec_dot_mxfp4_q8_1>(
958                                     vx, vy, dst, ncols, nrows, item_ct1);
959                             });
960        });
961    }
962}
963
964template <int ncols_dst>
965static void mul_mat_vec_mxfp4_q8_1_sycl_ncols(
966        const void * vx, const void * vy, float * dst,
967        const int ncols, const int nrows,
968        const int stride_col_y, const int stride_col_dst,
969        dpct::queue_ptr stream) {
970    GGML_ASSERT(ncols % QK_MXFP4 == 0);
971    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
972    const sycl::range<3> block_nums(1, 1, block_num_y);
973    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
974    stream->submit([&](sycl::handler & cgh) {
975        cgh.parallel_for(
976            sycl::nd_range<3>(block_nums * block_dims, block_dims),
977            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
978                mul_mat_vec_q_ncols<QK_MXFP4, QI_MXFP4, block_mxfp4,
979                                    VDR_MXFP4_Q8_1_MMVQ, vec_dot_mxfp4_q8_1, ncols_dst>(
980                    vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, item_ct1);
981            });
982    });
983}
984
985static void mul_mat_vec_mxfp4_q8_1_sycl_switch_ncols(
986        const void * vx, const void * vy, float * dst,
987        const int ncols, const int nrows, const int ncols_dst,
988        const int stride_col_y, const int stride_col_dst,
989        dpct::queue_ptr stream) {
990    switch (ncols_dst) {
991        case 1: mul_mat_vec_mxfp4_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
992        case 2: mul_mat_vec_mxfp4_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
993        case 3: mul_mat_vec_mxfp4_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
994        case 4: mul_mat_vec_mxfp4_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
995        case 5: mul_mat_vec_mxfp4_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
996        case 6: mul_mat_vec_mxfp4_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
997        case 7: mul_mat_vec_mxfp4_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
998        case 8: mul_mat_vec_mxfp4_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
999        default: GGML_ABORT("unsupported ncols_dst=%d for MXFP4 multi-col MMVQ", ncols_dst);
1000    }
1001}
1002
1003static void mul_mat_vec_nvfp4_q8_1_sycl(const void * vx, const void * vy, float * dst, const int ncols, const int nrows,
1004                                        dpct::queue_ptr stream) {
1005    GGML_ASSERT(ncols % QK_NVFP4 == 0);
1006    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1007    const sycl::range<3> block_nums(1, 1, block_num_y);
1008    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1009
1010    {
1011        stream->submit([&](sycl::handler & cgh) {
1012            cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
1013                             [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1014                                 mul_mat_vec_q<QK_NVFP4, QI_NVFP4, block_nvfp4, VDR_NVFP4_Q8_1_MMVQ, vec_dot_nvfp4_q8_1>(
1015                                     vx, vy, dst, ncols, nrows, item_ct1);
1016                             });
1017        });
1018    }
1019}
1020
1021template <int ncols_dst>
1022static void mul_mat_vec_nvfp4_q8_1_sycl_ncols(
1023        const void * vx, const void * vy, float * dst,
1024        const int ncols, const int nrows,
1025        const int stride_col_y, const int stride_col_dst,
1026        dpct::queue_ptr stream) {
1027    GGML_ASSERT(ncols % QK_NVFP4 == 0);
1028    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1029    const sycl::range<3> block_nums(1, 1, block_num_y);
1030    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1031    stream->submit([&](sycl::handler & cgh) {
1032        cgh.parallel_for(
1033            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1034            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1035                mul_mat_vec_q_ncols<QK_NVFP4, QI_NVFP4, block_nvfp4,
1036                                    VDR_NVFP4_Q8_1_MMVQ, vec_dot_nvfp4_q8_1, ncols_dst>(
1037                    vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, item_ct1);
1038            });
1039    });
1040}
1041
1042static void mul_mat_vec_nvfp4_q8_1_sycl_switch_ncols(
1043        const void * vx, const void * vy, float * dst,
1044        const int ncols, const int nrows, const int ncols_dst,
1045        const int stride_col_y, const int stride_col_dst,
1046        dpct::queue_ptr stream) {
1047    switch (ncols_dst) {
1048        case 1: mul_mat_vec_nvfp4_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1049        case 2: mul_mat_vec_nvfp4_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1050        case 3: mul_mat_vec_nvfp4_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1051        case 4: mul_mat_vec_nvfp4_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1052        case 5: mul_mat_vec_nvfp4_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1053        case 6: mul_mat_vec_nvfp4_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1054        case 7: mul_mat_vec_nvfp4_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1055        case 8: mul_mat_vec_nvfp4_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1056        default: GGML_ABORT("unsupported ncols_dst=%d for NVFP4 multi-col MMVQ", ncols_dst);
1057    }
1058}
1059
1060static void mul_mat_vec_q5_0_q8_1_sycl(const void *vx, const void *vy,
1061                                       float *dst, const int ncols,
1062                                       const int nrows,
1063                                       dpct::queue_ptr stream) {
1064    GGML_ASSERT(ncols % QK5_0 == 0);
1065    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1066    const sycl::range<3> block_nums(1, 1, block_num_y);
1067    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1068    {
1069
1070        stream->submit([&](sycl::handler &cgh) {
1071
1072            cgh.parallel_for(
1073                sycl::nd_range<3>(block_nums * block_dims, block_dims),
1074                [=](sycl::nd_item<3> item_ct1)
1075                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1076                        mul_mat_vec_q<QK5_0, QI5_0, block_q5_0,
1077                                      VDR_Q5_0_Q8_1_MMVQ, vec_dot_q5_0_q8_1>(
1078                            vx, vy, dst, ncols, nrows, item_ct1);
1079                    });
1080        });
1081    }
1082}
1083
1084template <int ncols_dst>
1085static void mul_mat_vec_q5_0_q8_1_sycl_ncols(
1086        const void * vx, const void * vy, float * dst,
1087        const int ncols, const int nrows,
1088        const int stride_col_y, const int stride_col_dst,
1089        dpct::queue_ptr stream) {
1090    GGML_ASSERT(ncols % QK5_0 == 0);
1091    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1092    const sycl::range<3> block_nums(1, 1, block_num_y);
1093    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1094    stream->submit([&](sycl::handler & cgh) {
1095        cgh.parallel_for(
1096            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1097            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1098                mul_mat_vec_q_ncols<QK5_0, QI5_0, block_q5_0,
1099                                    VDR_Q5_0_Q8_1_MMVQ, vec_dot_q5_0_q8_1, ncols_dst>(
1100                    vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, item_ct1);
1101            });
1102    });
1103}
1104
1105static void mul_mat_vec_q5_0_q8_1_sycl_switch_ncols(
1106        const void * vx, const void * vy, float * dst,
1107        const int ncols, const int nrows, const int ncols_dst,
1108        const int stride_col_y, const int stride_col_dst,
1109        dpct::queue_ptr stream) {
1110    switch (ncols_dst) {
1111        case 1: mul_mat_vec_q5_0_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1112        case 2: mul_mat_vec_q5_0_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1113        case 3: mul_mat_vec_q5_0_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1114        case 4: mul_mat_vec_q5_0_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1115        case 5: mul_mat_vec_q5_0_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1116        case 6: mul_mat_vec_q5_0_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1117        case 7: mul_mat_vec_q5_0_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1118        case 8: mul_mat_vec_q5_0_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1119        default: GGML_ABORT("unsupported ncols_dst=%d for Q5_0 multi-col MMVQ", ncols_dst);
1120    }
1121}
1122
1123static void mul_mat_vec_q5_1_q8_1_sycl(const void *vx, const void *vy,
1124                                       float *dst, const int ncols,
1125                                       const int nrows,
1126                                       dpct::queue_ptr stream) {
1127    GGML_ASSERT(ncols % QK5_1 == 0);
1128    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1129    const sycl::range<3> block_nums(1, 1, block_num_y);
1130    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1131    {
1132
1133        stream->submit([&](sycl::handler &cgh) {
1134
1135            cgh.parallel_for(
1136                sycl::nd_range<3>(block_nums * block_dims, block_dims),
1137                [=](sycl::nd_item<3> item_ct1)
1138                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1139                        mul_mat_vec_q<QK5_1, QI5_1, block_q5_1,
1140                                      VDR_Q5_1_Q8_1_MMVQ, vec_dot_q5_1_q8_1>(
1141                            vx, vy, dst, ncols, nrows, item_ct1);
1142                    });
1143        });
1144    }
1145}
1146
1147template <int ncols_dst>
1148static void mul_mat_vec_q5_1_q8_1_sycl_ncols(
1149        const void * vx, const void * vy, float * dst,
1150        const int ncols, const int nrows,
1151        const int stride_col_y, const int stride_col_dst,
1152        dpct::queue_ptr stream) {
1153    GGML_ASSERT(ncols % QK5_1 == 0);
1154    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1155    const sycl::range<3> block_nums(1, 1, block_num_y);
1156    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1157    stream->submit([&](sycl::handler & cgh) {
1158        cgh.parallel_for(
1159            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1160            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1161                mul_mat_vec_q_ncols<QK5_1, QI5_1, block_q5_1,
1162                                    VDR_Q5_1_Q8_1_MMVQ, vec_dot_q5_1_q8_1, ncols_dst>(
1163                    vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, item_ct1);
1164            });
1165    });
1166}
1167
1168static void mul_mat_vec_q5_1_q8_1_sycl_switch_ncols(
1169        const void * vx, const void * vy, float * dst,
1170        const int ncols, const int nrows, const int ncols_dst,
1171        const int stride_col_y, const int stride_col_dst,
1172        dpct::queue_ptr stream) {
1173    switch (ncols_dst) {
1174        case 1: mul_mat_vec_q5_1_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1175        case 2: mul_mat_vec_q5_1_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1176        case 3: mul_mat_vec_q5_1_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1177        case 4: mul_mat_vec_q5_1_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1178        case 5: mul_mat_vec_q5_1_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1179        case 6: mul_mat_vec_q5_1_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1180        case 7: mul_mat_vec_q5_1_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1181        case 8: mul_mat_vec_q5_1_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1182        default: GGML_ABORT("unsupported ncols_dst=%d for Q5_1 multi-col MMVQ", ncols_dst);
1183    }
1184}
1185
1186static void reorder_mul_mat_vec_q8_0_q8_1_sycl(const void * vx, const void * vy, float * dst, const int ncols,
1187                                                    const int nrows, dpct::queue_ptr stream) {
1188    GGML_ASSERT(ncols % QK8_0 == 0);
1189    // Round up to a whole number of subgroup-sized workgroups; out-of-range rows are skipped inside the kernel.
1190    constexpr size_t num_subgroups = WARP_SIZE;
1191    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups);
1192    const sycl::range<3> block_nums(1, 1, block_num_y);
1193    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
1194
1195    stream->submit([&](sycl::handler & cgh) {
1196        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
1197                         [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1198                             mul_mat_vec_q_reorder<reorder_vec_dot_q_sycl<GGML_TYPE_Q8_0>>(vx, vy, dst, ncols, nrows,
1199                                                                                           nd_item);
1200                         });
1201    });
1202}
1203
1204template <int ncols_dst>
1205static void reorder_mul_mat_vec_q8_0_q8_1_sycl_ncols(
1206        const void * vx, const void * vy, float * dst,
1207        const int ncols, const int nrows,
1208        const int stride_col_y_bytes, const int stride_col_dst,
1209        dpct::queue_ptr stream) {
1210    GGML_ASSERT(ncols % QK8_0 == 0);
1211    constexpr size_t num_subgroups = WARP_SIZE;
1212    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups);
1213    const sycl::range<3> block_nums(1, 1, block_num_y);
1214    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
1215
1216    stream->submit([&](sycl::handler & cgh) {
1217        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
1218                         [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1219                             mul_mat_vec_q_reorder_ncols<reorder_vec_dot_q_sycl<GGML_TYPE_Q8_0>, ncols_dst>(
1220                                 vx, /*vgate=*/ nullptr, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst,
1221                                 /*glu_op=*/ GGML_GLU_OP_SWIGLU, nd_item);
1222                         });
1223    });
1224}
1225
1226static void reorder_mul_mat_vec_q8_0_q8_1_sycl_switch_ncols(
1227        const void * vx, const void * vy, float * dst,
1228        const int ncols, const int nrows, const int ncols_dst,
1229        const int stride_col_y_bytes, const int stride_col_dst,
1230        dpct::queue_ptr stream) {
1231    switch (ncols_dst) {
1232        case 1: reorder_mul_mat_vec_q8_0_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1233        case 2: reorder_mul_mat_vec_q8_0_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1234        case 3: reorder_mul_mat_vec_q8_0_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1235        case 4: reorder_mul_mat_vec_q8_0_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1236        case 5: reorder_mul_mat_vec_q8_0_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1237        case 6: reorder_mul_mat_vec_q8_0_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1238        case 7: reorder_mul_mat_vec_q8_0_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1239        case 8: reorder_mul_mat_vec_q8_0_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1240        default: GGML_ABORT("unsupported ncols_dst=%d for Q8_0 reorder multi-col MMVQ", ncols_dst);
1241    }
1242}
1243
1244static void mul_mat_vec_q8_0_q8_1_sycl(const void *vx, const void *vy,
1245                                       float *dst, const int ncols,
1246                                       const int nrows,
1247                                       dpct::queue_ptr stream) {
1248    GGML_ASSERT(ncols % QK8_0 == 0);
1249    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1250    const sycl::range<3> block_nums(1, 1, block_num_y);
1251    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1252    {
1253
1254        stream->submit([&](sycl::handler &cgh) {
1255
1256            cgh.parallel_for(
1257                sycl::nd_range<3>(block_nums * block_dims, block_dims),
1258                [=](sycl::nd_item<3> item_ct1)
1259                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1260                        mul_mat_vec_q<QK8_0, QI8_0, block_q8_0,
1261                                      VDR_Q8_0_Q8_1_MMVQ, vec_dot_q8_0_q8_1>(
1262                            vx, vy, dst, ncols, nrows, item_ct1);
1263                    });
1264        });
1265    }
1266}
1267
1268template <int ncols_dst>
1269static void mul_mat_vec_q8_0_q8_1_sycl_ncols(
1270        const void * vx, const void * vy, float * dst,
1271        const int ncols, const int nrows,
1272        const int stride_col_y, const int stride_col_dst,
1273        dpct::queue_ptr stream) {
1274    GGML_ASSERT(ncols % QK8_0 == 0);
1275    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1276    const sycl::range<3> block_nums(1, 1, block_num_y);
1277    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1278    stream->submit([&](sycl::handler & cgh) {
1279        cgh.parallel_for(
1280            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1281            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1282                mul_mat_vec_q_ncols<QK8_0, QI8_0, block_q8_0,
1283                                    VDR_Q8_0_Q8_1_MMVQ, vec_dot_q8_0_q8_1, ncols_dst>(
1284                    vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, item_ct1);
1285            });
1286    });
1287}
1288
1289static void mul_mat_vec_q8_0_q8_1_sycl_switch_ncols(
1290        const void * vx, const void * vy, float * dst,
1291        const int ncols, const int nrows, const int ncols_dst,
1292        const int stride_col_y, const int stride_col_dst,
1293        dpct::queue_ptr stream) {
1294    switch (ncols_dst) {
1295        case 1: mul_mat_vec_q8_0_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1296        case 2: mul_mat_vec_q8_0_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1297        case 3: mul_mat_vec_q8_0_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1298        case 4: mul_mat_vec_q8_0_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1299        case 5: mul_mat_vec_q8_0_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1300        case 6: mul_mat_vec_q8_0_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1301        case 7: mul_mat_vec_q8_0_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1302        case 8: mul_mat_vec_q8_0_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1303        default: GGML_ABORT("unsupported ncols_dst=%d for Q8_0 multi-col MMVQ", ncols_dst);
1304    }
1305}
1306
1307static void mul_mat_vec_q1_0_q8_1_sycl(const void * vx, const void * vy,
1308                                       float * dst, const int ncols,
1309                                       const int nrows,
1310                                       dpct::queue_ptr stream) {
1311    GGML_ASSERT(ncols % QK1_0 == 0);
1312    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1313    const sycl::range<3> block_nums(1, 1, block_num_y);
1314    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1315
1316    stream->submit([&](sycl::handler & cgh) {
1317        cgh.parallel_for(
1318            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1319            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1320                mul_mat_vec_q<QK1_0, QI1_0, block_q1_0,
1321                              VDR_Q1_0_Q8_1_MMVQ, vec_dot_q1_0_q8_1>(
1322                    vx, vy, dst, ncols, nrows, item_ct1);
1323            });
1324    });
1325}
1326
1327template <int ncols_dst>
1328static void mul_mat_vec_q1_0_q8_1_sycl_ncols(
1329        const void * vx, const void * vy, float * dst,
1330        const int ncols, const int nrows,
1331        const int stride_col_y, const int stride_col_dst,
1332        dpct::queue_ptr stream) {
1333    GGML_ASSERT(ncols % QK1_0 == 0);
1334    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1335    const sycl::range<3> block_nums(1, 1, block_num_y);
1336    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1337
1338    stream->submit([&](sycl::handler & cgh) {
1339        cgh.parallel_for(
1340            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1341            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1342                mul_mat_vec_q_ncols<QK1_0, QI1_0, block_q1_0,
1343                                    VDR_Q1_0_Q8_1_MMVQ, vec_dot_q1_0_q8_1, ncols_dst>(
1344                    vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, item_ct1);
1345            });
1346    });
1347}
1348
1349static void mul_mat_vec_q1_0_q8_1_sycl_switch_ncols(
1350        const void * vx, const void * vy, float * dst,
1351        const int ncols, const int nrows, const int ncols_dst,
1352        const int stride_col_y, const int stride_col_dst,
1353        dpct::queue_ptr stream) {
1354    switch (ncols_dst) {
1355        case 1: mul_mat_vec_q1_0_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1356        case 2: mul_mat_vec_q1_0_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1357        case 3: mul_mat_vec_q1_0_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1358        case 4: mul_mat_vec_q1_0_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1359        case 5: mul_mat_vec_q1_0_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1360        case 6: mul_mat_vec_q1_0_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1361        case 7: mul_mat_vec_q1_0_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1362        case 8: mul_mat_vec_q1_0_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1363        default: GGML_ABORT("unsupported ncols_dst=%d for Q1_0 multi-col MMVQ", ncols_dst);
1364    }
1365}
1366
1367static void mul_mat_vec_q2_0_q8_1_sycl(const void * vx, const void * vy,
1368                                       float * dst, const int ncols,
1369                                       const int nrows,
1370                                       dpct::queue_ptr stream) {
1371    GGML_ASSERT(ncols % QK2_0 == 0);
1372    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1373    const sycl::range<3> block_nums(1, 1, block_num_y);
1374    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1375
1376    stream->submit([&](sycl::handler & cgh) {
1377        cgh.parallel_for(
1378            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1379            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1380                mul_mat_vec_q<QK2_0, QI2_0, block_q2_0,
1381                              VDR_Q2_0_Q8_1_MMVQ, vec_dot_q2_0_q8_1>(
1382                    vx, vy, dst, ncols, nrows, item_ct1);
1383            });
1384    });
1385}
1386
1387template <int ncols_dst>
1388static void mul_mat_vec_q2_0_q8_1_sycl_ncols(
1389        const void * vx, const void * vy, float * dst,
1390        const int ncols, const int nrows,
1391        const int stride_col_y, const int stride_col_dst,
1392        dpct::queue_ptr stream) {
1393    GGML_ASSERT(ncols % QK2_0 == 0);
1394    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1395    const sycl::range<3> block_nums(1, 1, block_num_y);
1396    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1397
1398    stream->submit([&](sycl::handler & cgh) {
1399        cgh.parallel_for(
1400            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1401            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1402                mul_mat_vec_q_ncols<QK2_0, QI2_0, block_q2_0,
1403                                    VDR_Q2_0_Q8_1_MMVQ, vec_dot_q2_0_q8_1, ncols_dst>(
1404                    vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, item_ct1);
1405            });
1406    });
1407}
1408
1409static void mul_mat_vec_q2_0_q8_1_sycl_switch_ncols(
1410        const void * vx, const void * vy, float * dst,
1411        const int ncols, const int nrows, const int ncols_dst,
1412        const int stride_col_y, const int stride_col_dst,
1413        dpct::queue_ptr stream) {
1414    switch (ncols_dst) {
1415        case 1: mul_mat_vec_q2_0_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1416        case 2: mul_mat_vec_q2_0_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1417        case 3: mul_mat_vec_q2_0_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1418        case 4: mul_mat_vec_q2_0_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1419        case 5: mul_mat_vec_q2_0_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1420        case 6: mul_mat_vec_q2_0_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1421        case 7: mul_mat_vec_q2_0_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1422        case 8: mul_mat_vec_q2_0_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1423        default: GGML_ABORT("unsupported ncols_dst=%d for Q2_0 multi-col MMVQ", ncols_dst);
1424    }
1425}
1426
1427static void mul_mat_vec_q2_K_q8_1_sycl(const void *vx, const void *vy,
1428                                       float *dst, const int ncols,
1429                                       const int nrows,
1430                                       dpct::queue_ptr stream) {
1431    GGML_ASSERT(ncols % QK_K == 0);
1432    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1433    const sycl::range<3> block_nums(1, 1, block_num_y);
1434    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1435    {
1436
1437        stream->submit([&](sycl::handler &cgh) {
1438
1439            cgh.parallel_for(
1440                sycl::nd_range<3>(block_nums * block_dims, block_dims),
1441                [=](sycl::nd_item<3> item_ct1)
1442                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1443                        mul_mat_vec_q<QK_K, QI2_K, block_q2_K,
1444                                      VDR_Q2_K_Q8_1_MMVQ, vec_dot_q2_K_q8_1>(
1445                            vx, vy, dst, ncols, nrows, item_ct1);
1446                    });
1447        });
1448    }
1449}
1450
1451template <int ncols_dst>
1452static void mul_mat_vec_q2_K_q8_1_sycl_ncols(
1453        const void * vx, const void * vy, float * dst,
1454        const int ncols, const int nrows,
1455        const int stride_col_y, const int stride_col_dst,
1456        dpct::queue_ptr stream) {
1457    GGML_ASSERT(ncols % QK_K == 0);
1458    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1459    const sycl::range<3> block_nums(1, 1, block_num_y);
1460    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1461    stream->submit([&](sycl::handler & cgh) {
1462        cgh.parallel_for(
1463            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1464            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1465                mul_mat_vec_q_ncols<QK_K, QI2_K, block_q2_K,
1466                                    VDR_Q2_K_Q8_1_MMVQ, vec_dot_q2_K_q8_1, ncols_dst>(
1467                    vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, item_ct1);
1468            });
1469    });
1470}
1471
1472static void mul_mat_vec_q2_K_q8_1_sycl_switch_ncols(
1473        const void * vx, const void * vy, float * dst,
1474        const int ncols, const int nrows, const int ncols_dst,
1475        const int stride_col_y, const int stride_col_dst,
1476        dpct::queue_ptr stream) {
1477    switch (ncols_dst) {
1478        case 1: mul_mat_vec_q2_K_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1479        case 2: mul_mat_vec_q2_K_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1480        case 3: mul_mat_vec_q2_K_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1481        case 4: mul_mat_vec_q2_K_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1482        case 5: mul_mat_vec_q2_K_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1483        case 6: mul_mat_vec_q2_K_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1484        case 7: mul_mat_vec_q2_K_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1485        case 8: mul_mat_vec_q2_K_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1486        default: GGML_ABORT("unsupported ncols_dst=%d for Q2_K multi-col MMVQ", ncols_dst);
1487    }
1488}
1489
1490static void reorder_mul_mat_vec_q2_k_q8_1_sycl(const void * vx, const void * vy, float * dst, const int ncols,
1491                                               const int nrows, dpct::queue_ptr stream) {
1492    GGML_ASSERT(ncols % QK_K == 0);
1493
1494    // Round up to a whole number of subgroup-sized workgroups; out-of-range rows are skipped inside the kernel.
1495    constexpr size_t num_subgroups = WARP_SIZE;
1496    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups);
1497    const sycl::range<3> block_nums(1, 1, block_num_y);
1498    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
1499
1500    stream->submit([&](sycl::handler & cgh) {
1501        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
1502                         [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1503                             mul_mat_vec_q_reorder<reorder_vec_dot_q_sycl<GGML_TYPE_Q2_K>>(vx, vy, dst, ncols, nrows,
1504                                                                                           nd_item);
1505                         });
1506    });
1507}
1508
1509template <int ncols_dst>
1510static void reorder_mul_mat_vec_q2_k_q8_1_sycl_ncols(
1511        const void * vx, const void * vy, float * dst,
1512        const int ncols, const int nrows,
1513        const int stride_col_y_bytes, const int stride_col_dst,
1514        dpct::queue_ptr stream) {
1515    GGML_ASSERT(ncols % QK_K == 0);
1516    constexpr size_t num_subgroups = WARP_SIZE;
1517    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups);
1518    const sycl::range<3> block_nums(1, 1, block_num_y);
1519    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
1520
1521    stream->submit([&](sycl::handler & cgh) {
1522        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
1523                         [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1524                             mul_mat_vec_q_reorder_ncols<reorder_vec_dot_q_sycl<GGML_TYPE_Q2_K>, ncols_dst>(
1525                                 vx, /*vgate=*/ nullptr, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst,
1526                                 /*glu_op=*/ GGML_GLU_OP_SWIGLU, nd_item);
1527                         });
1528    });
1529}
1530
1531static void reorder_mul_mat_vec_q2_k_q8_1_sycl_switch_ncols(
1532        const void * vx, const void * vy, float * dst,
1533        const int ncols, const int nrows, const int ncols_dst,
1534        const int stride_col_y_bytes, const int stride_col_dst,
1535        dpct::queue_ptr stream) {
1536    switch (ncols_dst) {
1537        case 1: reorder_mul_mat_vec_q2_k_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1538        case 2: reorder_mul_mat_vec_q2_k_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1539        case 3: reorder_mul_mat_vec_q2_k_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1540        case 4: reorder_mul_mat_vec_q2_k_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1541        case 5: reorder_mul_mat_vec_q2_k_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1542        case 6: reorder_mul_mat_vec_q2_k_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1543        case 7: reorder_mul_mat_vec_q2_k_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1544        case 8: reorder_mul_mat_vec_q2_k_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1545        default: GGML_ABORT("unsupported ncols_dst=%d for Q2_K reorder multi-col MMVQ", ncols_dst);
1546    }
1547}
1548
1549static void mul_mat_vec_q3_K_q8_1_sycl(const void *vx, const void *vy,
1550                                       float *dst, const int ncols,
1551                                       const int nrows,
1552                                       dpct::queue_ptr stream) {
1553    GGML_ASSERT(ncols % QK_K == 0);
1554    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1555    const sycl::range<3> block_nums(1, 1, block_num_y);
1556    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1557    {
1558
1559        stream->submit([&](sycl::handler &cgh) {
1560
1561            cgh.parallel_for(
1562                sycl::nd_range<3>(block_nums * block_dims, block_dims),
1563                [=](sycl::nd_item<3> item_ct1)
1564                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1565                        mul_mat_vec_q<QK_K, QI3_K, block_q3_K,
1566                                      VDR_Q3_K_Q8_1_MMVQ, vec_dot_q3_K_q8_1>(
1567                            vx, vy, dst, ncols, nrows, item_ct1);
1568                    });
1569        });
1570    }
1571}
1572
1573static void reorder_mul_mat_vec_q3_k_q8_1_sycl(const void * vx, const void * vy, float * dst, const int ncols,
1574                                               const int nrows, dpct::queue_ptr stream) {
1575    GGML_ASSERT(ncols % QK_K == 0);
1576
1577    // Round up to a whole number of subgroup-sized workgroups; out-of-range rows are skipped inside the kernel.
1578    constexpr size_t num_subgroups = WARP_SIZE;
1579    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups);
1580    const sycl::range<3> block_nums(1, 1, block_num_y);
1581    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
1582
1583    stream->submit([&](sycl::handler & cgh) {
1584        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
1585                         [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1586                             mul_mat_vec_q_reorder<reorder_vec_dot_q_sycl<GGML_TYPE_Q3_K>>(vx, vy, dst, ncols, nrows,
1587                                                                                           nd_item);
1588                         });
1589    });
1590}
1591
1592template <int ncols_dst>
1593static void reorder_mul_mat_vec_q3_k_q8_1_sycl_ncols(
1594        const void * vx, const void * vy, float * dst,
1595        const int ncols, const int nrows,
1596        const int stride_col_y_bytes, const int stride_col_dst,
1597        dpct::queue_ptr stream) {
1598    GGML_ASSERT(ncols % QK_K == 0);
1599    constexpr size_t num_subgroups = WARP_SIZE;
1600    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups);
1601    const sycl::range<3> block_nums(1, 1, block_num_y);
1602    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
1603
1604    stream->submit([&](sycl::handler & cgh) {
1605        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
1606                         [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1607                             mul_mat_vec_q_reorder_ncols<reorder_vec_dot_q_sycl<GGML_TYPE_Q3_K>, ncols_dst>(
1608                                 vx, /*vgate=*/ nullptr, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst,
1609                                 /*glu_op=*/ GGML_GLU_OP_SWIGLU, nd_item);
1610                         });
1611    });
1612}
1613
1614static void reorder_mul_mat_vec_q3_k_q8_1_sycl_switch_ncols(
1615        const void * vx, const void * vy, float * dst,
1616        const int ncols, const int nrows, const int ncols_dst,
1617        const int stride_col_y_bytes, const int stride_col_dst,
1618        dpct::queue_ptr stream) {
1619    switch (ncols_dst) {
1620        case 1: reorder_mul_mat_vec_q3_k_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1621        case 2: reorder_mul_mat_vec_q3_k_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1622        case 3: reorder_mul_mat_vec_q3_k_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1623        case 4: reorder_mul_mat_vec_q3_k_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1624        case 5: reorder_mul_mat_vec_q3_k_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1625        case 6: reorder_mul_mat_vec_q3_k_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1626        case 7: reorder_mul_mat_vec_q3_k_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1627        case 8: reorder_mul_mat_vec_q3_k_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1628        default: GGML_ABORT("unsupported ncols_dst=%d for Q3_K reorder multi-col MMVQ", ncols_dst);
1629    }
1630}
1631
1632template <int ncols_dst>
1633static void mul_mat_vec_q3_K_q8_1_sycl_ncols(
1634        const void * vx, const void * vy, float * dst,
1635        const int ncols, const int nrows,
1636        const int stride_col_y, const int stride_col_dst,
1637        dpct::queue_ptr stream) {
1638    GGML_ASSERT(ncols % QK_K == 0);
1639    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1640    const sycl::range<3> block_nums(1, 1, block_num_y);
1641    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1642    stream->submit([&](sycl::handler & cgh) {
1643        cgh.parallel_for(
1644            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1645            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1646                mul_mat_vec_q_ncols<QK_K, QI3_K, block_q3_K,
1647                                    VDR_Q3_K_Q8_1_MMVQ, vec_dot_q3_K_q8_1, ncols_dst>(
1648                    vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, item_ct1);
1649            });
1650    });
1651}
1652
1653static void mul_mat_vec_q3_K_q8_1_sycl_switch_ncols(
1654        const void * vx, const void * vy, float * dst,
1655        const int ncols, const int nrows, const int ncols_dst,
1656        const int stride_col_y, const int stride_col_dst,
1657        dpct::queue_ptr stream) {
1658    switch (ncols_dst) {
1659        case 1: mul_mat_vec_q3_K_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1660        case 2: mul_mat_vec_q3_K_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1661        case 3: mul_mat_vec_q3_K_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1662        case 4: mul_mat_vec_q3_K_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1663        case 5: mul_mat_vec_q3_K_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1664        case 6: mul_mat_vec_q3_K_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1665        case 7: mul_mat_vec_q3_K_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1666        case 8: mul_mat_vec_q3_K_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1667        default: GGML_ABORT("unsupported ncols_dst=%d for Q3_K multi-col MMVQ", ncols_dst);
1668    }
1669}
1670
1671
1672static void mul_mat_vec_q4_K_q8_1_sycl(const void *vx, const void *vy,
1673                                       float *dst, const int ncols,
1674                                       const int nrows,
1675                                       dpct::queue_ptr stream) {
1676    GGML_ASSERT(ncols % QK_K == 0);
1677    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1678    const sycl::range<3> block_nums(1, 1, block_num_y);
1679    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1680    {
1681
1682        stream->submit([&](sycl::handler &cgh) {
1683
1684            cgh.parallel_for(
1685                sycl::nd_range<3>(block_nums * block_dims, block_dims),
1686                [=](sycl::nd_item<3> item_ct1)
1687                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1688                        mul_mat_vec_q<QK_K, QI4_K, block_q4_K,
1689                                      VDR_Q4_K_Q8_1_MMVQ, vec_dot_q4_K_q8_1>(
1690                            vx, vy, dst, ncols, nrows, item_ct1);
1691                    });
1692        });
1693    }
1694}
1695
1696template <int ncols_dst>
1697static void mul_mat_vec_q4_K_q8_1_sycl_ncols(
1698        const void * vx, const void * vy, float * dst,
1699        const int ncols, const int nrows,
1700        const int stride_col_y, const int stride_col_dst,
1701        dpct::queue_ptr stream) {
1702    GGML_ASSERT(ncols % QK_K == 0);
1703    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1704    const sycl::range<3> block_nums(1, 1, block_num_y);
1705    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1706
1707    stream->submit([&](sycl::handler & cgh) {
1708        cgh.parallel_for(
1709            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1710            [=](sycl::nd_item<3> item_ct1)
1711                [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1712                    mul_mat_vec_q_ncols<QK_K, QI4_K, block_q4_K,
1713                                        VDR_Q4_K_Q8_1_MMVQ,
1714                                        vec_dot_q4_K_q8_1,
1715                                        ncols_dst>(
1716                        vx, vy, dst, ncols, nrows,
1717                        stride_col_y, stride_col_dst, item_ct1);
1718                });
1719    });
1720}
1721
1722static void mul_mat_vec_q4_K_q8_1_sycl_switch_ncols(
1723        const void * vx, const void * vy, float * dst,
1724        const int ncols, const int nrows,
1725        const int ncols_dst,
1726        const int stride_col_y, const int stride_col_dst,
1727        dpct::queue_ptr stream) {
1728    switch (ncols_dst) {
1729        case 1: mul_mat_vec_q4_K_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1730        case 2: mul_mat_vec_q4_K_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1731        case 3: mul_mat_vec_q4_K_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1732        case 4: mul_mat_vec_q4_K_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1733        case 5: mul_mat_vec_q4_K_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1734        case 6: mul_mat_vec_q4_K_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1735        case 7: mul_mat_vec_q4_K_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1736        case 8: mul_mat_vec_q4_K_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1737        default: GGML_ABORT("unsupported ncols_dst=%d for Q4_K multi-col MMVQ", ncols_dst);
1738    }
1739}
1740
1741static void reorder_mul_mat_vec_q4_k_q8_1_sycl(const void * vx, const void * vy, float * dst, const int ncols,
1742    const int nrows, dpct::queue_ptr stream) {
1743    GGML_ASSERT(ncols % QK_K == 0);
1744
1745    // Round up to a whole number of subgroup-sized workgroups; out-of-range rows are skipped inside the kernel.
1746    constexpr size_t num_subgroups = WARP_SIZE;
1747    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups);
1748    const sycl::range<3> block_nums(1, 1, block_num_y);
1749    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
1750
1751    stream->submit([&](sycl::handler & cgh) {
1752        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
1753                            [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1754                                mul_mat_vec_q_reorder<reorder_vec_dot_q_sycl<GGML_TYPE_Q4_K>>(vx, vy, dst, ncols,
1755                                                                                            nrows, nd_item);
1756                            });
1757    });
1758}
1759
1760template <int ncols_dst, int rows_per_sg>
1761static void reorder_mul_mat_vec_q4_k_q8_1_sycl_ncols_impl(
1762        const void * vx, const void * vy, float * dst,
1763        const int ncols, const int nrows,
1764        const int stride_col_y_bytes, const int stride_col_dst,
1765        dpct::queue_ptr stream) {
1766    GGML_ASSERT(ncols % QK_K == 0);
1767
1768    constexpr size_t num_subgroups = WARP_SIZE;
1769    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups * rows_per_sg);
1770    const sycl::range<3> block_nums(1, 1, block_num_y);
1771    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
1772
1773    stream->submit([&](sycl::handler & cgh) {
1774        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
1775                         [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1776                             mul_mat_vec_q_reorder_ncols<reorder_vec_dot_q_sycl<GGML_TYPE_Q4_K>, ncols_dst,
1777                                                        /*has_fusion=*/ false, rows_per_sg>(
1778                                 vx, /*vgate=*/ nullptr, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst,
1779                                 /*glu_op=*/ GGML_GLU_OP_SWIGLU, nd_item);
1780                         });
1781    });
1782}
1783
1784template <int ncols_dst>
1785static void reorder_mul_mat_vec_q4_k_q8_1_sycl_ncols(
1786        const void * vx, const void * vy, float * dst,
1787        const int ncols, const int nrows,
1788        const int stride_col_y_bytes, const int stride_col_dst,
1789        dpct::queue_ptr stream) {
1790    constexpr int rows_per_sg = ncols_dst >= 3 && ncols_dst <= 4 ? 2 : 1;
1791    reorder_mul_mat_vec_q4_k_q8_1_sycl_ncols_impl<ncols_dst, rows_per_sg>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream);
1792}
1793
1794static void reorder_mul_mat_vec_q4_k_q8_1_sycl_switch_ncols(
1795        const void * vx, const void * vy, float * dst,
1796        const int ncols, const int nrows, const int ncols_dst,
1797        const int stride_col_y_bytes, const int stride_col_dst,
1798        dpct::queue_ptr stream) {
1799    switch (ncols_dst) {
1800        case 1: reorder_mul_mat_vec_q4_k_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1801        case 2:
1802            if (nrows >= Q4_K_MMVQ_ROW_PAIR_MIN_NROWS) {
1803                reorder_mul_mat_vec_q4_k_q8_1_sycl_ncols_impl<2, 2>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream);
1804            } else {
1805                reorder_mul_mat_vec_q4_k_q8_1_sycl_ncols_impl<2, 1>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream);
1806            }
1807            break;
1808        case 3: reorder_mul_mat_vec_q4_k_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1809        case 4: reorder_mul_mat_vec_q4_k_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1810        case 5: reorder_mul_mat_vec_q4_k_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1811        case 6: reorder_mul_mat_vec_q4_k_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1812        case 7: reorder_mul_mat_vec_q4_k_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1813        case 8: reorder_mul_mat_vec_q4_k_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1814        default: GGML_ABORT("unsupported ncols_dst=%d for Q4_K reorder multi-col MMVQ", ncols_dst);
1815    }
1816}
1817
1818static void mul_mat_vec_q5_K_q8_1_sycl(const void *vx, const void *vy,
1819                                       float *dst, const int ncols,
1820                                       const int nrows,
1821                                       dpct::queue_ptr stream) {
1822    GGML_ASSERT(ncols % QK_K == 0);
1823    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1824    const sycl::range<3> block_nums(1, 1, block_num_y);
1825    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1826    {
1827
1828        stream->submit([&](sycl::handler &cgh) {
1829
1830            cgh.parallel_for(
1831                sycl::nd_range<3>(block_nums * block_dims, block_dims),
1832                [=](sycl::nd_item<3> item_ct1)
1833                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1834                        mul_mat_vec_q<QK_K, QI5_K, block_q5_K,
1835                                      VDR_Q5_K_Q8_1_MMVQ, vec_dot_q5_K_q8_1>(
1836                            vx, vy, dst, ncols, nrows, item_ct1);
1837                    });
1838        });
1839    }
1840}
1841
1842template <int ncols_dst>
1843static void mul_mat_vec_q5_K_q8_1_sycl_ncols(
1844        const void * vx, const void * vy, float * dst,
1845        const int ncols, const int nrows,
1846        const int stride_col_y, const int stride_col_dst,
1847        dpct::queue_ptr stream) {
1848    GGML_ASSERT(ncols % QK_K == 0);
1849    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
1850    const sycl::range<3> block_nums(1, 1, block_num_y);
1851    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
1852
1853    stream->submit([&](sycl::handler & cgh) {
1854        cgh.parallel_for(
1855            sycl::nd_range<3>(block_nums * block_dims, block_dims),
1856            [=](sycl::nd_item<3> item_ct1)
1857                [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1858                    mul_mat_vec_q_ncols<QK_K, QI5_K, block_q5_K,
1859                                        VDR_Q5_K_Q8_1_MMVQ,
1860                                        vec_dot_q5_K_q8_1,
1861                                        ncols_dst>(
1862                        vx, vy, dst, ncols, nrows,
1863                        stride_col_y, stride_col_dst, item_ct1);
1864                });
1865    });
1866}
1867
1868static void mul_mat_vec_q5_K_q8_1_sycl_switch_ncols(
1869        const void * vx, const void * vy, float * dst,
1870        const int ncols, const int nrows,
1871        const int ncols_dst,
1872        const int stride_col_y, const int stride_col_dst,
1873        dpct::queue_ptr stream) {
1874    switch (ncols_dst) {
1875        case 1: mul_mat_vec_q5_K_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1876        case 2: mul_mat_vec_q5_K_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1877        case 3: mul_mat_vec_q5_K_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1878        case 4: mul_mat_vec_q5_K_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1879        case 5: mul_mat_vec_q5_K_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1880        case 6: mul_mat_vec_q5_K_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1881        case 7: mul_mat_vec_q5_K_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1882        case 8: mul_mat_vec_q5_K_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
1883        default: GGML_ABORT("unsupported ncols_dst=%d for Q5_K multi-col MMVQ", ncols_dst);
1884    }
1885}
1886
1887static void reorder_mul_mat_vec_q5_k_q8_1_sycl(const void * vx, const void * vy, float * dst, const int ncols,
1888                                               const int nrows, dpct::queue_ptr stream) {
1889    GGML_ASSERT(ncols % QK_K == 0);
1890
1891    constexpr size_t num_subgroups = WARP_SIZE;
1892    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups);
1893    const sycl::range<3> block_nums(1, 1, block_num_y);
1894    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
1895
1896    stream->submit([&](sycl::handler & cgh) {
1897        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
1898                            [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1899                                mul_mat_vec_q_reorder<reorder_vec_dot_q_sycl<GGML_TYPE_Q5_K>>(vx, vy, dst, ncols,
1900                                                                                            nrows, nd_item);
1901                            });
1902    });
1903}
1904
1905template <int ncols_dst>
1906static void reorder_mul_mat_vec_q5_k_q8_1_sycl_ncols(
1907        const void * vx, const void * vy, float * dst,
1908        const int ncols, const int nrows,
1909        const int stride_col_y_bytes, const int stride_col_dst,
1910        dpct::queue_ptr stream) {
1911    GGML_ASSERT(ncols % QK_K == 0);
1912
1913    constexpr size_t num_subgroups = WARP_SIZE;
1914    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups);
1915    const sycl::range<3> block_nums(1, 1, block_num_y);
1916    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
1917
1918    stream->submit([&](sycl::handler & cgh) {
1919        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
1920                         [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1921                             mul_mat_vec_q_reorder_ncols<reorder_vec_dot_q_sycl<GGML_TYPE_Q5_K>, ncols_dst>(
1922                                 vx, /*vgate=*/ nullptr, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst,
1923                                 /*glu_op=*/ GGML_GLU_OP_SWIGLU, nd_item);
1924                         });
1925    });
1926}
1927
1928static void reorder_mul_mat_vec_q5_k_q8_1_sycl_switch_ncols(
1929        const void * vx, const void * vy, float * dst,
1930        const int ncols, const int nrows, const int ncols_dst,
1931        const int stride_col_y_bytes, const int stride_col_dst,
1932        dpct::queue_ptr stream) {
1933    switch (ncols_dst) {
1934        case 1: reorder_mul_mat_vec_q5_k_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1935        case 2: reorder_mul_mat_vec_q5_k_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1936        case 3: reorder_mul_mat_vec_q5_k_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1937        case 4: reorder_mul_mat_vec_q5_k_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1938        case 5: reorder_mul_mat_vec_q5_k_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1939        case 6: reorder_mul_mat_vec_q5_k_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1940        case 7: reorder_mul_mat_vec_q5_k_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1941        case 8: reorder_mul_mat_vec_q5_k_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1942        default: GGML_ABORT("unsupported ncols_dst=%d for Q5_K reorder multi-col MMVQ", ncols_dst);
1943    }
1944}
1945
1946static void reorder_mul_mat_vec_q6_k_q8_1_sycl(const void * vx, const void * vy, float * dst, const int ncols,
1947                                               const int nrows, dpct::queue_ptr stream) {
1948    GGML_ASSERT(ncols % QK_K == 0);
1949    // Round up to a whole number of subgroup-sized workgroups; out-of-range rows are skipped inside the kernel.
1950    constexpr size_t num_subgroups = WARP_SIZE;
1951    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups);
1952    const sycl::range<3> block_nums(1, 1, block_num_y);
1953    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
1954
1955
1956    stream->submit([&](sycl::handler & cgh) {
1957        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
1958                         [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1959                             mul_mat_vec_q_reorder<reorder_vec_dot_q_sycl<GGML_TYPE_Q6_K>>(vx, vy, dst, ncols, nrows,
1960                                                                                           nd_item);
1961                         });
1962    });
1963}
1964
1965template <int ncols_dst>
1966static void reorder_mul_mat_vec_q6_k_q8_1_sycl_ncols(
1967        const void * vx, const void * vy, float * dst,
1968        const int ncols, const int nrows,
1969        const int stride_col_y_bytes, const int stride_col_dst,
1970        dpct::queue_ptr stream) {
1971    GGML_ASSERT(ncols % QK_K == 0);
1972    constexpr size_t num_subgroups = WARP_SIZE;
1973    const int block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups);
1974    const sycl::range<3> block_nums(1, 1, block_num_y);
1975    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
1976
1977    stream->submit([&](sycl::handler & cgh) {
1978        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
1979                         [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1980                             mul_mat_vec_q_reorder_ncols<reorder_vec_dot_q_sycl<GGML_TYPE_Q6_K>, ncols_dst>(
1981                                 vx, /*vgate=*/ nullptr, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst,
1982                                 /*glu_op=*/ GGML_GLU_OP_SWIGLU, nd_item);
1983                         });
1984    });
1985}
1986
1987static void reorder_mul_mat_vec_q6_k_q8_1_sycl_switch_ncols(
1988        const void * vx, const void * vy, float * dst,
1989        const int ncols, const int nrows, const int ncols_dst,
1990        const int stride_col_y_bytes, const int stride_col_dst,
1991        dpct::queue_ptr stream) {
1992    switch (ncols_dst) {
1993        case 1: reorder_mul_mat_vec_q6_k_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
1994        case 2: reorder_mul_mat_vec_q6_k_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1995        case 3: reorder_mul_mat_vec_q6_k_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1996        case 4: reorder_mul_mat_vec_q6_k_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1997        case 5: reorder_mul_mat_vec_q6_k_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1998        case 6: reorder_mul_mat_vec_q6_k_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
1999        case 7: reorder_mul_mat_vec_q6_k_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
2000        case 8: reorder_mul_mat_vec_q6_k_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, stream); break;
2001        default: GGML_ABORT("unsupported ncols_dst=%d for Q6_K reorder multi-col MMVQ", ncols_dst);
2002    }
2003}
2004
2005static void mul_mat_vec_q6_K_q8_1_sycl(const void *vx, const void *vy,
2006                                       float *dst, const int ncols,
2007                                       const int nrows,
2008                                       dpct::queue_ptr stream) {
2009    GGML_ASSERT(ncols % QK_K == 0);
2010    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2011    const sycl::range<3> block_nums(1, 1, block_num_y);
2012    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2013    {
2014
2015        stream->submit([&](sycl::handler &cgh) {
2016
2017            cgh.parallel_for(
2018                sycl::nd_range<3>(block_nums * block_dims, block_dims),
2019                [=](sycl::nd_item<3> item_ct1)
2020                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2021                        mul_mat_vec_q<QK_K, QI6_K, block_q6_K,
2022                                      VDR_Q6_K_Q8_1_MMVQ, vec_dot_q6_K_q8_1>(
2023                            vx, vy, dst, ncols, nrows, item_ct1);
2024                    });
2025        });
2026    }
2027}
2028
2029template <int ncols_dst>
2030static void mul_mat_vec_q6_K_q8_1_sycl_ncols(
2031        const void * vx, const void * vy, float * dst,
2032        const int ncols, const int nrows,
2033        const int stride_col_y, const int stride_col_dst,
2034        dpct::queue_ptr stream) {
2035    GGML_ASSERT(ncols % QK_K == 0);
2036    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2037    const sycl::range<3> block_nums(1, 1, block_num_y);
2038    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2039
2040    stream->submit([&](sycl::handler & cgh) {
2041        cgh.parallel_for(
2042            sycl::nd_range<3>(block_nums * block_dims, block_dims),
2043            [=](sycl::nd_item<3> item_ct1)
2044                [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2045                    mul_mat_vec_q_ncols<QK_K, QI6_K, block_q6_K,
2046                                        VDR_Q6_K_Q8_1_MMVQ,
2047                                        vec_dot_q6_K_q8_1,
2048                                        ncols_dst>(
2049                        vx, vy, dst, ncols, nrows,
2050                        stride_col_y, stride_col_dst, item_ct1);
2051                });
2052    });
2053}
2054
2055static void mul_mat_vec_q6_K_q8_1_sycl_switch_ncols(
2056        const void * vx, const void * vy, float * dst,
2057        const int ncols, const int nrows,
2058        const int ncols_dst,
2059        const int stride_col_y, const int stride_col_dst,
2060        dpct::queue_ptr stream) {
2061    switch (ncols_dst) {
2062        case 1: mul_mat_vec_q6_K_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
2063        case 2: mul_mat_vec_q6_K_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2064        case 3: mul_mat_vec_q6_K_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2065        case 4: mul_mat_vec_q6_K_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2066        case 5: mul_mat_vec_q6_K_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2067        case 6: mul_mat_vec_q6_K_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2068        case 7: mul_mat_vec_q6_K_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2069        case 8: mul_mat_vec_q6_K_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2070        default: GGML_ABORT("unsupported ncols_dst=%d for Q6_K multi-col MMVQ", ncols_dst);
2071    }
2072}
2073
2074
2075static void mul_mat_vec_iq2_xxs_q8_1_sycl(const void *vx, const void *vy,
2076                                          float *dst, const int ncols,
2077                                          const int nrows,
2078                                          dpct::queue_ptr stream) {
2079    GGML_ASSERT(ncols % QK_K == 0);
2080    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2081    const sycl::range<3> block_nums(1, 1, block_num_y);
2082    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2083    {
2084        stream->submit([&](sycl::handler &cgh) {
2085            cgh.parallel_for(
2086                sycl::nd_range<3>(block_nums * block_dims, block_dims),
2087                [=](sycl::nd_item<3> item_ct1)
2088                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2089                        mul_mat_vec_q_iq2_xxs_q8_1<QK_K, QI2_XXS/2, block_iq2_xxs, 1>(
2090                            vx, vy, dst, ncols, nrows, item_ct1);
2091                    });
2092        });
2093    }
2094}
2095
2096static void mul_mat_vec_iq2_xs_q8_1_sycl(const void *vx, const void *vy,
2097                                         float *dst, const int ncols,
2098                                         const int nrows,
2099                                         dpct::queue_ptr stream) {
2100    GGML_ASSERT(ncols % QK_K == 0);
2101    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2102    const sycl::range<3> block_nums(1, 1, block_num_y);
2103    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2104    {
2105        stream->submit([&](sycl::handler & cgh) {
2106            cgh.parallel_for(
2107                sycl::nd_range<3>(block_nums * block_dims, block_dims),
2108                [=](sycl::nd_item<3> item_ct1)
2109                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2110                        mul_mat_vec_q_iq2_xs_q8_1<QK_K, QI2_XS/2, block_iq2_xs, 1>(
2111                            vx, vy, dst, ncols, nrows, item_ct1);
2112                    });
2113        });
2114    }
2115}
2116
2117static void mul_mat_vec_iq2_s_q8_1_sycl(const void *vx, const void *vy,
2118                                         float *dst, const int ncols,
2119                                         const int nrows,
2120                                         dpct::queue_ptr stream) {
2121    GGML_ASSERT(ncols % QK_K == 0);
2122    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2123    const sycl::range<3> block_nums(1, 1, block_num_y);
2124    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2125    {
2126
2127        stream->submit([&](sycl::handler &cgh) {
2128            cgh.parallel_for(
2129                sycl::nd_range<3>(block_nums * block_dims, block_dims),
2130                [=](sycl::nd_item<3> item_ct1)
2131                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2132                        mul_mat_vec_q_iq2_s_q8_1<QK_K, QI2_S/2, block_iq2_s, 1>(
2133                            vx, vy, dst, ncols, nrows, item_ct1);
2134                    });
2135        });
2136    }
2137}
2138
2139static void mul_mat_vec_iq3_xxs_q8_1_sycl(const void *vx, const void *vy,
2140                                          float *dst, const int ncols,
2141                                          const int nrows,
2142                                          dpct::queue_ptr stream) {
2143    GGML_ASSERT(ncols % QK_K == 0);
2144    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2145    const sycl::range<3> block_nums(1, 1, block_num_y);
2146    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2147    {
2148
2149        stream->submit([&](sycl::handler &cgh) {
2150            cgh.parallel_for(
2151                sycl::nd_range<3>(block_nums * block_dims, block_dims),
2152                [=](sycl::nd_item<3> item_ct1)
2153                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2154                        mul_mat_vec_q_iq3_xxs_q8_1<QK_K, QI3_XXS/2, block_iq3_xxs, 1>(
2155                            vx, vy, dst, ncols, nrows, item_ct1);
2156                    });
2157        });
2158    }
2159}
2160
2161static void mul_mat_vec_iq3_s_q8_1_sycl(const void *vx, const void *vy,
2162                                          float *dst, const int ncols,
2163                                          const int nrows,
2164                                          dpct::queue_ptr stream) {
2165    GGML_ASSERT(ncols % QK_K == 0);
2166    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2167    const sycl::range<3> block_nums(1, 1, block_num_y);
2168    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2169    {
2170
2171        stream->submit([&](sycl::handler &cgh) {
2172            cgh.parallel_for(
2173                sycl::nd_range<3>(block_nums * block_dims, block_dims),
2174                [=](sycl::nd_item<3> item_ct1)
2175                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2176                        mul_mat_vec_q_iq3_s_q8_1<QK_K, QI3_S/2, block_iq3_s, 1>(
2177                            vx, vy, dst, ncols, nrows, item_ct1);
2178                    });
2179        });
2180    }
2181}
2182
2183static void mul_mat_vec_iq1_s_q8_1_sycl(const void *vx, const void *vy,
2184                                          float *dst, const int ncols,
2185                                          const int nrows,
2186                                          dpct::queue_ptr stream) {
2187    GGML_ASSERT(ncols % QK_K == 0);
2188    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2189    const sycl::range<3> block_nums(1, 1, block_num_y);
2190    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2191    {
2192
2193        stream->submit([&](sycl::handler &cgh) {
2194            cgh.parallel_for(
2195                sycl::nd_range<3>(block_nums * block_dims, block_dims),
2196                [=](sycl::nd_item<3> item_ct1)
2197                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2198                        mul_mat_vec_q_iq1_s_q8_1<QK_K, QI1_S, block_iq1_s, 1>(
2199                            vx, vy, dst, ncols, nrows, item_ct1);
2200                    });
2201        });
2202    }
2203}
2204
2205static void mul_mat_vec_iq1_m_q8_1_sycl(const void *vx, const void *vy,
2206                                          float *dst, const int ncols,
2207                                          const int nrows,
2208                                          dpct::queue_ptr stream) {
2209    GGML_ASSERT(ncols % QK_K == 0);
2210    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2211    const sycl::range<3> block_nums(1, 1, block_num_y);
2212    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2213    {
2214        stream->submit([&](sycl::handler &cgh) {
2215            cgh.parallel_for(
2216                sycl::nd_range<3>(block_nums * block_dims, block_dims),
2217                [=](sycl::nd_item<3> item_ct1)
2218                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2219                        mul_mat_vec_q_iq1_m_q8_1<QK_K, QI1_S, block_iq1_m, 1>(
2220                            vx, vy, dst, ncols, nrows, item_ct1);
2221                    });
2222        });
2223    }
2224}
2225
2226static void mul_mat_vec_iq4_nl_q8_1_sycl(const void *vx, const void *vy,
2227                                          float *dst, const int ncols,
2228                                          const int nrows,
2229                                          dpct::queue_ptr stream) {
2230    GGML_ASSERT(ncols % QK4_NL == 0);
2231    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2232    const sycl::range<3> block_nums(1, 1, block_num_y);
2233    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2234    {
2235
2236        stream->submit([&](sycl::handler &cgh) {
2237            cgh.parallel_for(
2238                sycl::nd_range<3>(block_nums * block_dims, block_dims),
2239                [=](sycl::nd_item<3> item_ct1)
2240                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2241                        mul_mat_vec_q_iq4_nl_q8_1<QK4_NL, QI4_NL, block_iq4_nl, 2>(
2242                            vx, vy, dst, ncols, nrows, item_ct1);
2243                    });
2244        });
2245    }
2246}
2247
2248static void mul_mat_vec_iq4_xs_q8_1_sycl(const void *vx, const void *vy,
2249                                          float *dst, const int ncols,
2250                                          const int nrows,
2251                                          dpct::queue_ptr stream) {
2252    GGML_ASSERT(ncols % QK_K == 0);
2253    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2254    const sycl::range<3> block_nums(1, 1, block_num_y);
2255    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2256    {
2257
2258        stream->submit([&](sycl::handler &cgh) {
2259            cgh.parallel_for(
2260                sycl::nd_range<3>(block_nums * block_dims, block_dims),
2261                [=](sycl::nd_item<3> item_ct1)
2262                    [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2263                        mul_mat_vec_q_iq4_xs_q8_1<QK_K, QI4_XS/4, block_iq4_xs, 1>(
2264                            vx, vy, dst, ncols, nrows, item_ct1);
2265                    });
2266        });
2267    }
2268}
2269
2270template <int ncols_dst>
2271static void mul_mat_vec_iq4_xs_q8_1_sycl_ncols(
2272        const void * vx, const void * vy, float * dst,
2273        const int ncols, const int nrows,
2274        const int stride_col_y, const int stride_col_dst,
2275        dpct::queue_ptr stream) {
2276    GGML_ASSERT(ncols % QK_K == 0);
2277    const int block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2278    const sycl::range<3> block_nums(1, 1, block_num_y);
2279    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2280
2281    stream->submit([&](sycl::handler & cgh) {
2282        cgh.parallel_for(
2283            sycl::nd_range<3>(block_nums * block_dims, block_dims),
2284            [=](sycl::nd_item<3> item_ct1)
2285                [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2286                    mul_mat_vec_q_ncols<QK_K, QI4_XS/4, block_iq4_xs,
2287                                        1,
2288                                        vec_dot_iq4_xs_q8_1,
2289                                        ncols_dst>(
2290                        vx, vy, dst, ncols, nrows,
2291                        stride_col_y, stride_col_dst, item_ct1);
2292                });
2293    });
2294}
2295
2296static void mul_mat_vec_iq4_xs_q8_1_sycl_switch_ncols(
2297        const void * vx, const void * vy, float * dst,
2298        const int ncols, const int nrows,
2299        const int ncols_dst,
2300        const int stride_col_y, const int stride_col_dst,
2301        dpct::queue_ptr stream) {
2302    switch (ncols_dst) {
2303        case 1: mul_mat_vec_iq4_xs_q8_1_sycl(vx, vy, dst, ncols, nrows, stream); break;
2304        case 2: mul_mat_vec_iq4_xs_q8_1_sycl_ncols<2>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2305        case 3: mul_mat_vec_iq4_xs_q8_1_sycl_ncols<3>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2306        case 4: mul_mat_vec_iq4_xs_q8_1_sycl_ncols<4>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2307        case 5: mul_mat_vec_iq4_xs_q8_1_sycl_ncols<5>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2308        case 6: mul_mat_vec_iq4_xs_q8_1_sycl_ncols<6>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2309        case 7: mul_mat_vec_iq4_xs_q8_1_sycl_ncols<7>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2310        case 8: mul_mat_vec_iq4_xs_q8_1_sycl_ncols<8>(vx, vy, dst, ncols, nrows, stride_col_y, stride_col_dst, stream); break;
2311        default: GGML_ABORT("unsupported ncols_dst=%d for IQ4_XS multi-col MMVQ", ncols_dst);
2312    }
2313}
2314
2315void ggml_sycl_op_mul_mat_vec_q(ggml_backend_sycl_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1,
2316                                ggml_tensor * dst, const char * src0_dd_i, const float * src1_ddf_i,
2317                                const char * src1_ddq_i, float * dst_dd_i, const int64_t row_low,
2318                                const int64_t row_high, const int64_t src1_ncols, const int64_t src1_padded_col_size,
2319                                const dpct::queue_ptr & stream) {
2320    const int64_t ne10 = src1->ne[0];
2321    GGML_ASSERT(ne10 % QK8_1 == 0);
2322
2323    const int64_t ne00     = src0->ne[0];
2324    const int64_t row_diff = row_high - row_low;
2325
2326    int id;
2327    SYCL_CHECK(CHECK_TRY_ERROR(id = get_current_device_id()));
2328    const size_t q8_1_ts = sizeof(block_q8_1);
2329    const size_t q8_1_bs = QK8_1;
2330    // the main device has a larger memory buffer to hold the results from all GPUs
2331    // nrows_dst == nrows of the matrix that the kernel writes into
2332
2333    for (int i = 0; i < src1_ncols; i++) {
2334        const size_t src1_ddq_i_offset = i * src1_padded_col_size * q8_1_ts / q8_1_bs;
2335        const char * src1_ddq_i_bs     = src1_ddq_i + src1_ddq_i_offset;
2336        float *      dst_dd_i_bs       = dst_dd_i + i * dst->ne[0];
2337        switch (src0->type) {
2338            case GGML_TYPE_Q4_0:
2339                if ((ggml_tensor_extra_gpu *) dst->src[0]->extra &&
2340                    ((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
2341                    if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2342                        const int stride_col_y_bytes = src1_padded_col_size * q8_1_ts / q8_1_bs;
2343                        const int stride_col_dst     = dst->ne[0];
2344                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q4_0_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2345                        reorder_mul_mat_vec_q4_0_q8_1_sycl_switch_ncols(
2346                            src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2347                            src1_ncols, stride_col_y_bytes, stride_col_dst, stream);
2348                        return;
2349                    } else {
2350                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q4_0_q8_1_sycl\n");
2351                        reorder_mul_mat_vec_q4_0_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2352                    }
2353                } else if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2354                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2355                    const int stride_col_dst = dst->ne[0];
2356                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q4_0_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2357                    mul_mat_vec_q4_0_q8_1_sycl_switch_ncols(
2358                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2359                        src1_ncols, stride_col_y, stride_col_dst, stream);
2360                    return;
2361                } else if (i == 0 || src1_ncols == 1) {
2362                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q4_0_q8_1_sycl\n");
2363                    mul_mat_vec_q4_0_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2364                }
2365                break;
2366            case GGML_TYPE_Q4_1:
2367                if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2368                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2369                    const int stride_col_dst = dst->ne[0];
2370                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q4_1_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2371                    mul_mat_vec_q4_1_q8_1_sycl_switch_ncols(
2372                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2373                        src1_ncols, stride_col_y, stride_col_dst, stream);
2374                    return;
2375                } else if (i == 0 || src1_ncols == 1) {
2376                    mul_mat_vec_q4_1_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2377                }
2378                break;
2379            case GGML_TYPE_Q5_0:
2380                if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2381                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2382                    const int stride_col_dst = dst->ne[0];
2383                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q5_0_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2384                    mul_mat_vec_q5_0_q8_1_sycl_switch_ncols(
2385                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2386                        src1_ncols, stride_col_y, stride_col_dst, stream);
2387                    return;
2388                } else if (i == 0 || src1_ncols == 1) {
2389                    mul_mat_vec_q5_0_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2390                }
2391                break;
2392            case GGML_TYPE_Q5_1:
2393                if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2394                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2395                    const int stride_col_dst = dst->ne[0];
2396                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q5_1_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2397                    mul_mat_vec_q5_1_q8_1_sycl_switch_ncols(
2398                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2399                        src1_ncols, stride_col_y, stride_col_dst, stream);
2400                    return;
2401                } else if (i == 0 || src1_ncols == 1) {
2402                    mul_mat_vec_q5_1_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2403                }
2404                break;
2405            case GGML_TYPE_Q8_0:
2406                if ((ggml_tensor_extra_gpu *) dst->src[0]->extra &&
2407                    ((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
2408                    if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2409                        const int stride_col_y_bytes = src1_padded_col_size * q8_1_ts / q8_1_bs;
2410                        const int stride_col_dst     = dst->ne[0];
2411                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q8_0_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2412                        reorder_mul_mat_vec_q8_0_q8_1_sycl_switch_ncols(
2413                            src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2414                            src1_ncols, stride_col_y_bytes, stride_col_dst, stream);
2415                        return;
2416                    } else {
2417                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q8_0_q8_1_sycl\n");
2418                        reorder_mul_mat_vec_q8_0_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2419                    }
2420                } else if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2421                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2422                    const int stride_col_dst = dst->ne[0];
2423                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q8_0_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2424                    mul_mat_vec_q8_0_q8_1_sycl_switch_ncols(
2425                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2426                        src1_ncols, stride_col_y, stride_col_dst, stream);
2427                    return;
2428                } else if (i == 0 || src1_ncols == 1) {
2429                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q8_0_q8_1_sycl\n");
2430                    mul_mat_vec_q8_0_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2431                }
2432                break;
2433            case GGML_TYPE_Q1_0:
2434                if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2435                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2436                    const int stride_col_dst = dst->ne[0];
2437                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q1_0_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2438                    mul_mat_vec_q1_0_q8_1_sycl_switch_ncols(
2439                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2440                        src1_ncols, stride_col_y, stride_col_dst, stream);
2441                    return;
2442                } else if (i == 0 || src1_ncols == 1) {
2443                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q1_0_q8_1_sycl\n");
2444                    mul_mat_vec_q1_0_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2445                }
2446                break;
2447            case GGML_TYPE_Q2_0:
2448                if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2449                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2450                    const int stride_col_dst = dst->ne[0];
2451                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q2_0_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2452                    mul_mat_vec_q2_0_q8_1_sycl_switch_ncols(
2453                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2454                        src1_ncols, stride_col_y, stride_col_dst, stream);
2455                    return;
2456                } else if (i == 0 || src1_ncols == 1) {
2457                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q2_0_q8_1_sycl\n");
2458                    mul_mat_vec_q2_0_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2459                }
2460                break;
2461            case GGML_TYPE_Q2_K:
2462                if ((ggml_tensor_extra_gpu *) dst->src[0]->extra &&
2463                    ((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
2464                    if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2465                        const int stride_col_y_bytes = src1_padded_col_size * q8_1_ts / q8_1_bs;
2466                        const int stride_col_dst     = dst->ne[0];
2467                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q2_k_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2468                        reorder_mul_mat_vec_q2_k_q8_1_sycl_switch_ncols(
2469                            src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2470                            src1_ncols, stride_col_y_bytes, stride_col_dst, stream);
2471                        return;
2472                    } else {
2473                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q2_k_q8_1_sycl\n");
2474                        reorder_mul_mat_vec_q2_k_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2475                    }
2476                } else if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2477                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2478                    const int stride_col_dst = dst->ne[0];
2479                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q2_K_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2480                    mul_mat_vec_q2_K_q8_1_sycl_switch_ncols(
2481                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2482                        src1_ncols, stride_col_y, stride_col_dst, stream);
2483                    return;
2484                } else if (i == 0 || src1_ncols == 1) {
2485                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q2_K_q8_1_sycl\n");
2486                    mul_mat_vec_q2_K_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2487                }
2488                break;
2489            case GGML_TYPE_Q3_K:
2490                if ((ggml_tensor_extra_gpu *) dst->src[0]->extra &&
2491                    ((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
2492                    if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2493                        const int stride_col_y_bytes = src1_padded_col_size * q8_1_ts / q8_1_bs;
2494                        const int stride_col_dst     = dst->ne[0];
2495                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q3_k_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2496                        reorder_mul_mat_vec_q3_k_q8_1_sycl_switch_ncols(
2497                            src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2498                            src1_ncols, stride_col_y_bytes, stride_col_dst, stream);
2499                        return;
2500                    } else {
2501                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q3_k_q8_1_sycl\n");
2502                        reorder_mul_mat_vec_q3_k_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2503                    }
2504                } else if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2505                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2506                    const int stride_col_dst = dst->ne[0];
2507                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q3_K_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2508                    mul_mat_vec_q3_K_q8_1_sycl_switch_ncols(
2509                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2510                        src1_ncols, stride_col_y, stride_col_dst, stream);
2511                    return;
2512                } else if (i == 0 || src1_ncols == 1) {
2513                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q3_K_q8_1_sycl\n");
2514                    mul_mat_vec_q3_K_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2515                }
2516                break;
2517            case GGML_TYPE_Q4_K:
2518                if ((ggml_tensor_extra_gpu *) dst->src[0]->extra &&
2519                    ((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
2520                    if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2521                        const int stride_col_y_bytes = src1_padded_col_size * q8_1_ts / q8_1_bs;
2522                        const int stride_col_dst     = dst->ne[0];
2523                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q4_k_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2524                        reorder_mul_mat_vec_q4_k_q8_1_sycl_switch_ncols(
2525                            src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2526                            src1_ncols, stride_col_y_bytes, stride_col_dst, stream);
2527                        return;
2528                    } else {
2529                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q4_k_q8_1_sycl\n");
2530                        reorder_mul_mat_vec_q4_k_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2531                    }
2532                } else if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2533                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2534                    const int stride_col_dst = dst->ne[0];
2535                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q4_K_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2536                    mul_mat_vec_q4_K_q8_1_sycl_switch_ncols(
2537                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2538                        src1_ncols, stride_col_y, stride_col_dst, stream);
2539                    return;
2540                } else if (i == 0 || src1_ncols == 1) {
2541                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q4_K_q8_1_sycl\n");
2542                    mul_mat_vec_q4_K_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2543                }
2544                break;
2545            case GGML_TYPE_Q5_K:
2546                if ((ggml_tensor_extra_gpu *) dst->src[0]->extra &&
2547                    ((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
2548                    if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2549                        const int stride_col_y_bytes = src1_padded_col_size * q8_1_ts / q8_1_bs;
2550                        const int stride_col_dst     = dst->ne[0];
2551                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q5_k_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2552                        reorder_mul_mat_vec_q5_k_q8_1_sycl_switch_ncols(
2553                            src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2554                            src1_ncols, stride_col_y_bytes, stride_col_dst, stream);
2555                        return;
2556                    } else {
2557                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q5_k_q8_1_sycl\n");
2558                        reorder_mul_mat_vec_q5_k_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2559                    }
2560                } else if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2561                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2562                    const int stride_col_dst = dst->ne[0];
2563                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q5_K_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2564                    mul_mat_vec_q5_K_q8_1_sycl_switch_ncols(
2565                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2566                        src1_ncols, stride_col_y, stride_col_dst, stream);
2567                    return;
2568                } else if (i == 0 || src1_ncols == 1) {
2569                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q5_K_q8_1_sycl\n");
2570                    mul_mat_vec_q5_K_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2571                }
2572                break;
2573            case GGML_TYPE_Q6_K:
2574                if ((ggml_tensor_extra_gpu *) dst->src[0]->extra &&
2575                    ((ggml_tensor_extra_gpu *) dst->src[0]->extra)->optimized_feature.reorder) {
2576                    if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2577                        const int stride_col_y_bytes = src1_padded_col_size * q8_1_ts / q8_1_bs;
2578                        const int stride_col_dst     = dst->ne[0];
2579                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q6_k_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2580                        reorder_mul_mat_vec_q6_k_q8_1_sycl_switch_ncols(
2581                            src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2582                            src1_ncols, stride_col_y_bytes, stride_col_dst, stream);
2583                        return;
2584                    } else {
2585                        GGML_SYCL_DEBUG("Calling reorder_mul_mat_vec_q6_k_q8_1_sycl\n");
2586                        reorder_mul_mat_vec_q6_k_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2587                    }
2588                } else if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2589                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2590                    const int stride_col_dst = dst->ne[0];
2591                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q6_K_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2592                    mul_mat_vec_q6_K_q8_1_sycl_switch_ncols(
2593                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2594                        src1_ncols, stride_col_y, stride_col_dst, stream);
2595                    return;
2596                } else if (i == 0 || src1_ncols == 1) {
2597                    GGML_SYCL_DEBUG("Calling mul_mat_vec_q6_k_q8_1_sycl\n");
2598                    mul_mat_vec_q6_K_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2599                }
2600                break;
2601            case GGML_TYPE_IQ1_S:
2602                mul_mat_vec_iq1_s_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2603                break;
2604            case GGML_TYPE_IQ1_M:
2605                mul_mat_vec_iq1_m_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2606                break;
2607            case GGML_TYPE_IQ2_XXS:
2608                mul_mat_vec_iq2_xxs_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2609                break;
2610            case GGML_TYPE_IQ2_XS:
2611                mul_mat_vec_iq2_xs_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2612                break;
2613            case GGML_TYPE_IQ2_S:
2614                mul_mat_vec_iq2_s_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2615                break;
2616            case GGML_TYPE_IQ3_XXS:
2617                mul_mat_vec_iq3_xxs_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2618                break;
2619            case GGML_TYPE_IQ3_S:
2620                mul_mat_vec_iq3_s_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2621                break;
2622            case GGML_TYPE_IQ4_NL:
2623                mul_mat_vec_iq4_nl_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2624                break;
2625            case GGML_TYPE_IQ4_XS:
2626                if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2627                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2628                    const int stride_col_dst = dst->ne[0];
2629                    GGML_SYCL_DEBUG("Calling mul_mat_vec_iq4_xs_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2630                    mul_mat_vec_iq4_xs_q8_1_sycl_switch_ncols(
2631                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2632                        src1_ncols, stride_col_y, stride_col_dst, stream);
2633                    return;
2634                } else if (i == 0 || src1_ncols == 1) {
2635                    mul_mat_vec_iq4_xs_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2636                }
2637                break;
2638            case GGML_TYPE_MXFP4:
2639                if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2640                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2641                    const int stride_col_dst = dst->ne[0];
2642                    GGML_SYCL_DEBUG("Calling mul_mat_vec_mxfp4_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2643                    mul_mat_vec_mxfp4_q8_1_sycl_switch_ncols(
2644                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2645                        src1_ncols, stride_col_y, stride_col_dst, stream);
2646                    return;
2647                } else if (i == 0 || src1_ncols == 1) {
2648                    mul_mat_vec_mxfp4_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2649                }
2650                break;
2651            case GGML_TYPE_NVFP4:
2652                if (i == 0 && src1_ncols > 1 && src1_ncols <= 8) {
2653                    const int stride_col_y   = src1_padded_col_size / QK8_1;
2654                    const int stride_col_dst = dst->ne[0];
2655                    GGML_SYCL_DEBUG("Calling mul_mat_vec_nvfp4_q8_1_sycl_switch_ncols ncols=%d\n", (int)src1_ncols);
2656                    mul_mat_vec_nvfp4_q8_1_sycl_switch_ncols(
2657                        src0_dd_i, src1_ddq_i, dst_dd_i, ne00, row_diff,
2658                        src1_ncols, stride_col_y, stride_col_dst, stream);
2659                    return;
2660                } else if (i == 0 || src1_ncols == 1) {
2661                    mul_mat_vec_nvfp4_q8_1_sycl(src0_dd_i, src1_ddq_i_bs, dst_dd_i_bs, ne00, row_diff, stream);
2662                }
2663                break;
2664            default:
2665                GGML_ABORT("fatal error: unsupport src0 data type %s\n", ggml_type_name(src0->type));
2666        }
2667    }
2668    GGML_UNUSED(src1);
2669    GGML_UNUSED(dst);
2670    GGML_UNUSED(src1_ddf_i);
2671    GGML_UNUSED(ctx);
2672}
2673
2674// vec_dot_q_sycl_t adapters for the IQ vec_dots that take their codebook tables as extra
2675// arguments: bind the constant tables here (as vec_dot_iq2_s_q8_1 / vec_dot_iq1_m_q8_1 already do
2676// internally) so they can be used as template arguments of mul_mat_vec_q_moe.
2677static __dpct_inline__ float vec_dot_iq2_xxs_q8_1_moe(const void * __restrict__ vbq,
2678                                                      const block_q8_1 * __restrict__ bq8_1, const int & iqs) {
2679    return vec_dot_iq2_xxs_q8_1(vbq, bq8_1, iqs, iq2xxs_grid, ksigns_iq2xs, kmask_iq2xs);
2680}
2681
2682static __dpct_inline__ float vec_dot_iq2_xs_q8_1_moe(const void * __restrict__ vbq,
2683                                                     const block_q8_1 * __restrict__ bq8_1, const int & iqs) {
2684    return vec_dot_iq2_xs_q8_1(vbq, bq8_1, iqs, iq2xs_grid, ksigns64);
2685}
2686
2687static __dpct_inline__ float vec_dot_iq3_xxs_q8_1_moe(const void * __restrict__ vbq,
2688                                                      const block_q8_1 * __restrict__ bq8_1, const int & iqs) {
2689    return vec_dot_iq3_xxs_q8_1(vbq, bq8_1, iqs, iq3xxs_grid, ksigns64);
2690}
2691
2692static __dpct_inline__ float vec_dot_iq3_s_q8_1_moe(const void * __restrict__ vbq,
2693                                                    const block_q8_1 * __restrict__ bq8_1, const int & iqs) {
2694    return vec_dot_iq3_s_q8_1(vbq, bq8_1, iqs, iq3s_grid);
2695}
2696
2697static __dpct_inline__ float vec_dot_iq1_s_q8_1_moe(const void * __restrict__ vbq,
2698                                                    const block_q8_1 * __restrict__ bq8_1, const int & iqs) {
2699    return vec_dot_iq1_s_q8_1(vbq, bq8_1, iqs, iq1s_grid_gpu);
2700}
2701
2702// src1_row_stride: 0 for shared src1 (gate/up proj), else per-expert stride (down proj).
2703template <int qk, int qi, typename block_q_t, int vdr, vec_dot_q_sycl_t vec_dot_q_sycl>
2704static void mul_mat_vec_q_moe(
2705    const void * __restrict__ vx_base, const void * __restrict__ vy_base,
2706    float * __restrict__ dst_base, const int32_t * __restrict__ ids_dev,
2707    const int ncols, const int nrows,
2708    const size_t expert_weight_stride, const size_t dst_row_stride,
2709    const size_t src1_row_stride,
2710    const sycl::nd_item<3> & item_ct1) {
2711
2712    const int expert_idx = item_ct1.get_group(1);
2713    const int i02        = ids_dev[expert_idx];
2714
2715    const char * vx = (const char *) vx_base + (size_t) i02 * expert_weight_stride;
2716    const char * vy = (const char *) vy_base + (size_t) expert_idx * src1_row_stride;
2717    float *      dst = (float *) ((char *) dst_base + (size_t) expert_idx * dst_row_stride);
2718
2719    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) + item_ct1.get_local_id(1);
2720
2721    if (row >= nrows) {
2722        return;
2723    }
2724
2725    const int     blocks_per_row  = ncols / qk;
2726    constexpr int blocks_per_warp = (vdr * WARP_SIZE + qi - 1) / qi;
2727
2728    float tmp = 0.0f;
2729
2730    const block_q_t *  x = (const block_q_t *) vx;
2731    const block_q8_1 * y = (const block_q8_1 *) vy;
2732
2733    for (int i = item_ct1.get_local_id(2) / (qi / vdr); i < blocks_per_row; i += blocks_per_warp) {
2734        const int ibx = row * blocks_per_row + i;
2735        const int iby = i * (qk / QK8_1);
2736
2737        for (size_t elem = 0; elem < qi / vdr; elem += WARP_SIZE) {
2738            const int iqs = elem + vdr * (item_ct1.get_local_id(2) % (qi / vdr));
2739            tmp += vec_dot_q_sycl(&x[ibx], &y[iby], iqs);
2740        }
2741    }
2742
2743#pragma unroll
2744    for (int mask = WARP_SIZE / 2; mask > 0; mask >>= 1) {
2745        tmp += dpct::permute_sub_group_by_xor(item_ct1.get_sub_group(), tmp, mask);
2746    }
2747
2748    if (item_ct1.get_local_id(2) == 0) {
2749        dst[row] = tmp;
2750    }
2751}
2752
2753template <int qk, int qi, typename block_q_t, int vdr, vec_dot_q_sycl_t vec_dot_q_sycl>
2754static void launch_mul_mat_vec_q_moe(
2755    const void * vx_base, const void * vy, const int32_t * ids_dev,
2756    float * dst_base, const int ncols, const int nrows, const int n_experts_used,
2757    const size_t expert_weight_stride, const size_t dst_row_stride,
2758    const size_t src1_row_stride,
2759    dpct::queue_ptr stream) {
2760    const int            block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2761    const sycl::range<3> block_nums(1, (unsigned) n_experts_used, (unsigned) block_num_y);
2762    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2763    stream->submit([&](sycl::handler & cgh) {
2764        cgh.parallel_for(
2765            sycl::nd_range<3>(block_nums * block_dims, block_dims),
2766            [=](sycl::nd_item<3> item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2767                mul_mat_vec_q_moe<qk, qi, block_q_t, vdr, vec_dot_q_sycl>(
2768                    vx_base, vy, dst_base, ids_dev, ncols, nrows,
2769                    expert_weight_stride, dst_row_stride, src1_row_stride, item);
2770            });
2771    });
2772}
2773
2774bool ggml_sycl_mul_mat_vec_q_id(
2775    enum ggml_type     src0_type,
2776    const void *       vx_base,
2777    const void *       vy,
2778    const int32_t *    ids_dev,
2779    float *            dst_base,
2780    int                ncols,
2781    int                nrows,
2782    int                n_experts_used,
2783    size_t             expert_weight_stride,
2784    size_t             dst_row_stride,
2785    size_t             src1_row_stride,
2786    dpct::queue_ptr    stream) {
2787    switch (src0_type) {
2788        case GGML_TYPE_Q4_0:
2789            launch_mul_mat_vec_q_moe<QK4_0, QI4_0, block_q4_0, VDR_Q4_0_Q8_1_MMVQ, vec_dot_q4_0_q8_1>(
2790                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2791                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2792            return true;
2793        case GGML_TYPE_Q4_1:
2794            launch_mul_mat_vec_q_moe<QK4_1, QI4_1, block_q4_1, VDR_Q4_1_Q8_1_MMVQ, vec_dot_q4_1_q8_1>(
2795                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2796                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2797            return true;
2798        case GGML_TYPE_Q5_0:
2799            launch_mul_mat_vec_q_moe<QK5_0, QI5_0, block_q5_0, VDR_Q5_0_Q8_1_MMVQ, vec_dot_q5_0_q8_1>(
2800                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2801                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2802            return true;
2803        case GGML_TYPE_Q5_1:
2804            launch_mul_mat_vec_q_moe<QK5_1, QI5_1, block_q5_1, VDR_Q5_1_Q8_1_MMVQ, vec_dot_q5_1_q8_1>(
2805                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2806                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2807            return true;
2808        case GGML_TYPE_Q8_0:
2809            launch_mul_mat_vec_q_moe<QK8_0, QI8_0, block_q8_0, VDR_Q8_0_Q8_1_MMVQ, vec_dot_q8_0_q8_1>(
2810                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2811                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2812            return true;
2813        case GGML_TYPE_Q2_0:
2814            launch_mul_mat_vec_q_moe<QK2_0, QI2_0, block_q2_0, VDR_Q2_0_Q8_1_MMVQ, vec_dot_q2_0_q8_1>(
2815                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2816                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2817            return true;
2818        case GGML_TYPE_Q2_K:
2819            launch_mul_mat_vec_q_moe<QK_K, QI2_K, block_q2_K, VDR_Q2_K_Q8_1_MMVQ, vec_dot_q2_K_q8_1>(
2820                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2821                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2822            return true;
2823        case GGML_TYPE_Q3_K:
2824            launch_mul_mat_vec_q_moe<QK_K, QI3_K, block_q3_K, VDR_Q3_K_Q8_1_MMVQ, vec_dot_q3_K_q8_1>(
2825                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2826                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2827            return true;
2828        case GGML_TYPE_Q4_K:
2829            launch_mul_mat_vec_q_moe<QK_K, QI4_K, block_q4_K, VDR_Q4_K_Q8_1_MMVQ, vec_dot_q4_K_q8_1>(
2830                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2831                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2832            return true;
2833        case GGML_TYPE_Q5_K:
2834            launch_mul_mat_vec_q_moe<QK_K, QI5_K, block_q5_K, VDR_Q5_K_Q8_1_MMVQ, vec_dot_q5_K_q8_1>(
2835                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2836                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2837            return true;
2838        case GGML_TYPE_Q6_K:
2839            launch_mul_mat_vec_q_moe<QK_K, QI6_K, block_q6_K, VDR_Q6_K_Q8_1_MMVQ, vec_dot_q6_K_q8_1>(
2840                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2841                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2842            return true;
2843        case GGML_TYPE_MXFP4:
2844            launch_mul_mat_vec_q_moe<QK_MXFP4, QI_MXFP4, block_mxfp4, VDR_MXFP4_Q8_1_MMVQ, vec_dot_mxfp4_q8_1>(
2845                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2846                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2847            return true;
2848        case GGML_TYPE_NVFP4:
2849            launch_mul_mat_vec_q_moe<QK_NVFP4, QI_NVFP4, block_nvfp4, VDR_NVFP4_Q8_1_MMVQ, vec_dot_nvfp4_q8_1>(
2850                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2851                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2852            return true;
2853        case GGML_TYPE_IQ2_XXS:
2854            launch_mul_mat_vec_q_moe<QK_K, QI2_XXS/2, block_iq2_xxs, VDR_IQ2_XXS_Q8_1_MMVQ, vec_dot_iq2_xxs_q8_1_moe>(
2855                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2856                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2857            return true;
2858        case GGML_TYPE_IQ2_XS:
2859            launch_mul_mat_vec_q_moe<QK_K, QI2_XS/2, block_iq2_xs, VDR_IQ2_XS_Q8_1_MMVQ, vec_dot_iq2_xs_q8_1_moe>(
2860                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2861                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2862            return true;
2863        case GGML_TYPE_IQ2_S:
2864            launch_mul_mat_vec_q_moe<QK_K, QI2_S/2, block_iq2_s, VDR_IQ2_S_Q8_1_MMVQ, vec_dot_iq2_s_q8_1>(
2865                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2866                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2867            return true;
2868        case GGML_TYPE_IQ3_XXS:
2869            launch_mul_mat_vec_q_moe<QK_K, QI3_XXS/2, block_iq3_xxs, VDR_IQ3_XXS_Q8_1_MMVQ, vec_dot_iq3_xxs_q8_1_moe>(
2870                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2871                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2872            return true;
2873        case GGML_TYPE_IQ3_S:
2874            launch_mul_mat_vec_q_moe<QK_K, QI3_S/2, block_iq3_s, VDR_IQ3_S_Q8_1_MMVQ, vec_dot_iq3_s_q8_1_moe>(
2875                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2876                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2877            return true;
2878        case GGML_TYPE_IQ1_S:
2879            launch_mul_mat_vec_q_moe<QK_K, QI1_S, block_iq1_s, VDR_IQ1_S_Q8_1_MMVQ, vec_dot_iq1_s_q8_1_moe>(
2880                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2881                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2882            return true;
2883        case GGML_TYPE_IQ1_M:
2884            launch_mul_mat_vec_q_moe<QK_K, QI1_S, block_iq1_m, VDR_IQ1_M_Q8_1_MMVQ, vec_dot_iq1_m_q8_1>(
2885                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2886                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2887            return true;
2888        case GGML_TYPE_IQ4_NL:
2889            launch_mul_mat_vec_q_moe<QK4_NL, QI4_NL, block_iq4_nl, VDR_IQ4_NL_Q8_1_MMVQ, vec_dot_iq4_nl_q8_1>(
2890                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2891                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2892            return true;
2893        case GGML_TYPE_IQ4_XS:
2894            launch_mul_mat_vec_q_moe<QK_K, QI4_XS/4, block_iq4_xs, VDR_IQ4_XS_Q8_1_MMVQ, vec_dot_iq4_xs_q8_1>(
2895                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
2896                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
2897            return true;
2898        default:
2899            return false;
2900    }
2901}
2902
2903// Reorder (SoA) MoE expert GEMV: MoE expert/row/lane indexing (from mul_mat_vec_q_moe) with the
2904// dense-reorder per-block reads (from mul_mat_vec_q_reorder). Each expert slice in vx_base is a
2905// self-contained SoA, so nblocks = nrows*(ncols/qk) per expert and the constant expert stride holds.
2906template <typename reorder_vec_dot_q_sycl>
2907static void mul_mat_vec_q_moe_reorder(
2908    const void * __restrict__ vx_base, const void * __restrict__ vy_base,
2909    float * __restrict__ dst_base, const int32_t * __restrict__ ids_dev,
2910    const int ncols, const int nrows,
2911    const size_t expert_weight_stride, const size_t dst_row_stride,
2912    const size_t src1_row_stride,
2913    const sycl::nd_item<3> & item_ct1) {
2914    using block_type   = ggml_sycl_reordered::block_q_t<reorder_vec_dot_q_sycl::gtype>;
2915    using block_traits = typename block_type::traits;
2916
2917    const int expert_idx = item_ct1.get_group(1);
2918    const int i02        = ids_dev[expert_idx];
2919
2920    const char * vx  = (const char *) vx_base + (size_t) i02 * expert_weight_stride;
2921    const char * vy  = (const char *) vy_base + (size_t) expert_idx * src1_row_stride;
2922    float *      dst = (float *) ((char *) dst_base + (size_t) expert_idx * dst_row_stride);
2923
2924    const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) + item_ct1.get_local_id(1);
2925    if (row >= nrows) {
2926        return;
2927    }
2928
2929    const auto sg = item_ct1.get_sub_group();
2930
2931    const int     blocks_per_row              = ncols / block_traits::qk;
2932    constexpr int blocks_per_subgroup         = ceil_div(block_traits::vdr_mmvq * WARP_SIZE, block_traits::qi);
2933    constexpr int block_elements_per_subgroup = block_traits::qi / block_traits::vdr_mmvq;
2934    const int     nblocks                     = nrows * (ncols / block_traits::qk);
2935
2936    static_assert(blocks_per_subgroup > 0);
2937    static_assert(block_elements_per_subgroup > 0);
2938
2939    float partial_sum = 0.0f;
2940    for (int i = sg.get_local_linear_id() / block_elements_per_subgroup; i < blocks_per_row; i += blocks_per_subgroup) {
2941        const int ibx = row * blocks_per_row + i;
2942
2943        const auto bx_offset = block_type::get_block_offset(ibx, nblocks);
2944        const auto d_offset  = block_type::get_d_offset(nrows, ncols, ibx);
2945
2946        const int           iby            = i * block_type::block_to_q8_1_ratio();
2947        const int8_t *      q8_1_quant_ptr = (const int8_t *) vy + iby * QK8_1;
2948        const sycl::half2 * q8_1_ds_ptr    = (const sycl::half2 *) ((const char *) vy + ncols + iby * sizeof(sycl::half2));
2949
2950#pragma unroll
2951        for (int elem = 0; elem < block_elements_per_subgroup; elem += WARP_SIZE) {
2952            const int iqs = elem + block_traits::vdr_mmvq * (sg.get_local_linear_id() % block_elements_per_subgroup);
2953            partial_sum += reorder_vec_dot_q_sycl()(vx, bx_offset, d_offset, q8_1_quant_ptr, q8_1_ds_ptr, iqs);
2954        }
2955    }
2956
2957    auto sum = sycl::reduce_over_group(sg, partial_sum, std::plus<>());
2958    if (sg.leader()) {
2959        dst[row] = sum;
2960    }
2961}
2962
2963template <typename reorder_vec_dot_q_sycl>
2964static void launch_mul_mat_vec_q_moe_reorder(
2965    const void * vx_base, const void * vy, const int32_t * ids_dev,
2966    float * dst_base, const int ncols, const int nrows, const int n_experts_used,
2967    const size_t expert_weight_stride, const size_t dst_row_stride,
2968    const size_t src1_row_stride,
2969    dpct::queue_ptr stream) {
2970    const int            block_num_y = (nrows + GGML_SYCL_MMV_Y - 1) / GGML_SYCL_MMV_Y;
2971    const sycl::range<3> block_nums(1, (unsigned) n_experts_used, (unsigned) block_num_y);
2972    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, WARP_SIZE);
2973    stream->submit([&](sycl::handler & cgh) {
2974        cgh.parallel_for(
2975            sycl::nd_range<3>(block_nums * block_dims, block_dims),
2976            [=](sycl::nd_item<3> item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
2977                mul_mat_vec_q_moe_reorder<reorder_vec_dot_q_sycl>(
2978                    vx_base, vy, dst_base, ids_dev, ncols, nrows,
2979                    expert_weight_stride, dst_row_stride, src1_row_stride, item);
2980            });
2981    });
2982}
2983
2984bool ggml_sycl_mul_mat_vec_q_id_reorder(
2985    enum ggml_type     src0_type,
2986    const void *       vx_base,
2987    const void *       vy,
2988    const int32_t *    ids_dev,
2989    float *            dst_base,
2990    int                ncols,
2991    int                nrows,
2992    int                n_experts_used,
2993    size_t             expert_weight_stride,
2994    size_t             dst_row_stride,
2995    size_t             src1_row_stride,
2996    dpct::queue_ptr    stream) {
2997    switch (src0_type) {
2998        case GGML_TYPE_Q4_K:
2999            launch_mul_mat_vec_q_moe_reorder<reorder_vec_dot_q_sycl<GGML_TYPE_Q4_K>>(
3000                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
3001                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
3002            return true;
3003        case GGML_TYPE_Q5_K:
3004            launch_mul_mat_vec_q_moe_reorder<reorder_vec_dot_q_sycl<GGML_TYPE_Q5_K>>(
3005                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
3006                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
3007            return true;
3008        case GGML_TYPE_Q6_K:
3009            launch_mul_mat_vec_q_moe_reorder<reorder_vec_dot_q_sycl<GGML_TYPE_Q6_K>>(
3010                vx_base, vy, ids_dev, dst_base, ncols, nrows, n_experts_used,
3011                expert_weight_stride, dst_row_stride, src1_row_stride, stream);
3012            return true;
3013        default:
3014            return false;
3015    }
3016}
3017
3018template <typename reorder_vec_dot_q_sycl, int ncols_dst, int rows_per_sg>
3019static void launch_mul_mat_vec_q_reorder_glu_impl(const void * vx, const void * vgate, const void * vy, float * dst,
3020                                             const int ncols, const int nrows, const int stride_col_y_bytes,
3021                                             const int stride_col_dst, const ggml_glu_op glu_op,
3022                                             dpct::queue_ptr stream) {
3023    GGML_ASSERT(ncols % QK_K == 0);
3024
3025    constexpr size_t num_subgroups = WARP_SIZE;
3026
3027    const int            block_num_y = ceil_div(nrows, GGML_SYCL_MMV_Y * (int) num_subgroups * rows_per_sg);
3028    const sycl::range<3> block_nums(1, 1, block_num_y);
3029    const sycl::range<3> block_dims(1, GGML_SYCL_MMV_Y, num_subgroups * WARP_SIZE);
3030
3031    stream->submit([&](sycl::handler & cgh) {
3032        cgh.parallel_for(sycl::nd_range<3>(block_nums * block_dims, block_dims),
3033                         [=](sycl::nd_item<3> nd_item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
3034                             mul_mat_vec_q_reorder_ncols<reorder_vec_dot_q_sycl, ncols_dst, /*has_fusion=*/ true,
3035                                                        rows_per_sg>(
3036                                 vx, vgate, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, glu_op,
3037                                 nd_item);
3038                         });
3039    });
3040}
3041
3042template <typename reorder_vec_dot_q_sycl, int ncols_dst>
3043static void launch_mul_mat_vec_q_reorder_glu(const void * vx, const void * vgate, const void * vy, float * dst,
3044                                             const int ncols, const int nrows, const int stride_col_y_bytes,
3045                                             const int stride_col_dst, const ggml_glu_op glu_op,
3046                                             dpct::queue_ptr stream) {
3047    constexpr int rows_per_sg =
3048        reorder_vec_dot_shared_activations<reorder_vec_dot_q_sycl::gtype>::value && ncols_dst >= 3 && ncols_dst <= 4
3049            ? 2
3050            : 1;
3051    launch_mul_mat_vec_q_reorder_glu_impl<reorder_vec_dot_q_sycl, ncols_dst, rows_per_sg>(vx, vgate, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, glu_op, stream);
3052}
3053
3054bool ggml_sycl_mul_mat_vec_q_glu_reorder(enum ggml_type src0_type, enum ggml_glu_op glu_op, const void * vx,
3055                                         const void * vgate, const void * vy, float * dst, int ncols, int nrows,
3056                                         int ncols_dst, int stride_col_y_bytes, int stride_col_dst,
3057                                         dpct::queue_ptr stream) {
3058    if (src0_type != GGML_TYPE_Q4_K) {
3059        return false;
3060    }
3061    if (glu_op != GGML_GLU_OP_SWIGLU && glu_op != GGML_GLU_OP_GEGLU) {
3062        return false;
3063    }
3064
3065    using vec_dot = reorder_vec_dot_q_sycl<GGML_TYPE_Q4_K>;
3066
3067    switch (ncols_dst) {
3068        case 1:
3069            launch_mul_mat_vec_q_reorder_glu<vec_dot, 1>(vx, vgate, vy, dst, ncols, nrows, stride_col_y_bytes,
3070                                                         stride_col_dst, glu_op, stream);
3071            return true;
3072        case 2:
3073            if (nrows >= Q4_K_MMVQ_ROW_PAIR_MIN_NROWS) {
3074                launch_mul_mat_vec_q_reorder_glu_impl<vec_dot, 2, 2>(vx, vgate, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, glu_op, stream);
3075            } else {
3076                launch_mul_mat_vec_q_reorder_glu_impl<vec_dot, 2, 1>(vx, vgate, vy, dst, ncols, nrows, stride_col_y_bytes, stride_col_dst, glu_op, stream);
3077            }
3078            return true;
3079        case 3:
3080            launch_mul_mat_vec_q_reorder_glu<vec_dot, 3>(vx, vgate, vy, dst, ncols, nrows, stride_col_y_bytes,
3081                                                         stride_col_dst, glu_op, stream);
3082            return true;
3083        case 4:
3084            launch_mul_mat_vec_q_reorder_glu<vec_dot, 4>(vx, vgate, vy, dst, ncols, nrows, stride_col_y_bytes,
3085                                                         stride_col_dst, glu_op, stream);
3086            return true;
3087        case 5:
3088            launch_mul_mat_vec_q_reorder_glu<vec_dot, 5>(vx, vgate, vy, dst, ncols, nrows, stride_col_y_bytes,
3089                                                         stride_col_dst, glu_op, stream);
3090            return true;
3091        case 6:
3092            launch_mul_mat_vec_q_reorder_glu<vec_dot, 6>(vx, vgate, vy, dst, ncols, nrows, stride_col_y_bytes,
3093                                                         stride_col_dst, glu_op, stream);
3094            return true;
3095        case 7:
3096            launch_mul_mat_vec_q_reorder_glu<vec_dot, 7>(vx, vgate, vy, dst, ncols, nrows, stride_col_y_bytes,
3097                                                         stride_col_dst, glu_op, stream);
3098            return true;
3099        case 8:
3100            launch_mul_mat_vec_q_reorder_glu<vec_dot, 8>(vx, vgate, vy, dst, ncols, nrows, stride_col_y_bytes,
3101                                                         stride_col_dst, glu_op, stream);
3102            return true;
3103        default:
3104            return false;
3105    }
3106}