char-fork/llama.cpp

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

Aman Guptaggml: add SWIGLU_CLAMP (#27930)0190529ec

char/aliceai-t5-moe
56.7 KiB1432 linesraw
1#include "common.hpp"
2#include "ggml-sycl/presets.hpp"
3#include "ggml.h"
4#include "element_wise.hpp"
5
6#define SYCL_GLOBAL_ID_LOOP(K, ITEM) \
7    for (auto i = ITEM.get_global_id(0); i < (size_t)K; i += ITEM.get_global_range(0))
8
9#define SYCL_LOCAL_ID_CALC(ITEM, IDX) \
10    (ITEM.get_local_range(IDX) * ITEM.get_group(IDX) + ITEM.get_local_id(IDX))
11
12static void acc_f32(const char * x, const char * y, float * dst, const int64_t ne,
13    const int64_t ne0, const int64_t ne1, const int64_t ne2,
14    const int64_t nb00, const int64_t nb01, const int64_t nb02, const int64_t nb03,
15    const int64_t ne10, const int64_t ne11, const int64_t ne12, const int64_t ne13,
16    const int64_t nb10, const int64_t nb11, const int64_t nb12, const int64_t nb13,
17    const int64_t s11, const int64_t s12, const int64_t s13, const int64_t offset) {
18    auto item_ct1 = sycl::ext::oneapi::this_work_item::get_nd_item<3>();
19    const int64_t i = SYCL_LOCAL_ID_CALC(item_ct1, 2);
20
21    if (i >= ne) {
22        return;
23    }
24
25    int64_t src1_idx = i - offset;
26
27    int64_t tmp = src1_idx;
28    const int64_t i13 = tmp / s13;
29    tmp -= i13 * s13;
30    const int64_t i12 = tmp / s12;
31    tmp -= i12 * s12;
32    const int64_t i11 = tmp / s11;
33    tmp -= i11 * s11;
34    const int64_t i10 = tmp;
35
36    int64_t tmp_dst = i;
37    const int64_t i3 = tmp_dst / (ne2*ne1*ne0);
38    tmp_dst -= i3 * (ne2*ne1*ne0);
39    const int64_t i2 = tmp_dst / (ne1*ne0);
40    tmp_dst -= i2 * (ne1*ne0);
41    const int64_t i1 = tmp_dst / ne0;
42    tmp_dst -= i1 * ne0;
43    const int64_t i0 = tmp_dst;
44
45    float val = *(const float *) (x + i0*nb00 + i1*nb01 + i2*nb02 + i3*nb03);
46    if (src1_idx >= 0 && i10 < ne10 && i11 < ne11 && i12 < ne12 && i13 < ne13) {
47        val += *(const float *) (y + i10*nb10 + i11*nb11 + i12*nb12 + i13*nb13);
48    }
49    dst[i] = val;
50}
51
52/* Unary OP funcs */
53template<typename T>
54static __dpct_inline__ T op_sgn(T x) {
55    return x > static_cast<T>(0.f) ? static_cast<T>(1.f) : ((x < static_cast<T>(0.f) ? static_cast<T>(-1.f) : static_cast<T>(0.f)));
56}
57
58
59template<typename T>
60static __dpct_inline__ T op_abs(T x) {
61    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
62        return sycl::ext::oneapi::experimental::fabs(x);  // or experimental namespace if needed
63    } else {
64        return sycl::fabs(x);
65    }
66}
67
68template<typename T>
69static __dpct_inline__ T op_expm1(T x) {
70    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
71        return static_cast<sycl::ext::oneapi::bfloat16>(
72            sycl::expm1(static_cast<float>(x))
73        );
74    } else {
75        return sycl::expm1(x);
76    }
77}
78
79template<typename T>
80static __dpct_inline__ T op_elu(T x) {
81    return (x > static_cast<T>(0.f)) ? x : op_expm1(x);
82}
83
84template<typename T>
85static __dpct_inline__ T op_erf(T x) {
86    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
87        return static_cast<sycl::ext::oneapi::bfloat16>(
88            sycl::erf(static_cast<float>(x))
89        );
90    } else {
91        return sycl::erf(x);
92    }
93}
94
95template<typename T>
96static __dpct_inline__ T op_gelu_erf(T x) {
97    const T SQRT_2_INV = static_cast<T>(0.70710678118654752440084436210484f);
98    return static_cast<T>(0.5f) * x * (static_cast<T>(1.0f) + op_erf(x * SQRT_2_INV));
99}
100
101template<typename T>
102static __dpct_inline__ T op_gelu_quick(T x) {
103    const T GELU_QUICK_COEF_LOCAL = static_cast<T>(-1.702f);
104    return x * (static_cast<T>(1.0f) / (static_cast<T>(1.0f) + op_exp(GELU_QUICK_COEF_LOCAL * x)));
105}
106
107template<typename T>
108static __dpct_inline__ T op_relu(T x) {
109    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
110        return sycl::ext::oneapi::experimental::fmax(x, static_cast<T>(0));
111    } else {
112        return sycl::fmax(x, static_cast<T>(0));
113    }
114}
115
116template<typename T>
117static __dpct_inline__ T op_sigmoid(T x) {
118    return static_cast<T>(1.0f) / (static_cast<T>(1.0f) + op_exp(-x));
119}
120
121template<typename T>
122static __dpct_inline__ T op_sqrt(T x) {
123    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
124        return sycl::ext::oneapi::experimental::sqrt(x);
125    } else {
126        return sycl::sqrt(x);
127    }
128}
129
130template<typename T>
131static __dpct_inline__ T op_sin(T x) {
132    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
133        return sycl::ext::oneapi::experimental::sin(x);
134    } else {
135        return sycl::sin(x);
136    }
137}
138
139template<typename T>
140static __dpct_inline__ T op_cos(T x) {
141    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
142        return sycl::ext::oneapi::experimental::cos(x);
143    } else {
144        return sycl::cos(x);
145    }
146}
147
148template<typename T>
149static __dpct_inline__ T op_hardsigmoid(T x) {
150    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
151        return sycl::ext::oneapi::experimental::fmin(
152            static_cast<T>(1.0f), sycl::ext::oneapi::experimental::fmax(
153                                      static_cast<T>(0.0f), (x + static_cast<T>(3.0f)) / static_cast<T>(6.0f)));
154    } else {
155        return sycl::fmin(static_cast<T>(1.0f),
156                          sycl::fmax(static_cast<T>(0.0f), (x + static_cast<T>(3.0f)) / static_cast<T>(6.0f)));
157    }
158}
159
160template<typename T>
161static __dpct_inline__ T op_hardswish(T x) {
162    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
163        return x * sycl::ext::oneapi::experimental::fmin(static_cast<T>(1.0f), sycl::ext::oneapi::experimental::fmax(static_cast<T>(0.0f), (x + static_cast<T>(3.0f)) / static_cast<T>(6.0f)));
164    } else {
165        return x * sycl::fmin(static_cast<T>(1.0f), sycl::fmax(static_cast<T>(0.0f), (x + static_cast<T>(3.0f)) / static_cast<T>(6.0f)));
166    }
167}
168
169template<typename T>
170static __dpct_inline__ T op_log(T x) {
171    if (x <= static_cast<T>(0)) {
172        return neg_infinity<T>();
173    }
174    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
175        return sycl::ext::oneapi::experimental::log(x);
176    } else {
177        return sycl::log(x);
178    }
179}
180
181template<typename T>
182static __dpct_inline__ T op_softplus(T x) {
183    const float xf = (float) x;
184    const float ax = op_abs(xf);
185    const float m  = sycl::fmax(xf, 0.0f);
186    const float y  = m + sycl::log1p(sycl::exp(-ax));
187    return (T) y;
188}
189
190template<typename T>
191static __dpct_inline__ T op_neg(T x) {
192    return -x;
193}
194
195template<typename T>
196static __dpct_inline__ T op_step(T x) {
197    return (x > static_cast<T>(0.0f)) ? static_cast<T>(1.0f) : static_cast<T>(0.0f);
198}
199
200template<typename T>
201static __dpct_inline__ T op_leaky_relu(T x, float negative_slope) {
202    T neg_slope_T = static_cast<T>(negative_slope);
203    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
204        return sycl::ext::oneapi::experimental::fmax(x, static_cast<T>(0)) +
205           sycl::ext::oneapi::experimental::fmin(x, static_cast<T>(0.0f)) * neg_slope_T;
206
207    } else {
208        return sycl::fmax(x, static_cast<T>(0)) +
209           sycl::fmin(x, static_cast<T>(0.0f)) * neg_slope_T;
210    }
211}
212
213template<typename T>
214static __dpct_inline__ T op_xielu(T x, float alpha_n, float alpha_p, float beta, float eps) {
215    const float xi        = static_cast<float>(x);
216    const float gate_pos  = (xi > 0.0f);
217    const float y_pos     = alpha_p * xi * xi + beta * xi;
218    const float min_v_eps = sycl::fmin(xi, eps);
219    const float y_neg     = (sycl::expm1(min_v_eps) - xi) * alpha_n + beta * xi;
220    const float out       = gate_pos * y_pos + (1.0f - gate_pos) * y_neg;
221    return static_cast<T>(out);
222}
223
224template<typename T>
225static __dpct_inline__ T op_sqr(T x) {
226    return x * x;
227}
228
229template<typename T>
230static __dpct_inline__ T op_clamp(T x, float min_val, float max_val) {
231    return x < static_cast<T>(min_val) ? static_cast<T>(min_val) : (x > static_cast<T>(max_val) ? static_cast<T>(max_val) : x);
232}
233
234template<typename T>
235static __dpct_inline__ T op_floor(T x) {
236    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
237        return sycl::ext::oneapi::experimental::floor(x);
238    } else {
239        return sycl::floor(x);
240    }
241}
242
243template<typename T>
244static __dpct_inline__ T op_ceil(T x) {
245    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
246        return sycl::ext::oneapi::experimental::ceil(x);
247    } else {
248        return sycl::ceil(x);
249    }
250}
251
252template<typename T>
253static __dpct_inline__ T op_round(T x) {
254    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
255        return static_cast<sycl::ext::oneapi::bfloat16>(
256            sycl::round(static_cast<float>(x))
257        );
258    } else {
259        return sycl::round(x);
260    }
261}
262
263template<typename T>
264static __dpct_inline__ T op_trunc(T x) {
265    if constexpr (std::is_same_v<T, sycl::ext::oneapi::bfloat16>) {
266        return sycl::ext::oneapi::experimental::trunc(x);
267    } else {
268        return sycl::trunc(x);
269    }
270}
271
272template<typename T, typename F>
273static void unary_op_flat_kernel(const T * x, T * dst, const int k, const sycl::nd_item<1> & item_ct1, F func) {
274    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
275        dst[i] = func(x[i]);
276    }
277}
278
279template<typename T, typename F>
280static void unary_op_generic_kernel(
281        const T * x,
282        T * dst,
283        const int k,
284        const sycl::uint3 ne0_fd, const sycl::uint3 ne1_fd, const sycl::uint3 ne2_fd,
285        const size_t nb0,  const size_t nb1,  const size_t nb2,  const size_t nb3,
286        const size_t nbd0, const size_t nbd1, const size_t nbd2, const size_t nbd3,
287        const sycl::nd_item<1> & item_ct1,
288        F func) {
289
290    // 32-bit index math: k is int, so every logical index fits u32. 64-bit integer div/mod is
291    // emulated on Xe and dominates this kernel otherwise, and even the 32-bit divide is worth
292    // avoiding -- the divisors are launch-invariant, so the magic numbers are precomputed
293    // host-side and each division becomes a multiply-high plus a shift.
294    // Byte offsets are widened back to size_t only for the final address math.
295    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
296        sycl::uint2 dm = fast_div_modulo((uint32_t) i, ne0_fd);
297        const uint32_t i0 = dm.y();
298        dm = fast_div_modulo(dm.x(), ne1_fd);
299        const uint32_t i1 = dm.y();
300        dm = fast_div_modulo(dm.x(), ne2_fd);
301        const uint32_t i2 = dm.y();
302        const uint32_t i3 = dm.x();
303
304        const char * src_base = (const char *) x;
305        char       * dst_base = (char *) dst;
306
307        const T * srcp = (const T *)(src_base + (size_t) i0*nb0  + (size_t) i1*nb1  + (size_t) i2*nb2  + (size_t) i3*nb3 );
308        T *       dstp = (T *)(dst_base + (size_t) i0*nbd0 + (size_t) i1*nbd1 + (size_t) i2*nbd2 + (size_t) i3*nbd3);
309
310        *dstp = func(*srcp);
311    }
312}
313
314template<typename T>
315static void unary_op_sqrt_kernel(const T * x, T * dst, const int k, const sycl::nd_item<1> &item_ct1) {
316    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
317        dst[i] = op_sqrt(x[i]);
318    }
319}
320
321template<typename T>
322static void unary_op_sin_kernel(const T * x, T * dst, const int k, const sycl::nd_item<1> &item_ct1) {
323    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
324        dst[i] = op_sin(x[i]);
325    }
326}
327
328template<typename T>
329static void unary_op_cos_kernel(const T * x, T * dst, const int k, const sycl::nd_item<1> &item_ct1) {
330    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
331        dst[i] = op_cos(x[i]);
332    }
333}
334
335template<typename T>
336static void unary_op_log_kernel(const T * x, T * dst, const int k, const sycl::nd_item<1> &item_ct1) {
337    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
338        dst[i] = op_log(x[i]);
339    }
340}
341
342
343template<typename T>
344static void unary_op_leaky_relu_kernel(const T * x, T * dst, const int k, float negative_slope, const sycl::nd_item<1> &item_ct1) {
345    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
346        dst[i] = op_leaky_relu(x[i], negative_slope);
347    }
348}
349
350template<typename T>
351static void unary_op_xielu_kernel(const T * x, T * dst, const int k, float alpha_n, float alpha_p, float beta, float eps, const sycl::nd_item<1> &item_ct1) {
352    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
353        dst[i] = op_xielu(x[i], alpha_n, alpha_p, beta, eps);
354    }
355}
356
357template<typename T>
358static void unary_op_sqr_kernel(const T * x, T * dst, const int k, const sycl::nd_item<1> &item_ct1) {
359    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
360        dst[i] = op_sqr(x[i]);
361    }
362}
363
364template<typename T>
365static void unary_op_clamp_kernel(const T * x, T * dst, const int k, const sycl::nd_item<1> &item_ct1, float min_val, float max_val) {
366    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
367        dst[i] = op_clamp(x[i], min_val, max_val);
368    }
369}
370
371template<typename T>
372static void unary_op_ceil_kernel(const T * x, T * dst, const int k, const sycl::nd_item<1> &item_ct1) {
373    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
374        dst[i] = op_ceil(x[i]);
375    }
376}
377
378template<typename T>
379static void clamp(const T * x, T * dst, const float min, const float max, const int k,
380                      const sycl::nd_item<1> &item_ct1) {
381    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
382        dst[i] = x[i] < static_cast<T>(min) ? static_cast<T>(min) : (x[i] > static_cast<T>(max) ? static_cast<T>(max) : x[i]);
383    }
384}
385
386template<typename T, typename F>
387static void unary_gated_op_flat_kernel(const T * x, const T * g, T * dst, const uint64_t k, const sycl::nd_item<1> & item_ct1, F func) {
388    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
389        dst[i] = func(x[i]) * g[i];
390    }
391}
392
393template<typename T, typename F>
394static void unary_gated_op_generic_kernel(
395        const T * x,
396        const T * g,
397        T * dst,
398        const uint64_t k,
399        const sycl::uint3 n_fd,
400        const uint64_t o0,
401        const uint64_t o1,
402        const sycl::nd_item<1> & item_ct1,
403        F func) {
404
405    // rows of n columns at strides o0 and o1: two halves of one fused tensor, or two tensors
406    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
407        const sycl::uint2 rc = fast_div_modulo((uint32_t) i, n_fd);
408        const int64_t j0 = rc.x() * o0 + rc.y();
409        const int64_t j1 = o0 == o1 ? j0 : rc.x() * o1 + rc.y();
410        dst[i] = func(x[j0]) * g[j1];
411    }
412}
413
414// Fused UNARY + MUL. Unlike the gated ops above, `x` and `g` are separate tensors of the
415// same shape; `o0`/`o1` are their row strides in elements, so a half-view needs no repack.
416// `dst` is contiguous and indexed flat. Math is done in f32, as the CPU and CUDA references do.
417template<typename T, typename F>
418static void unary_mul_flat_kernel(const T * x, const T * g, T * dst, const int64_t k, const sycl::nd_item<1> &item_ct1, F op) {
419    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
420        dst[i] = (T) (op((float) x[i]) * (float) g[i]);
421    }
422}
423
424template<typename T, typename F>
425static void unary_mul_strided_kernel(const T * x, const T * g, T * dst, const int64_t k, const sycl::uint3 n_fd, const int64_t o0, const int64_t o1, const sycl::nd_item<1> &item_ct1, F op) {
426    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
427        const sycl::uint2 rc = fast_div_modulo((uint32_t) i, n_fd);
428        const int64_t j0 = rc.x() * o0 + rc.y();
429        const int64_t j1 = o0 == o1 ? j0 : rc.x() * o1 + rc.y();
430        dst[i] = (T) (op((float) x[j0]) * (float) g[j1]);
431    }
432}
433
434template<typename T, typename F>
435static void unary_mul_sycl(const T * x, const T * g, T * dst, const int64_t k, const int64_t n, const int64_t o0, const int64_t o1, queue_ptr main_stream, F op) {
436    const size_t            num_blocks = ceil_div((size_t) k, (size_t) SYCL_GLU_BLOCK_SIZE);
437    const sycl::nd_range<1> range(num_blocks * sycl::range<1>(SYCL_GLU_BLOCK_SIZE), sycl::range<1>(SYCL_GLU_BLOCK_SIZE));
438
439    // o0 == o1 == n makes (i/n)*o0 + (i%n) == i, so the strided kernel degenerates to the flat one
440    if (o0 == n && o1 == n) {
441        main_stream->parallel_for(range, [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
442            unary_mul_flat_kernel(x, g, dst, k, item_ct1, op);
443        });
444        return;
445    }
446
447    // 32-bit fastdiv, exact only below 2^31; ggml_sycl_can_fuse() already declined past that
448    GGML_ASSERT(k < ((int64_t) 1 << 31));
449    const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
450    main_stream->parallel_for(range, [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
451        unary_mul_strided_kernel(x, g, dst, k, n_fd, o0, o1, item_ct1, op);
452    });
453}
454
455namespace ggml_sycl_detail {
456static void acc_f32_sycl(const char *x, const char *y, float *dst,
457                         const int64_t n_elements,
458                         const int64_t ne0, const int64_t ne1, const int64_t ne2,
459                         const int64_t nb00, const int64_t nb01, const int64_t nb02, const int64_t nb03,
460                         const int64_t ne10, const int64_t ne11, const int64_t ne12, const int64_t ne13,
461                         const int64_t nb10, const int64_t nb11, const int64_t nb12, const int64_t nb13,
462                         const int64_t s1, const int64_t s2, const int64_t s3,
463                         const int64_t offset, queue_ptr stream) {
464    const int num_blocks = (n_elements + SYCL_ACC_BLOCK_SIZE - 1) / SYCL_ACC_BLOCK_SIZE;
465    stream->parallel_for(sycl::nd_range<3>(sycl::range<3>(1, 1, num_blocks) * sycl::range<3>(1, 1, SYCL_ACC_BLOCK_SIZE),
466                                           sycl::range<3>(1, 1, SYCL_ACC_BLOCK_SIZE)),
467                         [=](sycl::nd_item<3> /*item_ct1*/) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
468                            acc_f32(x, y, dst, n_elements,
469                                ne0, ne1, ne2,
470                                nb00, nb01, nb02, nb03,
471                                ne10, ne11, ne12, ne13,
472                                nb10, nb11, nb12, nb13,
473                                s1, s2, s3, offset);
474                         });
475}
476
477template<typename T>
478static void arange_kernel(T * dst, const int k, T start, T step,
479                         const sycl::nd_item<1> &item_ct1) {
480    SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
481        dst[i] = start + static_cast<T>(i) * step;
482    }
483}
484
485template<typename KernelInvoker, typename... Args>
486static inline void dispatch_ggml_sycl_op_unary(ggml_backend_sycl_context & ctx, ggml_tensor * dst, KernelInvoker kernel_invoker, Args&&... args) {
487    GGML_ASSERT(dst->src[0]->type == GGML_TYPE_F32 || dst->src[0]->type == GGML_TYPE_F16 || dst->src[0]->type == GGML_TYPE_BF16);
488    GGML_ASSERT(dst->type == GGML_TYPE_F32 || dst->type == GGML_TYPE_F16 || dst->type == GGML_TYPE_BF16);
489    GGML_ASSERT(dst->src[0]->type == dst->type);
490
491    dpct::queue_ptr main_stream = ctx.stream();
492    SYCL_CHECK(ggml_sycl_set_device(ctx.device));
493    switch (dst->type) {
494        case GGML_TYPE_F16:
495            {
496                auto data_pts = cast_data<sycl::half>(dst);
497                kernel_invoker(data_pts.src, data_pts.dst, (int)ggml_nelements(dst->src[0]), main_stream, std::forward<Args>(args)...);
498                break;
499            }
500#ifdef GGML_SYCL_HAS_BF16
501        case GGML_TYPE_BF16:
502            {
503                auto data_pts = cast_data<sycl::ext::oneapi::bfloat16>(dst);
504                kernel_invoker(data_pts.src, data_pts.dst, (int)ggml_nelements(dst->src[0]), main_stream, std::forward<Args>(args)...);
505                break;
506            }
507#endif
508        case GGML_TYPE_F32:
509            {
510                auto data_pts = cast_data<float>(dst);
511                kernel_invoker(data_pts.src, data_pts.dst, (int)ggml_nelements(dst->src[0]), main_stream, std::forward<Args>(args)...);
512                break;
513            }
514        default:
515            GGML_ABORT("GGML tensor type not supported!\n");
516    }
517}
518
519template<typename KernelInvoker, typename... Args>
520static inline void dispatch_ggml_sycl_op_fused_glu(ggml_backend_sycl_context & ctx, ggml_tensor * dst, KernelInvoker kernel_invoker, Args&&... args) {
521    GGML_ASSERT(dst->src[0]->type == GGML_TYPE_F32 || dst->src[0]->type == GGML_TYPE_F16);
522    GGML_ASSERT(dst->type == GGML_TYPE_F32 || dst->type == GGML_TYPE_F16);
523    GGML_ASSERT(dst->src[0]->type == dst->type);
524
525    dpct::queue_ptr main_stream = ctx.stream();
526    SYCL_CHECK(ggml_sycl_set_device(ctx.device));
527    const ggml_tensor * src0 = dst->src[0];
528    const ggml_tensor * src1 = dst->src[1];
529    const int64_t nc = src1 ? src0->ne[0] : src0->ne[0] / 2;;
530    GGML_ASSERT(dst->ne[0] == nc);
531    GGML_ASSERT(ggml_is_contiguous_1(dst->src[0]));
532    GGML_ASSERT(ggml_is_contiguous(dst));
533    // The fused GLU kernels index with 32-bit fastdiv, which is exact only for indices below
534    // 2^31. A dst that large is ~8 GB at f32, and the grid sizing already narrows to 32 bits,
535    // so assert the bound rather than carry a second code path for it.
536    GGML_ASSERT(ggml_nelements(dst) < ((int64_t) 1 << 31));
537    const int32_t swapped = ((const int32_t *) dst->op_params)[1];
538    void * src0_d = src0->data;
539    void * src1_d = src1 ? src1->data : src0->data;
540    const int64_t src0_o = src0->nb[1];
541    const int64_t src1_o = src1 ? src1->nb[1] : src0->nb[1];
542    void * dst_d = dst->data;
543    if (src1) {
544        GGML_ASSERT(ggml_is_contiguous_1(src1));
545        GGML_ASSERT(src1->nb[0] == ggml_element_size(src1));
546        GGML_ASSERT(src1->ne[0] == nc);
547        GGML_ASSERT(src0->type == src1->type);
548    }
549    switch (dst->type) {
550        case GGML_TYPE_F16:
551            {
552                sycl::half * src0_p = (sycl::half *) src0_d;
553                sycl::half * src1_p = (sycl::half *) src1_d;
554
555                    if (!src1) {
556                        src0_p += swapped ? nc : 0;
557                        src1_p += swapped ? 0 : nc;
558                    }
559                kernel_invoker(src0_p,
560                               src1_p,
561                               (sycl::half *) dst_d,
562                               ggml_nelements(dst),
563                               nc,
564                               src0_o / sizeof(sycl::half),
565                               src1_o / sizeof(sycl::half),
566                               main_stream,
567                               std::forward<Args>(args)...);
568                break;
569            }
570        case GGML_TYPE_F32:
571            {
572                float * src0_p = (float *) src0_d;
573                float * src1_p = (float *) src1_d;
574
575                    if (!src1) {
576                        src0_p += swapped ? nc : 0;
577                        src1_p += swapped ? 0 : nc;
578                    }
579
580                kernel_invoker(src0_p,
581                               src1_p,
582                               (float *) dst_d,
583                               ggml_nelements(dst),
584                               nc,
585                               src0_o / sizeof(float),
586                               src1_o / sizeof(float),
587                               main_stream,
588                               std::forward<Args>(args)...);
589                break;
590            }
591        default:
592            GGML_ABORT("GGML tensor type not supported!\n");
593    }
594}
595
596template<typename F>
597static inline void ggml_sycl_op_unary(
598        ggml_backend_sycl_context & ctx, ggml_tensor * dst, F func) {
599
600    ggml_tensor * src0 = dst->src[0];
601
602    const int64_t ne0  = dst->ne[0];
603    const int64_t ne1  = dst->ne[1];
604    const int64_t ne2  = dst->ne[2];
605
606    const size_t  nb0  = src0->nb[0];
607    const size_t  nb1  = src0->nb[1];
608    const size_t  nb2  = src0->nb[2];
609    const size_t  nb3  = src0->nb[3];
610
611    const size_t  nbd0 = dst->nb[0];
612    const size_t  nbd1 = dst->nb[1];
613    const size_t  nbd2 = dst->nb[2];
614    const size_t  nbd3 = dst->nb[3];
615
616    // Hot unary ops (FFN/GDN silu, sigmoid, ...) run on contiguous tensors;
617    // skip the strided index math entirely for them.
618    const bool contiguous = ggml_is_contiguous(src0) && ggml_is_contiguous(dst);
619
620    ggml_sycl_detail::dispatch_ggml_sycl_op_unary(ctx, dst,
621        [=](const auto* src, auto* dst_ptr, int k_elements, queue_ptr stream) {
622
623            const int num_blocks = ceil_div(k_elements, 256);
624
625            if (contiguous) {
626                stream->parallel_for(
627                    sycl::nd_range<1>(sycl::range<1>(num_blocks) * sycl::range<1>(256),
628                                      sycl::range<1>(256)),
629                    [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
630                        unary_op_flat_kernel(src, dst_ptr, k_elements, item_ct1, func);
631                    });
632            } else {
633                // Launch-invariant divisors: compute the magic numbers once on the host so the
634                // kernel never issues an integer divide. Only the strided path needs them.
635                const sycl::uint3 ne0_fd = init_fastdiv_values((uint32_t) ne0);
636                const sycl::uint3 ne1_fd = init_fastdiv_values((uint32_t) ne1);
637                const sycl::uint3 ne2_fd = init_fastdiv_values((uint32_t) ne2);
638                stream->parallel_for(
639                    sycl::nd_range<1>(sycl::range<1>(num_blocks) * sycl::range<1>(256),
640                                      sycl::range<1>(256)),
641                    [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
642                        unary_op_generic_kernel(
643                            src, dst_ptr, k_elements,
644                            ne0_fd, ne1_fd, ne2_fd,
645                            nb0, nb1, nb2, nb3,
646                            nbd0, nbd1, nbd2, nbd3,
647                            item_ct1,
648                            func
649                        );
650                    });
651            }
652        });
653}
654
655template<typename F>
656static inline void ggml_sycl_op_unary_gated(
657        ggml_backend_sycl_context & ctx, ggml_tensor * dst, F func) {
658
659    dispatch_ggml_sycl_op_fused_glu(ctx, dst,
660        [func](const auto * x_ptr, const auto * g_ptr, auto * dst_ptr, uint64_t k, uint64_t n, uint64_t o0, uint64_t o1, queue_ptr main_stream) {
661
662            const uint32_t num_blocks = (uint32_t) ceil_div(k, SYCL_GLU_BLOCK_SIZE);
663            const sycl::nd_range<1> launch_range(num_blocks * sycl::range<1>(SYCL_GLU_BLOCK_SIZE),
664                                                 sycl::range<1>(SYCL_GLU_BLOCK_SIZE));
665
666            // o0 == n and o1 == n make the index math the identity, so index flat
667            // note: not ggml_is_contiguous - a fused [gate|up] src0 is contiguous with o0 == 2n
668            if (o0 == n && o1 == n) {
669                main_stream->parallel_for(launch_range,
670                    [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
671                        unary_gated_op_flat_kernel(x_ptr, g_ptr, dst_ptr, k, item_ct1, func);
672                    });
673            } else {
674                // launch-invariant divisor, and only this path needs it
675                const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
676                main_stream->parallel_for(launch_range,
677                    [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
678                        unary_gated_op_generic_kernel(x_ptr, g_ptr, dst_ptr, k, n_fd, o0, o1, item_ct1, func);
679                    });
680            }
681        });
682}
683
684
685static inline void ggml_sycl_op_arange(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
686    GGML_ASSERT(dst->type == GGML_TYPE_F32);
687    float start, stop, step;
688    memcpy(&start, dst->op_params, sizeof(float));
689    memcpy(&stop, (float *) dst->op_params + 1, sizeof(float));
690    memcpy(&step, (float *) dst->op_params + 2, sizeof(float));
691    dpct::queue_ptr stream = ctx.stream();
692    SYCL_CHECK(ggml_sycl_set_device(ctx.device));
693    float * dst_ptr = (float *)dst->data;
694    const int k = (int)ggml_nelements(dst);
695    const int num_blocks = ceil_div(k, SYCL_ARANGE_BLOCK_SIZE);
696    stream->parallel_for(
697        sycl::nd_range<1>(sycl::range<1>(num_blocks) * sycl::range<1>(SYCL_ARANGE_BLOCK_SIZE),
698                          sycl::range<1>(SYCL_ARANGE_BLOCK_SIZE)),
699        [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
700            arange_kernel(dst_ptr, k, start, step, item_ct1);
701        });
702}
703
704} // namespace ggml_sycl_detail
705
706
707
708static inline void ggml_sycl_op_sgn(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
709    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
710        return op_sgn(x);
711    });
712}
713
714
715static inline void ggml_sycl_op_abs(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
716    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
717        return op_abs(x);
718    });
719}
720
721static inline void ggml_sycl_op_elu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
722    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
723        return op_elu(x);
724    });
725}
726static inline void ggml_sycl_op_silu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
727    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
728        return op_silu(x);
729    });
730}
731
732static inline void ggml_sycl_op_gelu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
733    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
734        return op_gelu(x);
735    });
736}
737
738static inline void ggml_sycl_op_gelu_quick(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
739    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
740        return op_gelu_quick(x);
741    });
742}
743
744static inline void ggml_sycl_op_gelu_erf(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
745    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
746        return op_gelu_erf(x);
747    });
748}
749
750static inline void ggml_sycl_op_tanh(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
751    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
752        return op_tanh(x);
753    });
754}
755
756static inline void ggml_sycl_op_relu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
757    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
758        return op_relu(x);
759    });
760}
761
762static inline void ggml_sycl_op_hardsigmoid(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
763    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
764        return op_hardsigmoid(x);
765    });
766}
767
768static inline void ggml_sycl_op_hardswish(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
769    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
770        return op_hardswish(x);
771    });
772}
773
774static inline void ggml_sycl_op_exp(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
775    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
776        return op_exp(x);
777    });
778}
779
780static inline void ggml_sycl_op_expm1(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
781    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
782        return op_expm1(x);
783    });
784}
785
786static inline void ggml_sycl_op_log(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
787    ggml_sycl_detail::dispatch_ggml_sycl_op_unary(ctx, dst,
788        [](const auto* src, auto* dst_ptr, int k_elements, queue_ptr stream) {
789            const int num_blocks = ceil_div(k_elements, SYCL_EXP_BLOCK_SIZE); // Using EXP block size
790            stream->parallel_for(
791                sycl::nd_range<1>(sycl::range<1>(num_blocks) * sycl::range<1>(SYCL_EXP_BLOCK_SIZE),
792                                  sycl::range<1>(SYCL_EXP_BLOCK_SIZE)),
793                [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
794                    unary_op_log_kernel(src, dst_ptr, k_elements, item_ct1);
795                });
796        });
797}
798
799static inline void ggml_sycl_op_softplus(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
800    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
801        return op_softplus(x);
802    });
803}
804
805static inline void ggml_sycl_op_neg(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
806    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
807        return op_neg(x);
808    });
809}
810
811
812static inline void ggml_sycl_op_step(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
813    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
814        return op_step(x);
815    });
816}
817
818static inline void ggml_sycl_op_sigmoid(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
819    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
820        return op_sigmoid(x);
821    });
822}
823
824static inline void ggml_sycl_op_sqrt(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
825    ggml_sycl_detail::dispatch_ggml_sycl_op_unary(ctx, dst,
826        [](const auto* src, auto* dst_ptr, int k_elements, queue_ptr stream) {
827            const int num_blocks = ceil_div(k_elements, SYCL_SQRT_BLOCK_SIZE);
828            stream->parallel_for(
829                sycl::nd_range<1>(sycl::range<1>(num_blocks) * sycl::range<1>(SYCL_SQRT_BLOCK_SIZE),
830                                  sycl::range<1>(SYCL_SQRT_BLOCK_SIZE)),
831                [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
832                    unary_op_sqrt_kernel(src, dst_ptr, k_elements, item_ct1);
833                });
834        });
835}
836
837static inline void ggml_sycl_op_sin(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
838    ggml_sycl_detail::dispatch_ggml_sycl_op_unary(ctx, dst,
839        [](const auto* src, auto* dst_ptr, int k_elements, queue_ptr stream) {
840            const int num_blocks = ceil_div(k_elements, SYCL_SIN_BLOCK_SIZE);
841            stream->parallel_for(
842                sycl::nd_range<1>(sycl::range<1>(num_blocks) * sycl::range<1>(SYCL_SIN_BLOCK_SIZE),
843                                  sycl::range<1>(SYCL_SIN_BLOCK_SIZE)),
844                [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
845                    unary_op_sin_kernel(src, dst_ptr, k_elements, item_ct1);
846                });
847        });
848}
849
850static inline void ggml_sycl_op_cos(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
851    ggml_sycl_detail::dispatch_ggml_sycl_op_unary(ctx, dst,
852        [](const auto* src, auto* dst_ptr, int k_elements, queue_ptr stream) {
853            const int num_blocks = ceil_div(k_elements, SYCL_SIN_BLOCK_SIZE); // Using SIN block size
854            stream->parallel_for(
855                sycl::nd_range<1>(sycl::range<1>(num_blocks) * sycl::range<1>(SYCL_SIN_BLOCK_SIZE),
856                                  sycl::range<1>(SYCL_SIN_BLOCK_SIZE)),
857                [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
858                    unary_op_cos_kernel(src, dst_ptr, k_elements, item_ct1);
859                });
860        });
861}
862
863static inline void ggml_sycl_op_leaky_relu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
864    float negative_slope;
865    memcpy(&negative_slope, dst->op_params, sizeof(float));
866    ggml_sycl_detail::dispatch_ggml_sycl_op_unary(ctx, dst,
867        [](const auto* src, auto* dst_ptr, int k_elements, queue_ptr stream, float slope) {
868            const int num_blocks = ceil_div(k_elements, SYCL_RELU_BLOCK_SIZE);
869            stream->parallel_for(
870                sycl::nd_range<1>(sycl::range<1>(num_blocks) * sycl::range<1>(SYCL_RELU_BLOCK_SIZE),
871                                  sycl::range<1>(SYCL_RELU_BLOCK_SIZE)),
872                [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
873                    unary_op_leaky_relu_kernel(src, dst_ptr, k_elements, slope, item_ct1);
874                });
875        }, negative_slope);
876}
877
878static inline void ggml_sycl_op_sqr(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
879    ggml_sycl_detail::dispatch_ggml_sycl_op_unary(ctx, dst,
880        [](const auto* src, auto* dst_ptr, int k_elements, queue_ptr stream) {
881            const int num_blocks = ceil_div(k_elements, SYCL_SQR_BLOCK_SIZE);
882            stream->parallel_for(
883                sycl::nd_range<1>(sycl::range<1>(num_blocks) * sycl::range<1>(SYCL_SQR_BLOCK_SIZE),
884                                  sycl::range<1>(SYCL_SQR_BLOCK_SIZE)),
885                [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
886                    unary_op_sqr_kernel(src, dst_ptr, k_elements, item_ct1);
887                });
888        });
889}
890
891static inline void ggml_sycl_op_clamp(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
892    float min_val;
893    float max_val;
894    memcpy(&min_val, dst->op_params, sizeof(float));
895    memcpy(&max_val, (float *) dst->op_params + 1, sizeof(float));
896    ggml_sycl_detail::dispatch_ggml_sycl_op_unary(ctx, dst,
897        [](const auto* src, auto* dst_ptr, int k_elements, queue_ptr stream, float min_arg, float max_arg) {
898            const int num_blocks = ceil_div(k_elements, SYCL_CLAMP_BLOCK_SIZE);
899            stream->parallel_for(
900                sycl::nd_range<1>(sycl::range<1>(num_blocks) * sycl::range<1>(SYCL_CLAMP_BLOCK_SIZE),
901                                  sycl::range<1>(SYCL_CLAMP_BLOCK_SIZE)),
902                [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
903                    clamp(src, dst_ptr, min_arg, max_arg, k_elements, item_ct1);
904                });
905        }, min_val, max_val);
906}
907
908static inline void ggml_sycl_op_xielu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
909    const float alpha_n = ggml_get_op_params_f32(dst, 1);
910    const float alpha_p = ggml_get_op_params_f32(dst, 2);
911    const float beta    = ggml_get_op_params_f32(dst, 3);
912    const float eps     = ggml_get_op_params_f32(dst, 4);
913    ggml_sycl_detail::dispatch_ggml_sycl_op_unary(ctx, dst,
914        [](const auto* src, auto* dst_ptr, int k_elements, queue_ptr stream, float alpha_n_arg, float alpha_p_arg, float beta_arg, float eps_arg) {
915            const int num_blocks = ceil_div(k_elements, SYCL_RELU_BLOCK_SIZE);
916            stream->parallel_for(
917                sycl::nd_range<1>(sycl::range<1>(num_blocks) * sycl::range<1>(SYCL_RELU_BLOCK_SIZE),
918                                  sycl::range<1>(SYCL_RELU_BLOCK_SIZE)),
919                [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
920                    unary_op_xielu_kernel(src, dst_ptr, k_elements, alpha_n_arg, alpha_p_arg, beta_arg, eps_arg, item_ct1);
921                });
922        }, alpha_n, alpha_p, beta, eps);
923}
924
925static inline void ggml_sycl_op_floor(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
926    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
927        return op_floor(x);
928    });
929}
930
931static inline void ggml_sycl_op_ceil(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
932    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
933        return op_ceil(x);
934    });
935}
936
937static inline void ggml_sycl_op_round(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
938    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
939        return op_round(x);
940    });
941}
942
943static inline void ggml_sycl_op_trunc(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
944    ggml_sycl_detail::ggml_sycl_op_unary(ctx, dst, [](auto x) {
945        return op_trunc(x);
946    });
947}
948
949static inline void ggml_sycl_op_acc(ggml_backend_sycl_context & ctx, ggml_tensor *dst) {
950    const ggml_tensor * src0 = dst->src[0];
951    const ggml_tensor * src1 = dst->src[1];
952
953    const char  * src0_d = (const char  *) src0->data;
954    const char  * src1_d = (const char  *) src1->data;
955    float       * dst_d  = (float       *)  dst->data;
956
957    dpct::queue_ptr stream = ctx.stream();
958
959    GGML_ASSERT(src0->type == GGML_TYPE_F32);
960    GGML_ASSERT(src1->type == GGML_TYPE_F32);
961    GGML_ASSERT( dst->type == GGML_TYPE_F32);
962
963    GGML_ASSERT(dst->nb[0] == ggml_element_size(dst));
964    GGML_ASSERT(ggml_is_contiguously_allocated(dst));
965    GGML_ASSERT(ggml_are_same_shape(src0, dst));
966
967    const int64_t s1     = (int64_t) ((const int32_t *) dst->op_params)[0] / (int64_t) sizeof(float);
968    const int64_t s2     = (int64_t) ((const int32_t *) dst->op_params)[1] / (int64_t) sizeof(float);
969    const int64_t s3     = (int64_t) ((const int32_t *) dst->op_params)[2] / (int64_t) sizeof(float);
970    const int64_t offset = (int64_t) ((const int32_t *) dst->op_params)[3] / (int64_t) sizeof(float);
971
972    ggml_sycl_detail::acc_f32_sycl(src0_d, src1_d, dst_d, ggml_nelements(dst),
973        dst->ne[0], dst->ne[1], dst->ne[2],
974        src0->nb[0], src0->nb[1], src0->nb[2], src0->nb[3],
975        src1->ne[0], src1->ne[1], src1->ne[2], src1->ne[3],
976        src1->nb[0], src1->nb[1], src1->nb[2], src1->nb[3],
977        s1, s2, s3, offset, stream);
978}
979
980static inline void ggml_sycl_op_geglu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
981    ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
982        return op_gelu(x);
983    });
984}
985
986static inline void ggml_sycl_op_reglu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
987    ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
988        return op_relu(x);
989    });
990}
991
992static inline void ggml_sycl_op_swiglu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
993    ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
994        return op_silu(x);
995    });
996}
997
998// dst = op(unary_node->src[0]) * other, written straight to the MUL output, saving the
999// standalone unary launch. Preconditions come from ggml_sycl_can_fuse(); re-asserted here.
1000void ggml_sycl_op_unary_mul_fused(ggml_backend_sycl_context & ctx, ggml_tensor * unary_node, ggml_tensor * mul_node) {
1001    scope_op_debug_print scope_dbg_print(__func__, mul_node, /*num_src=*/2);
1002
1003    const ggml_tensor * x = unary_node->src[0];
1004    const ggml_tensor * g = (mul_node->src[0] == unary_node) ? mul_node->src[1] : mul_node->src[0];
1005
1006    // g is picked by elimination; ggml_can_fuse()'s single-use rule rules out MUL(unary, unary)
1007    GGML_ASSERT(g != unary_node);
1008    GGML_ASSERT(x->type == g->type && x->type == mul_node->type);
1009    GGML_ASSERT(ggml_are_same_shape(x, g) && ggml_are_same_shape(x, mul_node));
1010    GGML_ASSERT(ggml_is_contiguous_1(x) && ggml_is_contiguous_1(g));
1011    // dst is indexed flat
1012    GGML_ASSERT(ggml_is_contiguous(mul_node));
1013
1014    queue_ptr main_stream = ctx.stream();
1015    SYCL_CHECK(ggml_sycl_set_device(ctx.device));
1016
1017    const int64_t k = ggml_nelements(mul_node);
1018    const int64_t n = mul_node->ne[0];
1019
1020    const auto dispatch_type = [&](auto op) {
1021        switch (mul_node->type) {
1022            case GGML_TYPE_F32:
1023                unary_mul_sycl((const float *) x->data, (const float *) g->data, (float *) mul_node->data,
1024                               k, n, x->nb[1] / sizeof(float), g->nb[1] / sizeof(float), main_stream, op);
1025                break;
1026            case GGML_TYPE_F16:
1027                unary_mul_sycl((const sycl::half *) x->data, (const sycl::half *) g->data, (sycl::half *) mul_node->data,
1028                               k, n, x->nb[1] / sizeof(sycl::half), g->nb[1] / sizeof(sycl::half), main_stream, op);
1029                break;
1030            default:
1031                GGML_ABORT("fused unary+mul: unsupported type %s", ggml_type_name(mul_node->type));
1032        }
1033    };
1034
1035    switch (ggml_get_unary_op(unary_node)) {
1036        case GGML_UNARY_OP_SILU:     dispatch_type([](float v) { return op_silu(v); });     break;
1037        case GGML_UNARY_OP_SIGMOID:  dispatch_type([](float v) { return op_sigmoid(v); });  break;
1038        case GGML_UNARY_OP_SOFTPLUS: dispatch_type([](float v) { return op_softplus(v); }); break;
1039        default:
1040            GGML_ABORT("fused unary+mul: unsupported unary op %s", ggml_unary_op_name(ggml_get_unary_op(unary_node)));
1041    }
1042}
1043
1044__dpct_inline__ float ggml_sycl_op_swiglu_oai_single(float x, float g, float alpha = 1.702f, float limit = 7.0f) {
1045    x = sycl::fmin(x, limit);
1046    g = sycl::fmax(sycl::fmin(g, limit), -limit);
1047
1048    float out_glu = x / (1.0f + sycl::native::exp(-x * alpha));
1049    out_glu = out_glu * (1.0f + g);
1050    return out_glu;
1051}
1052
1053template <typename T>
1054static void swiglu_oai_kernel(const T * x, const T * g, T * dst, const int64_t k,
1055                              const int64_t n, const int64_t o0, const int64_t o1,
1056                              float alpha, float limit, sycl::nd_item<3> item_ct1) {
1057    const int64_t i = int64_t(item_ct1.get_local_range(2)) * item_ct1.get_group(2) + item_ct1.get_local_id(2);
1058
1059    if (i >= k) {
1060        return;
1061    }
1062
1063    const int64_t j0 = (i / n) * o0 + (i % n);
1064    const int64_t j1 = o0 == o1 ? j0 : (i / n) * o1 + (i % n);
1065
1066    float xi = x[j0];
1067    float gi = g[j1];
1068
1069    dst[i] = ggml_sycl_op_swiglu_oai_single(xi, gi, alpha, limit);
1070}
1071
1072template <typename T>
1073static void swiglu_oai_sycl(const T *       x,
1074                            const T *       g,
1075                            T *             dst,
1076                            const int64_t   k,
1077                            const int64_t   n,
1078                            const int64_t   o0,
1079                            const int64_t   o1,
1080                            const float     alpha,
1081                            const float     limit,
1082                            dpct::queue_ptr stream) {
1083    const int64_t num_blocks = (k + SYCL_GLU_BLOCK_SIZE - 1) / SYCL_GLU_BLOCK_SIZE;
1084    stream->parallel_for(sycl::nd_range<3>(sycl::range<3>(1, 1, num_blocks) * sycl::range<3>(1, 1, SYCL_GLU_BLOCK_SIZE),
1085                                           sycl::range<3>(1, 1, SYCL_GLU_BLOCK_SIZE)),
1086                         [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1087                             swiglu_oai_kernel(x, g, dst, k, n, o0, o1, alpha, limit, item_ct1);
1088                         });
1089}
1090
1091void ggml_sycl_op_swiglu_oai(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1092    const ggml_tensor * src0 = dst->src[0];
1093    const ggml_tensor * src1 = dst->src[1];
1094    void * src0_d = src0->data;
1095    void * src1_d = src1 ? src1->data : src0->data;
1096    const int64_t src0_o = src0->nb[1];
1097    const int64_t src1_o = src1 ? src1->nb[1] : src0->nb[1];
1098    void * dst_d = dst->data;
1099    const int64_t nc = src1 ? src0->ne[0] : src0->ne[0] / 2;
1100    dpct::queue_ptr     stream = ctx.stream();
1101
1102    GGML_ASSERT(ggml_is_contiguous_1(src0));
1103    GGML_ASSERT(src0->nb[0] == ggml_element_size(src0));
1104    GGML_ASSERT(ggml_is_contiguous(dst));
1105
1106    GGML_ASSERT(src0->type == GGML_TYPE_F32);
1107    GGML_ASSERT( dst->type == GGML_TYPE_F32);
1108    GGML_ASSERT(src0->type == dst->type);
1109    GGML_ASSERT(dst->ne[0] == nc);
1110    GGML_ASSERT(ggml_nrows(dst) == ggml_nrows(src0));
1111
1112    if (src1) {
1113        GGML_ASSERT(ggml_is_contiguous_1(src1));
1114        GGML_ASSERT(src1->nb[0] == ggml_element_size(src1));
1115        GGML_ASSERT(src1->ne[0] == nc);
1116        GGML_ASSERT(src0->type == src1->type);
1117    }
1118
1119    //const int32_t swapped = ((const int32_t *) dst->op_params)[1];
1120    const int32_t swapped = ggml_get_op_params_i32(dst, 1);
1121    const float alpha = ggml_get_op_params_f32(dst, 2);
1122    const float limit = ggml_get_op_params_f32(dst, 3);
1123
1124    float * src0_p = (float *) src0_d;
1125    float * src1_p = (float *) src1_d;
1126
1127    if (!src1) {
1128        src0_p += swapped ? nc : 0;
1129        src1_p += swapped ? 0 : nc;
1130    }
1131
1132    swiglu_oai_sycl(src0_p, src1_p, (float *)dst_d, ggml_nelements(dst), nc, src0_o / sizeof(float), src1_o / sizeof(float), alpha, limit, stream);
1133}
1134
1135template <typename T>
1136static void swiglu_clamp_kernel(const T *        gate,
1137                                const T *        up,
1138                                T *              dst,
1139                                const int64_t    k,
1140                                const int64_t    n,
1141                                const int64_t    o0,
1142                                const int64_t    o1,
1143                                float            limit,
1144                                sycl::nd_item<3> item_ct1) {
1145    const int64_t i = int64_t(item_ct1.get_local_range(2)) * item_ct1.get_group(2) + item_ct1.get_local_id(2);
1146
1147    if (i >= k) {
1148        return;
1149    }
1150
1151    const int64_t j0 = (i / n) * o0 + (i % n);
1152    const int64_t j1 = o0 == o1 ? j0 : (i / n) * o1 + (i % n);
1153
1154    const float gate_value = sycl::fmin((float) gate[j0], limit);
1155    const float up_value   = sycl::fmax(sycl::fmin((float) up[j1], limit), -limit);
1156    dst[i]                 = (T) (gate_value / (1.0f + sycl::native::exp(-gate_value)) * up_value);
1157}
1158
1159template <typename T>
1160static void swiglu_clamp_sycl(const T *       gate,
1161                              const T *       up,
1162                              T *             dst,
1163                              const int64_t   k,
1164                              const int64_t   n,
1165                              const int64_t   o0,
1166                              const int64_t   o1,
1167                              float           limit,
1168                              dpct::queue_ptr stream) {
1169    const int64_t num_blocks = (k + SYCL_GLU_BLOCK_SIZE - 1) / SYCL_GLU_BLOCK_SIZE;
1170    stream->parallel_for(sycl::nd_range<3>(sycl::range<3>(1, 1, num_blocks) * sycl::range<3>(1, 1, SYCL_GLU_BLOCK_SIZE),
1171                                           sycl::range<3>(1, 1, SYCL_GLU_BLOCK_SIZE)),
1172                         [=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
1173                             swiglu_clamp_kernel(gate, up, dst, k, n, o0, o1, limit, item_ct1);
1174                         });
1175}
1176
1177static void ggml_sycl_op_swiglu_clamp(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1178    const ggml_tensor * src0   = dst->src[0];
1179    const ggml_tensor * src1   = dst->src[1];
1180    void *              src0_d = src0->data;
1181    void *              src1_d = src1 ? src1->data : src0->data;
1182    const int64_t       src0_o = src0->nb[1];
1183    const int64_t       src1_o = src1 ? src1->nb[1] : src0->nb[1];
1184    void *              dst_d  = dst->data;
1185    const int64_t       nc     = src1 ? src0->ne[0] : src0->ne[0] / 2;
1186    dpct::queue_ptr     stream = ctx.stream();
1187
1188    GGML_ASSERT(ggml_is_contiguous_1(src0));
1189    GGML_ASSERT(src0->nb[0] == ggml_element_size(src0));
1190    GGML_ASSERT(ggml_is_contiguous(dst));
1191    GGML_ASSERT(src0->type == GGML_TYPE_F32 || src0->type == GGML_TYPE_F16);
1192    GGML_ASSERT(src0->type == dst->type);
1193    GGML_ASSERT(dst->ne[0] == nc);
1194    GGML_ASSERT(ggml_nrows(dst) == ggml_nrows(src0));
1195
1196    if (src1) {
1197        GGML_ASSERT(ggml_is_contiguous_1(src1));
1198        GGML_ASSERT(src1->nb[0] == ggml_element_size(src1));
1199        GGML_ASSERT(src1->ne[0] == nc);
1200        GGML_ASSERT(src0->type == src1->type);
1201    }
1202
1203    const int32_t swapped = ggml_get_op_params_i32(dst, 1);
1204    const float   limit   = ggml_get_op_params_f32(dst, 3);
1205
1206    if (src0->type == GGML_TYPE_F16) {
1207        sycl::half * src0_p = (sycl::half *) src0_d;
1208        sycl::half * src1_p = (sycl::half *) src1_d;
1209
1210        if (!src1) {
1211            src0_p += swapped ? nc : 0;
1212            src1_p += swapped ? 0 : nc;
1213        }
1214
1215        swiglu_clamp_sycl(src0_p, src1_p, (sycl::half *) dst_d, ggml_nelements(dst), nc, src0_o / sizeof(sycl::half),
1216                          src1_o / sizeof(sycl::half), limit, stream);
1217    } else {
1218        float * src0_p = (float *) src0_d;
1219        float * src1_p = (float *) src1_d;
1220
1221        if (!src1) {
1222            src0_p += swapped ? nc : 0;
1223            src1_p += swapped ? 0 : nc;
1224        }
1225
1226        swiglu_clamp_sycl(src0_p, src1_p, (float *) dst_d, ggml_nelements(dst), nc, src0_o / sizeof(float),
1227                          src1_o / sizeof(float), limit, stream);
1228    }
1229}
1230
1231static inline void ggml_sycl_op_geglu_erf(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1232    ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
1233        return op_gelu_erf(x);
1234    });
1235}
1236
1237static inline void ggml_sycl_op_geglu_quick(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1238    ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
1239        return op_gelu_quick(x);
1240    });
1241}
1242
1243
1244void ggml_sycl_sqrt(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1245    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1246    ggml_sycl_op_sqrt(ctx, dst);
1247}
1248
1249void ggml_sycl_sin(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1250    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1251    ggml_sycl_op_sin(ctx, dst);
1252}
1253
1254void ggml_sycl_cos(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1255    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1256    ggml_sycl_op_cos(ctx, dst);
1257}
1258
1259void ggml_sycl_acc(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1260    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/2);
1261    ggml_sycl_op_acc(ctx, dst);
1262}
1263
1264void ggml_sycl_gelu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1265    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1266    ggml_sycl_op_gelu(ctx, dst);
1267}
1268
1269void ggml_sycl_silu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1270    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1271    ggml_sycl_op_silu(ctx, dst);
1272}
1273
1274void ggml_sycl_gelu_quick(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1275    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1276    ggml_sycl_op_gelu_quick(ctx, dst);
1277}
1278
1279void ggml_sycl_gelu_erf(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1280    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1281    ggml_sycl_op_gelu_erf(ctx, dst);
1282}
1283
1284void ggml_sycl_tanh(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1285    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1286    ggml_sycl_op_tanh(ctx, dst);
1287}
1288
1289void ggml_sycl_relu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1290    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1291    ggml_sycl_op_relu(ctx, dst);
1292}
1293
1294void ggml_sycl_sigmoid(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1295    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1296    ggml_sycl_op_sigmoid(ctx, dst);
1297}
1298
1299void ggml_sycl_hardsigmoid(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1300    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1301    ggml_sycl_op_hardsigmoid(ctx, dst);
1302}
1303
1304void ggml_sycl_hardswish(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1305    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1306    ggml_sycl_op_hardswish(ctx, dst);
1307}
1308
1309void ggml_sycl_exp(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1310    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1311    ggml_sycl_op_exp(ctx, dst);
1312}
1313
1314void ggml_sycl_expm1(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1315    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1316    ggml_sycl_op_expm1(ctx, dst);
1317}
1318
1319void ggml_sycl_log(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1320    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1321    ggml_sycl_op_log(ctx, dst);
1322}
1323
1324void ggml_sycl_softplus(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1325    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1326    ggml_sycl_op_softplus(ctx, dst);
1327}
1328
1329void ggml_sycl_neg(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1330    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1331    ggml_sycl_op_neg(ctx, dst);
1332}
1333
1334void ggml_sycl_step(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1335    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1336    ggml_sycl_op_step(ctx, dst);
1337}
1338
1339void ggml_sycl_leaky_relu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1340    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1341    ggml_sycl_op_leaky_relu(ctx, dst);
1342}
1343
1344void ggml_sycl_sqr(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1345    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1346    ggml_sycl_op_sqr(ctx, dst);
1347}
1348
1349void ggml_sycl_clamp(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1350    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1351    ggml_sycl_op_clamp(ctx, dst);
1352}
1353
1354void ggml_sycl_xielu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1355    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1356    ggml_sycl_op_xielu(ctx, dst);
1357}
1358
1359void ggml_sycl_sgn(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1360    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1361    ggml_sycl_op_sgn(ctx, dst);
1362}
1363
1364void ggml_sycl_abs(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1365    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1366    ggml_sycl_op_abs(ctx, dst);
1367}
1368
1369void ggml_sycl_elu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1370    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1371    ggml_sycl_op_elu(ctx, dst);
1372}
1373
1374void ggml_sycl_geglu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1375    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1376    ggml_sycl_op_geglu(ctx, dst);
1377}
1378
1379void ggml_sycl_reglu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1380    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1381    ggml_sycl_op_reglu(ctx, dst);
1382}
1383
1384void ggml_sycl_swiglu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1385    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1386    ggml_sycl_op_swiglu(ctx, dst);
1387}
1388
1389void ggml_sycl_swiglu_oai(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1390    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1391    ggml_sycl_op_swiglu_oai(ctx, dst);
1392}
1393
1394void ggml_sycl_swiglu_clamp(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1395    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1396    ggml_sycl_op_swiglu_clamp(ctx, dst);
1397}
1398
1399void ggml_sycl_geglu_erf(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1400    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1401    ggml_sycl_op_geglu_erf(ctx, dst);
1402}
1403
1404void ggml_sycl_geglu_quick(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1405    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1406    ggml_sycl_op_geglu_quick(ctx, dst);
1407}
1408
1409void ggml_sycl_arange(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1410    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/0);
1411    ggml_sycl_detail::ggml_sycl_op_arange(ctx, dst);
1412}
1413
1414void ggml_sycl_floor(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1415    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1416    ggml_sycl_op_floor(ctx, dst);
1417}
1418
1419void ggml_sycl_ceil(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1420    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1421    ggml_sycl_op_ceil(ctx, dst);
1422}
1423
1424void ggml_sycl_round(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1425    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1426    ggml_sycl_op_round(ctx, dst);
1427}
1428
1429void ggml_sycl_trunc(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
1430    scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/1);
1431    ggml_sycl_op_trunc(ctx, dst);
1432}