char-fork/llama.cpp

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

Nick Farrellsycl: make --fit respect --fit-target better (#27629)cc83d7b48

char/aliceai-t5-moe
44.9 KiB1185 linesraw
1#pragma once
2
3#include <sycl/sycl.hpp>
4#include "dpct/helper.hpp"
5#include "common.hpp"
6#include "convert.hpp"
7#include "vecdotq.hpp"
8#include "fattn-buffers.hpp"
9#include "fattn.hpp"
10
11#include "ggml.h"
12
13#include <cstdint>
14#include <cmath>
15#include <float.h>
16
17
18#define FATTN_KQ_STRIDE       256
19#define HALF_MAX_HALF         sycl::half(65504.0f/2) // Use neg. of this instead of -INFINITY to initialize KQ max vals to avoid NaN upon subtraction.
20#define SOFTMAX_FTZ_THRESHOLD -20.0f                   // Softmax exp. of values smaller than this are flushed to zero to avoid NaNs.
21#define FATTN_KQ_MAX_OFFSET (3.0f*0.6931f)
22
23typedef void (*fattn_kernel_t)(
24    const char* Q,
25    const char* K,
26    const char* V,
27    const char* mask,
28    const char* sinks,
29    const int* KV_max,
30    float* dst,
31    sycl::float2* dst_meta,
32    const float scale,
33    const float max_bias,
34    const float m0,
35    const float m1,
36    const uint32_t n_head_log2,
37    const float logit_softcap,
38    const int32_t ne00,
39    const sycl::uint3 ne01,
40    const int32_t ne02,
41    const int32_t ne03,
42    const int32_t nb01,
43    const int32_t nb02,
44    const int32_t nb03,
45    const int32_t ne10,
46    const int32_t ne11,
47    const int32_t ne12,
48    const int32_t ne13,
49    const int32_t nb11,
50    const int32_t nb12,
51    const int64_t nb13,
52    const int32_t nb21,
53    const int32_t nb22,
54    const int64_t nb23,
55    const int32_t ne31,
56    const int32_t ne32,
57    const int32_t ne33,
58    const int32_t nb31,
59    const int32_t nb32,
60    const int64_t nb33);
61
62typedef float (*vec_dot_KQ_t)(
63    const char * __restrict__ K_c, const void * __restrict__ Q_v, const int * __restrict__ Q_q8 , const void * __restrict__ Q_ds);
64
65template <int D, int nthreads>
66static __dpct_inline__ float vec_dot_fattn_vec_KQ_f16(const char * __restrict__ K_c,
67                                                      const void * __restrict__ Q_v,
68                                                      const int * __restrict__ Q_q8,
69                                                      const void * __restrict__ Q_ds_v) {
70    const sycl::half2 * K_h2 = (const sycl::half2 *) K_c;
71    GGML_UNUSED(Q_q8);
72    GGML_UNUSED(Q_ds_v);
73
74    constexpr int cpy_nb = ggml_sycl_get_max_cpy_bytes();
75    constexpr int cpy_ne = cpy_nb / 4;
76
77    float sum = 0.0f;
78
79#pragma unroll
80    for (int k_KQ_0 = 0; k_KQ_0 < D/2; k_KQ_0 += nthreads*cpy_ne) {
81        sycl::half2 tmp[cpy_ne];
82        ggml_sycl_memcpy_1<sizeof(tmp)>(
83            tmp,
84            K_h2 + k_KQ_0 + (sycl::ext::oneapi::this_work_item::get_nd_item<3>().get_local_id(2) % nthreads) * cpy_ne);
85#pragma unroll
86        for (int k_KQ_1 = 0; k_KQ_1 < cpy_ne; ++k_KQ_1) {
87#ifdef GGML_SYCL_F16
88            ggml_sycl_mad(sum,                tmp[k_KQ_1] , ((const sycl::half2 *) Q_v)[k_KQ_0/nthreads + k_KQ_1]);
89#else
90            ggml_sycl_mad(sum, __half22float2(tmp[k_KQ_1]), ((const sycl::float2 *) Q_v)[k_KQ_0/nthreads + k_KQ_1]);
91#endif // GGML_SYCL_F16
92        }
93    }
94
95    return sum;
96}
97
98template <int D, int nthreads, int warp_size>
99static __dpct_inline__ float vec_dot_fattn_vec_KQ_q4_0(const char * __restrict__ K_c,
100                                                       const void * __restrict__ Q_v,
101                                                       const int * __restrict__ Q_q8,
102                                                       const void * __restrict__ Q_ds_v) {
103    auto item_ct1 = sycl::ext::oneapi::this_work_item::get_nd_item<3>();
104
105    const block_q4_0 * K_q4_0   = (const block_q4_0 *) K_c;
106    GGML_UNUSED(Q_v);
107
108    float sum = 0.0f;
109
110#pragma unroll
111    for (int k_KQ_0 = 0; k_KQ_0 < int(D/sizeof(int)); k_KQ_0 += nthreads) {
112        const int k_KQ =
113            k_KQ_0 + (nthreads == warp_size ? item_ct1.get_local_id(2) : item_ct1.get_local_id(2) % nthreads);
114
115        const int ib    = k_KQ /  QI8_1;
116        const int iqs4  = k_KQ %  QI4_0;
117        const int shift = k_KQ & (QI8_1/2);
118
119        int v;
120        ggml_sycl_memcpy_1<sizeof(int), 2>(&v, K_q4_0[ib].qs + sizeof(int)*iqs4);
121        v = (v >> shift) & 0x0F0F0F0F;
122        const int u = Q_q8[k_KQ_0/nthreads];
123
124        const int sumi = ggml_sycl_dp4a(v, u, 0);
125
126        const sycl::float2 Q_ds = ((const sycl::float2 *) Q_ds_v)[k_KQ_0 / nthreads];
127        sum += __half2float(K_q4_0[ib].d) * (sumi*Q_ds.x() - (8/QI8_1)*Q_ds.y());
128    }
129
130    return sum;
131}
132
133template <int D, int nthreads , int warp_size>
134static __dpct_inline__ float vec_dot_fattn_vec_KQ_q4_1(const char * __restrict__ K_c,
135                                                       const void * __restrict__ Q_v,
136                                                       const int * __restrict__ Q_q8,
137                                                       const void * __restrict__ Q_ds_v) {
138    auto               item_ct1 = sycl::ext::oneapi::this_work_item::get_nd_item<3>();
139    const block_q4_1 * K_q4_1   = (const block_q4_1 *) K_c;
140    GGML_UNUSED(Q_v);
141
142    float sum = 0.0f;
143
144#pragma unroll
145    for (int k_KQ_0 = 0; k_KQ_0 < int(D/sizeof(int)); k_KQ_0 += nthreads) {
146        const int k_KQ =
147            k_KQ_0 + (nthreads == warp_size ? item_ct1.get_local_id(2) : item_ct1.get_local_id(2) % nthreads);
148
149        const int ib    = k_KQ /  QI8_1;
150        const int iqs4  = k_KQ %  QI4_1;
151        const int shift = k_KQ & (QI8_1/2);
152
153        int v;
154        ggml_sycl_memcpy_1<sizeof(int)>(&v, K_q4_1[ib].qs + sizeof(int)*iqs4);
155        v = (v >> shift) & 0x0F0F0F0F;
156        const int u = Q_q8[k_KQ_0/nthreads];
157
158        const int sumi = ggml_sycl_dp4a(v, u, 0);
159
160        const sycl::float2 K_dm = (K_q4_1[ib].dm).template convert<float, sycl::rounding_mode::automatic>();
161        const sycl::float2 Q_ds = ((const sycl::float2 *) Q_ds_v)[k_KQ_0 / nthreads];
162
163        sum += K_dm.x()*Q_ds.x()*sumi + K_dm.y()*Q_ds.y()/QI8_1;
164    }
165
166    return sum;
167}
168
169template <int D, int nthreads, int warp_size>
170static __dpct_inline__ float vec_dot_fattn_vec_KQ_q5_0(const char * __restrict__ K_c,
171                                                       const void * __restrict__ Q_v,
172                                                       const int * __restrict__ Q_q8,
173                                                       const void * __restrict__ Q_ds_v) {
174    auto               item_ct1 = sycl::ext::oneapi::this_work_item::get_nd_item<3>();
175    const block_q5_0 * K_q5_0   = (const block_q5_0 *) K_c;
176    GGML_UNUSED(Q_v);
177
178    float sum = 0.0f;
179
180#pragma unroll
181    for (int k_KQ_0 = 0; k_KQ_0 < int(D/sizeof(int)); k_KQ_0 += nthreads) {
182        const int k_KQ =
183            k_KQ_0 + (nthreads == warp_size ? item_ct1.get_local_id(2) : item_ct1.get_local_id(2) % nthreads);
184
185        const int ib    = k_KQ /  QI8_1;
186        const int iqs4  = k_KQ %  QI5_0;
187        const int iqs8  = k_KQ %  QI8_1;
188        const int shift = k_KQ & (QI8_1/2);
189
190        int v;
191        ggml_sycl_memcpy_1<sizeof(int), 2>(&v, K_q5_0[ib].qs + sizeof(int)*iqs4);
192        v = (v >> shift) & 0x0F0F0F0F;
193
194        {
195            int vh;
196            ggml_sycl_memcpy_1<sizeof(int), 2>(&vh, K_q5_0[ib].qh);
197            vh >>= iqs8 * QI5_0;
198
199            v |= (vh <<  4) & 0x00000010; // 0 ->  4
200            v |= (vh << 11) & 0x00001000; // 1 -> 12
201            v |= (vh << 18) & 0x00100000; // 2 -> 20
202            v |= (vh << 25) & 0x10000000; // 3 -> 28
203        }
204
205        const int u = Q_q8[k_KQ_0/nthreads];
206
207        const int sumi = ggml_sycl_dp4a(v, u, 0);
208
209        const sycl::float2 Q_ds = ((const sycl::float2 *) Q_ds_v)[k_KQ_0 / nthreads];
210
211        sum += __half2float(K_q5_0[ib].d) * (sumi*Q_ds.x() - (16/QI8_1)*Q_ds.y());
212    }
213
214    return sum;
215}
216
217template <int D, int nthreads, int warp_size>
218static __dpct_inline__ float vec_dot_fattn_vec_KQ_q5_1(const char * __restrict__ K_c,
219                                                       const void * __restrict__ Q_v,
220                                                       const int * __restrict__ Q_q8,
221                                                       const void * __restrict__ Q_ds_v) {
222    auto               item_ct1 = sycl::ext::oneapi::this_work_item::get_nd_item<3>();
223    const block_q5_1 * K_q5_1   = (const block_q5_1 *) K_c;
224    GGML_UNUSED(Q_v);
225
226    float sum = 0.0f;
227
228#pragma unroll
229    for (int k_KQ_0 = 0; k_KQ_0 < int(D/sizeof(int)); k_KQ_0 += nthreads) {
230        const int k_KQ =
231            k_KQ_0 + (nthreads == warp_size ? item_ct1.get_local_id(2) : item_ct1.get_local_id(2) % nthreads);
232
233        const int ib    = k_KQ /  QI8_1;
234        const int iqs4  = k_KQ %  QI5_1;
235        const int iqs8  = k_KQ %  QI8_1;
236        const int shift = k_KQ & (QI8_1/2);
237
238        int v;
239        ggml_sycl_memcpy_1<sizeof(int)>(&v, K_q5_1[ib].qs + sizeof(int)*iqs4);
240        v = (v >> shift) & 0x0F0F0F0F;
241
242        {
243            int vh;
244            ggml_sycl_memcpy_1<sizeof(int)>(&vh, K_q5_1[ib].qh);
245            vh >>= iqs8 * QI5_0;
246
247            v |= (vh <<  4) & 0x00000010; // 0 ->  4
248            v |= (vh << 11) & 0x00001000; // 1 -> 12
249            v |= (vh << 18) & 0x00100000; // 2 -> 20
250            v |= (vh << 25) & 0x10000000; // 3 -> 28
251        }
252
253        const int u = Q_q8[k_KQ_0/nthreads];
254
255        const int sumi = ggml_sycl_dp4a(v, u, 0);
256
257        const sycl::float2 K_dm = (K_q5_1[ib].dm).template convert<float, sycl::rounding_mode::automatic>();
258        const sycl::float2 Q_ds = ((const sycl::float2 *) Q_ds_v)[k_KQ_0 / nthreads];
259
260        sum += K_dm.x()*Q_ds.x()*sumi + K_dm.y()*Q_ds.y()/QI8_1;
261    }
262
263    return sum;
264}
265
266template <int D, int nthreads, int warp_size>
267static __dpct_inline__ float vec_dot_fattn_vec_KQ_q8_0(const char * __restrict__ K_c,
268                                                       const void * __restrict__ Q_v,
269                                                       const int * __restrict__ Q_q8,
270                                                       const void * __restrict__ Q_ds_v) {
271    auto               item_ct1 = sycl::ext::oneapi::this_work_item::get_nd_item<3>();
272    const block_q8_0 * K_q8_0   = (const block_q8_0 *) K_c;
273    GGML_UNUSED(Q_v);
274
275    float sum = 0.0f;
276
277#pragma unroll
278    for (int k_KQ_0 = 0; k_KQ_0 < int(D/sizeof(int)); k_KQ_0 += nthreads) {
279        const int k_KQ =
280            k_KQ_0 + (nthreads == warp_size ? item_ct1.get_local_id(2) : item_ct1.get_local_id(2) % nthreads);
281
282        const int ib  = k_KQ / QI8_0;
283        const int iqs = k_KQ % QI8_0;
284
285        int v;
286        ggml_sycl_memcpy_1<sizeof(v), 2>(&v, K_q8_0[ib].qs + 4*iqs);
287
288        const sycl::float2 * Q_ds = (const sycl::float2 *) Q_ds_v;
289        const float          Q_d  = Q_ds[k_KQ_0 / nthreads].x();
290
291        sum += vec_dot_q8_0_q8_1_impl<float, 1>(&v, &Q_q8[k_KQ_0/nthreads], K_q8_0[ib].d, Q_d);
292    }
293
294    return sum;
295}
296
297template <typename Tds, int ni, int warp_size>
298static __dpct_inline__ void quantize_q8_1_to_shared(const float * __restrict__ x,
299                                                    const float scale,
300                                                    int * __restrict__ yq32,
301                                                    void * __restrict__ yds) {
302    auto item_ct1 = sycl::ext::oneapi::this_work_item::get_nd_item<3>();
303
304    float vals[sizeof(int)] = { 0.0f };
305#pragma unroll
306    for (int l = 0; l < int(sizeof(int)); ++l) {
307        vals[l] =
308            (ni == warp_size || item_ct1.get_local_id(2) < ni) ? scale * x[4 * item_ct1.get_local_id(2) + l] : 0.0f;
309    }
310
311    float amax = sycl::fabs(vals[0]);
312    float sum  = vals[0];
313#pragma unroll
314    for (int l = 1; l < int(sizeof(int)); ++l) {
315        amax = sycl::fmax(amax, sycl::fabs(vals[l]));
316        sum += vals[l];
317    }
318#pragma unroll
319    for (int mask = QI8_1/2; mask > 0; mask >>= 1) {
320        amax = sycl::fmax(
321            amax, dpct::permute_sub_group_by_xor(sycl::ext::oneapi::this_work_item::get_sub_group(), amax, mask));
322        sum += dpct::permute_sub_group_by_xor(sycl::ext::oneapi::this_work_item::get_sub_group(), sum, mask);
323    }
324
325    const float d = amax / 127;
326    int q32 = 0;
327    int8_t * q8 = (int8_t *) &q32;
328
329    if (d != 0.0f) {
330#pragma unroll
331        for (int l = 0; l < int(sizeof(int)); ++l) {
332            q8[l] = sycl::round(vals[l] / d);
333        }
334    }
335
336    yq32[item_ct1.get_local_id(2)] = q32;
337    if (item_ct1.get_local_id(2) % QI8_1 == 0 && (ni == warp_size || item_ct1.get_local_id(2) < ni)) {
338        if (std::is_same<Tds, sycl::half2>::value) {
339            ((sycl::half2  *) yds)[item_ct1.get_local_id(2)/QI8_1] =  make_half2(d, sum);
340        } else {
341            ((sycl::float2 *) yds)[item_ct1.get_local_id(2)/QI8_1] = make_float2(d, sum);
342        }
343    }
344}
345
346typedef void (*dequantize_V_t)(const void *, void *, const int64_t);
347
348template <typename T, int ne>
349static __dpct_inline__ void dequantize_V_f16(const void * __restrict__ vx, void * __restrict__ dst, const int64_t i0) {
350    if constexpr (std::is_same_v<T, sycl::half>) {
351        ggml_sycl_memcpy_1<ne * sizeof(sycl::half)>(dst, (const sycl::half *) vx + i0);
352    } else if constexpr (std::is_same_v<T, float>) {
353        static_assert(ne % 2 == 0, "bad ne");
354        sycl::half2 tmp[ne / 2];
355        ggml_sycl_memcpy_1<ne * sizeof(sycl::half)>(tmp, (const sycl::half *) vx + i0);
356        sycl::float2 * dst_f2 = (sycl::float2 *) dst;
357#pragma unroll
358        for (int l = 0; l < ne/2; ++l) {
359            dst_f2[l] = tmp[l].template convert<float, sycl::rounding_mode::automatic>();
360        }
361    } else {
362        static_assert(std::is_same_v<T, void>, "unsupported type");
363    }
364}
365
366template <typename T, int ne>
367static __dpct_inline__ void dequantize_V_q4_0(const void * __restrict__ vx, void * __restrict__ dst, const int64_t i0) {
368    const block_q4_0 * x = (const block_q4_0 *) vx;
369
370    const int64_t ib    =  i0          /  QK4_0;
371    const int     iqs   =  i0          % (QK4_0/2);
372    const int     shift = (i0 % QK4_0) / (QK4_0/2);
373
374    int q;
375    static_assert(ne == 2 || ne == 4, "bad ne");
376    ggml_sycl_memcpy_1<ne, 2>(&q, x[ib].qs + iqs);
377    q >>= 4*shift;
378    q &= 0x0F0F0F0F;
379    q = dpct::vectorized_binary<sycl::char4>(q, 0x08080808, dpct::sub_sat());
380
381    const int8_t * q8 = (const int8_t *) &q;
382
383#ifdef GGML_SYCL_F16
384    if constexpr (std::is_same_v<T, sycl::half>) {
385        const sycl::half2 d = sycl::half2(x[ib].d);
386
387#pragma unroll
388        for (int l0 = 0; l0 < ne; l0 += 2) {
389            ((sycl::half2 *) dst)[l0 / 2] = d * sycl::half2(q8[l0 + 0], q8[l0 + 1]);
390        }
391    } else
392#endif // GGML_SYCL_F16
393    if constexpr (std::is_same_v<T, float>) {
394        const float d = x[ib].d;
395
396#pragma unroll
397        for (int l = 0; l < ne; ++l) {
398            ((float *) dst)[l] = d * q8[l];
399        }
400    } else {
401        static_assert(std::is_same_v<T, void>, "bad type");
402    }
403}
404
405template <typename T, int ne>
406static __dpct_inline__ void dequantize_V_q4_1(const void * __restrict__ vx, void * __restrict__ dst, const int64_t i0) {
407    const block_q4_1 * x = (const block_q4_1 *) vx;
408
409    const int64_t ib    =  i0          /  QK4_1;
410    const int     iqs   =  i0          % (QK4_1/2);
411    const int     shift = (i0 % QK4_1) / (QK4_1/2);
412
413    int q;
414    static_assert(ne == 2 || ne == 4, "bad ne");
415    ggml_sycl_memcpy_1<ne>(&q, x[ib].qs + iqs);
416    q >>= 4*shift;
417    q &= 0x0F0F0F0F;
418
419    const int8_t * q8 = (const int8_t *) &q;
420
421#ifdef GGML_SYCL_F16
422    if constexpr (std::is_same_v<T, sycl::half>) {
423        const sycl::half2 dm = x[ib].dm;
424        const sycl::half2 d  = sycl::half2(dm[0]);
425        const sycl::half2 m  = sycl::half2(dm[1]);
426
427#pragma unroll
428        for (int l0 = 0; l0 < ne; l0 += 2) {
429            ((sycl::half2 *) dst)[l0 / 2] = d * sycl::half2(q8[l0 + 0], q8[l0 + 1]) + m;
430        }
431    } else
432#endif // GGML_SYCL_F16
433    if constexpr (std::is_same_v<T, float>) {
434        const sycl::float2 dm = (x[ib].dm).template convert<float, sycl::rounding_mode::automatic>();
435
436#pragma unroll
437        for (int l = 0; l < ne; ++l) {
438            ((float *) dst)[l] = dm.x() * q8[l] + dm.y();
439        }
440    } else {
441        static_assert(std::is_same_v<T, void>, "bad type");
442    }
443}
444
445template <typename T, int ne>
446static __dpct_inline__ void dequantize_V_q5_0(const void * __restrict__ vx, void * __restrict__ dst, const int64_t i0) {
447    const block_q5_0 * x = (const block_q5_0 *) vx;
448
449    const int64_t ib    =  i0          /  QK5_0;
450    const int     idq   =  i0          %  QK5_0;
451    const int     iqs   =  i0          % (QK5_0/2);
452    const int     shift = (i0 % QK5_0) / (QK5_0/2);
453
454    int q;
455    static_assert(ne == 2 || ne == 4, "bad ne");
456    ggml_sycl_memcpy_1<ne, 2>(&q, x[ib].qs + iqs);
457    q >>= 4*shift;
458    q &= 0x0F0F0F0F;
459
460    {
461        int qh;
462        ggml_sycl_memcpy_1<ne, 2>(&qh, x[ib].qh);
463#pragma unroll
464        for (int l = 0; l < ne; ++l) {
465            q |= ((qh >> (idq + l)) & 0x00000001) << (8*l + 4);
466        }
467    }
468
469    q = dpct::vectorized_binary<sycl::char4>(q, 0x10101010, dpct::sub_sat());
470
471    const int8_t * q8 = (const int8_t *) &q;
472
473#ifdef GGML_SYCL_F16
474    if constexpr (std::is_same_v<T, sycl::half>) {
475        const sycl::half2 d = sycl::half2(x[ib].d);
476
477#pragma unroll
478        for (int l0 = 0; l0 < ne; l0 += 2) {
479            ((sycl::half2 *) dst)[l0 / 2] = d * sycl::half2(q8[l0 + 0], q8[l0 + 1]);
480        }
481    } else
482#endif // GGML_SYCL_F16
483    if constexpr (std::is_same_v<T, float>) {
484        const float d = x[ib].d;
485
486#pragma unroll
487        for (int l = 0; l < ne; ++l) {
488            ((float *) dst)[l] = d * q8[l];
489        }
490    } else {
491        static_assert(std::is_same_v<T, void>, "bad type");
492    }
493}
494
495template <typename T, int ne>
496static __dpct_inline__ void dequantize_V_q5_1(const void * __restrict__ vx, void * __restrict__ dst, const int64_t i0) {
497    const block_q5_1 * x = (const block_q5_1 *) vx;
498
499    const int64_t ib    =  i0          /  QK5_1;
500    const int     idq   =  i0          %  QK5_1;
501    const int     iqs   =  i0          % (QK5_1/2);
502    const int     shift = (i0 % QK5_1) / (QK5_1/2);
503
504    int q;
505    static_assert(ne == 2 || ne == 4, "bad ne");
506    ggml_sycl_memcpy_1<ne>(&q, x[ib].qs + iqs);
507    q >>= 4*shift;
508    q &= 0x0F0F0F0F;
509
510    {
511        int qh;
512        ggml_sycl_memcpy_1<ne>(&qh, x[ib].qh);
513#pragma unroll
514        for (int l = 0; l < ne; ++l) {
515            q |= ((qh >> (idq + l)) & 0x00000001) << (8*l + 4);
516        }
517    }
518
519    const int8_t * q8 = (const int8_t *) &q;
520
521#ifdef GGML_SYCL_F16
522    if constexpr (std::is_same_v<T, sycl::half>) {
523        const sycl::half2 dm = x[ib].dm;
524        const sycl::half2 d  = sycl::half2(dm[0]);
525        const sycl::half2 m  = sycl::half2(dm[1]);
526
527#pragma unroll
528        for (int l0 = 0; l0 < ne; l0 += 2) {
529            ((sycl::half2 *) dst)[l0 / 2] = d * sycl::half2(q8[l0 + 0], q8[l0 + 1]) + m;
530        }
531    } else
532#endif // GGML_SYCL_F16
533    if constexpr (std::is_same_v<T, float>) {
534        const sycl::float2 dm = (x[ib].dm).template convert<float, sycl::rounding_mode::automatic>();
535
536#pragma unroll
537        for (int l = 0; l < ne; ++l) {
538            ((float *) dst)[l] = dm.x() * q8[l] + dm.y();
539        }
540    } else {
541        static_assert(std::is_same_v<T, void>, "bad type");
542    }
543}
544
545template <typename T, int ne>
546static __dpct_inline__ void dequantize_V_q8_0(const void * __restrict__ vx, void * __restrict__ dst, const int64_t i0) {
547    const block_q8_0 * x = (const block_q8_0 *) vx;
548
549    const int64_t ib  = i0 / QK8_0;
550    const int     iqs = i0 % QK8_0;
551
552    static_assert(ne % 2 == 0, "bad ne");
553    int8_t qs[ne];
554    ggml_sycl_memcpy_1<ne, 2>(qs, x[ib].qs + iqs);
555
556#ifdef GGML_SYCL_F16
557    if constexpr (std::is_same<T, sycl::half>::value) {
558        const sycl::half2 d = sycl::half2(x[ib].d);
559
560#pragma unroll
561        for (int l0 = 0; l0 < ne; l0 += 2) {
562            ((sycl::half2 *) dst)[l0 / 2] = d * make_half2(qs[l0 + 0], qs[l0 + 1]);
563        }
564    } else
565#endif // GGML_SYCL_F16
566    if constexpr (std::is_same<T, float>::value) {
567        const float d = x[ib].d;
568
569#pragma unroll
570        for (int l = 0; l < ne; ++l) {
571            ((float *) dst)[l] = d * qs[l];
572        }
573    } else {
574        static_assert(std::is_same_v<T, void>, "unsupported type");
575    }
576}
577
578template <int type_K, int D, int nthreads, int warp_size>
579constexpr vec_dot_KQ_t get_vec_dot_KQ() {
580    if constexpr (type_K == GGML_TYPE_F16) {
581        return vec_dot_fattn_vec_KQ_f16<D, nthreads>;
582    } else if constexpr (type_K == GGML_TYPE_Q4_0) {
583        return vec_dot_fattn_vec_KQ_q4_0<D, nthreads, warp_size>;
584    } else if constexpr (type_K == GGML_TYPE_Q4_1) {
585        return vec_dot_fattn_vec_KQ_q4_1<D, nthreads, warp_size>;
586    } else if constexpr (type_K == GGML_TYPE_Q5_0) {
587        return vec_dot_fattn_vec_KQ_q5_0<D, nthreads, warp_size>;
588    } else if constexpr (type_K == GGML_TYPE_Q5_1) {
589        return vec_dot_fattn_vec_KQ_q5_1<D, nthreads, warp_size>;
590    } else if constexpr (type_K == GGML_TYPE_Q8_0) {
591        return vec_dot_fattn_vec_KQ_q8_0<D, nthreads, warp_size>;
592    } else {
593        static_assert(type_K == -1, "bad type");
594        return nullptr;
595    }
596}
597
598template <int type_V, typename T, int ne>
599constexpr dequantize_V_t get_dequantize_V() {
600    if constexpr (type_V == GGML_TYPE_F16) {
601        return dequantize_V_f16<T, ne>;
602    } else if constexpr (type_V == GGML_TYPE_Q4_0) {
603        return dequantize_V_q4_0<T, ne>;
604    } else if constexpr (type_V == GGML_TYPE_Q4_1) {
605        return dequantize_V_q4_1<T, ne>;
606    } else if constexpr (type_V == GGML_TYPE_Q5_0) {
607        return dequantize_V_q5_0<T, ne>;
608    } else if constexpr (type_V == GGML_TYPE_Q5_1) {
609        return dequantize_V_q5_1<T, ne>;
610    } else if constexpr (type_V == GGML_TYPE_Q8_0) {
611        return dequantize_V_q8_0<T, ne>;
612    } else {
613        static_assert(type_V == -1, "bad type");
614        return nullptr;
615    }
616}
617
618template <int ncols1, int warp_size>
619static void flash_attn_mask_to_KV_max(const sycl::half2 * __restrict__ mask,
620                                      int * __restrict__ KV_max,
621                                      const int ne30,
622                                      const int s31,
623                                      const int s33,
624                                      int *     buf_iw) {
625    auto      item_ct1 = sycl::ext::oneapi::this_work_item::get_nd_item<3>();
626    const int ne31     = item_ct1.get_group_range(2);
627    const int tid      = item_ct1.get_local_id(2);
628    const int sequence = item_ct1.get_group(1);
629    const int jt       = item_ct1.get_group(2);
630
631    mask += sequence*s33 + jt*ncols1*s31;
632
633    if (tid < warp_size) {
634        buf_iw[tid] = 1;
635    }
636    item_ct1.barrier(sycl::access::fence_space::local_space);
637
638    int KV_max_sj = (ne30 - 1) * FATTN_KQ_STRIDE;
639    for (; KV_max_sj >= 0; KV_max_sj -= FATTN_KQ_STRIDE) {
640        int all_inf = 1;
641
642#pragma unroll
643        for (int j = 0; j < ncols1; ++j) {
644            const sycl::float2 tmp =
645                mask[j * s31 + KV_max_sj / 2 + tid].template convert<float, sycl::rounding_mode::automatic>();
646            all_inf = all_inf && int(sycl::isinf((float) (tmp.x()))) && int(sycl::isinf((float) (tmp.y())));
647        }
648
649        all_inf = warp_reduce_all<warp_size>(all_inf);
650        if (tid % warp_size == 0) {
651            buf_iw[tid / warp_size] = all_inf;
652        }
653        item_ct1.barrier(sycl::access::fence_space::local_space);
654        all_inf = buf_iw[tid % warp_size];
655        item_ct1.barrier(sycl::access::fence_space::local_space);
656        all_inf = warp_reduce_all<warp_size>(all_inf);
657
658        if (!all_inf) {
659            break;
660        }
661    }
662
663    // If the break in the loop was not triggered, KV_max_sj is now -FATTN_KQ_STRIDE.
664    // If the break was triggered it's the lower edge of the tile with the first non-masked values.
665    // In either case, walk back the decrementation by FATTN_KQ_STRIDE.
666    KV_max_sj += FATTN_KQ_STRIDE;
667
668    if (item_ct1.get_local_id(2) != 0) {
669        return;
670    }
671
672    KV_max[sequence*ne31 + jt] = KV_max_sj;
673}
674
675template <int D, int ncols1, int ncols2>  // D == head size
676
677static void flash_attn_stream_k_fixup(float * __restrict__ dst,
678                                      const sycl::float2 * __restrict__ dst_fixup,
679                                      const int ne01,
680                                      const int ne02,
681                                      const int ne03,
682                                      const int ne11,
683                                      const int ne12,
684                                      const int nbatch_fa) {
685    auto          item_ct1 = sycl::ext::oneapi::this_work_item::get_nd_item<3>();
686    constexpr int ncols    = ncols1 * ncols2;
687
688    const int bidx0 = item_ct1.get_group(2);
689    const int j     = item_ct1.get_group(1);
690    const int c     = item_ct1.get_group(0);
691    const int jc    = j*ncols2 + c;
692    const int tid   = item_ct1.get_local_id(2);
693
694    const float * dst_fixup_data = ((const float *) dst_fixup) + item_ct1.get_group_range(2) * (2 * 2 * ncols);
695
696    const int gqa_ratio = ne02 / ne12; // With grouped query attention there are > 1 Q matrices per K, V matrix.
697
698    const int iter_k     = (ne11      + (nbatch_fa - 1)) / nbatch_fa;
699    const int iter_j     = (ne01      + (ncols1    - 1)) / ncols1;
700    const int iter_z_gqa = (gqa_ratio + (ncols2    - 1)) / ncols2;
701
702    const int kbc0 = int64_t(bidx0 + 0) * (iter_k * iter_j * iter_z_gqa * ne12 * ne03) / item_ct1.get_group_range(2);
703    const int kbc0_stop =
704        int64_t(bidx0 + 1) * (iter_k * iter_j * iter_z_gqa * ne12 * ne03) / item_ct1.get_group_range(2);
705
706    const bool did_not_have_any_data   = kbc0 == kbc0_stop;
707    const bool wrote_beginning_of_tile = kbc0 % iter_k == 0;
708    const bool did_not_write_last      = kbc0/iter_k == kbc0_stop/iter_k && kbc0_stop % iter_k != 0;
709    if (did_not_have_any_data || wrote_beginning_of_tile || did_not_write_last) {
710        return;
711    }
712
713    // z_KV == K/V head index, zt_gqa = Q head start index per K/V head, jt = token position start index
714    const int sequence =  kbc0 /(iter_k*iter_j*iter_z_gqa*ne12);
715    const int z_KV     = (kbc0 - iter_k*iter_j*iter_z_gqa*ne12 * sequence)/(iter_k*iter_j*iter_z_gqa);
716    const int zt_gqa   = (kbc0 - iter_k*iter_j*iter_z_gqa*ne12 * sequence - iter_k*iter_j*iter_z_gqa * z_KV)/(iter_k*iter_j);
717    const int jt       = (kbc0 - iter_k*iter_j*iter_z_gqa*ne12 * sequence - iter_k*iter_j*iter_z_gqa * z_KV - iter_k*iter_j * zt_gqa) / iter_k;
718
719    const int zt_Q = z_KV*gqa_ratio + zt_gqa*ncols2; // Global Q head start index.
720
721    if (jt*ncols1 + j >= ne01 || zt_gqa*ncols2 + c >= gqa_ratio) {
722        return;
723    }
724
725    dst += sequence*ne02*ne01*D + jt*ne02*(ncols1*D) + zt_Q*D + (j*ne02 + c)*D + tid;
726
727    // Load the partial result that needs a fixup:
728    float dst_val = 0.0f;
729    float max_val = 0.0f;
730    float rowsum  = 0.0f;
731    {
732        dst_val = *dst;
733
734        const sycl::float2 tmp = dst_fixup[bidx0 * ncols + jc];
735        max_val                = tmp.x();
736        rowsum                 = tmp.y();
737    }
738
739    // Iterate over previous blocks and compute the combined results.
740    // All SYCL blocks that get here must have a previous block that needs a fixup.
741    int bidx = bidx0 - 1;
742    int kbc_stop = kbc0;
743    while(true) {
744        const int kbc = int64_t(bidx) * (iter_k * iter_j * iter_z_gqa * ne12 * ne03) / item_ct1.get_group_range(2);
745        if (kbc == kbc_stop) { // Did not have any data.
746            bidx--;
747            kbc_stop = kbc;
748            continue;
749        }
750
751        const float dst_add = dst_fixup_data[bidx*ncols*D + jc*D + tid];
752
753        const sycl::float2 tmp = dst_fixup[(item_ct1.get_group_range(2) + bidx) * ncols + jc];
754
755        // Scale the current and new value accumulators depending on the max. values.
756        const float max_val_new = sycl::fmax(max_val, tmp.x());
757
758        const float diff_val = max_val - max_val_new;
759        const float diff_add = tmp.x() - max_val_new;
760
761        const float scale_val = diff_val >= SOFTMAX_FTZ_THRESHOLD ? sycl::native::exp(diff_val) : 0.0f;
762        const float scale_add = diff_add >= SOFTMAX_FTZ_THRESHOLD ? sycl::native::exp(diff_add) : 0.0f;
763
764        dst_val = scale_val*dst_val + scale_add*dst_add;
765        rowsum  = scale_val * rowsum + scale_add * tmp.y();
766
767        max_val = max_val_new;
768
769        // If this block started in a previous tile we are done and don't need to combine additional partial results.
770        if (kbc % iter_k == 0 || kbc/iter_k < kbc0/iter_k) {
771            break;
772        }
773        bidx--;
774        kbc_stop = kbc;
775    }
776
777    // Write back final result:
778    *dst = dst_val / rowsum;
779}
780
781template <int D>  // D == head size
782
783static void flash_attn_combine_results(const float * __restrict__ VKQ_parts,
784                                       const sycl::float2 * __restrict__ VKQ_meta,
785                                       float * __restrict__ dst,
786                                       const int parallel_blocks,
787                                       uint8_t * dpct_local) {
788    // Dimension 0: threadIdx.x
789    // Dimension 1: blockIdx.x
790    // Dimension 2: blockIdx.y
791    // Dimension 3: blockIdx.z
792    // Memory layout is permuted with [0, 2, 1, 3]
793
794    auto      item_ct1 = sycl::ext::oneapi::this_work_item::get_nd_item<3>();
795    const int ne01     = item_ct1.get_group_range(2);
796    const int ne02     = item_ct1.get_group_range(1);
797
798    const int col      = item_ct1.get_group(2);
799    const int head     = item_ct1.get_group(1);
800    const int sequence = item_ct1.get_group(0);
801
802    const int j_dst_unrolled = (sequence*ne01 + col)*ne02 + head;
803
804    VKQ_parts += j_dst_unrolled * parallel_blocks*D;
805    VKQ_meta  += j_dst_unrolled * parallel_blocks;
806    dst       += j_dst_unrolled *                 D;
807
808    const int tid = item_ct1.get_local_id(2);
809    __builtin_assume(tid < D);
810
811    auto meta = (sycl::float2 *) dpct_local;
812    for (int i = tid; i < 2*parallel_blocks; i += D) {
813        ((float *) meta)[i] = ((const float *)VKQ_meta) [i];
814    }
815
816    item_ct1.barrier(sycl::access::fence_space::local_space);
817
818    float kqmax = meta[0].x();
819    for (int l = 1; l < parallel_blocks; ++l) {
820        kqmax = sycl::max(kqmax, meta[l].x());
821    }
822
823    float VKQ_numerator   = 0.0f;
824    float VKQ_denominator = 0.0f;
825    for (int l = 0; l < parallel_blocks; ++l) {
826        const float KQ_max_scale = sycl::native::exp(meta[l].x() - kqmax);
827
828        VKQ_numerator   += KQ_max_scale * VKQ_parts[l*D + tid];
829        VKQ_denominator += KQ_max_scale * meta[l].y();
830    }
831
832    dst[tid] = VKQ_numerator / VKQ_denominator;
833}
834
835template <fattn_kernel_t fattn_kernel, int warp_size>
836static void lauch_kernel(
837    dpct::dim3 group_range,
838    dpct::dim3 local_range,
839    queue_ptr q,
840    unsigned int local_mem_size,
841    const char* __restrict__ Q,
842    const char* __restrict__ K,
843    const char* __restrict__ V,
844    const char* __restrict__ mask,
845    const char* __restrict__ sinks,
846    const int* __restrict__ KV_max,
847    float* __restrict__ dst,
848    sycl::float2* __restrict__ dst_meta,
849    const float scale,
850    const float max_bias,
851    const float m0,
852    const float m1,
853    const uint32_t n_head_log2,
854    const float logit_softcap,
855    const int32_t ne00,
856    const sycl::uint3 ne01,
857    const int32_t ne02,
858    const int32_t ne03,
859    const int32_t nb01,
860    const int32_t nb02,
861    const int32_t nb03,
862    const int32_t ne10,
863    const int32_t ne11,
864    const int32_t ne12,
865    const int32_t ne13,
866    const int32_t nb11,
867    const int32_t nb12,
868    const int64_t nb13,
869    const int32_t nb21,
870    const int32_t nb22,
871    const int64_t nb23,
872    const int32_t ne31,
873    const int32_t ne32,
874    const int32_t ne33,
875    const int32_t nb31,
876    const int32_t nb32,
877    const int64_t nb33) {
878    GGML_UNUSED(local_mem_size);
879    q->submit([&](sycl::handler &cgh) {
880        cgh.parallel_for(
881            sycl::nd_range<3>(
882                static_cast<sycl::range<3>>(group_range * local_range),
883                static_cast<sycl::range<3>>(local_range)),
884            [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(warp_size)]] {
885                GGML_UNUSED(item_ct1);
886                fattn_kernel(Q, K, V, mask, sinks, KV_max, dst, dst_meta, scale,
887                             max_bias, m0, m1, n_head_log2, logit_softcap, ne00,
888                             ne01, ne02, ne03, nb01, nb02, nb03, ne10, ne11,
889                             ne12, ne13, nb11, nb12, nb13, nb21, nb22, nb23,
890                             ne31, ne32, ne33, nb31, nb32, nb33);
891            });
892    });
893}
894
895template <int DV, int ncols1, int ncols2, fattn_kernel_t fattn_kernel, int warp_size>
896void launch_fattn(
897    ggml_backend_sycl_context & ctx, ggml_tensor * dst, const int nwarps, const size_t nbytes_shared,
898    const int nbatch_fa, const bool need_f16_K, const bool need_f16_V, const bool stream_k) {
899
900    constexpr int ncols = ncols1 * ncols2;
901
902    const ggml_tensor * Q = dst->src[0];
903    const ggml_tensor * K = dst->src[1];
904    const ggml_tensor * V = dst->src[2];
905
906    const bool V_is_K_view = V->view_src && (V->view_src == K || (V->view_src == K->view_src && V->view_offs == K->view_offs));
907
908    const ggml_tensor * mask  = dst->src[3];
909    const ggml_tensor * sinks = dst->src[4];
910
911    ggml_tensor * KQV = dst;
912
913    GGML_ASSERT(Q->type == GGML_TYPE_F32);
914    GGML_ASSERT(KQV->type == GGML_TYPE_F32);
915
916    GGML_ASSERT(Q->nb[0] == ggml_element_size(Q));
917    GGML_ASSERT(K->nb[0] == ggml_element_size(K));
918    GGML_ASSERT(V->nb[0] == ggml_element_size(V));
919
920    GGML_ASSERT(!mask || mask->type == GGML_TYPE_F16);
921
922    ggml_sycl_pool & pool = ctx.pool();
923    ggml_sycl_fattn_kv_buffers & fbuf = ctx.fattn_buffers();
924    dpct::queue_ptr  main_stream = ctx.stream();
925    const int id  = ggml_sycl_get_device();
926    const int nsm = ggml_sycl_info().devices[id].nsm;
927
928    ggml_sycl_fattn_alloc        K_f16(fbuf.K);
929    ggml_sycl_fattn_alloc        V_f16(fbuf.V);
930    const ggml_sycl_fattn_extra  extra = ggml_sycl_fattn_get_extra(dst);
931    ggml_sycl_pool_alloc<int>    KV_max(pool);
932    ggml_sycl_pool_alloc<float>  dst_tmp(pool);
933    ggml_sycl_pool_alloc<sycl::float2> dst_tmp_meta(pool);
934
935    const char * K_data = (const char *) K->data;
936    size_t nb11 = K->nb[1];
937    size_t nb12 = K->nb[2];
938    size_t nb13 = K->nb[3];
939
940    const char * V_data = (const char *) V->data;
941    size_t nb21 = V->nb[1];
942    size_t nb22 = V->nb[2];
943    size_t nb23 = V->nb[3];
944
945    if (need_f16_K && K->type != GGML_TYPE_F16) {
946        const size_t bs = ggml_blck_size(K->type);
947        const size_t ts = ggml_type_size(K->type);
948
949        sycl::half * K_f16_ptr = extra.K_buffer_ptr ? (sycl::half *) extra.K_buffer_ptr
950                                                    : K_f16.alloc(ggml_nelements(K));
951        if (ggml_is_contiguously_allocated(K)) {
952            to_fp16_sycl_t to_fp16 = ggml_get_to_fp16_sycl(K->type, dst);
953            to_fp16(K_data, K_f16_ptr, ggml_nelements(K), main_stream);
954
955            nb11 = nb11 * bs * sizeof(sycl::half) / ts;
956            nb12 = nb12 * bs * sizeof(sycl::half) / ts;
957            nb13 = nb13 * bs * sizeof(sycl::half) / ts;
958        } else {
959            GGML_ASSERT(K->nb[0] == ts);
960            to_fp16_nc_sycl_t to_fp16 = ggml_get_to_fp16_nc_sycl(K->type);
961            const int64_t s01 = nb11 / ts;
962            const int64_t s02 = nb12 / ts;
963            const int64_t s03 = nb13 / ts;
964            to_fp16(K_data, K_f16_ptr, K->ne[0], K->ne[1], K->ne[2], K->ne[3], s01, s02, s03, main_stream);
965
966            nb11 = K->ne[0] * sizeof(sycl::half);
967            nb12 = K->ne[1] * nb11;
968            nb13 = K->ne[2] * nb12;
969        }
970        K_data = (char *) K_f16_ptr;
971    }
972
973    if (need_f16_V && V->type != GGML_TYPE_F16) {
974        if (V_is_K_view) {
975            V_data = K_data;
976            nb21   = nb11;
977            nb22   = nb12;
978            nb23   = nb13;
979        } else {
980            const size_t bs = ggml_blck_size(V->type);
981            const size_t ts = ggml_type_size(V->type);
982
983            sycl::half * V_f16_ptr = extra.V_buffer_ptr ? (sycl::half *) extra.V_buffer_ptr
984                                                        : V_f16.alloc(ggml_nelements(V));
985            if (ggml_is_contiguously_allocated(V)) {
986                to_fp16_sycl_t to_fp16 = ggml_get_to_fp16_sycl(V->type, dst);
987                to_fp16(V_data, V_f16_ptr, ggml_nelements(V), main_stream);
988                V_data = (char *) V_f16_ptr;
989
990                nb21 = nb21 * bs * sizeof(sycl::half) / ts;
991                nb22 = nb22 * bs * sizeof(sycl::half) / ts;
992                nb23 = nb23 * bs * sizeof(sycl::half) / ts;
993            } else {
994                GGML_ASSERT(V->nb[0] == ts);
995                to_fp16_nc_sycl_t to_fp16 = ggml_get_to_fp16_nc_sycl(V->type);
996                const int64_t s01 = nb21 / ts;
997                const int64_t s02 = nb22 / ts;
998                const int64_t s03 = nb23 / ts;
999                to_fp16(V_data, V_f16_ptr, V->ne[0], V->ne[1], V->ne[2], V->ne[3], s01, s02, s03, main_stream);
1000
1001                nb21 = V->ne[0] * sizeof(sycl::half);
1002                nb22 = V->ne[1] * nb21;
1003                nb23 = V->ne[2] * nb22;
1004            }
1005            V_data = (char *) V_f16_ptr;
1006        }
1007    }
1008
1009    const int ntiles_x     = ((Q->ne[1] + ncols1 - 1) / ncols1);
1010    const int gqa_ratio    = Q->ne[2] / K->ne[2];
1011    const int ntiles_z_gqa = ((gqa_ratio + ncols2 - 1) / ncols2);
1012    const int ntiles_total = ntiles_x * ntiles_z_gqa * K->ne[2] * Q->ne[3];
1013
1014    // Optional optimization where the mask is scanned to determine whether part of the calculation can be skipped.
1015    // Only worth the overhead if there is at lease one FATTN_KQ_STRIDE x FATTN_KQ_STRIDE square to be skipped or
1016    //     multiple sequences of possibly different lengths.
1017    if (mask && K->ne[1] % FATTN_KQ_STRIDE == 0 && (Q->ne[1] >= 1024 || Q->ne[3] > 1)) {
1018        const int s31 = mask->nb[1] / sizeof(sycl::half2);
1019        const int s33 = mask->nb[3] / sizeof(sycl::half2);
1020
1021        const dpct::dim3 blocks_num_KV_max(ntiles_x, Q->ne[3], 1);
1022        const dpct::dim3 block_dim_KV_max(FATTN_KQ_STRIDE / 2, 1, 1);
1023
1024        const int ne_KV_max = blocks_num_KV_max.x*blocks_num_KV_max.y;
1025        const int iter_k = K->ne[1] / FATTN_KQ_STRIDE;
1026
1027        KV_max.alloc(ne_KV_max);
1028        {
1029            dpct::has_capability_or_fail(main_stream->get_device(), { sycl::aspect::fp16 });
1030
1031            main_stream->submit([&](sycl::handler & cgh) {
1032                sycl::local_accessor<int, 1> buf_iw_acc_ct1(sycl::range<1>(warp_size), cgh);
1033
1034                auto mask_data_ct0  = (const sycl::half2 *) mask->data;
1035                auto KV_max_ptr_ct1 = KV_max.ptr;
1036
1037                cgh.parallel_for(sycl::nd_range<3>(blocks_num_KV_max * block_dim_KV_max, block_dim_KV_max),
1038                                 [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(warp_size)]] {
1039                                     GGML_UNUSED(item_ct1);
1040                                     flash_attn_mask_to_KV_max<ncols1, warp_size>(
1041                                         mask_data_ct0, KV_max_ptr_ct1, iter_k, s31, s33,
1042                                         buf_iw_acc_ct1.get_multi_ptr<sycl::access::decorated::no>().get());
1043                                 });
1044            });
1045        }
1046        SYCL_CHECK(0);
1047    }
1048
1049    const dpct::dim3 block_dim(warp_size, nwarps, 1);
1050
1051    // Max. number of active blocks limited by occupancy.
1052    int max_blocks_per_sm = ggml_sycl_info().devices[id].max_wg_per_cu;
1053    int parallel_blocks = max_blocks_per_sm;
1054    dpct::dim3 blocks_num;
1055    if (stream_k) {
1056        // For short contexts it can be faster to have the SMs work on whole tiles because this lets us skip the fixup.
1057        const int max_blocks = max_blocks_per_sm*nsm;
1058        const int nblocks_stream_k = max_blocks;
1059        const bool use_stream_k = true;
1060
1061        blocks_num.x = use_stream_k ? nblocks_stream_k : ntiles_total;
1062        blocks_num.y = 1;
1063        blocks_num.z = 1;
1064
1065        if (ntiles_total % blocks_num.x != 0) { // Fixup is only needed if the SMs work on fractional tiles.
1066            dst_tmp_meta.alloc((size_t(blocks_num.x) * ncols * (2 + DV/2)));
1067        }
1068    } else {
1069        const int ntiles_KQ = (K->ne[1] + nbatch_fa - 1) / nbatch_fa; // Max. number of parallel blocks limited by tensor size.
1070
1071        // parallel_blocks must not be larger than what the tensor size allows:
1072        parallel_blocks = std::min(parallel_blocks, ntiles_KQ);
1073        // todo fix the hard code change
1074        // parallel_blocks = ntiles_KQ;
1075
1076        // If ntiles_total % blocks_per_wave != 0 then some efficiency is lost due to tail effects.
1077        // Test whether parallel_blocks can be set to a higher value for better efficiency.
1078        const int blocks_per_wave = nsm * max_blocks_per_sm;
1079        int nwaves_best = 0;
1080        int efficiency_percent_best = 0;
1081        for (int parallel_blocks_test = parallel_blocks; parallel_blocks_test <= ntiles_KQ; ++parallel_blocks_test) {
1082            const int nblocks_total = ntiles_total * parallel_blocks_test;
1083            const int nwaves = (nblocks_total + blocks_per_wave - 1) / blocks_per_wave;
1084            const int efficiency_percent = 100 * nblocks_total / (nwaves*blocks_per_wave);
1085
1086            // Stop trying configurations with more waves if we already have good efficiency to avoid excessive overhead.
1087            if (efficiency_percent_best >= 95 && nwaves > nwaves_best) {
1088                break;
1089            }
1090
1091            if (efficiency_percent > efficiency_percent_best) {
1092                nwaves_best = nwaves;
1093                efficiency_percent_best = efficiency_percent;
1094                parallel_blocks = parallel_blocks_test;
1095            }
1096        }
1097
1098        blocks_num.x = ntiles_x;
1099        blocks_num.y = parallel_blocks;
1100        blocks_num.z = ntiles_z_gqa*K->ne[2]*Q->ne[3];
1101
1102        if (parallel_blocks > 1) {
1103            dst_tmp.alloc(parallel_blocks*ggml_nelements(KQV));
1104            dst_tmp_meta.alloc(parallel_blocks*ggml_nrows(KQV));
1105        }
1106    }
1107
1108    float scale         = 1.0f;
1109    float max_bias      = 0.0f;
1110    float logit_softcap = 0.0f;
1111
1112    memcpy(&scale,         (const float *) KQV->op_params + 0, sizeof(float));
1113    memcpy(&max_bias,      (const float *) KQV->op_params + 1, sizeof(float));
1114    memcpy(&logit_softcap, (const float *) KQV->op_params + 2, sizeof(float));
1115
1116    if (logit_softcap != 0.0f) {
1117        scale /= logit_softcap;
1118    }
1119
1120    const uint32_t n_head      = Q->ne[2];
1121    const uint32_t n_head_log2 = 1u << uint32_t(floorf(log2f(float(n_head))));
1122
1123    const float m0 = powf(2.0f, -(max_bias       ) / n_head_log2);
1124    const float m1 = powf(2.0f, -(max_bias / 2.0f) / n_head_log2);
1125
1126    // TODO other tensor dimensions after removal of WMMA kernel:
1127    const sycl::uint3 ne01 = init_fastdiv_values(Q->ne[1]);
1128
1129    GGML_ASSERT(block_dim.x % warp_size == 0);
1130
1131    lauch_kernel<fattn_kernel, warp_size>(
1132        blocks_num, block_dim, main_stream, (unsigned int) nbytes_shared, (const char *) Q->data, K_data, V_data,
1133        mask ? ((const char *) mask->data) : nullptr, sinks ? ((const char *) sinks->data) : nullptr, KV_max.ptr,
1134        !stream_k && parallel_blocks > 1 ? dst_tmp.ptr : (float *) KQV->data, (sycl::float2 *)dst_tmp_meta.ptr, scale, max_bias, m0, m1,
1135        n_head_log2, logit_softcap, Q->ne[0], ne01, Q->ne[2], Q->ne[3], Q->nb[1], Q->nb[2], Q->nb[3], K->ne[0],
1136        K->ne[1], K->ne[2], K->ne[3], nb11, nb12, nb13, nb21, nb22, nb23, mask ? mask->ne[1] : 0,
1137        mask ? mask->ne[2] : 0, mask ? mask->ne[3] : 0, mask ? mask->nb[1] : 0, mask ? mask->nb[2] : 0,
1138        mask ? mask->nb[3] : 0);
1139    SYCL_CHECK(0);
1140
1141    if (stream_k) {
1142        if (ntiles_total % blocks_num.x != 0) { // Fixup is only needed if the SMs work on fractional tiles.
1143            const dpct::dim3 block_dim_combine(DV, 1, 1);
1144            const dpct::dim3 blocks_num_combine = { blocks_num.x, ncols1, ncols2 };
1145
1146            main_stream->submit([&](sycl::handler & cgh) {
1147                auto KQV_data_ct0         = (float *) KQV->data;
1148                auto dst_tmp_meta_ptr_ct1 = dst_tmp_meta.ptr;
1149                auto Q_ne_ct2             = Q->ne[1];
1150                auto Q_ne_ct3             = Q->ne[2];
1151                auto Q_ne_ct4             = Q->ne[3];
1152                auto K_ne_ct5             = K->ne[1];
1153                auto K_ne_ct6             = K->ne[2];
1154
1155                cgh.parallel_for(sycl::nd_range<3>(blocks_num_combine * block_dim_combine, block_dim_combine),
1156                                 [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(warp_size)]] {
1157                                     GGML_UNUSED(item_ct1);
1158                                     flash_attn_stream_k_fixup<DV, ncols1, ncols2>(KQV_data_ct0, dst_tmp_meta_ptr_ct1,
1159                                                                                   Q_ne_ct2, Q_ne_ct3, Q_ne_ct4,
1160                                                                                   K_ne_ct5, K_ne_ct6, nbatch_fa);
1161                                 });
1162            });
1163        }
1164    } else if (parallel_blocks > 1) {
1165        const dpct::dim3 block_dim_combine(DV, 1, 1);
1166        const dpct::dim3 blocks_num_combine(Q->ne[1], Q->ne[2], Q->ne[3]);
1167        const size_t     nbytes_shared_combine = parallel_blocks * sizeof(sycl::float2);
1168        main_stream->submit([&](sycl::handler & cgh) {
1169            sycl::local_accessor<uint8_t, 1> dpct_local_acc_ct1(sycl::range<1>(nbytes_shared_combine), cgh);
1170
1171            auto dst_tmp_ptr_ct0      = dst_tmp.ptr;
1172            auto dst_tmp_meta_ptr_ct1 = dst_tmp_meta.ptr;
1173            auto KQV_data_ct2         = (float *) KQV->data;
1174
1175            cgh.parallel_for(sycl::nd_range<3>(blocks_num_combine * block_dim_combine, block_dim_combine),
1176                             [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(warp_size)]] {
1177                                 GGML_UNUSED(item_ct1);
1178                                 flash_attn_combine_results<DV>(
1179                                     dst_tmp_ptr_ct0, dst_tmp_meta_ptr_ct1, KQV_data_ct2, parallel_blocks,
1180                                     dpct_local_acc_ct1.get_multi_ptr<sycl::access::decorated::no>().get());
1181                             });
1182        });
1183    }
1184    SYCL_CHECK(0);
1185}