char-fork/llama.cpp

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

Georgi Gerganovmetal : single-source fusion table + fusion debug rework (#28164)a2878d30d

char/aliceai-t5-moe
191.4 KiB5550 linesraw
1#include "ggml-metal-ops.h"
2
3#include "ggml.h"
4#include "ggml-impl.h"
5#include "ggml-backend-impl.h"
6
7#include "ggml-metal-impl.h"
8#include "ggml-metal-common.h"
9#include "ggml-metal-device.h"
10#include "ggml-metal-fusion.h"
11#include "ggml-metal-tuning.h"
12
13#include <cassert>
14#include <algorithm>
15#include <limits>
16#include <cmath>
17
18static ggml_metal_buffer_id ggml_metal_get_buffer_id(const ggml_tensor * t) {
19    if (!t) {
20        return { nullptr, 0 };
21    }
22
23    ggml_backend_buffer_t buffer = t->view_src ? t->view_src->buffer : t->buffer;
24
25    ggml_metal_buffer_t ctx = (ggml_metal_buffer_t) buffer->context;
26
27    return ggml_metal_buffer_get_id(ctx, t);
28}
29
30struct ggml_metal_op {
31    ggml_metal_op(
32        ggml_metal_device_t dev,
33        ggml_metal_cmd_buf_t cmd_buf,
34        ggml_cgraph * gf,
35        ggml_metal_fusion_info * finfo,
36        int  idx_start,
37        int  idx_end,
38        bool use_concurrency,
39        bool use_capture,
40        int  debug_graph) {
41        this->dev             = dev;
42        this->lib             = ggml_metal_device_get_library(dev);
43        this->enc             = ggml_metal_encoder_init(cmd_buf, use_concurrency);
44        this->mem_ranges      = ggml_mem_ranges_init(debug_graph);
45        this->finfo           = finfo;
46        this->idx_start       = idx_start;
47        this->idx_end         = idx_end;
48        this->use_concurrency = use_concurrency;
49        this->use_capture     = use_capture;
50        this->debug_graph     = debug_graph;
51        this->gf              = gf;
52
53        idxs.reserve(gf->n_nodes);
54
55        // filter empty nodes
56        // TODO: this can be removed when the allocator starts filtering them earlier
57        //       https://github.com/ggml-org/llama.cpp/pull/16130#issuecomment-3327905830
58        for (int i = idx_start; i < idx_end; i++) {
59            if (!ggml_op_is_empty(gf->nodes[i]->op) && !ggml_is_empty(gf->nodes[i])) {
60                idxs.push_back(i);
61            }
62        }
63    }
64
65    ~ggml_metal_op() {
66        ggml_metal_encoder_end_encoding(this->enc);
67        ggml_metal_encoder_free(this->enc);
68        ggml_mem_ranges_free(this->mem_ranges);
69    }
70
71    int n_nodes() const {
72        return idxs.size();
73    }
74
75    ggml_tensor * node(int i) const {
76        assert(i >= 0 && i < (int) idxs.size());
77        return ggml_graph_node(gf, idxs[i]);
78    }
79
80    // consult the fusion table for the longest pattern starting at i0
81    // returns the matching pattern (nullptr if no fusion) and sets *n_out to the number of nodes
82    const ggml_metal_fusion * can_fuse(int i0, enum ggml_metal_fusion_mode mode, int * n_out) const {
83        assert(use_fusion());
84        assert(i0 >= 0 && i0 < n_nodes());
85
86        return ggml_metal_fusion_next(gf, idxs.data(), (int) idxs.size(), i0, mode, n_out);
87    }
88
89    // whether to attempt fusion; the toggle lives in the shared fusion debugging context owned
90    // by the device (initialized from GGML_METAL_FUSION_DISABLE, overridable by the test)
91    bool use_fusion() const {
92        return ggml_metal_fusion_info_enabled(finfo);
93    }
94
95    // record that a fusion fired, indexed by the matching table entry
96    void count_fusions(const ggml_metal_fusion * fusion) const {
97        ggml_metal_fusion_info_count_fusion(finfo, fusion);
98    }
99
100    ggml_metal_device_t  dev;
101    ggml_metal_library_t lib;
102    ggml_metal_encoder_t enc;
103    ggml_mem_ranges_t    mem_ranges;
104
105    // shared fusion debugging context
106    ggml_metal_fusion_info * finfo;
107
108    bool use_concurrency;
109    bool use_capture;
110
111    int debug_graph;
112
113private:
114    ggml_cgraph * gf;
115
116    int idx_start;
117    int idx_end;
118
119    // non-empty node indices
120    std::vector<int> idxs;
121};
122
123ggml_metal_op_t ggml_metal_op_init(
124        ggml_metal_device_t dev,
125        ggml_metal_cmd_buf_t cmd_buf,
126        ggml_cgraph * gf,
127        ggml_metal_fusion_info * finfo,
128        int idx_start,
129        int idx_end,
130        bool use_concurrency,
131        bool use_capture,
132        int debug_graph) {
133    ggml_metal_op_t res = new ggml_metal_op(
134        dev,
135        cmd_buf,
136        gf,
137        finfo,
138        idx_start,
139        idx_end,
140        use_concurrency,
141        use_capture,
142        debug_graph);
143
144    return res;
145}
146
147void ggml_metal_op_free(ggml_metal_op_t ctx) {
148    delete ctx;
149}
150
151int ggml_metal_op_n_nodes(ggml_metal_op_t ctx) {
152    return ctx->n_nodes();
153}
154
155static bool ggml_metal_op_concurrency_reset(ggml_metal_op_t ctx) {
156    if (!ctx->mem_ranges) {
157        return true;
158    }
159
160    ggml_metal_encoder_memory_barrier(ctx->enc);
161
162    ggml_mem_ranges_reset(ctx->mem_ranges);
163
164    return true;
165}
166
167static bool ggml_metal_op_concurrency_check(ggml_metal_op_t ctx, const ggml_tensor * node) {
168    if (!ctx->mem_ranges) {
169        return false;
170    }
171
172    return ggml_mem_ranges_check(ctx->mem_ranges, node);
173}
174
175static bool ggml_metal_op_concurrency_add(ggml_metal_op_t ctx, const ggml_tensor * node) {
176    if (!ctx->mem_ranges) {
177        return true;
178    }
179
180    return ggml_mem_ranges_add(ctx->mem_ranges, node);
181}
182
183static int ggml_metal_op_encode_impl(ggml_metal_op_t ctx, int idx) {
184    struct ggml_tensor * node = ctx->node(idx);
185
186    //GGML_LOG_INFO("%s: encoding node %3d, op = %8s\n", __func__, idx, ggml_op_name(node->op));
187
188    if (ggml_is_empty(node)) {
189        return 1;
190    }
191
192    switch (node->op) {
193        case GGML_OP_NONE:
194        case GGML_OP_RESHAPE:
195        case GGML_OP_VIEW:
196        case GGML_OP_TRANSPOSE:
197        case GGML_OP_PERMUTE:
198            {
199                // noop -> next node
200                if (ctx->debug_graph > 0) {
201                    GGML_LOG_DEBUG("%s: node[%5d] - %-12s %s\n", __func__, idx, ggml_op_name(node->op), "(noop)");
202                }
203            } return 1;
204        default:
205            {
206            } break;
207    }
208
209    if (!ggml_metal_device_supports_op(ctx->dev, node)) {
210        GGML_LOG_ERROR("%s: error: unsupported op '%s'\n", __func__, ggml_op_desc(node));
211        GGML_ABORT("unsupported op");
212    }
213
214    if ((node->flags & GGML_TENSOR_FLAG_COMPUTE) == 0) {
215        return 1;
216    }
217
218    int n_fuse = 1;
219
220    // check if the current node can run concurrently with other nodes before it
221    // the condition is that:
222    //  - the current node cannot write to any previous src or dst ranges
223    //  - the current node cannot read from any previous dst ranges
224    //
225    // if the condition is not satisfied, we put a memory barrier and clear all ranges
226    // otherwise, we add the new ranges to the encoding context and process the node concurrently
227    //
228    {
229        const bool is_concurrent = ggml_metal_op_concurrency_check(ctx, node);
230
231        if (!is_concurrent) {
232            ggml_metal_op_concurrency_reset(ctx);
233        }
234
235        if (ctx->debug_graph > 0) {
236            GGML_LOG_DEBUG("%s: node[%5d] - %-12s %-12s %s\n", __func__, idx, ggml_op_name(node->op), ggml_get_name(node), is_concurrent ? "(concurrent)" : "");
237        }
238        if (ctx->debug_graph > 1) {
239            GGML_TENSOR_LOCALS( int64_t, ne0, node->src[0], ne);
240            GGML_TENSOR_LOCALS(uint64_t, nb0, node->src[0], nb);
241            GGML_TENSOR_LOCALS( int64_t, ne1, node->src[1], ne);
242            GGML_TENSOR_LOCALS(uint64_t, nb1, node->src[1], nb);
243            GGML_TENSOR_LOCALS( int64_t, ne2, node->src[2], ne);
244            GGML_TENSOR_LOCALS(uint64_t, nb2, node->src[2], nb);
245            GGML_TENSOR_LOCALS( int64_t, ne3, node->src[3], ne);
246            GGML_TENSOR_LOCALS(uint64_t, nb3, node->src[3], nb);
247            GGML_TENSOR_LOCALS( int64_t, ne,  node,         ne);
248            GGML_TENSOR_LOCALS(uint64_t, nb,  node,         nb);
249
250            if (node->src[0]) {
251                GGML_LOG_DEBUG("%s: src0 - %4s [%5lld, %5lld, %5lld, %5lld] [%5lld, %5lld, %5lld, %5lld], %d, %s\n", __func__, ggml_type_name(node->src[0]->type), ne00, ne01, ne02, ne03, nb00, nb01, nb02, nb03,
252                        ggml_is_contiguous(node->src[0]), node->src[0]->name);
253            }
254            if (node->src[1]) {
255                GGML_LOG_DEBUG("%s: src1 - %4s [%5lld, %5lld, %5lld, %5lld] [%5lld, %5lld, %5lld, %5lld], %d, %s\n", __func__, ggml_type_name(node->src[1]->type), ne10, ne11, ne12, ne13, nb10, nb11, nb12, nb13,
256                        ggml_is_contiguous(node->src[1]), node->src[1]->name);
257            }
258            if (node->src[2]) {
259                GGML_LOG_DEBUG("%s: src2 - %4s [%5lld, %5lld, %5lld, %5lld] [%5lld, %5lld, %5lld, %5lld], %d, %s\n", __func__, ggml_type_name(node->src[2]->type), ne20, ne21, ne22, ne23, nb20, nb21, nb22, nb23,
260                        ggml_is_contiguous(node->src[2]), node->src[2]->name);
261            }
262            if (node->src[3]) {
263                GGML_LOG_DEBUG("%s: src3 - %4s [%5lld, %5lld, %5lld, %5lld] [%5lld, %5lld, %5lld, %5lld], %d, %s\n", __func__, ggml_type_name(node->src[3]->type), ne30, ne31, ne32, ne33, nb30, nb31, nb32, nb33,
264                        ggml_is_contiguous(node->src[3]), node->src[3]->name);
265            }
266            if (node) {
267                GGML_LOG_DEBUG("%s: node  - %4s [%5lld, %5lld, %5lld, %5lld] [%5lld, %5lld, %5lld, %5lld], 1, %s\n", __func__, ggml_type_name(node->type), ne0, ne1, ne2, ne3, nb0, nb1, nb2, nb3,
268                        node->name);
269            }
270        }
271    }
272
273    switch (node->op) {
274        case GGML_OP_CONCAT:
275            {
276                n_fuse = ggml_metal_op_concat(ctx, idx);
277            } break;
278        case GGML_OP_ADD:
279        case GGML_OP_SUB:
280        case GGML_OP_MUL:
281        case GGML_OP_DIV:
282            {
283                n_fuse = ggml_metal_op_bin(ctx, idx);
284            } break;
285        case GGML_OP_ADD_ID:
286            {
287                n_fuse = ggml_metal_op_add_id(ctx, idx);
288            } break;
289        case GGML_OP_REPEAT:
290            {
291                n_fuse = ggml_metal_op_repeat(ctx, idx);
292            } break;
293        case GGML_OP_ACC:
294            {
295                n_fuse = ggml_metal_op_acc(ctx, idx);
296            } break;
297        case GGML_OP_SCALE:
298        case GGML_OP_FILL:
299        case GGML_OP_CLAMP:
300        case GGML_OP_LEAKY_RELU:
301        case GGML_OP_SQR:
302        case GGML_OP_SQRT:
303        case GGML_OP_SIN:
304        case GGML_OP_COS:
305        case GGML_OP_LOG:
306        case GGML_OP_UNARY:
307            {
308                n_fuse = ggml_metal_op_unary(ctx, idx);
309            } break;
310        case GGML_OP_SILU_BACK:
311            {
312                n_fuse = ggml_metal_op_silu_back(ctx, idx);
313            } break;
314        case GGML_OP_GLU:
315            {
316                n_fuse = ggml_metal_op_glu(ctx, idx);
317            } break;
318        case GGML_OP_SUM:
319            {
320                n_fuse = ggml_metal_op_sum(ctx, idx);
321            } break;
322        case GGML_OP_SUM_ROWS:
323        case GGML_OP_MEAN:
324            {
325                n_fuse = ggml_metal_op_sum_rows(ctx, idx);
326            } break;
327        case GGML_OP_CUMSUM:
328            {
329                n_fuse = ggml_metal_op_cumsum(ctx, idx);
330            } break;
331        case GGML_OP_LIGHTNING_INDEXER:
332            {
333                n_fuse = ggml_metal_op_lightning_indexer(ctx, idx);
334            } break;
335        case GGML_OP_DSV4_HC_COMB:
336        case GGML_OP_DSV4_HC_PRE:
337        case GGML_OP_DSV4_HC_POST:
338            {
339                n_fuse = ggml_metal_op_dsv4_hc(ctx, idx);
340            } break;
341        case GGML_OP_SOFT_MAX:
342            {
343                n_fuse = ggml_metal_op_soft_max(ctx, idx);
344            } break;
345        case GGML_OP_SSM_CONV:
346            {
347                n_fuse = ggml_metal_op_ssm_conv(ctx, idx);
348            } break;
349        case GGML_OP_SSM_SCAN:
350            {
351                n_fuse = ggml_metal_op_ssm_scan(ctx, idx);
352            } break;
353        case GGML_OP_RWKV_WKV6:
354        case GGML_OP_RWKV_WKV7:
355            {
356                n_fuse = ggml_metal_op_rwkv(ctx, idx);
357            } break;
358        case GGML_OP_GATED_DELTA_NET:
359            {
360                n_fuse = ggml_metal_op_gated_delta_net(ctx, idx);
361            } break;
362        case GGML_OP_SOLVE_TRI:
363            {
364                n_fuse = ggml_metal_op_solve_tri(ctx, idx);
365            } break;
366        case GGML_OP_MUL_MAT:
367            {
368                n_fuse = ggml_metal_op_mul_mat(ctx, idx);
369            } break;
370        case GGML_OP_MUL_MAT_ID:
371            {
372                n_fuse = ggml_metal_op_mul_mat_id(ctx, idx);
373            } break;
374        case GGML_OP_GET_ROWS:
375            {
376                n_fuse = ggml_metal_op_get_rows(ctx, idx);
377            } break;
378        case GGML_OP_SET_ROWS:
379            {
380                n_fuse = ggml_metal_op_set_rows(ctx, idx);
381            } break;
382        case GGML_OP_DIAG:
383            {
384                n_fuse = ggml_metal_op_diag(ctx, idx);
385            } break;
386        case GGML_OP_L2_NORM:
387            {
388                n_fuse = ggml_metal_op_l2_norm(ctx, idx);
389            } break;
390        case GGML_OP_GROUP_NORM:
391            {
392                n_fuse = ggml_metal_op_group_norm(ctx, idx);
393            } break;
394        case GGML_OP_NORM:
395        case GGML_OP_RMS_NORM:
396            {
397                n_fuse = ggml_metal_op_norm(ctx, idx);
398            } break;
399        case GGML_OP_ROPE:
400        case GGML_OP_ROPE_BACK:
401            {
402                n_fuse = ggml_metal_op_rope(ctx, idx);
403            } break;
404        case GGML_OP_IM2COL:
405            {
406                n_fuse = ggml_metal_op_im2col(ctx, idx);
407            } break;
408        case GGML_OP_CONV_2D:
409            {
410                n_fuse = ggml_metal_op_conv_2d(ctx, idx);
411            } break;
412        case GGML_OP_CONV_2D_DW:
413            {
414                n_fuse = ggml_metal_op_conv_2d_dw(ctx, idx);
415            } break;
416        case GGML_OP_CONV_TRANSPOSE_1D:
417            {
418                n_fuse = ggml_metal_op_conv_transpose_1d(ctx, idx);
419            } break;
420        case GGML_OP_CONV_TRANSPOSE_2D:
421            {
422                n_fuse = ggml_metal_op_conv_transpose_2d(ctx, idx);
423            } break;
424        case GGML_OP_COL2IM_1D:
425            {
426                n_fuse = ggml_metal_op_col2im_1d(ctx, idx);
427            } break;
428        case GGML_OP_CONV_3D:
429            {
430                n_fuse = ggml_metal_op_conv_3d(ctx, idx);
431            } break;
432        case GGML_OP_UPSCALE:
433            {
434                n_fuse = ggml_metal_op_upscale(ctx, idx);
435            } break;
436        case GGML_OP_PAD:
437            {
438                n_fuse = ggml_metal_op_pad(ctx, idx);
439            } break;
440        case GGML_OP_PAD_REFLECT_1D:
441            {
442                n_fuse = ggml_metal_op_pad_reflect_1d(ctx, idx);
443            } break;
444        case GGML_OP_ROLL:
445            {
446                n_fuse = ggml_metal_op_roll(ctx, idx);
447            } break;
448        case GGML_OP_ARANGE:
449            {
450                n_fuse = ggml_metal_op_arange(ctx, idx);
451            } break;
452        case GGML_OP_TIMESTEP_EMBEDDING:
453            {
454                n_fuse = ggml_metal_op_timestep_embedding(ctx, idx);
455            } break;
456        case GGML_OP_ARGSORT:
457            {
458                n_fuse = ggml_metal_op_argsort(ctx, idx);
459            } break;
460        case GGML_OP_TOP_K:
461            {
462                n_fuse = ggml_metal_op_top_k(ctx, idx);
463            } break;
464        case GGML_OP_TRI:
465            {
466                n_fuse = ggml_metal_op_tri(ctx, idx);
467            } break;
468        case GGML_OP_FLASH_ATTN_EXT:
469            {
470                n_fuse = ggml_metal_op_flash_attn_ext(ctx, idx);
471            } break;
472        case GGML_OP_SET:
473            {
474                n_fuse = ggml_metal_op_set(ctx, idx);
475            } break;
476        case GGML_OP_DUP:
477        case GGML_OP_CPY:
478        case GGML_OP_CONT:
479            {
480                n_fuse = ggml_metal_op_cpy(ctx, idx);
481            } break;
482        case GGML_OP_POOL_1D:
483            {
484                n_fuse = ggml_metal_op_pool_1d(ctx, idx);
485            } break;
486        case GGML_OP_POOL_2D:
487            {
488                n_fuse = ggml_metal_op_pool_2d(ctx, idx);
489            } break;
490        case GGML_OP_ARGMAX:
491            {
492                n_fuse = ggml_metal_op_argmax(ctx, idx);
493            } break;
494        case GGML_OP_OPT_STEP_ADAMW:
495            {
496                n_fuse = ggml_metal_op_opt_step_adamw(ctx, idx);
497            } break;
498        case GGML_OP_OPT_STEP_SGD:
499            {
500                n_fuse = ggml_metal_op_opt_step_sgd(ctx, idx);
501            } break;
502        case GGML_OP_COUNT_EQUAL:
503            {
504                n_fuse = ggml_metal_op_count_equal(ctx, idx);
505            } break;
506        default:
507            {
508                GGML_LOG_ERROR("%s: error: node %3d, op = %8s not implemented\n", __func__, idx, ggml_op_name(node->op));
509                GGML_ABORT("fatal error");
510            }
511    }
512
513    if (ctx->debug_graph > 0) {
514        if (n_fuse > 1) {
515            GGML_LOG_DEBUG("%s:               fuse %d ops\n", __func__, n_fuse);
516        }
517    }
518
519    // update the mem ranges in the encoding context
520    for (int i = 0; i < n_fuse; ++i) {
521        if (!ggml_metal_op_concurrency_add(ctx, ctx->node(idx + i))) {
522            ggml_metal_op_concurrency_reset(ctx);
523        }
524    }
525
526    return n_fuse;
527}
528
529int ggml_metal_op_encode(ggml_metal_op_t ctx, int idx) {
530    if (ctx->use_capture) {
531        ggml_metal_encoder_debug_group_push(ctx->enc, ggml_op_desc(ctx->node(idx)));
532    }
533
534    int res = ggml_metal_op_encode_impl(ctx, idx);
535    if (idx + res > ctx->n_nodes()) {
536        GGML_ABORT("fusion error: nodes spanning multiple encoders have been fused. this indicates a bug in the fusion logic %s",
537                "https://github.com/ggml-org/llama.cpp/pull/14849");
538    }
539
540    if (ctx->use_capture) {
541        ggml_metal_encoder_debug_group_pop(ctx->enc);
542    }
543
544    return res;
545}
546
547int ggml_metal_op_concat(ggml_metal_op_t ctx, int idx) {
548    ggml_tensor * op = ctx->node(idx);
549
550    ggml_metal_library_t lib = ctx->lib;
551    ggml_metal_encoder_t enc = ctx->enc;
552
553    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
554    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
555    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
556    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
557    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
558    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
559
560    const int32_t dim = ((const int32_t *) op->op_params)[0];
561
562    const bool is_q = ggml_is_quantized(op->type);
563
564    // for quantized types, concat is done at the block level (nb0 == type_size == block size)
565    int32_t ne00_arg = ne00;
566    int32_t ne10_arg = ne10;
567    int32_t ne0_arg  = ne0;
568    if (is_q) {
569        const int32_t blck = ggml_blck_size(op->type);
570        GGML_ASSERT(ne00 % blck == 0);
571        GGML_ASSERT(ne10 % blck == 0);
572        GGML_ASSERT(ne0  % blck == 0);
573        ne00_arg = ne00/blck;
574        ne10_arg = ne10/blck;
575        ne0_arg  = ne0/blck;
576    }
577
578    ggml_metal_kargs_concat args = {
579        /*.ne00 =*/ ne00_arg,
580        /*.ne01 =*/ ne01,
581        /*.ne02 =*/ ne02,
582        /*.ne03 =*/ ne03,
583        /*.nb00 =*/ nb00,
584        /*.nb01 =*/ nb01,
585        /*.nb02 =*/ nb02,
586        /*.nb03 =*/ nb03,
587        /*.ne10 =*/ ne10_arg,
588        /*.ne11 =*/ ne11,
589        /*.ne12 =*/ ne12,
590        /*.ne13 =*/ ne13,
591        /*.nb10 =*/ nb10,
592        /*.nb11 =*/ nb11,
593        /*.nb12 =*/ nb12,
594        /*.nb13 =*/ nb13,
595        /*.ne0  =*/ ne0_arg,
596        /*.ne1  =*/ ne1,
597        /*.ne2  =*/ ne2,
598        /*.ne3  =*/ ne3,
599        /*.nb0  =*/ nb0,
600        /*.nb1  =*/ nb1,
601        /*.nb2  =*/ nb2,
602        /*.nb3  =*/ nb3,
603        /*.dim  =*/ dim,
604    };
605
606    auto pipeline = ggml_metal_library_get_pipeline_concat(lib, op->type);
607
608    ggml_metal_encoder_set_pipeline(enc, pipeline);
609    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
610    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
611    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
612    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
613
614    int nth = std::min(256, ne0_arg);
615
616    // when rows are small, we can batch them together in a single threadgroup
617    int nrptg = 1;
618    if (nth < 256) {
619        nrptg = std::min((256 + nth - 1) / nth, ne1);
620        if (nrptg * nth > 256) {
621            nrptg = 256 / nth;
622        }
623    }
624
625    const int nw0 = (ne1 + nrptg - 1) / nrptg;
626
627    ggml_metal_encoder_dispatch_threadgroups(enc, nw0, ne2, ne3, nth, nrptg, 1);
628
629    return 1;
630}
631
632int ggml_metal_op_repeat(ggml_metal_op_t ctx, int idx) {
633    ggml_tensor * op = ctx->node(idx);
634
635    ggml_metal_library_t lib = ctx->lib;
636    ggml_metal_encoder_t enc = ctx->enc;
637
638    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
639    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
640    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
641    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
642
643    auto pipeline = ggml_metal_library_get_pipeline_repeat(lib, op->type);
644
645    ggml_metal_kargs_repeat args = {
646        /*.ne00 =*/ ne00,
647        /*.ne01 =*/ ne01,
648        /*.ne02 =*/ ne02,
649        /*.ne03 =*/ ne03,
650        /*.nb00 =*/ nb00,
651        /*.nb01 =*/ nb01,
652        /*.nb02 =*/ nb02,
653        /*.nb03 =*/ nb03,
654        /*.ne0  =*/ ne0,
655        /*.ne1  =*/ ne1,
656        /*.ne2  =*/ ne2,
657        /*.ne3  =*/ ne3,
658        /*.nb0  =*/ nb0,
659        /*.nb1  =*/ nb1,
660        /*.nb2  =*/ nb2,
661        /*.nb3  =*/ nb3,
662    };
663
664    ggml_metal_encoder_set_pipeline(enc, pipeline);
665    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
666    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
667    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
668
669    const int nth = std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline), ne0);
670
671    ggml_metal_encoder_dispatch_threadgroups(enc, ne1, ne2, ne3, nth, 1, 1);
672
673    return 1;
674}
675
676int ggml_metal_op_acc(ggml_metal_op_t ctx, int idx) {
677    ggml_tensor * op = ctx->node(idx);
678
679    ggml_metal_library_t lib = ctx->lib;
680    ggml_metal_encoder_t enc = ctx->enc;
681
682    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
683    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
684    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
685    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
686    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
687    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
688
689    GGML_ASSERT(op->src[0]->type == GGML_TYPE_F32);
690    GGML_ASSERT(op->src[1]->type == GGML_TYPE_F32);
691    GGML_ASSERT(op->type         == GGML_TYPE_F32);
692
693    GGML_ASSERT(ggml_is_contiguous_rows(op->src[0]));
694    GGML_ASSERT(ggml_is_contiguous_rows(op->src[1]));
695
696    const size_t pnb1 = ((const int32_t *) op->op_params)[0];
697    const size_t pnb2 = ((const int32_t *) op->op_params)[1];
698    const size_t pnb3 = ((const int32_t *) op->op_params)[2];
699    const size_t offs = ((const int32_t *) op->op_params)[3];
700
701    const bool inplace = (bool) ((const int32_t *) op->op_params)[4];
702
703    if (!inplace) {
704        // run a separate kernel to cpy src->dst
705        // not sure how to avoid this
706        // TODO: make a simpler cpy_bytes kernel
707
708        //const id<MTLComputePipelineState> pipeline = ctx->pipelines[GGML_METAL_PIPELINE_TYPE_CPY_F32_F32].obj;
709        auto pipeline = ggml_metal_library_get_pipeline_cpy(lib, op->src[0]->type, op->type);
710
711        ggml_metal_kargs_cpy args = {
712            /*.nk0  =*/ ne00,
713            /*.ne00 =*/ ne00,
714            /*.ne01 =*/ ne01,
715            /*.ne02 =*/ ne02,
716            /*.ne03 =*/ ne03,
717            /*.nb00 =*/ nb00,
718            /*.nb01 =*/ nb01,
719            /*.nb02 =*/ nb02,
720            /*.nb03 =*/ nb03,
721            /*.ne0  =*/ ne0,
722            /*.ne1  =*/ ne1,
723            /*.ne2  =*/ ne2,
724            /*.ne3  =*/ ne3,
725            /*.nb0  =*/ nb0,
726            /*.nb1  =*/ nb1,
727            /*.nb2  =*/ nb2,
728            /*.nb3  =*/ nb3,
729        };
730
731        ggml_metal_encoder_set_pipeline(enc, pipeline);
732        ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
733        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
734        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
735
736        const int nth = std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline), ne00);
737
738        ggml_metal_encoder_dispatch_threadgroups(enc, ne01, ne02, ne03, nth, 1, 1);
739
740        ggml_metal_op_concurrency_reset(ctx);
741    }
742
743    ggml_metal_kargs_bin args = {
744        /*.ne00 =*/ ne10,
745        /*.ne01 =*/ ne11,
746        /*.ne02 =*/ ne12,
747        /*.ne03 =*/ ne13,
748        /*.nb00 =*/ nb00,
749        /*.nb01 =*/ pnb1,
750        /*.nb02 =*/ pnb2,
751        /*.nb03 =*/ pnb3,
752        /*.ne10 =*/ ne10,
753        /*.ne11 =*/ ne11,
754        /*.ne12 =*/ ne12,
755        /*.ne13 =*/ ne13,
756        /*.nb10 =*/ nb10,
757        /*.nb11 =*/ nb11,
758        /*.nb12 =*/ nb12,
759        /*.nb13 =*/ nb13,
760        /*.ne0  =*/ ne10,
761        /*.ne1  =*/ ne11,
762        /*.ne2  =*/ ne12,
763        /*.ne3  =*/ ne13,
764        /*.nb0  =*/ nb0,
765        /*.nb1  =*/ pnb1,
766        /*.nb2  =*/ pnb2,
767        /*.nb3  =*/ pnb3,
768        /*.offs =*/ offs,
769        /*.o1   =*/ { 0 },
770    };
771
772    auto pipeline = ggml_metal_library_get_pipeline_bin_one(lib, GGML_OP_ADD);
773
774    ggml_metal_encoder_set_pipeline(enc, pipeline);
775    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
776    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
777    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
778    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
779
780    const int nth_max = MIN(256, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
781
782    int nth = 1;
783
784    while (2*nth < args.ne0 && nth < nth_max) {
785        nth *= 2;
786    }
787
788    ggml_metal_encoder_dispatch_threadgroups(enc, ne11, ne12, ne13, nth, 1, 1);
789
790    return 1;
791}
792
793int ggml_metal_op_unary(ggml_metal_op_t ctx, int idx) {
794    ggml_tensor * op = ctx->node(idx);
795
796    ggml_metal_library_t lib = ctx->lib;
797    ggml_metal_encoder_t enc = ctx->enc;
798
799    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
800    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
801    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
802    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
803
804    GGML_ASSERT(ggml_is_contiguous_rows(op->src[0]));
805
806    ggml_metal_buffer_id bid_src0 = ggml_metal_get_buffer_id(op->src[0]);
807    ggml_metal_buffer_id bid_dst  = ggml_metal_get_buffer_id(op);
808
809    ggml_metal_kargs_unary args = {
810        /*.ne00  =*/ ne00,
811        /*.ne01  =*/ ne01,
812        /*.ne02  =*/ ne02,
813        /*.ne03  =*/ ne03,
814        /*.nb00  =*/ nb00,
815        /*.nb01  =*/ nb01,
816        /*.nb02  =*/ nb02,
817        /*.nb03  =*/ nb03,
818        /*.ne0   =*/ ne0,
819        /*.ne1   =*/ ne1,
820        /*.ne2   =*/ ne2,
821        /*.ne3   =*/ ne3,
822        /*.nb0   =*/ nb0,
823        /*.nb1   =*/ nb1,
824        /*.nb2   =*/ nb2,
825        /*.nb3   =*/ nb3,
826        /*.slope =*/ 0.0,
827        /*.scale =*/ 0.0,
828        /*.bias  =*/ 0.0,
829        /*.val   =*/ 0.0,
830        /*.min   =*/ 0.0,
831        /*.max   =*/ 0.0,
832    };
833
834    if (op->op == GGML_OP_LEAKY_RELU) {
835        args.slope = ggml_get_op_params_f32(op, 0);
836    }
837
838    if (op->op == GGML_OP_SCALE) {
839        args.scale = ggml_get_op_params_f32(op, 0);
840        args.bias  = ggml_get_op_params_f32(op, 1);
841    }
842
843    if (op->op == GGML_OP_FILL) {
844        args.val = ggml_get_op_params_f32(op, 0);
845    }
846
847    if (op->op == GGML_OP_CLAMP) {
848        args.min = ggml_get_op_params_f32(op, 0);
849        args.max = ggml_get_op_params_f32(op, 1);
850    }
851
852    if (op->op == GGML_OP_UNARY && ggml_get_unary_op(op) == GGML_UNARY_OP_XIELU) {
853        args.slope = ggml_get_op_params_f32(op, 1); // alpha_n
854        args.scale = ggml_get_op_params_f32(op, 2); // alpha_p
855        args.bias  = ggml_get_op_params_f32(op, 3); // beta
856        args.val   = ggml_get_op_params_f32(op, 4); // eps
857    }
858
859    auto pipeline = ggml_metal_library_get_pipeline_unary(lib, op);
860
861    if (pipeline.c4) {
862        args.ne00 = ne00/4;
863        args.ne0  = ne0/4;
864    }
865
866    ggml_metal_encoder_set_pipeline(enc, pipeline);
867    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
868    ggml_metal_encoder_set_buffer  (enc, bid_src0, 1);
869    ggml_metal_encoder_set_buffer  (enc, bid_dst,  2);
870
871    if (pipeline.cnt) {
872        const int n = pipeline.c4 ? ggml_nelements(op)/4 : ggml_nelements(op);
873
874        ggml_metal_encoder_dispatch_threadgroups(enc, n, 1, 1, 1, 1, 1);
875    } else {
876        const int nth_max = MIN(256, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
877        const int nth = MIN(args.ne00, nth_max);
878        const int nk0 = (args.ne00 + nth - 1)/nth;
879
880        ggml_metal_encoder_dispatch_threadgroups(enc, nk0*ne01, ne02, ne03, nth, 1, 1);
881    }
882
883    return 1;
884}
885
886int ggml_metal_op_glu(ggml_metal_op_t ctx, int idx) {
887    ggml_tensor * op = ctx->node(idx);
888
889    ggml_metal_library_t lib = ctx->lib;
890    ggml_metal_encoder_t enc = ctx->enc;
891
892    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
893    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
894    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
895    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
896    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
897    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
898
899    if (op->src[1]) {
900        GGML_ASSERT(ggml_are_same_shape(op->src[0], op->src[1]));
901    }
902
903    auto pipeline = ggml_metal_library_get_pipeline_glu(lib, op);
904
905    const int32_t swp = ggml_get_op_params_i32(op, 1);
906    const float alpha = ggml_get_op_params_f32(op, 2);
907    const float limit = ggml_get_op_params_f32(op, 3);
908
909    const int32_t i00 = swp ? ne0 : 0;
910    const int32_t i10 = swp ? 0 : ne0;
911
912    ggml_metal_kargs_glu args = {
913        /*.ne00 =*/ ne00,
914        /*.nb01 =*/ nb01,
915        /*.ne10 =*/ op->src[1] ? ne10 : ne00,
916        /*.nb11 =*/ op->src[1] ? nb11 : nb01,
917        /*.ne0  =*/ ne0,
918        /*.nb1  =*/ nb1,
919        /*.i00  =*/ op->src[1] ? 0 : i00,
920        /*.i10  =*/ op->src[1] ? 0 : i10,
921        /*.alpha=*/ alpha,
922        /*.limit=*/ limit
923    };
924
925    const int64_t nrows = ggml_nrows(op->src[0]);
926
927    const int32_t nth = std::max(1, std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline), ne00/2));
928
929    ggml_metal_encoder_set_pipeline(enc, pipeline);
930    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
931    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
932    if (op->src[1]) {
933        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
934    } else {
935        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 2);
936    }
937    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
938
939    ggml_metal_encoder_dispatch_threadgroups(enc, nrows, 1, 1, nth, 1, 1);
940
941    return 1;
942}
943
944int ggml_metal_op_sum(ggml_metal_op_t ctx, int idx) {
945    ggml_tensor * op  = ctx->node(idx);
946
947    ggml_metal_library_t lib = ctx->lib;
948    ggml_metal_encoder_t enc = ctx->enc;
949
950    const uint64_t n = (uint64_t) ggml_nelements(op->src[0]);
951
952    ggml_metal_kargs_sum args = {
953        /*.np =*/ n,
954    };
955
956    auto pipeline = ggml_metal_library_get_pipeline_sum(lib, op);
957
958    int nth = 32; // SIMD width
959
960    while (nth < (int) n && nth < ggml_metal_pipeline_max_theads_per_threadgroup(pipeline)) {
961        nth *= 2;
962    }
963
964    nth = std::min(nth, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
965    nth = std::min(nth, (int) n);
966
967    const int nsg = (nth + 31) / 32;
968
969    ggml_metal_encoder_set_pipeline(enc, pipeline);
970    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
971    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
972    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
973
974    ggml_metal_encoder_set_threadgroup_memory_size(enc, GGML_PAD(nsg * sizeof(float), 16), 0);
975
976    ggml_metal_encoder_dispatch_threadgroups(enc, 1, 1, 1, nth, 1, 1);
977
978    return 1;
979}
980
981int ggml_metal_op_sum_rows(ggml_metal_op_t ctx, int idx) {
982    ggml_tensor * op = ctx->node(idx);
983
984    ggml_metal_library_t lib = ctx->lib;
985    ggml_metal_encoder_t enc = ctx->enc;
986
987    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
988    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
989    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
990    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
991
992    GGML_ASSERT(ggml_is_contiguous_rows(op->src[0]));
993
994    ggml_metal_buffer_id bid_src0 = ggml_metal_get_buffer_id(op->src[0]);
995    ggml_metal_buffer_id bid_dst  = ggml_metal_get_buffer_id(op);
996
997    ggml_metal_kargs_sum_rows args = {
998        /*.ne00 =*/ ne00,
999        /*.ne01 =*/ ne01,
1000        /*.ne02 =*/ ne02,
1001        /*.ne03 =*/ ne03,
1002        /*.nb00 =*/ nb00,
1003        /*.nb01 =*/ nb01,
1004        /*.nb02 =*/ nb02,
1005        /*.nb03 =*/ nb03,
1006        /*.ne0  =*/ ne0,
1007        /*.ne1  =*/ ne1,
1008        /*.ne2  =*/ ne2,
1009        /*.ne3  =*/ ne3,
1010        /*.nb0  =*/ nb0,
1011        /*.nb1  =*/ nb1,
1012        /*.nb2  =*/ nb2,
1013        /*.nb3  =*/ nb3,
1014    };
1015
1016    auto pipeline = ggml_metal_library_get_pipeline_sum_rows(lib, op);
1017
1018    if (pipeline.c4) {
1019        args.ne00 = ne00/4;
1020        args.ne0  = ne0/4;
1021    }
1022
1023    int nth = 32; // SIMD width
1024
1025    while (nth < args.ne00 && nth < ggml_metal_pipeline_max_theads_per_threadgroup(pipeline)) {
1026        nth *= 2;
1027    }
1028
1029    nth = std::min(nth, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
1030    nth = std::min(nth, (int) args.ne00);
1031
1032    const size_t smem = pipeline.smem;
1033
1034    ggml_metal_encoder_set_pipeline(enc, pipeline);
1035    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
1036    ggml_metal_encoder_set_buffer  (enc, bid_src0, 1);
1037    ggml_metal_encoder_set_buffer  (enc, bid_dst,  2);
1038
1039    ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
1040
1041    ggml_metal_encoder_dispatch_threadgroups(enc, ne01, ne02, ne03, nth, 1, 1);
1042
1043    return 1;
1044}
1045
1046int ggml_metal_op_cumsum(ggml_metal_op_t ctx, int idx) {
1047    ggml_tensor * op = ctx->node(idx);
1048
1049    ggml_metal_library_t lib = ctx->lib;
1050    ggml_metal_encoder_t enc = ctx->enc;
1051
1052    GGML_ASSERT(ggml_is_contiguous_rows(op->src[0]));
1053
1054    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
1055    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
1056    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
1057    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
1058
1059    auto pipeline_blk = ggml_metal_library_get_pipeline_cumsum_blk(lib, op);
1060
1061    int nth = 1;
1062    while (nth < ne00 && 2*nth <= ggml_metal_pipeline_max_theads_per_threadgroup(pipeline_blk)) {
1063        nth *= 2;
1064    }
1065
1066    GGML_ASSERT(ne00 <= nth*nth);
1067
1068    const int64_t net0 = (ne00 + nth - 1) / nth;
1069    const int64_t net1 = ne01;
1070    const int64_t net2 = ne02;
1071    const int64_t net3 = ne03;
1072
1073    const uint64_t nbt0 = sizeof(float);
1074    const uint64_t nbt1 = net0*nbt0;
1075    const uint64_t nbt2 = net1*nbt1;
1076    const uint64_t nbt3 = net2*nbt2;
1077
1078    const size_t smem = GGML_PAD(32*sizeof(float), 16);
1079
1080    ggml_metal_buffer_id bid_src0 = ggml_metal_get_buffer_id(op->src[0]);
1081    ggml_metal_buffer_id bid_dst  = ggml_metal_get_buffer_id(op);
1082
1083    ggml_metal_buffer_id bid_tmp = bid_dst;
1084    bid_tmp.offs += ggml_nbytes(op);
1085
1086    {
1087        ggml_metal_kargs_cumsum_blk args = {
1088            /*.ne00 =*/ ne00,
1089            /*.ne01 =*/ ne01,
1090            /*.ne02 =*/ ne02,
1091            /*.ne03 =*/ ne03,
1092            /*.nb00 =*/ nb00,
1093            /*.nb01 =*/ nb01,
1094            /*.nb02 =*/ nb02,
1095            /*.nb03 =*/ nb03,
1096            /*.net0 =*/ net0,
1097            /*.net1 =*/ net1,
1098            /*.net2 =*/ net2,
1099            /*.net3 =*/ net3,
1100            /*.nbt0 =*/ nbt0,
1101            /*.nbt1 =*/ nbt1,
1102            /*.nbt2 =*/ nbt2,
1103            /*.nbt3 =*/ nbt3,
1104            /*.outb =*/ ne00 > nth,
1105        };
1106
1107        ggml_metal_encoder_set_pipeline(enc, pipeline_blk);
1108        ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
1109        ggml_metal_encoder_set_buffer  (enc, bid_src0, 1);
1110        ggml_metal_encoder_set_buffer  (enc, bid_tmp,  2);
1111        ggml_metal_encoder_set_buffer  (enc, bid_dst,  3);
1112
1113        ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
1114
1115        ggml_metal_encoder_dispatch_threadgroups(enc, net0*ne01, ne02, ne03, nth, 1, 1);
1116    }
1117
1118    if (ne00 > nth) {
1119        ggml_metal_op_concurrency_reset(ctx);
1120
1121        {
1122            ggml_metal_kargs_cumsum_blk args = {
1123                /*.ne00 =*/ net0,
1124                /*.ne01 =*/ net1,
1125                /*.ne02 =*/ net2,
1126                /*.ne03 =*/ net3,
1127                /*.nb00 =*/ nbt0,
1128                /*.nb01 =*/ nbt1,
1129                /*.nb02 =*/ nbt2,
1130                /*.nb03 =*/ nbt3,
1131                /*.net0 =*/ net0,
1132                /*.net1 =*/ net1,
1133                /*.net2 =*/ net2,
1134                /*.net3 =*/ net3,
1135                /*.nbt0 =*/ nbt0,
1136                /*.nbt1 =*/ nbt1,
1137                /*.nbt2 =*/ nbt2,
1138                /*.nbt3 =*/ nbt3,
1139                /*.outb =*/ false,
1140            };
1141
1142            ggml_metal_encoder_set_pipeline(enc, pipeline_blk);
1143            ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
1144            ggml_metal_encoder_set_buffer  (enc, bid_tmp, 1);
1145            ggml_metal_encoder_set_buffer  (enc, bid_tmp, 2);
1146            ggml_metal_encoder_set_buffer  (enc, bid_tmp, 3);
1147
1148            ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
1149
1150            ggml_metal_encoder_dispatch_threadgroups(enc, net1, net2, net3, nth, 1, 1);
1151        }
1152
1153        ggml_metal_op_concurrency_reset(ctx);
1154
1155        {
1156            auto pipeline_add = ggml_metal_library_get_pipeline_cumsum_add(lib, op);
1157
1158            ggml_metal_kargs_cumsum_add args = {
1159                /*.ne00 =*/ ne00,
1160                /*.ne01 =*/ ne01,
1161                /*.ne02 =*/ ne02,
1162                /*.ne03 =*/ ne03,
1163                /*.nb00 =*/ nb00,
1164                /*.nb01 =*/ nb01,
1165                /*.nb02 =*/ nb02,
1166                /*.nb03 =*/ nb03,
1167                /*.net0 =*/ net0,
1168                /*.net1 =*/ net1,
1169                /*.net2 =*/ net2,
1170                /*.net3 =*/ net3,
1171                /*.nbt0 =*/ nbt0,
1172                /*.nbt1 =*/ nbt1,
1173                /*.nbt2 =*/ nbt2,
1174                /*.nbt3 =*/ nbt3,
1175            };
1176
1177            ggml_metal_encoder_set_pipeline(enc, pipeline_add);
1178            ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
1179            ggml_metal_encoder_set_buffer  (enc, bid_tmp, 1);
1180            ggml_metal_encoder_set_buffer  (enc, bid_dst, 2);
1181
1182            ggml_metal_encoder_dispatch_threadgroups(enc, net0*ne01, ne02, ne03, nth, 1, 1);
1183        }
1184    }
1185
1186    return 1;
1187}
1188
1189int ggml_metal_op_get_rows(ggml_metal_op_t ctx, int idx) {
1190    ggml_tensor * op = ctx->node(idx);
1191
1192    ggml_metal_library_t lib = ctx->lib;
1193    ggml_metal_encoder_t enc = ctx->enc;
1194
1195    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
1196    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
1197    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
1198    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
1199    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
1200    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
1201
1202    auto pipeline = ggml_metal_library_get_pipeline_get_rows(lib, op->src[0]->type);
1203
1204    ggml_metal_kargs_get_rows args = {
1205        /*.ne00t =*/ ggml_is_quantized(op->src[0]->type) ? ne00/16 : ne00,
1206        /*.ne00  =*/ ne00,
1207        /*.nb01  =*/ nb01,
1208        /*.nb02  =*/ nb02,
1209        /*.nb03  =*/ nb03,
1210        /*.ne10  =*/ ne10,
1211        /*.nb10  =*/ nb10,
1212        /*.nb11  =*/ nb11,
1213        /*.nb12  =*/ nb12,
1214        /*.nb1   =*/ nb1,
1215        /*.nb2   =*/ nb2,
1216        /*.nb3   =*/ nb3,
1217    };
1218
1219    const int nth = std::min(args.ne00t, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
1220
1221    const int nw0 = (args.ne00t + nth - 1)/nth;
1222
1223    ggml_metal_encoder_set_pipeline(enc, pipeline);
1224    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
1225    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
1226    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
1227    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
1228
1229    ggml_metal_encoder_dispatch_threadgroups(enc, nw0*ne10, ne11, ne12, nth, 1, 1);
1230
1231    return 1;
1232}
1233
1234int ggml_metal_op_set_rows(ggml_metal_op_t ctx, int idx) {
1235    ggml_tensor * op = ctx->node(idx);
1236
1237    ggml_metal_library_t lib = ctx->lib;
1238    ggml_metal_encoder_t enc = ctx->enc;
1239
1240    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
1241    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
1242    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
1243    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
1244    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
1245    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
1246
1247    auto pipeline = ggml_metal_library_get_pipeline_set_rows(lib, op);
1248
1249    const int32_t nk0 = ne0/ggml_blck_size(op->type);
1250
1251    int nth = 32; // SIMD width
1252
1253    while (nth < nk0 && nth < ggml_metal_pipeline_max_theads_per_threadgroup(pipeline)) {
1254        nth *= 2;
1255    }
1256
1257    int nrptg = 1;
1258    if (nth > nk0) {
1259        nrptg = (nth + nk0 - 1)/nk0;
1260        nth   = nk0;
1261
1262        if (nrptg*nth > ggml_metal_pipeline_max_theads_per_threadgroup(pipeline)) {
1263            nrptg--;
1264        }
1265    }
1266
1267    nth = std::min(nth, nk0);
1268
1269    ggml_metal_kargs_set_rows args = {
1270        /*.nk0  =*/ nk0,
1271        /*.ne01 =*/ ne01,
1272        /*.nb01 =*/ nb01,
1273        /*.nb02 =*/ nb02,
1274        /*.nb03 =*/ nb03,
1275        /*.ne11 =*/ ne11,
1276        /*.ne12 =*/ ne12,
1277        /*.nb10 =*/ nb10,
1278        /*.nb11 =*/ nb11,
1279        /*.nb12 =*/ nb12,
1280        /*.nb1  =*/ nb1,
1281        /*.nb2  =*/ nb2,
1282        /*.nb3  =*/ nb3,
1283    };
1284
1285    ggml_metal_encoder_set_pipeline(enc, pipeline);
1286    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
1287    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
1288    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
1289    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
1290
1291    ggml_metal_encoder_dispatch_threadgroups(enc, (ne01 + nrptg - 1)/nrptg, ne02, ne03, nth, nrptg, 1);
1292
1293    return 1;
1294}
1295
1296int ggml_metal_op_diag(ggml_metal_op_t ctx, int idx) {
1297    ggml_tensor * op = ctx->node(idx);
1298
1299    ggml_metal_library_t lib = ctx->lib;
1300    ggml_metal_encoder_t enc = ctx->enc;
1301
1302    GGML_TENSOR_LOCALS(int32_t,  ne0, op->src[0], ne);
1303    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
1304    GGML_TENSOR_LOCALS(int32_t,  ne, op, ne);
1305    GGML_TENSOR_LOCALS(uint64_t, nb, op, nb);
1306
1307    ggml_metal_kargs_diag args = {
1308        /*.ne00 =*/ne00,
1309        /*.ne01 =*/ne01,
1310        /*.ne02 =*/ne02,
1311        /*.ne03 =*/ne03,
1312        /*.nb00 =*/nb00,
1313        /*.nb01 =*/nb01,
1314        /*.nb02 =*/nb02,
1315        /*.nb03 =*/nb03,
1316        /*.ne0  =*/ne0,
1317        /*.ne1  =*/ne1,
1318        /*.ne2  =*/ne2,
1319        /*.ne3  =*/ne3,
1320        /*.nb0  =*/nb0,
1321        /*.nb1  =*/nb1,
1322        /*.nb2  =*/nb2,
1323        /*.nb3  =*/nb3,
1324    };
1325
1326    auto pipeline = ggml_metal_library_get_pipeline_diag(lib, op);
1327
1328    ggml_metal_encoder_set_pipeline(enc, pipeline);
1329    ggml_metal_encoder_set_bytes(enc, &args, sizeof(args), 0);
1330    ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op->src[0]), 1);
1331    ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op),         2);
1332
1333    ggml_metal_encoder_dispatch_threadgroups(enc, ne1, ne2, ne3, 32, 1, 1);
1334
1335    return 1;
1336}
1337
1338int ggml_metal_op_lightning_indexer(ggml_metal_op_t ctx, int idx) {
1339    ggml_tensor * op = ctx->node(idx);
1340
1341    ggml_metal_encoder_t enc = ctx->enc;
1342
1343    GGML_ASSERT(op->op == GGML_OP_LIGHTNING_INDEXER);
1344
1345    const ggml_tensor * q = op->src[0];
1346    const ggml_tensor * k = op->src[1];
1347    const ggml_tensor * w = op->src[2];
1348    const ggml_tensor * m = op->src[3];
1349
1350    GGML_ASSERT(q->type == GGML_TYPE_F32);
1351    GGML_ASSERT(k->type == GGML_TYPE_F32  ||
1352                k->type == GGML_TYPE_F16  ||
1353                k->type == GGML_TYPE_BF16 ||
1354                k->type == GGML_TYPE_Q4_0 ||
1355                k->type == GGML_TYPE_Q4_1 ||
1356                k->type == GGML_TYPE_Q5_0 ||
1357                k->type == GGML_TYPE_Q5_1 ||
1358                k->type == GGML_TYPE_Q8_0);
1359    GGML_ASSERT(w->type == GGML_TYPE_F32);
1360    GGML_ASSERT(m->type == GGML_TYPE_F16);
1361    GGML_ASSERT(op->type == GGML_TYPE_F32);
1362
1363    GGML_ASSERT(q->ne[0] == OP_LIGHTNING_INDEXER_DK);
1364    GGML_ASSERT(q->ne[1] == OP_LIGHTNING_INDEXER_NH);
1365
1366    ggml_metal_kargs_lightning_indexer args = {
1367        /*.n_kv      =*/ (int32_t) k->ne[2],
1368        /*.n_batch   =*/ (int32_t) q->ne[2],
1369        /*.mask_ne3  =*/ (int32_t) m->ne[3],
1370        /*.nb1       =*/ op->nb[1],
1371        /*.nb3       =*/ op->nb[3],
1372        /*.nbq1      =*/ q->nb[1],
1373        /*.nbq2      =*/ q->nb[2],
1374        /*.nbq3      =*/ q->nb[3],
1375        /*.nbk2      =*/ k->nb[2],
1376        /*.nbk3      =*/ k->nb[3],
1377        /*.nbw1      =*/ w->nb[1],
1378        /*.nbw3      =*/ w->nb[3],
1379        /*.nbm1      =*/ m->nb[1],
1380        /*.nbm3      =*/ m->nb[3],
1381    };
1382
1383    ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(q),  1);
1384    ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(k),  2);
1385    ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(w),  3);
1386    ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(m),  4);
1387    ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op), 5);
1388
1389    const int nsg   = OP_LIGHTNING_INDEXER_NSG;
1390    const int nkptg = OP_LIGHTNING_INDEXER_NKPSG*nsg;
1391    const int nbptg = OP_LIGHTNING_INDEXER_NBPTG;
1392
1393    auto pipeline = ggml_metal_library_get_pipeline_lightning_indexer(ctx->lib, op);
1394    ggml_metal_encoder_set_pipeline(enc, pipeline);
1395    ggml_metal_encoder_set_bytes(enc, &args, sizeof(args), 0);
1396    ggml_metal_encoder_dispatch_threadgroups(enc,
1397            (k->ne[2] + nkptg - 1)/nkptg,
1398            (q->ne[2] + nbptg - 1)/nbptg,
1399            q->ne[3], 32, nsg, 1);
1400
1401    return 1;
1402}
1403
1404int ggml_metal_op_dsv4_hc(ggml_metal_op_t ctx, int idx) {
1405    ggml_tensor * op = ctx->node(idx);
1406
1407    ggml_metal_encoder_t enc = ctx->enc;
1408    auto pipeline = ggml_metal_library_get_pipeline_dsv4_hc(ctx->lib, op->op);
1409
1410    ggml_metal_encoder_set_pipeline(enc, pipeline);
1411
1412    switch (op->op) {
1413        case GGML_OP_DSV4_HC_COMB:
1414            {
1415                const ggml_tensor * mixes = op->src[0];
1416                const ggml_tensor * scale = op->src[1];
1417                const ggml_tensor * base  = op->src[2];
1418
1419                GGML_ASSERT(mixes->type == GGML_TYPE_F32);
1420                GGML_ASSERT(scale->type == GGML_TYPE_F32);
1421                GGML_ASSERT(base->type  == GGML_TYPE_F32);
1422                GGML_ASSERT(op->type    == GGML_TYPE_F32);
1423                GGML_ASSERT(mixes->ne[0] == 24);
1424                GGML_ASSERT(op->ne[0] == 4 && op->ne[1] == 4);
1425
1426                ggml_metal_kargs_dsv4_hc_comb args = {
1427                    /*.n_tokens =*/ (int32_t) mixes->ne[1],
1428                    /*.n_iter   =*/ ggml_get_op_params_i32(op, 1),
1429                    /*.nb_m0    =*/ mixes->nb[0],
1430                    /*.nb_m1    =*/ mixes->nb[1],
1431                    /*.nb_s0    =*/ scale->nb[0],
1432                    /*.nb_b0    =*/ base->nb[0],
1433                    /*.nb_d0    =*/ op->nb[0],
1434                    /*.nb_d1    =*/ op->nb[1],
1435                    /*.nb_d2    =*/ op->nb[2],
1436                    /*.eps      =*/ ggml_get_op_params_f32(op, 0),
1437                };
1438
1439                ggml_metal_encoder_set_bytes (enc, &args, sizeof(args), 0);
1440                ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(mixes), 1);
1441                ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(scale), 2);
1442                ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(base),  3);
1443                ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op),    4);
1444
1445                // One SIMDgroup owns one 4x4 Sinkhorn matrix. Packing up to four
1446                // independent tokens per threadgroup keeps both decode and prompt
1447                // dispatches compact without any threadgroup-memory synchronization.
1448                const int nsg = std::min(4, args.n_tokens);
1449                ggml_metal_encoder_dispatch_threadgroups(
1450                        enc, (args.n_tokens + nsg - 1)/nsg, 1, 1, 32, nsg, 1);
1451            } break;
1452        case GGML_OP_DSV4_HC_PRE:
1453            {
1454                const ggml_tensor * x       = op->src[0];
1455                const ggml_tensor * weights = op->src[1];
1456
1457                GGML_ASSERT(x->type       == GGML_TYPE_F32);
1458                GGML_ASSERT(weights->type == GGML_TYPE_F32);
1459                GGML_ASSERT(op->type      == GGML_TYPE_F32);
1460                GGML_ASSERT(x->ne[1] == 4);
1461
1462                ggml_metal_kargs_dsv4_hc_pre args = {
1463                    /*.n_embd   =*/ (int32_t) x->ne[0],
1464                    /*.n_tokens =*/ (int32_t) x->ne[2],
1465                    /*.nb_x0    =*/ x->nb[0],
1466                    /*.nb_x1    =*/ x->nb[1],
1467                    /*.nb_x2    =*/ x->nb[2],
1468                    /*.nb_w0    =*/ weights->nb[0],
1469                    /*.nb_w1    =*/ weights->nb[1],
1470                    /*.nb_d0    =*/ op->nb[0],
1471                    /*.nb_d1    =*/ op->nb[1],
1472                };
1473
1474                ggml_metal_encoder_set_bytes (enc, &args, sizeof(args), 0);
1475                ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(x),       1);
1476                ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(weights), 2);
1477                ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op),      3);
1478
1479                const int n_tiles = (args.n_embd + 31)/32;
1480                const int nsg = std::min(4, n_tiles);
1481                ggml_metal_encoder_dispatch_threadgroups(
1482                        enc, (n_tiles + nsg - 1)/nsg, args.n_tokens, 1, 32, nsg, 1);
1483            } break;
1484        case GGML_OP_DSV4_HC_POST:
1485            {
1486                const ggml_tensor * x        = op->src[0];
1487                const ggml_tensor * residual = op->src[1];
1488                const ggml_tensor * post     = op->src[2];
1489                const ggml_tensor * comb     = op->src[3];
1490
1491                GGML_ASSERT(x->type        == GGML_TYPE_F32);
1492                GGML_ASSERT(residual->type == GGML_TYPE_F32);
1493                GGML_ASSERT(post->type     == GGML_TYPE_F32);
1494                GGML_ASSERT(comb->type     == GGML_TYPE_F32);
1495                GGML_ASSERT(op->type       == GGML_TYPE_F32);
1496                GGML_ASSERT(residual->ne[1] == 4);
1497
1498                ggml_metal_kargs_dsv4_hc_post args = {
1499                    /*.n_embd   =*/ (int32_t) x->ne[0],
1500                    /*.n_tokens =*/ (int32_t) x->ne[1],
1501                    /*.nb_x0    =*/ x->nb[0],
1502                    /*.nb_x1    =*/ x->nb[1],
1503                    /*.nb_r0    =*/ residual->nb[0],
1504                    /*.nb_r1    =*/ residual->nb[1],
1505                    /*.nb_r2    =*/ residual->nb[2],
1506                    /*.nb_p0    =*/ post->nb[0],
1507                    /*.nb_p1    =*/ post->nb[1],
1508                    /*.nb_c0    =*/ comb->nb[0],
1509                    /*.nb_c1    =*/ comb->nb[1],
1510                    /*.nb_c2    =*/ comb->nb[2],
1511                    /*.nb_d0    =*/ op->nb[0],
1512                    /*.nb_d1    =*/ op->nb[1],
1513                    /*.nb_d2    =*/ op->nb[2],
1514                };
1515
1516                ggml_metal_encoder_set_bytes (enc, &args, sizeof(args), 0);
1517                ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(x),        1);
1518                ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(residual), 2);
1519                ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(post),     3);
1520                ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(comb),     4);
1521                ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op),       5);
1522
1523                const int n_tiles = (args.n_embd + 31)/32;
1524                const int nsg = std::min(4, n_tiles);
1525                ggml_metal_encoder_dispatch_threadgroups(
1526                        enc, (n_tiles + nsg - 1)/nsg, args.n_tokens, 1, 32, nsg, 1);
1527            } break;
1528        default:
1529            GGML_ABORT("fatal error");
1530    }
1531
1532    return 1;
1533}
1534
1535int ggml_metal_op_soft_max(ggml_metal_op_t ctx, int idx) {
1536    ggml_tensor * op = ctx->node(idx);
1537
1538    ggml_metal_library_t lib = ctx->lib;
1539    ggml_metal_encoder_t enc = ctx->enc;
1540
1541    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
1542    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
1543    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
1544    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
1545    GGML_TENSOR_LOCALS( int32_t, ne2, op->src[2], ne);
1546    GGML_TENSOR_LOCALS(uint64_t, nb2, op->src[2], nb);
1547    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
1548    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
1549
1550    float scale;
1551    float max_bias;
1552
1553    memcpy(&scale,    ((const int32_t *) op->op_params) + 0, sizeof(scale));
1554    memcpy(&max_bias, ((const int32_t *) op->op_params) + 1, sizeof(max_bias));
1555
1556    const uint32_t n_head      = op->src[0]->ne[2];
1557    const  int32_t n_head_log2 = 1u << (uint32_t) floorf(log2f((float) n_head));
1558
1559    const float m0 = powf(2.0f, -(max_bias       ) / n_head_log2);
1560    const float m1 = powf(2.0f, -(max_bias / 2.0f) / n_head_log2);
1561
1562    // softmax
1563
1564    ggml_metal_kargs_soft_max args = {
1565        /*.ne00        =*/ ne00,
1566        /*.ne01        =*/ ne01,
1567        /*.ne02        =*/ ne02,
1568        /*.nb01        =*/ nb01,
1569        /*.nb02        =*/ nb02,
1570        /*.nb03        =*/ nb03,
1571        /*.ne11        =*/ ne11,
1572        /*.ne12        =*/ ne12,
1573        /*.ne13        =*/ ne13,
1574        /*.nb11        =*/ nb11,
1575        /*.nb12        =*/ nb12,
1576        /*.nb13        =*/ nb13,
1577        /*.nb1         =*/ nb1,
1578        /*.nb2         =*/ nb2,
1579        /*.nb3         =*/ nb3,
1580        /*.scale       =*/ scale,
1581        /*.max_bias    =*/ max_bias,
1582        /*.m0          =*/ m0,
1583        /*.m1          =*/ m1,
1584        /*.n_head_log2 =*/ n_head_log2,
1585    };
1586
1587    auto pipeline = ggml_metal_library_get_pipeline_soft_max(lib, op);
1588
1589    int nth = 32; // SIMD width
1590
1591    if (ne00%4 == 0) {
1592        while (nth < ne00/4 && nth*ne01*ne02*ne03 < 256) {
1593            nth *= 2;
1594        }
1595    } else {
1596        while (nth < ne00 && nth*ne01*ne02*ne03 < 256) {
1597            nth *= 2;
1598        }
1599    }
1600
1601    const size_t smem = pipeline.smem;
1602
1603    ggml_metal_encoder_set_pipeline(enc, pipeline);
1604    ggml_metal_encoder_set_bytes(enc, &args, sizeof(args), 0);
1605    ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op->src[0]), 1);
1606    if (op->src[1]) {
1607        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op->src[1]), 2);
1608    } else {
1609        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op->src[0]), 2);
1610    }
1611    if (op->src[2]) {
1612        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op->src[2]), 3);
1613    } else {
1614        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op->src[0]), 3);
1615    }
1616    ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op), 4);
1617
1618    ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
1619
1620    ggml_metal_encoder_dispatch_threadgroups(enc, ne01, ne02, ne03, nth, 1, 1);
1621
1622    return 1;
1623}
1624
1625int ggml_metal_op_ssm_conv(ggml_metal_op_t ctx, int idx) {
1626    ggml_tensor * op = ctx->node(idx);
1627
1628    ggml_metal_library_t lib = ctx->lib;
1629    ggml_metal_encoder_t enc = ctx->enc;
1630
1631    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
1632    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
1633    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
1634    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
1635    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
1636    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
1637
1638    ggml_metal_kargs_ssm_conv args = {
1639        /*.ne00 =*/ ne00,
1640        /*.ne01 =*/ ne01,
1641        /*.ne02 =*/ ne02,
1642        /*.nb00 =*/ nb00,
1643        /*.nb01 =*/ nb01,
1644        /*.nb02 =*/ nb02,
1645        /*.ne10 =*/ ne10,
1646        /*.ne11 =*/ ne11,
1647        /*.nb10 =*/ nb10,
1648        /*.nb11 =*/ nb11,
1649        /*.ne0  =*/ ne0,
1650        /*.ne1  =*/ ne1,
1651        /*.ne2  =*/ ne2,
1652        /*.nb0  =*/ nb0,
1653        /*.nb1  =*/ nb1,
1654        /*.nb2  =*/ nb2,
1655    };
1656
1657    // Use batched kernel for prefill (ne1 > 1) to reduce threadgroup dispatch overhead
1658    const bool use_batched = (ne1 > 1);
1659
1660    if (use_batched) {
1661        // Determine the smallest power of 2 that's >= ne1, but <= 256
1662        int BATCH_SIZE;
1663        if      (ne1 > 128) BATCH_SIZE = 256;
1664        else if (ne1 > 64 ) BATCH_SIZE = 128;
1665        else if (ne1 > 32 ) BATCH_SIZE = 64;
1666        else if (ne1 > 16 ) BATCH_SIZE = 32;
1667        else if (ne1 > 8  ) BATCH_SIZE = 16;
1668        else if (ne1 > 4  ) BATCH_SIZE = 8;
1669        else                BATCH_SIZE = 2;
1670
1671        auto pipeline = ggml_metal_library_get_pipeline_ssm_conv_batched(lib, op, BATCH_SIZE);
1672
1673        ggml_metal_encoder_set_pipeline(enc, pipeline);
1674        ggml_metal_encoder_set_bytes(enc, &args, sizeof(args), 0);
1675        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op->src[0]), 1);
1676        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op->src[1]), 2);
1677        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op),         3);
1678
1679        // Dispatch: ne01 rows, ceil(ne1/BATCH_SIZE) token batches, ne02 sequences
1680        // Each threadgroup has BATCH_SIZE threads, each handling one token
1681        const int n_token_batches = (ne1 + BATCH_SIZE - 1) / BATCH_SIZE;
1682        ggml_metal_encoder_dispatch_threadgroups(enc, ne01, n_token_batches, ne02, BATCH_SIZE, 1, 1);
1683    } else {
1684        auto pipeline = ggml_metal_library_get_pipeline_ssm_conv(lib, op);
1685
1686        ggml_metal_encoder_set_pipeline(enc, pipeline);
1687        ggml_metal_encoder_set_bytes(enc, &args, sizeof(args), 0);
1688        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op->src[0]), 1);
1689        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op->src[1]), 2);
1690        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op),         3);
1691
1692        ggml_metal_encoder_dispatch_threadgroups(enc, ne01, ne1, ne02, 1, 1, 1);
1693    }
1694
1695    return 1;
1696}
1697
1698int ggml_metal_op_ssm_scan(ggml_metal_op_t ctx, int idx) {
1699    ggml_tensor * op = ctx->node(idx);
1700
1701    ggml_metal_library_t lib = ctx->lib;
1702    ggml_metal_encoder_t enc = ctx->enc;
1703    const ggml_metal_device_props * props_dev = ggml_metal_device_get_props(ctx->dev);
1704
1705    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
1706    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
1707    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
1708    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
1709    GGML_TENSOR_LOCALS( int32_t, ne2, op->src[2], ne);
1710    GGML_TENSOR_LOCALS(uint64_t, nb2, op->src[2], nb);
1711    GGML_TENSOR_LOCALS( int32_t, ne3, op->src[3], ne);
1712    GGML_TENSOR_LOCALS(uint64_t, nb3, op->src[3], nb);
1713    GGML_TENSOR_LOCALS( int32_t, ne4, op->src[4], ne);
1714    GGML_TENSOR_LOCALS(uint64_t, nb4, op->src[4], nb);
1715    GGML_TENSOR_LOCALS( int32_t, ne5, op->src[5], ne);
1716    GGML_TENSOR_LOCALS(uint64_t, nb5, op->src[5], nb);
1717    GGML_TENSOR_LOCALS( int32_t, ne6, op->src[6], ne);
1718    GGML_TENSOR_LOCALS(uint64_t, nb6, op->src[6], nb);
1719    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
1720    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
1721
1722    const ggml_tensor * src3 = op->src[3];
1723    const ggml_tensor * src4 = op->src[4];
1724    const ggml_tensor * src5 = op->src[5];
1725    const ggml_tensor * src6 = op->src[6];
1726
1727    GGML_ASSERT(src3);
1728    GGML_ASSERT(src4);
1729    GGML_ASSERT(src5);
1730    GGML_ASSERT(src6);
1731
1732    const int64_t d_state      = ne00;
1733    const int64_t d_inner      = ne01;
1734    const int64_t n_head       = ne02;
1735    const int64_t n_group      = ne41;
1736    const int64_t n_seq_tokens = ne12;
1737    const int64_t n_seqs       = ne13;
1738    const int64_t K            = ggml_get_op_params_i32(op, 0);
1739
1740    GGML_ASSERT(K >= 1);
1741    GGML_ASSERT(ggml_nelements(op->src[1]) + K*d_state*d_inner*n_head*n_seqs == ggml_nelements(op));
1742
1743    ggml_metal_kargs_ssm_scan args = {
1744        /*.d_state      =*/ d_state,
1745        /*.d_inner      =*/ d_inner,
1746        /*.n_head       =*/ n_head,
1747        /*.n_group      =*/ n_group,
1748        /*.n_seq_tokens =*/ n_seq_tokens,
1749        /*.n_seq_tokens_total =*/ n_seq_tokens,
1750        /*.token_offset =*/ 0,
1751        /*.n_seqs       =*/ n_seqs,
1752        /*.K            =*/ K,
1753        /*.s_off        =*/ ggml_nelements(op->src[1]) * sizeof(float),
1754        /*.nb00         =*/ nb00,
1755        /*.nb01         =*/ nb01,
1756        /*.nb02         =*/ nb02,
1757        /*.nb03         =*/ nb03,
1758        /*.nb10         =*/ nb10,
1759        /*.nb11         =*/ nb11,
1760        /*.nb12         =*/ nb12,
1761        /*.ns12         =*/ nb12/nb10,
1762        /*.nb13         =*/ nb13,
1763        /*.nb20         =*/ nb20,
1764        /*.nb21         =*/ nb21,
1765        /*.ns21         =*/ nb21/nb20,
1766        /*.nb22         =*/ nb22,
1767        /*.ne30         =*/ ne30,
1768        /*.nb31         =*/ nb31,
1769        /*.nb41         =*/ nb41,
1770        /*.nb42         =*/ nb42,
1771        /*.ns42         =*/ nb42/nb40,
1772        /*.nb43         =*/ nb43,
1773        /*.nb51         =*/ nb51,
1774        /*.nb52         =*/ nb52,
1775        /*.ns52         =*/ nb52/nb50,
1776        /*.nb53         =*/ nb53,
1777        /*.nb0          =*/ nb0,
1778    };
1779
1780    constexpr int64_t CHUNK = OP_SSM_SCAN_SSD_CS;
1781
1782    const int64_t snap_reserve = K > 1 ? K : 0; // tokens reserved for sequential kernel rollback snapshots
1783    const int64_t mma_tokens = ((n_seq_tokens - snap_reserve) / CHUNK) * CHUNK; // largest multiple of CHUNK that leaves snap_reserve for the tail
1784    const bool use_mma =
1785        mma_tokens > 0 &&
1786        ne30 == 1 && // checks that A tensor is set to scalar decay per head (A shape {1, n_head})
1787        props_dev->has_simdgroup_mm && // hardware check for M1 or newer
1788        d_state % 8 == 0 && // d_state must be multiple of 8 to align with simdgroup_float 8x8 tiles
1789        d_inner == OP_SSM_SCAN_SSD_HD; // mma kernel is specialized for the Mamba-2 head dim; this checks it
1790
1791    const auto dispatch = [&](ggml_metal_pipeline_with_params pipeline, int64_t nth, int64_t n_tg_x) {
1792        GGML_ASSERT(nth <= ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
1793        GGML_ASSERT(pipeline.smem <= props_dev->max_theadgroup_memory_size);
1794
1795        ggml_metal_encoder_set_pipeline(enc, pipeline);
1796        ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
1797        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
1798        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
1799        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[2]), 3);
1800        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[3]), 4);
1801        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[4]), 5);
1802        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[5]), 6);
1803        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[6]), 7);
1804        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         8);
1805        ggml_metal_encoder_set_threadgroup_memory_size(enc, pipeline.smem, 0);
1806        ggml_metal_encoder_dispatch_threadgroups(enc, n_tg_x, n_head, n_seqs, nth, 1, 1);
1807    };
1808
1809    if (!use_mma) {
1810        dispatch(ggml_metal_library_get_pipeline_ssm_scan(lib, op, false), d_state, d_inner);
1811        return 1;
1812    }
1813
1814    args.n_seq_tokens = mma_tokens;
1815    dispatch(
1816        ggml_metal_library_get_pipeline_ssm_scan_ssd_mma(lib, op),
1817        OP_SSM_SCAN_SSD_NSG*32,
1818        1);
1819
1820    if (mma_tokens < n_seq_tokens) {
1821        ggml_metal_op_concurrency_reset(ctx);
1822
1823        args.n_seq_tokens = n_seq_tokens - mma_tokens;
1824        args.token_offset = mma_tokens;
1825        dispatch(ggml_metal_library_get_pipeline_ssm_scan(lib, op, true), d_state, d_inner);
1826    }
1827
1828    return 1;
1829}
1830
1831int ggml_metal_op_rwkv(ggml_metal_op_t ctx, int idx) {
1832    ggml_tensor * op = ctx->node(idx);
1833
1834    ggml_metal_library_t lib = ctx->lib;
1835    ggml_metal_encoder_t enc = ctx->enc;
1836
1837    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
1838    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
1839    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
1840    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
1841
1842    const int64_t B = op->op == GGML_OP_RWKV_WKV6 ? op->src[5]->ne[1] : op->src[6]->ne[1];
1843    const int64_t T = op->src[0]->ne[2];
1844    const int64_t C = op->ne[0];
1845    const int64_t H = op->src[0]->ne[1];
1846
1847    auto pipeline = ggml_metal_library_get_pipeline_rwkv(lib, op);
1848
1849    int ida = 0;
1850
1851    ggml_metal_encoder_set_pipeline(enc, pipeline);
1852    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), ida++);
1853    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), ida++);
1854    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[2]), ida++);
1855    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[3]), ida++);
1856    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[4]), ida++);
1857    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[5]), ida++);
1858    if (op->op == GGML_OP_RWKV_WKV7) {
1859        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[6]), ida++);
1860    }
1861    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         ida++);
1862    ggml_metal_encoder_set_bytes   (enc, (void *) &B, sizeof(B), ida++);
1863    ggml_metal_encoder_set_bytes   (enc, (void *) &T, sizeof(T), ida++);
1864    ggml_metal_encoder_set_bytes   (enc, (void *) &C, sizeof(C), ida++);
1865    ggml_metal_encoder_set_bytes   (enc, (void *) &H, sizeof(H), ida++);
1866
1867    ggml_metal_encoder_dispatch_threadgroups(enc, B * H, 1, 1, C/H, 1, 1);
1868
1869    return 1;
1870}
1871
1872int ggml_metal_op_gated_delta_net(ggml_metal_op_t ctx, int idx) {
1873    ggml_tensor * op = ctx->node(idx);
1874
1875    ggml_metal_library_t lib = ctx->lib;
1876    ggml_metal_encoder_t enc = ctx->enc;
1877
1878    const bool use_fusion = ctx->use_fusion();
1879    const int  debug_fusion = ggml_metal_fusion_info_debug(ctx->finfo);
1880
1881    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
1882    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
1883    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
1884    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
1885    GGML_TENSOR_LOCALS( int32_t, ne2, op->src[2], ne);
1886    GGML_TENSOR_LOCALS(uint64_t, nb2, op->src[2], nb);
1887    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
1888    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
1889
1890    auto pipeline = ggml_metal_library_get_pipeline_gated_delta_net(lib, op);
1891
1892    // when fused with the trailing cache cpy, the snapshots are written straight into the
1893    // recurrent cache and the cpy is skipped (see GGML_METAL_FUSION_GDN_CACHE)
1894    ggml_metal_buffer_id bid_out = ggml_metal_get_buffer_id(op);
1895    uint64_t nb_out = 0;
1896    int n_fuse = 1;
1897
1898    if (use_fusion) {
1899        int n = 1;
1900        const ggml_metal_fusion * fusion = ctx->can_fuse(idx, GGML_METAL_FUSION_FULL, &n);
1901
1902        if (fusion && fusion->id == GGML_METAL_FUSION_GDN_CACHE) {
1903            const ggml_tensor * dst_cache = ctx->node(idx + 1)->src[1]; // cache view
1904
1905            bid_out = ggml_metal_get_buffer_id(dst_cache);
1906            nb_out  = dst_cache->nb[2]/sizeof(float);
1907            n_fuse = 2;
1908
1909            ctx->count_fusions(fusion);
1910
1911            if (debug_fusion > 1) {
1912                GGML_LOG_DEBUG("%s: fuse: GATED_DELTA_NET + CPY\n", __func__);
1913            }
1914        }
1915    }
1916
1917    int ida = 0;
1918
1919    ggml_metal_kargs_gated_delta_net args = {
1920        /*.ne00 =*/ ne00,
1921        /*.ne01 =*/ ne01,
1922        /*.ne02 =*/ ne02,
1923        /*.ne03 =*/ ne03,
1924        /*.nb00 =*/ nb00,
1925        /*.nb01 =*/ nb01,
1926        /*.nb02 =*/ nb02,
1927        /*.nb03 =*/ nb03,
1928        /*.ne10 =*/ ne10,
1929        /*.ne11 =*/ ne11,
1930        /*.ne12 =*/ ne12,
1931        /*.ne13 =*/ ne13,
1932        /*.nb10 =*/ nb10,
1933        /*.nb11 =*/ nb11,
1934        /*.nb12 =*/ nb12,
1935        /*.nb13 =*/ nb13,
1936        /*.ne20 =*/ ne20,
1937        /*.ne21 =*/ ne21,
1938        /*.ne22 =*/ ne22,
1939        /*.ne23 =*/ ne23,
1940        /*.nb20 =*/ nb20,
1941        /*.nb21 =*/ nb21,
1942        /*.nb22 =*/ nb22,
1943        /*.nb23 =*/ nb23,
1944        /*.ns02 =*/ (int32_t) (nb02/sizeof(float)),
1945        /*.ns12 =*/ (int32_t) (nb12/sizeof(float)),
1946        /*.ns22 =*/ (int32_t) (nb22/sizeof(float)),
1947        /*.ne0  =*/ ne0,
1948        /*.ne1  =*/ ne1,
1949        /*.ne2  =*/ ne2,
1950        /*.ne3  =*/ ne3,
1951        /*.nb0  =*/ nb0,
1952        /*.nb1  =*/ nb1,
1953        /*.nb2  =*/ nb2,
1954        /*.nb3  =*/ nb3,
1955        /*.nb_out =*/ nb_out,
1956    };
1957
1958    ggml_metal_encoder_set_pipeline(enc, pipeline);
1959    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args),                  ida++); // args
1960    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), ida++); // q
1961    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), ida++); // k
1962    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[2]), ida++); // v
1963    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[3]), ida++); // gate
1964    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[4]), ida++); // beta
1965    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[5]), ida++); // state
1966    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         ida++); // dst (attn)
1967    ggml_metal_encoder_set_buffer  (enc, bid_out,                              ida++); // state_out
1968
1969    const int nsg = pipeline.nsg;
1970
1971    ggml_metal_encoder_dispatch_threadgroups(enc, op->src[2]->ne[0]/nsg, op->src[2]->ne[1], op->src[2]->ne[3], 32, nsg, 1);
1972
1973    return n_fuse;
1974}
1975
1976int ggml_metal_op_solve_tri(ggml_metal_op_t ctx, int idx) {
1977    ggml_tensor * op = ctx->node(idx);
1978
1979    ggml_metal_library_t lib = ctx->lib;
1980    ggml_metal_encoder_t enc = ctx->enc;
1981
1982    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
1983    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
1984    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
1985    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
1986    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
1987    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
1988
1989    ggml_metal_kargs_solve_tri args = {
1990        /*.ne00 =*/ ne00,
1991        /*.ne01 =*/ ne01,
1992        /*.ne02 =*/ ne02,
1993        /*.ne03 =*/ ne03,
1994        /*.nb00 =*/ nb00,
1995        /*.nb01 =*/ nb01,
1996        /*.nb02 =*/ nb02,
1997        /*.nb03 =*/ nb03,
1998        /*.ne10 =*/ ne10,
1999        /*.ne11 =*/ ne11,
2000        /*.ne12 =*/ ne12,
2001        /*.ne13 =*/ ne13,
2002        /*.nb10 =*/ nb10,
2003        /*.nb11 =*/ nb11,
2004        /*.nb12 =*/ nb12,
2005        /*.nb13 =*/ nb13,
2006        /*.ne0  =*/ ne0,
2007        /*.ne1  =*/ ne1,
2008        /*.ne2  =*/ ne2,
2009        /*.ne3  =*/ ne3,
2010        /*.nb0  =*/ nb0,
2011        /*.nb1  =*/ nb1,
2012        /*.nb2  =*/ nb2,
2013        /*.nb3  =*/ nb3,
2014    };
2015
2016    auto pipeline = ggml_metal_library_get_pipeline_solve_tri(lib, op);
2017
2018    ggml_metal_encoder_set_pipeline(enc, pipeline);
2019    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
2020    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
2021    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
2022    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
2023
2024    const int nsg = pipeline.nsg;
2025
2026    ggml_metal_encoder_set_threadgroup_memory_size(enc, pipeline.smem, 0);
2027
2028    ggml_metal_encoder_dispatch_threadgroups(enc, (ne10 + nsg - 1)/nsg, ne02, ne03, 32, nsg, 1);
2029
2030    return 1;
2031}
2032
2033int ggml_metal_op_set(ggml_metal_op_t ctx, int idx) {
2034    ggml_tensor * op = ctx->node(idx);
2035
2036    ggml_metal_library_t lib = ctx->lib;
2037    ggml_metal_encoder_t enc = ctx->enc;
2038
2039    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
2040    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
2041    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
2042    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
2043    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
2044    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
2045
2046    ggml_metal_buffer_id bid_src0 = ggml_metal_get_buffer_id(op->src[0]);
2047    ggml_metal_buffer_id bid_src1 = ggml_metal_get_buffer_id(op->src[1]);
2048    ggml_metal_buffer_id bid_dst  = ggml_metal_get_buffer_id(op);
2049
2050    const size_t pnb1 = ((const int32_t *) op->op_params)[0];
2051    const size_t pnb2 = ((const int32_t *) op->op_params)[1];
2052    const size_t pnb3 = ((const int32_t *) op->op_params)[2];
2053    const size_t offs = ((const int32_t *) op->op_params)[3];
2054
2055    const bool inplace = (bool) ((const int32_t *) op->op_params)[4];
2056
2057    if (!inplace) {
2058        // run a separate kernel to cpy src->dst
2059        // not sure how to avoid this
2060        // TODO: make a simpler cpy_bytes kernel
2061
2062        //const id<MTLComputePipelineState> pipeline = ctx->pipelines[GGML_METAL_PIPELINE_TYPE_CPY_F32_F32].obj;
2063        auto pipeline = ggml_metal_library_get_pipeline_cpy(lib, op->src[0]->type, op->type);
2064
2065        ggml_metal_kargs_cpy args = {
2066            /*.nk0  =*/ ne00,
2067            /*.ne00 =*/ ne00,
2068            /*.ne01 =*/ ne01,
2069            /*.ne02 =*/ ne02,
2070            /*.ne03 =*/ ne03,
2071            /*.nb00 =*/ nb00,
2072            /*.nb01 =*/ nb01,
2073            /*.nb02 =*/ nb02,
2074            /*.nb03 =*/ nb03,
2075            /*.ne0  =*/ ne0,
2076            /*.ne1  =*/ ne1,
2077            /*.ne2  =*/ ne2,
2078            /*.ne3  =*/ ne3,
2079            /*.nb0  =*/ nb0,
2080            /*.nb1  =*/ nb1,
2081            /*.nb2  =*/ nb2,
2082            /*.nb3  =*/ nb3,
2083        };
2084
2085        ggml_metal_encoder_set_pipeline(enc, pipeline);
2086        ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
2087        ggml_metal_encoder_set_buffer  (enc, bid_src0, 1);
2088        ggml_metal_encoder_set_buffer  (enc, bid_dst,  2);
2089
2090        const int nth = std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline), ne00);
2091
2092        ggml_metal_encoder_dispatch_threadgroups(enc, ne01, ne02, ne03, nth, 1, 1);
2093
2094        ggml_metal_op_concurrency_reset(ctx);
2095    }
2096
2097    auto pipeline = ggml_metal_library_get_pipeline_cpy(lib, op->src[1]->type, op->type);
2098
2099    GGML_ASSERT(ne10 % ggml_blck_size(op->src[1]->type) == 0);
2100
2101    int64_t nk0 = ne10;
2102    if (ggml_is_quantized(op->src[1]->type)) {
2103        nk0 = ne10/16;
2104    } else if (ggml_is_quantized(op->type)) {
2105        nk0 = ne10/ggml_blck_size(op->type);
2106    }
2107
2108    int nth = std::min<int>(nk0*ne11, 256);
2109
2110    // when rows are small, we can batch them together in a single threadgroup
2111    int nrptg = 1;
2112
2113    // TODO: relax this constraint in the future
2114    if (ggml_blck_size(op->src[1]->type) == 1 && ggml_blck_size(op->type) == 1) {
2115        if (nth > nk0) {
2116            nrptg = (nth + nk0 - 1)/nk0;
2117            nth   = nk0;
2118
2119            if (nrptg*nth > 256) {
2120                nrptg--;
2121            }
2122        }
2123    }
2124
2125    nth = std::min<int>(nth, nk0);
2126
2127    ggml_metal_kargs_cpy args = {
2128        /*.nk0  =*/ nk0,
2129        /*.ne00 =*/ ne10,
2130        /*.ne01 =*/ ne11,
2131        /*.ne02 =*/ ne12,
2132        /*.ne03 =*/ ne13,
2133        /*.nb00 =*/ nb10,
2134        /*.nb01 =*/ nb11,
2135        /*.nb02 =*/ nb12,
2136        /*.nb03 =*/ nb13,
2137        /*.ne0  =*/ ne10,
2138        /*.ne1  =*/ ne11,
2139        /*.ne2  =*/ ne12,
2140        /*.ne3  =*/ ne13,
2141        /*.nb0  =*/ ggml_element_size(op),
2142        /*.nb1  =*/ pnb1,
2143        /*.nb2  =*/ pnb2,
2144        /*.nb3  =*/ pnb3,
2145    };
2146
2147    const int nw0 = nrptg == 1 ? (nk0 + nth - 1)/nth : 1;
2148
2149    bid_dst.offs += offs;
2150
2151    ggml_metal_encoder_set_pipeline(enc, pipeline);
2152    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
2153    ggml_metal_encoder_set_buffer  (enc, bid_src1, 1);
2154    ggml_metal_encoder_set_buffer  (enc, bid_dst,  2);
2155
2156    ggml_metal_encoder_dispatch_threadgroups(enc, nw0*(ne11 + nrptg - 1)/nrptg, ne12, ne13, nth, nrptg, 1);
2157
2158    return 1;
2159}
2160
2161int ggml_metal_op_cpy(ggml_metal_op_t ctx, int idx) {
2162    ggml_tensor * op = ctx->node(idx);
2163
2164    ggml_metal_library_t lib = ctx->lib;
2165    ggml_metal_encoder_t enc = ctx->enc;
2166
2167    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
2168    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
2169    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
2170    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
2171
2172    auto pipeline = ggml_metal_library_get_pipeline_cpy(lib, op->src[0]->type, op->type);
2173
2174    GGML_ASSERT(ne00 % ggml_blck_size(op->src[0]->type) == 0);
2175
2176    int64_t nk0 = ne00;
2177    if (ggml_is_quantized(op->src[0]->type)) {
2178        nk0 = ne00/16;
2179    } else if (ggml_is_quantized(op->type)) {
2180        nk0 = ne00/ggml_blck_size(op->type);
2181    }
2182
2183    int nth = std::min<int>(nk0*ne01, 256);
2184
2185    // when rows are small, we can batch them together in a single threadgroup
2186    int nrptg = 1;
2187
2188    // TODO: relax this constraint in the future
2189    if (ggml_blck_size(op->src[0]->type) == 1 && ggml_blck_size(op->type) == 1) {
2190        if (nth > nk0) {
2191            nrptg = (nth + nk0 - 1)/nk0;
2192            nth   = nk0;
2193
2194            if (nrptg*nth > 256) {
2195                nrptg--;
2196            }
2197        }
2198    }
2199
2200    nth = std::min<int>(nth, nk0);
2201
2202    ggml_metal_kargs_cpy args = {
2203        /*.nk0  =*/ nk0,
2204        /*.ne00 =*/ ne00,
2205        /*.ne01 =*/ ne01,
2206        /*.ne02 =*/ ne02,
2207        /*.ne03 =*/ ne03,
2208        /*.nb00 =*/ nb00,
2209        /*.nb01 =*/ nb01,
2210        /*.nb02 =*/ nb02,
2211        /*.nb03 =*/ nb03,
2212        /*.ne0  =*/ ne0,
2213        /*.ne1  =*/ ne1,
2214        /*.ne2  =*/ ne2,
2215        /*.ne3  =*/ ne3,
2216        /*.nb0  =*/ nb0,
2217        /*.nb1  =*/ nb1,
2218        /*.nb2  =*/ nb2,
2219        /*.nb3  =*/ nb3,
2220    };
2221
2222    const int nw0 = nrptg == 1 ? (nk0 + nth - 1)/nth : 1;
2223
2224    ggml_metal_encoder_set_pipeline(enc, pipeline);
2225    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
2226    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
2227    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
2228
2229    ggml_metal_encoder_dispatch_threadgroups(enc, nw0*(ne01 + nrptg - 1)/nrptg, ne02, ne03, nth, nrptg, 1);
2230
2231    return 1;
2232}
2233
2234int ggml_metal_op_pool_1d(ggml_metal_op_t ctx, int idx) {
2235    ggml_tensor * op = ctx->node(idx);
2236
2237    ggml_metal_library_t lib = ctx->lib;
2238    ggml_metal_encoder_t enc = ctx->enc;
2239
2240    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
2241    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
2242    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
2243    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
2244
2245    const int32_t * opts = op->op_params;
2246    ggml_op_pool op_pool = (ggml_op_pool) opts[0];
2247
2248    const int32_t k0 = opts[1];
2249    const int32_t s0 = opts[2];
2250    const int32_t p0 = opts[3];
2251
2252    const int64_t IW = op->src[0]->ne[0];
2253    const int64_t OW = op->ne[0];
2254
2255    const int64_t np = ggml_nelements(op);
2256
2257    ggml_metal_kargs_pool_1d args_pool_1d = {
2258        /* .k0 = */  k0,
2259        /* .s0 = */  s0,
2260        /* .p0 = */  p0,
2261        /* .IW = */  IW,
2262        /* .OW = */  OW,
2263        /* .np = */  np
2264    };
2265
2266    auto pipeline = ggml_metal_library_get_pipeline_pool_1d(lib, op, op_pool);
2267
2268    const int nth = std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline), (int) np);
2269    const int ntg = (np + nth - 1) / nth;
2270
2271    ggml_metal_encoder_set_pipeline(enc, pipeline);
2272    ggml_metal_encoder_set_bytes   (enc, &args_pool_1d, sizeof(args_pool_1d),  0);
2273    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
2274    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
2275
2276    ggml_metal_encoder_dispatch_threadgroups(enc, ntg, 1, 1, nth, 1, 1);
2277
2278    return 1;
2279}
2280
2281// supported FWHT sizes, must stay in sync with the
2282// kernel_fwht_f32_<N> templates in ggml-metal.metal
2283static bool ggml_metal_fwht_supported_size(int64_t n) {
2284    return n == 64 || n == 128 || n == 256 || n == 512;
2285}
2286
2287int ggml_metal_op_fwht(ggml_metal_op_t ctx, int idx) {
2288    ggml_tensor * op = ctx->node(idx);
2289
2290    ggml_metal_library_t lib = ctx->lib;
2291    ggml_metal_encoder_t enc = ctx->enc;
2292
2293    ggml_tensor * src1 = op->src[1];
2294
2295    const int64_t n = src1->ne[0];
2296    const int64_t nrows = ggml_nrows(src1);
2297
2298    ggml_metal_kargs_fwht args = {
2299        /*.nrows = */ (int32_t) nrows,
2300    };
2301
2302    auto pipeline = ggml_metal_library_get_pipeline_fwht(lib, n);
2303
2304    ggml_metal_encoder_set_pipeline(enc, pipeline);
2305    ggml_metal_encoder_set_bytes(enc, &args, sizeof(args), 0);
2306    ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(src1), 1);
2307    ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op), 2);
2308
2309    const int th_max = ggml_metal_pipeline_max_theads_per_threadgroup(pipeline);
2310    const int simd_size = 32;
2311
2312    int sg_per_tg = 2;
2313    sg_per_tg = std::min(sg_per_tg, th_max/simd_size);
2314    sg_per_tg = std::max(sg_per_tg, 1);
2315
2316    const int64_t n_tg = (nrows + sg_per_tg - 1) / sg_per_tg;
2317    ggml_metal_encoder_dispatch_threadgroups(enc, n_tg, 1, 1, 32*sg_per_tg, 1, 1);
2318
2319    return 1;
2320}
2321
2322int ggml_metal_op_pool_2d(ggml_metal_op_t ctx, int idx) {
2323    ggml_tensor * op = ctx->node(idx);
2324
2325    ggml_metal_library_t lib = ctx->lib;
2326    ggml_metal_encoder_t enc = ctx->enc;
2327
2328    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
2329    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
2330    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
2331    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
2332
2333    const int32_t * opts = op->op_params;
2334    ggml_op_pool op_pool = (ggml_op_pool) opts[0];
2335
2336    const int32_t k0 = opts[1];
2337    const int32_t k1 = opts[2];
2338    const int32_t s0 = opts[3];
2339    const int32_t s1 = opts[4];
2340    const int32_t p0 = opts[5];
2341    const int32_t p1 = opts[6];
2342
2343    const int64_t IH = op->src[0]->ne[1];
2344    const int64_t IW = op->src[0]->ne[0];
2345
2346    const int64_t N  = op->ne[3];
2347    const int64_t OC = op->ne[2];
2348    const int64_t OH = op->ne[1];
2349    const int64_t OW = op->ne[0];
2350
2351    const int64_t np = N * OC * OH * OW;
2352
2353    ggml_metal_kargs_pool_2d args_pool_2d = {
2354        /* .k0 = */ k0,
2355        /* .k1 = */ k1,
2356        /* .s0 = */ s0,
2357        /* .s1 = */ s1,
2358        /* .p0 = */ p0,
2359        /* .p1 = */ p1,
2360        /* .IH = */ IH,
2361        /* .IW = */ IW,
2362        /* .OH = */ OH,
2363        /* .OW = */ OW,
2364        /* .np = */ np
2365    };
2366
2367    auto pipeline = ggml_metal_library_get_pipeline_pool_2d(lib, op, op_pool);
2368
2369    const int nth = std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline), (int) np);
2370    const int ntg = (np + nth - 1) / nth;
2371
2372    ggml_metal_encoder_set_pipeline(enc, pipeline);
2373    ggml_metal_encoder_set_bytes   (enc, &args_pool_2d, sizeof(args_pool_2d), 0);
2374    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
2375    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
2376
2377    ggml_metal_encoder_dispatch_threadgroups(enc, ntg, 1, 1, nth, 1, 1);
2378
2379    return 1;
2380}
2381
2382int ggml_metal_op_mul_mat(ggml_metal_op_t ctx, int idx) {
2383    ggml_tensor * op = ctx->node(idx);
2384
2385    ggml_metal_library_t lib = ctx->lib;
2386    ggml_metal_encoder_t enc = ctx->enc;
2387
2388    const int32_t hint = ggml_get_op_params_i32(op, 1);
2389
2390    if (hint == GGML_HINT_SRC0_IS_HADAMARD) {
2391        if (op->src[1]->type == GGML_TYPE_F32 &&
2392            op->type == GGML_TYPE_F32 &&
2393            ggml_is_contiguous(op->src[1]) &&
2394            ggml_is_contiguous(op) &&
2395            ggml_are_same_shape(op->src[1], op) &&
2396            ggml_metal_fwht_supported_size(op->src[1]->ne[0])) {
2397            return ggml_metal_op_fwht(ctx, idx);
2398        }
2399    }
2400    const ggml_metal_device_props * props_dev = ggml_metal_device_get_props(ctx->dev);
2401
2402    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
2403    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
2404    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
2405    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
2406    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
2407    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
2408
2409    GGML_ASSERT(ne00 == ne10);
2410
2411    GGML_ASSERT(ne12 % ne02 == 0);
2412    GGML_ASSERT(ne13 % ne03 == 0);
2413
2414    const int16_t r2 = ne12/ne02;
2415    const int16_t r3 = ne13/ne03;
2416
2417    // first try to use small-batch mat-mv kernels
2418    // these should be efficient for BS [2, ~8]
2419    if (op->src[1]->type == GGML_TYPE_F32 && (ne00%128 == 0) &&
2420        (
2421         (
2422          (
2423           op->src[0]->type == GGML_TYPE_F32  || // TODO: helper function
2424           op->src[0]->type == GGML_TYPE_F16  ||
2425           op->src[0]->type == GGML_TYPE_BF16 ||
2426           op->src[0]->type == GGML_TYPE_Q1_0 ||
2427           op->src[0]->type == GGML_TYPE_Q2_0 ||
2428           op->src[0]->type == GGML_TYPE_Q4_0 ||
2429           op->src[0]->type == GGML_TYPE_Q4_1 ||
2430           op->src[0]->type == GGML_TYPE_Q5_0 ||
2431           op->src[0]->type == GGML_TYPE_Q5_1 ||
2432           op->src[0]->type == GGML_TYPE_Q8_0 ||
2433           op->src[0]->type == GGML_TYPE_MXFP4 ||
2434           op->src[0]->type == GGML_TYPE_IQ4_NL ||
2435           false) && (ne11 >= 2 && ne11 <= 8)
2436         ) ||
2437         (
2438          (
2439           op->src[0]->type == GGML_TYPE_Q4_K ||
2440           op->src[0]->type == GGML_TYPE_Q5_K ||
2441           op->src[0]->type == GGML_TYPE_Q6_K ||
2442           op->src[0]->type == GGML_TYPE_Q2_K ||
2443           op->src[0]->type == GGML_TYPE_Q3_K ||
2444           false) && (ne11 >= 4 && ne11 <= 8)
2445         )
2446        )
2447       ) {
2448        // TODO: determine the optimal parameters based on grid utilization
2449        //       I still don't know why we should not always use the maximum available threads:
2450        //
2451        //       nsg = pipeline.maxTotalThreadsPerThreadgroup / 32
2452        //
2453        //       my current hypothesis is that the work grid is not evenly divisible for different nsg
2454        //       values and there can be some tail effects when nsg is high. need to confirm this
2455        //
2456        const int nsg    = 2;                 // num simdgroups per threadgroup
2457
2458        // num threads along row per simdgroup
2459        int16_t nxpsg = 0;
2460        if (ne00 % 256 == 0 && ne11 < 3) {
2461            nxpsg = 16;
2462        } else if (ne00 % 128 == 0) {
2463            nxpsg = 8;
2464        } else {
2465            nxpsg = 4;
2466        }
2467
2468        const int16_t nypsg  = 32/nxpsg;          // num threads along col per simdgroup (i.e. a simdgroup processes that many src0 rows at a time)
2469        const int16_t r0ptg  = nypsg*nsg;         // num src0 rows per threadgroup
2470              int16_t r1ptg  = 4;                 // num src1 rows per threadgroup
2471
2472        // note: not sure how optimal are those across all different hardware. there might be something cleverer
2473        switch (ne11) {
2474            case 2:
2475                r1ptg = 2; break;
2476            case 3:
2477            case 6:
2478                r1ptg = 3; break;
2479            case 4:
2480            case 7:
2481            case 8:
2482                r1ptg = 4; break;
2483            case 5:
2484                r1ptg = 5; break;
2485            default:
2486                GGML_ABORT("unsupported ne11");
2487        };
2488
2489        auto pipeline = ggml_metal_library_get_pipeline_mul_mv_ext(lib, op, nsg, nxpsg, r1ptg);
2490
2491        ggml_metal_kargs_mul_mv_ext args = {
2492            /*.ne00  =*/ ne00,
2493            /*.ne01  =*/ ne01,
2494            /*.ne02  =*/ ne02,
2495            /*.nb00  =*/ nb00,
2496            /*.nb01  =*/ nb01,
2497            /*.nb02  =*/ nb02,
2498            /*.nb03  =*/ nb03,
2499            /*.ne10  =*/ ne10,
2500            /*.ne11  =*/ ne11,
2501            /*.ne12  =*/ ne12,
2502            /*.nb10  =*/ nb10,
2503            /*.nb11  =*/ nb11,
2504            /*.nb12  =*/ nb12,
2505            /*.nb13  =*/ nb13,
2506            /*.ne0   =*/ ne0,
2507            /*.ne1   =*/ ne1,
2508            /*.r2    =*/ r2,
2509            /*.r3    =*/ r3,
2510        };
2511
2512        ggml_metal_encoder_set_pipeline(enc, pipeline);
2513        ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
2514        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
2515        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
2516        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
2517
2518        ggml_metal_encoder_dispatch_threadgroups(enc, ((ne01 + r0ptg - 1)/r0ptg), ((ne11 + r1ptg - 1)/r1ptg), ne12*ne13, 32, nsg, 1);
2519    } else if (ggml_metal_op_mul_mat_use_mm(op, props_dev->has_simdgroup_mm)) {
2520        //GGML_LOG_INFO("matrix: ne00 = %6d, ne01 = %6d, ne02 = %6d, ne11 = %6d, ne12 = %6d\n", ne00, ne01, ne02, ne11, ne12);
2521
2522        // some Metal matrix data types require aligned pointers
2523        // ref: https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf (Table 2.5)
2524        //switch (op->src[0]->type) {
2525        //    case GGML_TYPE_F32:  GGML_ASSERT(nb01 % 16 == 0); break;
2526        //    case GGML_TYPE_F16:  GGML_ASSERT(nb01 % 8  == 0); break;
2527        //    case GGML_TYPE_BF16: GGML_ASSERT(nb01 % 8  == 0); break;
2528        //    default: break;
2529        //}
2530
2531        auto pipeline = ggml_metal_library_get_pipeline_mul_mm(lib, op);
2532
2533        ggml_metal_kargs_mul_mm args = {
2534            /*.ne00 =*/ ne00,
2535            /*.ne02 =*/ ne02,
2536            /*.nb01 =*/ nb01,
2537            /*.nb02 =*/ nb02,
2538            /*.nb03 =*/ nb03,
2539            /*.ne12 =*/ ne12,
2540            /*.nb10 =*/ nb10,
2541            /*.nb11 =*/ nb11,
2542            /*.nb12 =*/ nb12,
2543            /*.nb13 =*/ nb13,
2544            /*.ne0  =*/ ne0,
2545            /*.ne1  =*/ ne1,
2546            /*.r2   =*/ r2,
2547            /*.r3   =*/ r3,
2548        };
2549
2550        ggml_metal_encoder_set_pipeline(enc, pipeline);
2551        ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
2552        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
2553        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
2554        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
2555
2556        const size_t smem = pipeline.smem;
2557
2558        ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
2559
2560        const int nr0 = pipeline.nr0;
2561        const int nr1 = pipeline.nr1;
2562        const int nsg = pipeline.nsg;
2563
2564        ggml_metal_encoder_dispatch_threadgroups(enc, ((ne11 + nr1 - 1) / nr1), ((ne01 + nr0 - 1) / nr0), ne12 * ne13, 32, nsg, 1);
2565    } else {
2566        auto pipeline = ggml_metal_library_get_pipeline_mul_mv(lib, op);
2567
2568        const int nr0 = pipeline.nr0;
2569        const int nr1 = pipeline.nr1;
2570        const int nsg = pipeline.nsg;
2571
2572        const size_t smem = pipeline.smem;
2573
2574        ggml_metal_kargs_mul_mv args = {
2575            /*.ne00 =*/ ne00,
2576            /*.ne01 =*/ ne01,
2577            /*.ne02 =*/ ne02,
2578            /*.nb00 =*/ nb00,
2579            /*.nb01 =*/ nb01,
2580            /*.nb02 =*/ nb02,
2581            /*.nb03 =*/ nb03,
2582            /*.ne10 =*/ ne10,
2583            /*.ne11 =*/ ne11,
2584            /*.ne12 =*/ ne12,
2585            /*.nb10 =*/ nb10,
2586            /*.nb11 =*/ nb11,
2587            /*.nb12 =*/ nb12,
2588            /*.nb13 =*/ nb13,
2589            /*.ne0  =*/ ne0,
2590            /*.ne1  =*/ ne1,
2591            /*.nr0  =*/ nr0,
2592            /*.r2   =*/ r2,
2593            /*.r3   =*/ r3,
2594        };
2595
2596        ggml_metal_encoder_set_pipeline(enc, pipeline);
2597        ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
2598        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
2599        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
2600        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
2601
2602        ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
2603
2604        if (op->src[0]->type == GGML_TYPE_F32 ||
2605            op->src[0]->type == GGML_TYPE_F16 ||
2606            op->src[0]->type == GGML_TYPE_BF16 ||
2607            op->src[0]->type == GGML_TYPE_Q8_0) {
2608            ggml_metal_encoder_dispatch_threadgroups(enc, ((ne01 + nr0 - 1)/(nr0)), ((ne11 + nr1 - 1)/nr1), ne12*ne13, 32, nsg, 1);
2609        } else {
2610            ggml_metal_encoder_dispatch_threadgroups(enc, ((ne01 + nr0*nsg - 1)/(nr0*nsg)), ((ne11 + nr1 - 1)/nr1), ne12*ne13, 32, nsg, 1);
2611        }
2612    }
2613
2614    return 1;
2615}
2616
2617size_t ggml_metal_op_mul_mat_id_extra_tpe(const ggml_tensor * op) {
2618    assert(op->op == GGML_OP_MUL_MAT_ID);
2619
2620    const int64_t ne02 = op->src[0]->ne[2]; // n_expert
2621
2622    return ggml_type_size(GGML_TYPE_I32)*ne02;
2623}
2624
2625size_t ggml_metal_op_mul_mat_id_extra_ids(const ggml_tensor * op) {
2626    assert(op->op == GGML_OP_MUL_MAT_ID);
2627
2628    const int64_t ne02 = op->src[0]->ne[2]; // n_expert
2629    const int64_t ne21 = op->src[2]->ne[1]; // n_token
2630
2631    return ggml_type_size(GGML_TYPE_I32)*ne02*ne21;
2632}
2633
2634int ggml_metal_op_mul_mat_id(ggml_metal_op_t ctx, int idx) {
2635    ggml_tensor * op = ctx->node(idx);
2636
2637    ggml_metal_library_t lib = ctx->lib;
2638    ggml_metal_encoder_t enc = ctx->enc;
2639
2640    const ggml_metal_device_props * props_dev = ggml_metal_device_get_props(ctx->dev);
2641
2642    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
2643    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
2644    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
2645    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
2646    GGML_TENSOR_LOCALS( int32_t, ne2, op->src[2], ne);
2647    GGML_TENSOR_LOCALS(uint64_t, nb2, op->src[2], nb);
2648    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
2649    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
2650
2651    // src2 = ids
2652    GGML_ASSERT(op->src[2]->type == GGML_TYPE_I32);
2653
2654    GGML_ASSERT(!ggml_is_transposed(op->src[0]));
2655    GGML_ASSERT(!ggml_is_transposed(op->src[1]));
2656
2657    GGML_ASSERT(ne03 == 1);
2658    GGML_ASSERT(ne13 == 1);
2659
2660    ggml_metal_buffer_id bid_src0 = ggml_metal_get_buffer_id(op->src[0]);
2661    ggml_metal_buffer_id bid_src1 = ggml_metal_get_buffer_id(op->src[1]);
2662    ggml_metal_buffer_id bid_src2 = ggml_metal_get_buffer_id(op->src[2]);
2663    ggml_metal_buffer_id bid_dst  = ggml_metal_get_buffer_id(op);
2664
2665    const uint32_t r2 = 1;
2666    const uint32_t r3 = 1;
2667
2668    if (ggml_metal_op_mul_mat_id_use_mm(op, props_dev->has_simdgroup_mm)) {
2669        // some Metal matrix data types require aligned pointers
2670        // ref: https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf (Table 2.5)
2671        //switch (op->src[0]->type) {
2672        //    case GGML_TYPE_F32:  GGML_ASSERT(nb01 % 16 == 0); break;
2673        //    case GGML_TYPE_F16:  GGML_ASSERT(nb01 % 8  == 0); break;
2674        //    case GGML_TYPE_BF16: GGML_ASSERT(nb01 % 8  == 0); break;
2675        //    default: break;
2676        //}
2677
2678        // extra buffers for intermediate id mapping
2679        ggml_metal_buffer_id bid_tpe = bid_dst;
2680        bid_tpe.offs += ggml_nbytes(op);
2681
2682        ggml_metal_buffer_id bid_ids = bid_tpe;
2683        bid_ids.offs += ggml_metal_op_mul_mat_id_extra_tpe(op);
2684
2685        {
2686            ggml_metal_kargs_mul_mm_id_map0 args = {
2687                ne02,
2688                ne10,
2689                ne11, // n_expert_used (bcast)
2690                nb11,
2691                nb12,
2692                ne21, // n_tokens
2693                ne20, // n_expert_used
2694                nb21,
2695            };
2696
2697            auto pipeline = ggml_metal_library_get_pipeline_mul_mm_id_map0(lib, ne02, ne20);
2698
2699            const size_t smem = pipeline.smem;
2700
2701            GGML_ASSERT(ne02 <= ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
2702
2703            GGML_ASSERT(smem <= props_dev->max_theadgroup_memory_size);
2704
2705            ggml_metal_encoder_set_pipeline(enc, pipeline);
2706            ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
2707            ggml_metal_encoder_set_buffer  (enc, bid_src2, 1);
2708            ggml_metal_encoder_set_buffer  (enc, bid_tpe,  2);
2709            ggml_metal_encoder_set_buffer  (enc, bid_ids,  3);
2710
2711            ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
2712
2713            ggml_metal_encoder_dispatch_threadgroups(enc, 1, 1, 1, ne02, 1, 1);
2714        }
2715
2716        // this barrier is always needed because the next kernel has to wait for the id maps to be computed
2717        ggml_metal_op_concurrency_reset(ctx);
2718
2719        {
2720            auto pipeline = ggml_metal_library_get_pipeline_mul_mm_id(lib, op);
2721
2722            ggml_metal_kargs_mul_mm_id args = {
2723                /*.ne00  =*/ ne00,
2724                /*.ne02  =*/ ne02,
2725                /*.nb01  =*/ nb01,
2726                /*.nb02  =*/ nb02,
2727                /*.nb03  =*/ nb03,
2728                /*.ne11  =*/ ne11, // n_expert_used (bcast)
2729                /*.nb10  =*/ nb10,
2730                /*.nb11  =*/ nb11,
2731                /*.nb12  =*/ nb12,
2732                /*.nb13  =*/ nb13,
2733                /*.ne20  =*/ ne20, // n_expert_used
2734                /*.ne21  =*/ ne21, // n_tokens
2735                /*.ne0   =*/ ne0,
2736                /*.ne1   =*/ ne1,
2737                /*.r2    =*/ r2,
2738                /*.r3    =*/ r3,
2739            };
2740
2741            ggml_metal_encoder_set_pipeline(enc, pipeline);
2742            ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
2743            ggml_metal_encoder_set_buffer  (enc, bid_src0, 1);
2744            ggml_metal_encoder_set_buffer  (enc, bid_src1, 2);
2745            ggml_metal_encoder_set_buffer  (enc, bid_tpe,  3);
2746            ggml_metal_encoder_set_buffer  (enc, bid_ids,  4);
2747            ggml_metal_encoder_set_buffer  (enc, bid_dst,  5);
2748
2749            const size_t smem = pipeline.smem;
2750
2751            ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
2752
2753            ggml_metal_encoder_dispatch_threadgroups(enc, (ne21 + 31)/32, (ne01 + 63)/64, ne02, 128, 1, 1);
2754        }
2755    } else {
2756        auto pipeline = ggml_metal_library_get_pipeline_mul_mv_id(lib, op);
2757
2758        const int nr0 = pipeline.nr0;
2759        const int nr1 = pipeline.nr1;
2760        const int nsg = pipeline.nsg;
2761
2762        const size_t smem = pipeline.smem;
2763
2764        ggml_metal_kargs_mul_mv_id args = {
2765            /*.nei0 =*/ ne20,
2766            /*.nei1 =*/ ne21,
2767            /*.nbi1 =*/ nb21,
2768            /*.ne00 =*/ ne00,
2769            /*.ne01 =*/ ne01,
2770            /*.ne02 =*/ ne02,
2771            /*.nb00 =*/ nb00,
2772            /*.nb01 =*/ nb01,
2773            /*.nb02 =*/ nb02,
2774            /*.ne10 =*/ ne10,
2775            /*.ne11 =*/ ne11,
2776            /*.ne12 =*/ ne12,
2777            /*.ne13 =*/ ne13,
2778            /*.nb10 =*/ nb10,
2779            /*.nb11 =*/ nb11,
2780            /*.nb12 =*/ nb12,
2781            /*.ne0  =*/ ne0,
2782            /*.ne1  =*/ ne1,
2783            /*.nb1  =*/ nb1,
2784            /*.nr0  =*/ nr0,
2785        };
2786
2787        if (ggml_is_quantized(op->src[0]->type)) {
2788            GGML_ASSERT(ne00 >= nsg*nr0);
2789        }
2790
2791        ggml_metal_encoder_set_pipeline(enc, pipeline);
2792        ggml_metal_encoder_set_bytes(enc, &args, sizeof(args), 0);
2793        ggml_metal_encoder_set_buffer(enc, bid_src0, 1);
2794        ggml_metal_encoder_set_buffer(enc, bid_src1, 2);
2795        ggml_metal_encoder_set_buffer(enc, bid_dst,  3);
2796        ggml_metal_encoder_set_buffer(enc, bid_src2, 4);
2797
2798        const int64_t _ne1 = 1;
2799        const int64_t ne123 = ne20*ne21;
2800
2801        ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
2802
2803        if (op->src[0]->type == GGML_TYPE_F32 ||
2804            op->src[0]->type == GGML_TYPE_F16 ||
2805            op->src[0]->type == GGML_TYPE_BF16 ||
2806            op->src[0]->type == GGML_TYPE_Q8_0) {
2807            ggml_metal_encoder_dispatch_threadgroups(enc, (ne01 + nr0 - 1)/(nr0), (_ne1 + nr1 - 1)/nr1, ne123, 32, nsg, 1);
2808        } else {
2809            ggml_metal_encoder_dispatch_threadgroups(enc, (ne01 + nr0*nsg - 1)/(nr0*nsg), (_ne1 + nr1 - 1)/nr1, ne123, 32, nsg, 1);
2810        }
2811    }
2812
2813    return 1;
2814}
2815
2816int ggml_metal_op_add_id(ggml_metal_op_t ctx, int idx) {
2817    ggml_tensor * op = ctx->node(idx);
2818
2819    ggml_metal_library_t lib = ctx->lib;
2820    ggml_metal_encoder_t enc = ctx->enc;
2821
2822    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
2823    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
2824    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
2825    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
2826    GGML_TENSOR_LOCALS( int32_t, ne2, op->src[2], ne);
2827    GGML_TENSOR_LOCALS(uint64_t, nb2, op->src[2], nb);
2828    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
2829
2830    GGML_ASSERT(op->src[0]->type == GGML_TYPE_F32);
2831    GGML_ASSERT(op->src[1]->type == GGML_TYPE_F32);
2832    GGML_ASSERT(op->src[2]->type == GGML_TYPE_I32);
2833    GGML_ASSERT(op->type         == GGML_TYPE_F32);
2834
2835    GGML_ASSERT(ggml_is_contiguous_rows(op->src[0]));
2836
2837    ggml_metal_kargs_add_id args = {
2838        /*.ne0  =*/ ne0,
2839        /*.ne1  =*/ ne1,
2840        /*.nb01 =*/ nb01,
2841        /*.nb02 =*/ nb02,
2842        /*.nb11 =*/ nb11,
2843        /*.nb21 =*/ nb21,
2844    };
2845
2846    auto pipeline = ggml_metal_library_get_pipeline_base(lib, GGML_OP_ADD_ID);
2847
2848    ggml_metal_encoder_set_pipeline(enc, pipeline);
2849    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
2850    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
2851    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
2852    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[2]), 3);
2853    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         4);
2854
2855    const int nth = std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline), ne00);
2856
2857    ggml_metal_encoder_dispatch_threadgroups(enc, ne01, ne02, 1, nth, 1, 1);
2858
2859    return 1;
2860}
2861
2862bool ggml_metal_op_flash_attn_ext_use_vec(const ggml_tensor * op) {
2863    assert(op->op == GGML_OP_FLASH_ATTN_EXT);
2864
2865    const int64_t ne00 = op->src[0]->ne[0]; // head size
2866    const int64_t ne01 = op->src[0]->ne[1]; // batch size
2867
2868    // use vec kernel if the batch size is small and if the head size is supported
2869    return (ne01 < 20) && (ne00 % 32 == 0);
2870}
2871
2872// ref: https://github.com/ggml-org/llama.cpp/pull/27390
2873// dequantize the quantized KV cache to F16 before running the F16 flash attention kernels
2874static bool ggml_metal_op_flash_attn_ext_use_kv_f16(const ggml_tensor * op) {
2875    assert(op->op == GGML_OP_FLASH_ATTN_EXT);
2876
2877    // depending on compute/bandwidth ratio, dequant to f16 kv is not always beneficial
2878    // ref: https://github.com/ggml-org/llama.cpp/pull/27390#issuecomment-5355152767
2879    // TODO: tune per device
2880    if (op->src[0]->ne[1] < 32) {
2881        return false;
2882    }
2883
2884    switch (op->src[1]->type) {
2885        case GGML_TYPE_Q4_0:
2886        case GGML_TYPE_Q4_1:
2887        case GGML_TYPE_Q5_0:
2888        case GGML_TYPE_Q5_1:
2889        case GGML_TYPE_Q8_0:
2890            return true;
2891        default:
2892            return false;
2893    }
2894}
2895
2896// returns the n_kv_max hint if the sparse path is available for this op, or 0 otherwise
2897// the mask (src[3]) remains the single source of truth: finite entries are the valid KV positions,
2898// n_kv_max is only an upper bound on their number per mask row, used to size the index lists
2899static int ggml_metal_op_flash_attn_ext_n_kv_max_sparse(const ggml_tensor * op) {
2900    assert(op->op == GGML_OP_FLASH_ATTN_EXT);
2901
2902    int32_t n_kv_max = 0;
2903    memcpy(&n_kv_max, ((const int32_t *) op->op_params) + 4, sizeof(n_kv_max));
2904
2905    if (n_kv_max <= 0) {
2906        return 0;
2907    }
2908
2909    // the sparse indices are gathered from the mask
2910    if (!op->src[3]) {
2911        return 0;
2912    }
2913
2914    // bound the size of the index lists
2915    if (n_kv_max > 4096) {
2916        return 0;
2917    }
2918
2919    // vec kernel instantiations exist for these (type, dk, dv) combinations only
2920    const int64_t dk = op->src[1]->ne[0];
2921    const int64_t dv = op->src[2]->ne[0];
2922
2923    const bool dk_dv_ok = (dk == 32  && dv == 32)  ||
2924                          (dk == 64  && dv == 64)  ||
2925                          (dk == 96  && dv == 96)  ||
2926                          (dk == 128 && dv == 128) ||
2927                          (dk == 192 && dv == 128) ||
2928                          (dk == 192 && dv == 192) ||
2929                          (dk == 256 && dv == 256) ||
2930                          (dk == 320 && dv == 256) ||
2931                          (dk == 512 && dv == 512) ||
2932                          (dk == 576 && dv == 512);
2933
2934    if (!dk_dv_ok) {
2935        return 0;
2936    }
2937
2938    switch (op->src[1]->type) {
2939        case GGML_TYPE_F16:
2940        case GGML_TYPE_BF16:
2941        case GGML_TYPE_F32:
2942        case GGML_TYPE_Q4_0:
2943        case GGML_TYPE_Q4_1:
2944        case GGML_TYPE_Q5_0:
2945        case GGML_TYPE_Q5_1:
2946        case GGML_TYPE_Q8_0:
2947            break;
2948        default:
2949            return 0;
2950    }
2951
2952    return n_kv_max;
2953}
2954
2955// in some models (e.g. MLA-based), V is a view of K (the first ne20 elements of each K row);
2956// the dequantized V is then a view of the dequantized K and does not need its own dequant or scratch
2957// - ref: https://github.com/ggml-org/llama.cpp/pull/13435
2958static bool ggml_metal_op_flash_attn_ext_v_is_view_of_k(const ggml_tensor * op) {
2959    assert(op->op == GGML_OP_FLASH_ATTN_EXT);
2960
2961    const ggml_tensor * K = op->src[1];
2962    const ggml_tensor * V = op->src[2];
2963
2964    return V->view_src && (V->view_src == K || (V->view_src == K->view_src && V->view_offs == K->view_offs));
2965}
2966
2967// size of the F16 dequantized K tensor; the dequantized V tensor follows it in the same scratch buffer
2968static size_t ggml_metal_op_flash_attn_ext_kv_f16_k_size(const ggml_tensor * op) {
2969    assert(op->op == GGML_OP_FLASH_ATTN_EXT);
2970
2971    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
2972
2973    return GGML_PAD(sizeof(ggml_fp16_t)*(size_t) ne10*ne11*ne12*ne13, 16);
2974}
2975
2976size_t ggml_metal_op_flash_attn_ext_extra_pad(const ggml_tensor * op) {
2977    assert(op->op == GGML_OP_FLASH_ATTN_EXT);
2978
2979    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
2980    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
2981    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
2982    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
2983    GGML_TENSOR_LOCALS( int32_t, ne2, op->src[2], ne);
2984    GGML_TENSOR_LOCALS(uint64_t, nb2, op->src[2], nb);
2985    GGML_TENSOR_LOCALS( int32_t, ne3, op->src[3], ne);
2986    GGML_TENSOR_LOCALS(uint64_t, nb3, op->src[3], nb);
2987
2988    size_t res = 0;
2989
2990    const bool has_mask = op->src[3] != nullptr;
2991    const bool use_kv_f16 = ggml_metal_op_flash_attn_ext_use_kv_f16(op);
2992
2993    // when the KV is dequantized to F16, the pad kernel copies the tail chunk from the F16 scratch buffer
2994    // note: when V is a view of K, the dequantized V is read from the dequantized K with K's row stride
2995    const bool v_is_view_of_k = use_kv_f16 && ggml_metal_op_flash_attn_ext_v_is_view_of_k(op);
2996    uint64_t nb11_pad = nb11;
2997    uint64_t nb21_pad = nb21;
2998
2999    if (use_kv_f16) {
3000        nb11_pad = sizeof(ggml_fp16_t)*ne10;
3001        nb21_pad = sizeof(ggml_fp16_t)*(v_is_view_of_k ? ne10 : ne20);
3002    }
3003
3004    // note: the non-vec kernel requires more extra memory, so always reserve for it
3005    GGML_ASSERT(OP_FLASH_ATTN_EXT_NCPSG >= OP_FLASH_ATTN_EXT_VEC_NCPSG);
3006
3007    //if (ggml_metal_op_flash_attn_ext_use_vec(op)) {
3008    if (false) {
3009        // note: always reserve the padding space to avoid graph reallocations
3010        //const bool has_kvpad = ne11 % OP_FLASH_ATTN_EXT_VEC_NCPSG != 0;
3011        const bool has_kvpad = true;
3012
3013        if (has_kvpad) {
3014            res += OP_FLASH_ATTN_EXT_VEC_NCPSG*(
3015                nb11_pad*ne12*ne13 +
3016                nb21_pad*ne22*ne23 +
3017                (has_mask ? ggml_type_size(GGML_TYPE_F16)*ne31*ne32*ne33 : 0));
3018        }
3019    } else {
3020        //const bool has_kvpad = ne11 % OP_FLASH_ATTN_EXT_NCPSG != 0;
3021        const bool has_kvpad = true;
3022
3023        if (has_kvpad) {
3024            res += OP_FLASH_ATTN_EXT_NCPSG*(
3025                nb11_pad*ne12*ne13 +
3026                nb21_pad*ne22*ne23 +
3027                (has_mask ? ggml_type_size(GGML_TYPE_F16)*ne31*ne32*ne33 : 0));
3028        }
3029    }
3030
3031    return res;
3032}
3033
3034size_t ggml_metal_op_flash_attn_ext_extra_blk(const ggml_tensor * op) {
3035    assert(op->op == GGML_OP_FLASH_ATTN_EXT);
3036
3037    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
3038  //GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
3039  //GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
3040  //GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
3041  //GGML_TENSOR_LOCALS( int32_t, ne2, op->src[2], ne);
3042  //GGML_TENSOR_LOCALS(uint64_t, nb2, op->src[2], nb);
3043    GGML_TENSOR_LOCALS( int32_t, ne3, op->src[3], ne);
3044    GGML_TENSOR_LOCALS(uint64_t, nb3, op->src[3], nb);
3045
3046    size_t res = 0;
3047
3048    const bool has_mask = op->src[3] != nullptr;
3049
3050    if (!has_mask) {
3051        return res;
3052    }
3053
3054    const bool is_vec = ggml_metal_op_flash_attn_ext_use_vec(op);
3055
3056    // this optimization is not useful for the vector kernels
3057    // note: always reserve the blk buffer to avoid graph reallocations
3058    //if (is_vec) {
3059    //    return res;
3060    //}
3061
3062    const int nqptg = is_vec ? OP_FLASH_ATTN_EXT_VEC_NQPSG : OP_FLASH_ATTN_EXT_NQPSG;
3063    const int ncpsg = is_vec ? OP_FLASH_ATTN_EXT_VEC_NCPSG : OP_FLASH_ATTN_EXT_NCPSG;
3064
3065    const int64_t ne1 = (ne01 + nqptg - 1)/nqptg;
3066    const int64_t ne0 = (ne30 + ncpsg - 1)/ncpsg;
3067
3068    res += GGML_PAD(ggml_type_size(GGML_TYPE_I8)*ne0*ne1*ne32*ne33, 32);
3069
3070    return res;
3071}
3072
3073size_t ggml_metal_op_flash_attn_ext_extra_tmp(const ggml_tensor * op) {
3074    assert(op->op == GGML_OP_FLASH_ATTN_EXT);
3075
3076    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
3077    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
3078  //GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
3079  //GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
3080    GGML_TENSOR_LOCALS( int32_t, ne2, op->src[2], ne);
3081    GGML_TENSOR_LOCALS(uint64_t, nb2, op->src[2], nb);
3082  //GGML_TENSOR_LOCALS( int32_t, ne3, op->src[3], ne);
3083  //GGML_TENSOR_LOCALS(uint64_t, nb3, op->src[3], nb);
3084
3085    size_t res = 0;
3086
3087    // note: always reserve the temp buffer to avoid graph reallocations
3088    //if (ggml_metal_op_flash_attn_ext_use_vec(op)) {
3089    if (true) {
3090        const int64_t nwg = 32;
3091        const int64_t ne01_max = std::min(ne01, 32);
3092
3093        // temp buffer for writing the results from each workgroup
3094        // - ne20: the size of the Value head
3095        // -  + 2: the S and M values for each intermediate result
3096        res += ggml_type_size(GGML_TYPE_F32)*(ne01_max*ne02*ne03*nwg*(ne20 + 2));
3097    }
3098
3099    return res;
3100}
3101
3102size_t ggml_metal_op_flash_attn_ext_extra_kv_f16(const ggml_tensor * op) {
3103    assert(op->op == GGML_OP_FLASH_ATTN_EXT);
3104
3105    // note: always reserve the temp buffer to avoid graph reallocations
3106    //if (!ggml_metal_op_flash_attn_ext_use_kv_f16(op)) {
3107    //    return 0;
3108    //}
3109
3110    GGML_TENSOR_LOCALS( int32_t, ne2, op->src[2], ne);
3111
3112    const size_t k_size = ggml_metal_op_flash_attn_ext_kv_f16_k_size(op);
3113
3114    // when V is a view of K, the dequantized V is a view of the dequantized K
3115    const bool v_is_view_of_k = ggml_metal_op_flash_attn_ext_v_is_view_of_k(op);
3116    if (v_is_view_of_k) {
3117        return k_size;
3118    }
3119
3120    const size_t v_size = GGML_PAD(sizeof(ggml_fp16_t)*(size_t) ne20*ne21*ne22*ne23, 16);
3121
3122    return k_size + v_size;
3123}
3124
3125// size of the sparse index lists: one list of KV indices per mask row,
3126// padded with -1 up to a multiple of OP_FLASH_ATTN_EXT_VEC_NCPSG
3127size_t ggml_metal_op_flash_attn_ext_extra_idx(const ggml_tensor * op) {
3128    assert(op->op == GGML_OP_FLASH_ATTN_EXT);
3129
3130    GGML_TENSOR_LOCALS( int32_t, ne3, op->src[3], ne);
3131
3132    const int n_kv_max = ggml_metal_op_flash_attn_ext_n_kv_max_sparse(op);
3133
3134    if (n_kv_max <= 0) {
3135        return 0;
3136    }
3137
3138    const int n_kv_max_padded = GGML_PAD(n_kv_max, OP_FLASH_ATTN_EXT_VEC_NCPSG);
3139
3140    return GGML_PAD(sizeof(int32_t)*(size_t) n_kv_max_padded*ne31*ne32*ne33, 16);
3141}
3142
3143int ggml_metal_op_flash_attn_ext(ggml_metal_op_t ctx, int idx) {
3144    ggml_tensor * op = ctx->node(idx);
3145
3146    ggml_metal_library_t lib = ctx->lib;
3147    ggml_metal_encoder_t enc = ctx->enc;
3148
3149    const ggml_metal_device_props * props_dev = ggml_metal_device_get_props(ctx->dev);
3150
3151    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
3152    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
3153    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
3154    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
3155    GGML_TENSOR_LOCALS( int32_t, ne2, op->src[2], ne);
3156    GGML_TENSOR_LOCALS(uint64_t, nb2, op->src[2], nb);
3157    GGML_TENSOR_LOCALS( int32_t, ne3, op->src[3], ne);
3158    GGML_TENSOR_LOCALS(uint64_t, nb3, op->src[3], nb);
3159    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
3160    GGML_TENSOR_LOCALS( int32_t, nb,  op,         nb);
3161
3162    GGML_ASSERT(ne00 % 4 == 0);
3163
3164    GGML_ASSERT(op->src[0]->type == GGML_TYPE_F32);
3165    GGML_ASSERT(op->src[1]->type == op->src[2]->type);
3166
3167    //GGML_ASSERT(ggml_are_same_shape (src1, src2));
3168    GGML_ASSERT(ne11 == ne21);
3169    GGML_ASSERT(ne12 == ne22);
3170
3171    GGML_ASSERT(!op->src[3] || op->src[3]->type == GGML_TYPE_F16);
3172    GGML_ASSERT(!op->src[3] || op->src[3]->ne[1] >= op->src[0]->ne[1] &&
3173            "the Flash-Attention Metal kernel requires the mask to be at least n_queries big");
3174
3175    float scale;
3176    float max_bias;
3177    float logit_softcap;
3178
3179    memcpy(&scale,         ((const int32_t *) op->op_params) + 0, sizeof(scale));
3180    memcpy(&max_bias,      ((const int32_t *) op->op_params) + 1, sizeof(max_bias));
3181    memcpy(&logit_softcap, ((const int32_t *) op->op_params) + 2, sizeof(logit_softcap));
3182
3183    if (logit_softcap != 0.0f) {
3184        scale /= logit_softcap;
3185    }
3186
3187    const bool has_mask  = op->src[3] != NULL;
3188    const bool has_sinks = op->src[4] != NULL;
3189    const bool has_bias  = max_bias != 0.0f;
3190    const bool has_scap  = logit_softcap != 0.0f;
3191
3192    const uint32_t n_head      = op->src[0]->ne[2];
3193    const  int32_t n_head_log2 = 1u << (uint32_t) floorf(log2f((float) n_head));
3194
3195    const float m0 = powf(2.0f, -(max_bias       ) / n_head_log2);
3196    const float m1 = powf(2.0f, -(max_bias / 2.0f) / n_head_log2);
3197
3198    GGML_ASSERT(ne01 < 65536);
3199
3200    ggml_metal_buffer_id bid_src0 = ggml_metal_get_buffer_id(op->src[0]);
3201    ggml_metal_buffer_id bid_src1 = ggml_metal_get_buffer_id(op->src[1]);
3202    ggml_metal_buffer_id bid_src2 = ggml_metal_get_buffer_id(op->src[2]);
3203    ggml_metal_buffer_id bid_src3 = has_mask  ? ggml_metal_get_buffer_id(op->src[3]) : bid_src0;
3204    ggml_metal_buffer_id bid_src4 = has_sinks ? ggml_metal_get_buffer_id(op->src[4]) : bid_src0;
3205
3206    ggml_metal_buffer_id bid_dst = ggml_metal_get_buffer_id(op);
3207
3208    ggml_metal_buffer_id bid_pad = bid_dst;
3209    bid_pad.offs += ggml_nbytes(op);
3210
3211    ggml_metal_buffer_id bid_blk = bid_pad;
3212    bid_blk.offs += ggml_metal_op_flash_attn_ext_extra_pad(op);
3213
3214    ggml_metal_buffer_id bid_tmp = bid_blk;
3215    bid_tmp.offs += ggml_metal_op_flash_attn_ext_extra_blk(op);
3216
3217    ggml_metal_buffer_id bid_kv_f16 = bid_tmp;
3218    bid_kv_f16.offs += ggml_metal_op_flash_attn_ext_extra_tmp(op);
3219
3220    // sparse path: gather the finite mask entries into index lists and run the vec kernels over them
3221    const int n_kv_max_sparse = ggml_metal_op_flash_attn_ext_n_kv_max_sparse(op);
3222    const bool use_sparse = n_kv_max_sparse > 0;
3223    const int n_kv_max_padded = use_sparse ? GGML_PAD(n_kv_max_sparse, OP_FLASH_ATTN_EXT_VEC_NCPSG) : 0;
3224
3225    // the vec kernels dequantize the KV inline; no need for the F16 dequant pass in the sparse path
3226    const bool use_kv_f16 = !use_sparse && ggml_metal_op_flash_attn_ext_use_kv_f16(op);
3227
3228    ggml_metal_buffer_id bid_idx = bid_kv_f16;
3229    bid_idx.offs += ggml_metal_op_flash_attn_ext_extra_kv_f16(op);
3230
3231    ggml_metal_buffer_id bid_k = bid_src1;
3232    ggml_metal_buffer_id bid_v = bid_src2;
3233
3234    uint64_t nb10_attn = nb10;
3235    uint64_t nb11_attn = nb11;
3236    uint64_t nb12_attn = nb12;
3237    uint64_t nb13_attn = nb13;
3238    uint64_t nb20_attn = nb20;
3239    uint64_t nb21_attn = nb21;
3240    uint64_t nb22_attn = nb22;
3241    uint64_t nb23_attn = nb23;
3242
3243    if (use_kv_f16) {
3244        assert(ggml_metal_op_flash_attn_ext_extra_kv_f16(op) != 0);
3245
3246        const bool v_is_view_of_k = ggml_metal_op_flash_attn_ext_v_is_view_of_k(op);
3247
3248        const int64_t nblocks1_64 = (ne10/ggml_blck_size(op->src[1]->type))*(int64_t) ne11*ne12*ne13;
3249        GGML_ASSERT(nblocks1_64 <= INT32_MAX);
3250        const int32_t nblocks1 = nblocks1_64;
3251
3252        ggml_metal_buffer_id bid_v_f16 = bid_kv_f16;
3253        bid_v_f16.offs += ggml_metal_op_flash_attn_ext_kv_f16_k_size(op);
3254
3255        auto pipeline0 = ggml_metal_library_get_pipeline_flash_attn_ext_kv_f16(lib, op);
3256        const int nth = std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline0), 256);
3257
3258        // K
3259        ggml_metal_kargs_flash_attn_ext_kv_f16 args_k = {
3260            /*.ne0    =*/ ne10,
3261            /*.ne1    =*/ ne11,
3262            /*.ne2    =*/ ne12,
3263            /*.ne3    =*/ ne13,
3264            /*.nb0    =*/ nb10,
3265            /*.nb1    =*/ nb11,
3266            /*.nb2    =*/ nb12,
3267            /*.nb3    =*/ nb13,
3268            /*.nblocks =*/ nblocks1,
3269        };
3270
3271        ggml_metal_encoder_set_pipeline(enc, pipeline0);
3272        ggml_metal_encoder_set_bytes   (enc, &args_k, sizeof(args_k), 0);
3273        ggml_metal_encoder_set_buffer  (enc, bid_src1,        1);
3274        ggml_metal_encoder_set_buffer  (enc, bid_kv_f16, 2);
3275
3276        ggml_metal_encoder_dispatch_threadgroups(enc, (nblocks1 + nth - 1)/nth, 1, 1, nth, 1, 1);
3277
3278        // V (skip when V is a view of K: the dequantized V is a view of the dequantized K)
3279        if (!v_is_view_of_k) {
3280            const int64_t nblocks2_64 = (ne20/ggml_blck_size(op->src[2]->type))*(int64_t) ne21*ne22*ne23;
3281            GGML_ASSERT(nblocks2_64 <= INT32_MAX);
3282            const int32_t nblocks2 = nblocks2_64;
3283
3284            ggml_metal_kargs_flash_attn_ext_kv_f16 args_v = {
3285                /*.ne0    =*/ ne20,
3286                /*.ne1    =*/ ne21,
3287                /*.ne2    =*/ ne22,
3288                /*.ne3    =*/ ne23,
3289                /*.nb0    =*/ nb20,
3290                /*.nb1    =*/ nb21,
3291                /*.nb2    =*/ nb22,
3292                /*.nb3    =*/ nb23,
3293                /*.nblocks =*/ nblocks2,
3294            };
3295
3296            ggml_metal_encoder_set_pipeline(enc, pipeline0);
3297            ggml_metal_encoder_set_bytes   (enc, &args_v, sizeof(args_v), 0);
3298            ggml_metal_encoder_set_buffer  (enc, bid_src2,        1);
3299            ggml_metal_encoder_set_buffer  (enc, bid_v_f16,       2);
3300
3301            ggml_metal_encoder_dispatch_threadgroups(enc, (nblocks2 + nth - 1)/nth, 1, 1, nth, 1, 1);
3302        }
3303
3304        // the pad and attention kernels read the dequantized KV
3305        ggml_metal_op_concurrency_reset(ctx);
3306
3307        bid_k = bid_kv_f16;
3308        bid_v = v_is_view_of_k ? bid_k : bid_v_f16;
3309
3310        // contiguous F16 layout of the dequantized K
3311        nb10_attn = sizeof(ggml_fp16_t);
3312        nb11_attn = nb10_attn*ne10;
3313        nb12_attn = nb11_attn*ne11;
3314        nb13_attn = nb12_attn*ne12;
3315
3316        // if V is a view of K, the dequantized V is read from the dequantized K with K's strides
3317        if (v_is_view_of_k) {
3318            nb20_attn = nb10_attn;
3319            nb21_attn = nb11_attn;
3320            nb22_attn = nb12_attn;
3321            nb23_attn = nb13_attn;
3322        } else {
3323            // contiguous F16 layout of the dequantized V
3324            nb20_attn = sizeof(ggml_fp16_t);
3325            nb21_attn = nb20_attn*ne20;
3326            nb22_attn = nb21_attn*ne21;
3327            nb23_attn = nb22_attn*ne22;
3328        }
3329    }
3330
3331    if (!use_sparse && !ggml_metal_op_flash_attn_ext_use_vec(op)) {
3332        // half8x8 kernel
3333        const int nqptg = OP_FLASH_ATTN_EXT_NQPSG; // queries per threadgroup
3334        const int ncpsg = OP_FLASH_ATTN_EXT_NCPSG; // cache values per simdgroup
3335
3336        GGML_ASSERT(nqptg <= 32);
3337        GGML_ASSERT(nqptg  % 8  == 0);
3338        GGML_ASSERT(ncpsg  % 32 == 0);
3339
3340        bool need_sync = false;
3341
3342        const bool has_kvpad = ne11 % ncpsg != 0;
3343
3344        if (has_kvpad) {
3345            assert(ggml_metal_op_flash_attn_ext_extra_pad(op) != 0);
3346
3347            ggml_metal_kargs_flash_attn_ext_pad args0 = {
3348                /*.ne11    =*/ne11,
3349                /*.ne_12_2 =*/ne12,
3350                /*.ne_12_3 =*/ne13,
3351                /*.nb11    =*/nb11_attn,
3352                /*.nb12    =*/nb12_attn,
3353                /*.nb13    =*/nb13_attn,
3354                /*.nb21    =*/nb21_attn,
3355                /*.nb22    =*/nb22_attn,
3356                /*.nb23    =*/nb23_attn,
3357                /*.ne31    =*/ne31,
3358                /*.ne32    =*/ne32,
3359                /*.ne33    =*/ne33,
3360                /*.nb31    =*/nb31,
3361                /*.nb32    =*/nb32,
3362                /*.nb33    =*/nb33,
3363            };
3364
3365            auto pipeline0 = ggml_metal_library_get_pipeline_flash_attn_ext_pad(lib, op, has_mask, ncpsg);
3366
3367            ggml_metal_encoder_set_pipeline(enc, pipeline0);
3368            ggml_metal_encoder_set_bytes   (enc, &args0, sizeof(args0), 0);
3369            ggml_metal_encoder_set_buffer  (enc, bid_k,    1);
3370            ggml_metal_encoder_set_buffer  (enc, bid_v,    2);
3371            ggml_metal_encoder_set_buffer  (enc, bid_src3, 3);
3372            ggml_metal_encoder_set_buffer  (enc, bid_pad,  4);
3373
3374            assert(ne12 == ne22);
3375            assert(ne13 == ne23);
3376
3377            ggml_metal_encoder_dispatch_threadgroups(enc, ncpsg, std::max(ne12, ne32), std::max(ne13, ne33), 32, 1, 1);
3378
3379            need_sync = true;
3380        }
3381
3382        if (has_mask) {
3383            assert(ggml_metal_op_flash_attn_ext_extra_blk(op) != 0);
3384
3385            ggml_metal_kargs_flash_attn_ext_blk args0 = {
3386                /*.ne01 =*/ ne01,
3387                /*.ne30 =*/ ne30,
3388                /*.ne31 =*/ ne31,
3389                /*.ne32 =*/ ne32,
3390                /*.ne33 =*/ ne33,
3391                /*.nb31 =*/ nb31,
3392                /*.nb32 =*/ nb32,
3393                /*.nb33 =*/ nb33,
3394            };
3395
3396            auto pipeline0 = ggml_metal_library_get_pipeline_flash_attn_ext_blk(lib, op, nqptg, ncpsg);
3397
3398            ggml_metal_encoder_set_pipeline(enc, pipeline0);
3399            ggml_metal_encoder_set_bytes   (enc, &args0, sizeof(args0), 0);
3400            ggml_metal_encoder_set_buffer  (enc, bid_src3, 1);
3401            ggml_metal_encoder_set_buffer  (enc, bid_blk,  2);
3402
3403            const int32_t nblk1 = ((ne01 + nqptg - 1)/nqptg);
3404            const int32_t nblk0 = ((ne30 + ncpsg - 1)/ncpsg);
3405
3406            ggml_metal_encoder_dispatch_threadgroups(enc, nblk0, nblk1, ne32*ne33, 32, 1, 1);
3407
3408            need_sync = true;
3409        }
3410
3411        if (need_sync) {
3412            ggml_metal_op_concurrency_reset(ctx);
3413        }
3414
3415        const int is_q = !use_kv_f16 && ggml_is_quantized(op->src[1]->type) ? 1 : 0;
3416
3417        // 2*(2*ncpsg)
3418        // ncpsg soft_max values + ncpsg mask values
3419        //
3420        // 16*32*(nsg)
3421        // the shared memory needed for the simdgroups to load the KV cache
3422        // each thread loads (dequantizes) 16 head elements, there are 32 threads in th SG
3423        //
3424#define FATTN_SMEM(nsg) (GGML_PAD((nqptg*(ne00 + 2*GGML_PAD(ne20, 64) + 2*(2*ncpsg)) + is_q*(16*32*(nsg)))*(sizeof(float)/2), 16))
3425
3426        //int64_t nsgmax = 4;
3427        //
3428        //if (is_q) {
3429        //    nsgmax = 2;
3430        //    while (true) {
3431        //        const size_t smem = FATTN_SMEM(nsgmax);
3432        //        if (smem > props_dev->max_theadgroup_memory_size) {
3433        //            break;
3434        //        }
3435        //        nsgmax *= 2;
3436        //    }
3437        //    nsgmax /= 2;
3438        //}
3439
3440        // simdgroups per threadgroup (a.k.a. warps)
3441        //nsg = ne01 <= nqptg ? MAX(4, MIN(nsgmax, MIN(ne11/ncpsg, (int64_t) pipeline.maxTotalThreadsPerThreadgroup/32))) : 4;
3442        int32_t nsg = ne00 >= 512 ? 8 : 4;
3443
3444        const size_t smem = FATTN_SMEM(nsg);
3445
3446        const int32_t ns10 = nb11_attn/nb10_attn;
3447        const int32_t ns20 = nb21_attn/nb20_attn;
3448
3449        ggml_metal_kargs_flash_attn_ext args = {
3450            /*.ne01          =*/ ne01,
3451            /*.ne02          =*/ ne02,
3452            /*.ne03          =*/ ne03,
3453            /*.nb01          =*/ nb01,
3454            /*.nb02          =*/ nb02,
3455            /*.nb03          =*/ nb03,
3456            /*.ne11          =*/ ne11,
3457            /*.ne_12_2       =*/ ne12,
3458            /*.ne_12_3       =*/ ne13,
3459            /*.ns10          =*/ ns10,
3460            /*.nb11          =*/ nb11_attn,
3461            /*.nb12          =*/ nb12_attn,
3462            /*.nb13          =*/ nb13_attn,
3463            /*.ns20          =*/ ns20,
3464            /*.nb21          =*/ nb21_attn,
3465            /*.nb22          =*/ nb22_attn,
3466            /*.nb23          =*/ nb23_attn,
3467            /*.ne31          =*/ ne31,
3468            /*.ne32          =*/ ne32,
3469            /*.ne33          =*/ ne33,
3470            /*.nb31          =*/ nb31,
3471            /*.nb32          =*/ nb32,
3472            /*.nb33          =*/ nb33,
3473            /*.ne1           =*/ ne1,
3474            /*.ne2           =*/ ne2,
3475            /*.ne3           =*/ ne3,
3476            /*.scale         =*/ scale,
3477            /*.max_bias      =*/ max_bias,
3478            /*.m0            =*/ m0,
3479            /*.m1            =*/ m1,
3480            /*.n_head_log2   =*/ n_head_log2,
3481            /*.logit_softcap =*/ logit_softcap,
3482        };
3483
3484        auto pipeline = ggml_metal_library_get_pipeline_flash_attn_ext(lib, op, has_mask, has_sinks, has_bias, has_scap, has_kvpad, nsg, use_kv_f16, ns10, ns20);
3485
3486        ggml_metal_encoder_set_pipeline(enc, pipeline);
3487        ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
3488        ggml_metal_encoder_set_buffer  (enc, bid_src0, 1);
3489        ggml_metal_encoder_set_buffer  (enc, bid_k,    2);
3490        ggml_metal_encoder_set_buffer  (enc, bid_v,    3);
3491        ggml_metal_encoder_set_buffer  (enc, bid_src3, 4);
3492        ggml_metal_encoder_set_buffer  (enc, bid_src4, 5);
3493        ggml_metal_encoder_set_buffer  (enc, bid_pad,  6);
3494        ggml_metal_encoder_set_buffer  (enc, bid_blk,  7);
3495        ggml_metal_encoder_set_buffer  (enc, bid_dst,  8);
3496
3497        ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
3498
3499        ggml_metal_encoder_dispatch_threadgroups(enc, (ne01 + nqptg - 1)/nqptg, ne02, ne03, 32, nsg, 1);
3500#undef FATTN_SMEM
3501    } else {
3502        // half4x4 kernel
3503        // sparse: the index lists are per query row, so a threadgroup can share KV with Q == 1 only
3504        auto cfg = use_sparse
3505                ? ggml_metal_tuning::fa_vec_baseline_cfg((int) ne00, (int) ne20)
3506                : ggml_metal_tuning::fa_vec_pick(
3507                          props_dev->device_id,
3508                          props_dev->gpu_family,
3509                          (int) op->src[1]->type,
3510                          (int) ne00, (int) ne20,   // dk, dv (ne00 == dk for FA)
3511                          ne11, ne01);
3512
3513        int nqptg = cfg.Q; // queries per threadgroup
3514
3515        const int ncpsg = OP_FLASH_ATTN_EXT_VEC_NCPSG; // cache values per simdgroup !! sync with kernel template arguments !!
3516        const int nhptg = 1;                           // heads per threadgroup
3517
3518        GGML_ASSERT(nqptg <= 32);
3519        GGML_ASSERT(nqptg == 1 || nqptg == 2 || nqptg == 4);  // only instantiated Q values
3520        GGML_ASSERT(ncpsg  % 32 == 0);
3521
3522        bool need_sync = false;
3523
3524        const bool has_kvpad = !use_sparse && ne11 % ncpsg != 0;
3525
3526        if (use_sparse) {
3527            assert(ggml_metal_op_flash_attn_ext_extra_idx(op) != 0);
3528
3529            GGML_ASSERT(ne30 == ne11);
3530
3531            ggml_metal_kargs_flash_attn_ext_vec_idx args0 = {
3532                /*.ne30              =*/ ne30,
3533                /*.ne31              =*/ ne31,
3534                /*.ne32              =*/ ne32,
3535                /*.ne33              =*/ ne33,
3536                /*.nb31              =*/ nb31,
3537                /*.nb32              =*/ nb32,
3538                /*.nb33              =*/ nb33,
3539                /*.n_kv_max          =*/ n_kv_max_sparse,
3540                /*.n_kv_max_padded   =*/ n_kv_max_padded,
3541            };
3542
3543            auto pipeline0 = ggml_metal_library_get_pipeline_flash_attn_ext_vec_idx(lib, op);
3544
3545            ggml_metal_encoder_set_pipeline(enc, pipeline0);
3546            ggml_metal_encoder_set_bytes   (enc, &args0, sizeof(args0), 0);
3547            ggml_metal_encoder_set_buffer  (enc, bid_src3, 1);
3548            ggml_metal_encoder_set_buffer  (enc, bid_idx,  2);
3549
3550            int nth = std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline0), 256);
3551            nth = std::max(32, (nth/32)*32);
3552
3553            ggml_metal_encoder_dispatch_threadgroups(enc, ne31, ne32, ne33, nth, 1, 1);
3554
3555            need_sync = true;
3556        }
3557
3558        if (has_kvpad) {
3559            assert(ggml_metal_op_flash_attn_ext_extra_pad(op) != 0);
3560
3561            ggml_metal_kargs_flash_attn_ext_pad args0 = {
3562                /*.ne11    =*/ne11,
3563                /*.ne_12_2 =*/ne12,
3564                /*.ne_12_3 =*/ne13,
3565                /*.nb11    =*/nb11_attn,
3566                /*.nb12    =*/nb12_attn,
3567                /*.nb13    =*/nb13_attn,
3568                /*.nb21    =*/nb21_attn,
3569                /*.nb22    =*/nb22_attn,
3570                /*.nb23    =*/nb23_attn,
3571                /*.ne31    =*/ne31,
3572                /*.ne32    =*/ne32,
3573                /*.ne33    =*/ne33,
3574                /*.nb31    =*/nb31,
3575                /*.nb32    =*/nb32,
3576                /*.nb33    =*/nb33,
3577            };
3578
3579            auto pipeline0 = ggml_metal_library_get_pipeline_flash_attn_ext_pad(lib, op, has_mask, ncpsg);
3580
3581            ggml_metal_encoder_set_pipeline(enc, pipeline0);
3582            ggml_metal_encoder_set_bytes   (enc, &args0, sizeof(args0), 0);
3583            ggml_metal_encoder_set_buffer  (enc, bid_k,    1);
3584            ggml_metal_encoder_set_buffer  (enc, bid_v,    2);
3585            ggml_metal_encoder_set_buffer  (enc, bid_src3, 3);
3586            ggml_metal_encoder_set_buffer  (enc, bid_pad,  4);
3587
3588            assert(ne12 == ne22);
3589            assert(ne13 == ne23);
3590
3591            ggml_metal_encoder_dispatch_threadgroups(enc, ncpsg, std::max(ne12, ne32), std::max(ne13, ne33), 32, 1, 1);
3592
3593            need_sync = true;
3594        }
3595
3596        if (need_sync) {
3597            ggml_metal_op_concurrency_reset(ctx);
3598        }
3599
3600        // note: for simplicity assume the K is larger or equal than V
3601        GGML_ASSERT(ne10 >= ne20);
3602
3603        // ne00 + 2*ncpsg*(nsg)
3604        // for each query, we load it as f16 in shared memory (ne00)
3605        // and store the soft_max values and the mask
3606        //
3607        // ne20*(nsg)
3608        // each simdgroup has a full f32 head vector in shared mem to accumulate results
3609        //
3610#define FATTN_SMEM(nsg) (GGML_PAD(((GGML_PAD(ne00, 128) + 4*ncpsg + 2*GGML_PAD(ne20, 128))*(nsg)*nqptg)*(sizeof(float)/2), 16))
3611
3612        int64_t nsg = 1;
3613
3614        // workgroups
3615        // each workgroup handles nsg*nkpsg cache values
3616        int32_t nwg = 1;
3617        if (use_sparse) {
3618            if (ne01 > 32) {
3619                // large sparse batch
3620                nwg = 1;
3621                nsg = 1;
3622                if (n_kv_max_padded == 640) {
3623                    nsg = 4; // 640 % (4*32) == 0
3624                } else {
3625                    while (2*nwg*nsg*ncpsg < n_kv_max_padded && nsg < 4) {
3626                        nsg *= 2;
3627                    }
3628                }
3629            } else {
3630                // small sparse batch
3631                nwg = 32;
3632                nsg = 1;
3633                while (2*nwg*nsg*ncpsg < n_kv_max_padded && nsg < 4) {
3634                    nsg *= 2;
3635                }
3636            }
3637        } else {
3638            nwg = 32;
3639            nsg = 1;
3640            while (2*nwg*nsg*ncpsg < ne11 && nsg < 4) {
3641                nsg *= 2;
3642            }
3643        }
3644
3645        // fall back to baseline (Q=1) if the tuned config exceeds threadgroup memory
3646        if ((size_t) FATTN_SMEM(nsg) > props_dev->max_theadgroup_memory_size) {
3647            cfg   = ggml_metal_tuning::fa_vec_baseline_cfg((int) ne00, (int) ne20);
3648            nqptg = cfg.Q;  // = 1
3649        }
3650
3651        const int32_t ns10 = nb11_attn/nb10_attn;
3652        const int32_t ns20 = nb21_attn/nb20_attn;
3653
3654        ggml_metal_kargs_flash_attn_ext_vec args = {
3655            /*.ne01          =*/ ne01,
3656            /*.ne02          =*/ ne02,
3657            /*.ne03          =*/ ne03,
3658            /*.nb01          =*/ nb01,
3659            /*.nb02          =*/ nb02,
3660            /*.nb03          =*/ nb03,
3661            /*.ne11          =*/ use_sparse ? n_kv_max_padded : ne11,
3662            /*.ne_12_2       =*/ ne12,
3663            /*.ne_12_3       =*/ ne13,
3664            /*.ns10          =*/ ns10,
3665            /*.nb11          =*/ nb11_attn,
3666            /*.nb12          =*/ nb12_attn,
3667            /*.nb13          =*/ nb13_attn,
3668            /*.ns20          =*/ ns20,
3669            /*.nb21          =*/ nb21_attn,
3670            /*.nb22          =*/ nb22_attn,
3671            /*.nb23          =*/ nb23_attn,
3672            /*.ne31          =*/ ne31,
3673            /*.ne32          =*/ ne32,
3674            /*.ne33          =*/ ne33,
3675            /*.nb31          =*/ nb31,
3676            /*.nb32          =*/ nb32,
3677            /*.nb33          =*/ nb33,
3678            /*.ne1           =*/ ne1,
3679            /*.ne2           =*/ ne2,
3680            /*.ne3           =*/ ne3,
3681            /*.scale         =*/ scale,
3682            /*.max_bias      =*/ max_bias,
3683            /*.m0            =*/ m0,
3684            /*.m1            =*/ m1,
3685            /*.n_head_log2   =*/ n_head_log2,
3686            /*.logit_softcap =*/ logit_softcap,
3687            /*.n_kv_max_padded =*/ n_kv_max_padded,
3688        };
3689
3690        auto pipeline = ggml_metal_library_get_pipeline_flash_attn_ext_vec(lib, op, has_mask, has_sinks, has_bias, has_scap, has_kvpad, use_sparse, nqptg, cfg.NE, nsg, nwg, use_kv_f16, ns10, ns20);
3691
3692        GGML_ASSERT(nsg*32 <= ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
3693
3694        ggml_metal_encoder_set_pipeline(enc, pipeline);
3695        ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
3696        ggml_metal_encoder_set_buffer  (enc, bid_src0, 1);
3697        ggml_metal_encoder_set_buffer  (enc, bid_k,    2);
3698        ggml_metal_encoder_set_buffer  (enc, bid_v,    3);
3699        ggml_metal_encoder_set_buffer  (enc, bid_src3, 4);
3700        ggml_metal_encoder_set_buffer  (enc, bid_src4, 5);
3701        ggml_metal_encoder_set_buffer  (enc, use_sparse ? bid_idx : bid_src0, 8);
3702
3703        const size_t smem = FATTN_SMEM(nsg);
3704
3705        //printf("smem: %zu, max: %zu, nsg = %d, nsgmax = %d\n", smem, props_dev->max_theadgroup_memory_size, (int) nsg, (int) nsgmax);
3706        GGML_ASSERT(smem <= props_dev->max_theadgroup_memory_size);
3707
3708        if (nwg == 1) {
3709            // using 1 workgroup -> write the result directly into dst
3710            ggml_metal_encoder_set_buffer(enc, bid_pad, 6);
3711            ggml_metal_encoder_set_buffer(enc, bid_dst, 7);
3712
3713            ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
3714
3715            ggml_metal_encoder_dispatch_threadgroups(enc, (ne01 + nqptg - 1)/nqptg, (ne02 + nhptg - 1)/nhptg, ne03*nwg, 32, nsg, 1);
3716        } else {
3717            // sanity checks
3718            assert(ggml_metal_op_flash_attn_ext_extra_tmp(op) != 0);
3719
3720            GGML_ASSERT(ne01*ne02*ne03 == ne1*ne2*ne3);
3721            GGML_ASSERT((uint64_t)ne1*ne2*ne3 <= (1u << 31));
3722
3723            // write the results from each workgroup into a temp buffer
3724            ggml_metal_encoder_set_buffer(enc, bid_pad, 6);
3725            ggml_metal_encoder_set_buffer(enc, bid_tmp, 7);
3726
3727            ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
3728            ggml_metal_encoder_dispatch_threadgroups(enc, (ne01 + nqptg - 1)/nqptg, (ne02 + nhptg - 1)/nhptg, ne03*nwg, 32, nsg, 1);
3729
3730            // sync the 2 kernels
3731            ggml_metal_op_concurrency_reset(ctx);
3732
3733            // reduce the results from the workgroups
3734            {
3735                const int32_t nrows = ne1*ne2*ne3;
3736
3737                ggml_metal_kargs_flash_attn_ext_vec_reduce args0 = {
3738                    nrows,
3739                };
3740
3741                auto pipeline0 = ggml_metal_library_get_pipeline_flash_attn_ext_vec_reduce(lib, op, ne20, nwg);
3742
3743                ggml_metal_encoder_set_pipeline(enc, pipeline0);
3744                ggml_metal_encoder_set_bytes   (enc, &args0, sizeof(args0), 0);
3745                ggml_metal_encoder_set_buffer  (enc, bid_tmp, 1);
3746                ggml_metal_encoder_set_buffer  (enc, bid_dst, 2);
3747
3748                ggml_metal_encoder_dispatch_threadgroups(enc, nrows, 1, 1, 32*nwg, 1, 1);
3749            }
3750        }
3751#undef FATTN_SMEM
3752    }
3753
3754    return 1;
3755}
3756
3757int ggml_metal_op_bin(ggml_metal_op_t ctx, int idx) {
3758    int n_fuse = 1;
3759    const ggml_metal_fusion * fusion = nullptr;
3760
3761    if (ctx->use_fusion()) {
3762        int n = 1;
3763        fusion = ctx->can_fuse(idx, GGML_METAL_FUSION_FULL, &n);
3764        n_fuse = n;
3765
3766        // snake activation autofuse: mul -> sin -> sqr -> mul -> add
3767        if (fusion && fusion->id == GGML_METAL_FUSION_SNAKE) {
3768            ctx->count_fusions(fusion);
3769            return ggml_metal_op_snake_fused(ctx, idx);
3770        }
3771    }
3772
3773    ggml_tensor * op = ctx->node(idx);
3774
3775    ggml_metal_library_t lib = ctx->lib;
3776    ggml_metal_encoder_t enc = ctx->enc;
3777
3778    const bool use_fusion = ctx->use_fusion();
3779
3780    const int debug_fusion = ggml_metal_fusion_info_debug(ctx->finfo);
3781
3782    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
3783    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
3784    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
3785    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
3786    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
3787    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
3788
3789    GGML_ASSERT(ggml_is_contiguous_rows(op->src[0]));
3790    GGML_ASSERT(ggml_is_contiguous_rows(op->src[1]));
3791
3792    ggml_metal_buffer_id bid_src0 = ggml_metal_get_buffer_id(op->src[0]);
3793    ggml_metal_buffer_id bid_src1 = ggml_metal_get_buffer_id(op->src[1]);
3794    ggml_metal_buffer_id bid_dst  = ggml_metal_get_buffer_id(op);
3795
3796    ggml_metal_kargs_bin args = {
3797        /*.ne00 =*/ ne00,
3798        /*.ne01 =*/ ne01,
3799        /*.ne02 =*/ ne02,
3800        /*.ne03 =*/ ne03,
3801        /*.nb00 =*/ nb00,
3802        /*.nb01 =*/ nb01,
3803        /*.nb02 =*/ nb02,
3804        /*.nb03 =*/ nb03,
3805        /*.ne10 =*/ ne10,
3806        /*.ne11 =*/ ne11,
3807        /*.ne12 =*/ ne12,
3808        /*.ne13 =*/ ne13,
3809        /*.nb10 =*/ nb10,
3810        /*.nb11 =*/ nb11,
3811        /*.nb12 =*/ nb12,
3812        /*.nb13 =*/ nb13,
3813        /*.ne0  =*/ ne0,
3814        /*.ne1  =*/ ne1,
3815        /*.ne2  =*/ ne2,
3816        /*.ne3  =*/ ne3,
3817        /*.nb0  =*/ nb0,
3818        /*.nb1  =*/ nb1,
3819        /*.nb2  =*/ nb2,
3820        /*.nb3  =*/ nb3,
3821        /*.offs =*/ 0,
3822        /*.o1   =*/ { bid_src1.offs },
3823    };
3824
3825    // c[0] = add(a,    b[0])
3826    // c[1] = add(c[0], b[1])
3827    // c[2] = add(c[1], b[2])
3828    // ...
3829    if (use_fusion && fusion && fusion->id == GGML_METAL_FUSION_ADD_CHAIN) {
3830        // the offsets of the fused addends are relative to the start of the src1 buffer
3831        for (int i = 1; i < n_fuse; i++) {
3832            args.o1[i] = ggml_metal_get_buffer_id(ctx->node(idx + i)->src[1]).offs;
3833        }
3834
3835        ctx->count_fusions(fusion);
3836
3837        if (debug_fusion > 1) {
3838            GGML_LOG_DEBUG("%s: fuse: ADD x %d\n", __func__, n_fuse);
3839        }
3840    }
3841
3842    // the offsets of src1 and all fused buffers are relative to the start of the src1 buffer
3843    bid_src1.offs = 0;
3844
3845    struct ggml_metal_pipeline_with_params pipeline;
3846
3847    pipeline = ggml_metal_library_get_pipeline_bin(lib, op, n_fuse);
3848
3849    if (n_fuse > 1) {
3850        bid_dst = ggml_metal_get_buffer_id(ctx->node(idx + n_fuse - 1));
3851
3852        for (int i = 1; i < n_fuse; ++i) {
3853            if (!ggml_metal_op_concurrency_check(ctx, ctx->node(idx + i))) {
3854                ggml_metal_op_concurrency_reset(ctx);
3855
3856                break;
3857            }
3858        }
3859    }
3860
3861    if (pipeline.c4) {
3862        args.ne00 = ne00/4;
3863        args.ne10 = ne10/4;
3864        args.ne0  = ne0/4;
3865    }
3866
3867    ggml_metal_encoder_set_pipeline(enc, pipeline);
3868    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
3869    ggml_metal_encoder_set_buffer  (enc, bid_src0, 1);
3870    ggml_metal_encoder_set_buffer  (enc, bid_src1, 2);
3871    ggml_metal_encoder_set_buffer  (enc, bid_dst,  3);
3872
3873    if (pipeline.cnt) {
3874        ggml_metal_encoder_dispatch_threadgroups(enc, args.ne0, ggml_nrows(op), 1, 1, 1, 1);
3875    } else {
3876        const int nth_max = MIN(256, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
3877
3878        int nth = 1;
3879
3880        while (2*nth < args.ne0 && nth < nth_max) {
3881            nth *= 2;
3882        }
3883
3884        ggml_metal_encoder_dispatch_threadgroups(enc, ne01, ne02, ne03, nth, 1, 1);
3885    }
3886
3887    return n_fuse;
3888}
3889
3890int ggml_metal_op_silu_back(ggml_metal_op_t ctx, int idx) {
3891    ggml_tensor * op = ctx->node(idx);
3892
3893    ggml_metal_library_t lib = ctx->lib;
3894    ggml_metal_encoder_t enc = ctx->enc;
3895
3896    auto pipeline = ggml_metal_library_get_pipeline_silu_back(lib, op);
3897
3898    const int64_t ne = ggml_nelements(op);
3899
3900    ggml_metal_kargs_silu_back args = {
3901        /*.ne =*/ ne,
3902    };
3903
3904    int arg_idx{0};
3905
3906    ggml_metal_encoder_set_pipeline(enc, pipeline);
3907    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), arg_idx++);
3908    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), arg_idx++);
3909    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), arg_idx++);
3910    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op), arg_idx++);
3911
3912    const int nth = std::min<int64_t>(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline), ne);
3913    const int64_t n = (ne + nth - 1) / nth;
3914
3915    ggml_metal_encoder_dispatch_threadgroups(enc, n, 1, 1, nth, 1, 1);
3916
3917    return 1;
3918}
3919
3920int ggml_metal_op_l2_norm(ggml_metal_op_t ctx, int idx) {
3921    ggml_tensor * op = ctx->node(idx);
3922
3923    ggml_metal_library_t lib = ctx->lib;
3924    ggml_metal_encoder_t enc = ctx->enc;
3925
3926    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
3927    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
3928    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
3929    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
3930
3931    GGML_ASSERT(ggml_is_contiguous_rows(op->src[0]));
3932
3933    ggml_metal_buffer_id bid_src0 = ggml_metal_get_buffer_id(op->src[0]);
3934    ggml_metal_buffer_id bid_dst  = ggml_metal_get_buffer_id(op);
3935
3936    float eps;
3937    memcpy(&eps, op->op_params, sizeof(float));
3938
3939    ggml_metal_kargs_l2_norm args = {
3940        /*.ne00  =*/ ne00,
3941        /*.ne01  =*/ ne01,
3942        /*.ne02  =*/ ne02,
3943        /*.ne03  =*/ ne03,
3944        /*.nb00  =*/ nb00,
3945        /*.nb01  =*/ nb01,
3946        /*.nb02  =*/ nb02,
3947        /*.nb03  =*/ nb03,
3948        /*.ne0   =*/ ne0,
3949        /*.ne1   =*/ ne1,
3950        /*.ne2   =*/ ne2,
3951        /*.ne3   =*/ ne3,
3952        /*.nb0   =*/ nb0,
3953        /*.nb1   =*/ nb1,
3954        /*.nb2   =*/ nb2,
3955        /*.nb3   =*/ nb3,
3956        /*.eps   =*/ eps,
3957    };
3958
3959    auto pipeline = ggml_metal_library_get_pipeline_l2_norm(lib, op);
3960
3961    if (pipeline.c4) {
3962        args.ne00 = ne00/4;
3963        args.ne0  = ne0/4;
3964    }
3965
3966    int nth = 32; // SIMD width
3967
3968    while (nth < ne00 && nth < ggml_metal_pipeline_max_theads_per_threadgroup(pipeline)) {
3969        nth *= 2;
3970    }
3971
3972    nth = std::min(nth, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
3973
3974    const size_t smem = pipeline.smem;
3975
3976    ggml_metal_encoder_set_pipeline(enc, pipeline);
3977    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
3978    ggml_metal_encoder_set_buffer  (enc, bid_src0, 1);
3979    ggml_metal_encoder_set_buffer  (enc, bid_dst,  2);
3980
3981    ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
3982
3983    ggml_metal_encoder_dispatch_threadgroups(enc, ne01, ne02, ne03, nth, 1, 1);
3984
3985    return 1;
3986}
3987
3988int ggml_metal_op_group_norm(ggml_metal_op_t ctx, int idx) {
3989    ggml_tensor * op = ctx->node(idx);
3990
3991    ggml_metal_library_t lib = ctx->lib;
3992    ggml_metal_encoder_t enc = ctx->enc;
3993
3994    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
3995    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
3996    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
3997    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
3998
3999    const int32_t ngrp = ((const int32_t *) op->op_params)[0];
4000
4001    float eps;
4002    memcpy(&eps, op->op_params + 1, sizeof(float));
4003
4004    ggml_metal_kargs_group_norm args = {
4005        /*.ne00 =*/ ne00,
4006        /*.ne01 =*/ ne01,
4007        /*.ne02 =*/ ne02,
4008        /*.nb00 =*/ nb00,
4009        /*.nb01 =*/ nb01,
4010        /*.nb02 =*/ nb02,
4011        /*.ngrp =*/ ngrp,
4012        /*.eps  =*/ eps,
4013    };
4014
4015    auto pipeline = ggml_metal_library_get_pipeline_group_norm(lib, op);
4016
4017    int nth = 32; // SIMD width
4018    //while (nth < ne00/4 && nth < ggml_metal_pipeline_max_theads_per_threadgroup(pipeline)) {
4019    //    nth *= 2;
4020    //}
4021
4022    //nth = std::min(nth, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
4023    //nth = std::min(nth, ne00/4);
4024
4025    const size_t smem = pipeline.smem;
4026
4027    ggml_metal_encoder_set_pipeline(enc, pipeline);
4028    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4029    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
4030    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
4031
4032    ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
4033
4034    ggml_metal_encoder_dispatch_threadgroups(enc, ngrp, 1, 1, nth, 1, 1);
4035
4036    return 1;
4037}
4038
4039int ggml_metal_op_norm(ggml_metal_op_t ctx, int idx) {
4040    ggml_tensor * op = ctx->node(idx);
4041
4042    ggml_metal_library_t lib = ctx->lib;
4043    ggml_metal_encoder_t enc = ctx->enc;
4044
4045    const bool use_fusion = ctx->use_fusion();
4046
4047    const int debug_fusion = ggml_metal_fusion_info_debug(ctx->finfo);
4048
4049    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
4050    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
4051    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
4052    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
4053
4054    float eps;
4055    memcpy(&eps, op->op_params, sizeof(float));
4056
4057    ggml_metal_buffer_id bid_src0 = ggml_metal_get_buffer_id(op->src[0]);
4058    ggml_metal_buffer_id bid_dst  = ggml_metal_get_buffer_id(op);
4059
4060    ggml_metal_kargs_norm args = {
4061        /*.ne00   =*/ ne00,
4062        /*.ne00_t =*/ ne00 % 4 == 0 ? ne00/4 : ne00,
4063        /*.nb1    =*/ nb1,
4064        /*.nb2    =*/ nb2,
4065        /*.nb3    =*/ nb3,
4066        /*.eps    =*/ eps,
4067        /*.nef1   =*/ { ne01 },
4068        /*.nef2   =*/ { ne02 },
4069        /*.nef3   =*/ { ne03 },
4070        /*.nbf1   =*/ { nb01 },
4071        /*.nbf2   =*/ { nb02 },
4072        /*.nbf3   =*/ { nb03 },
4073    };
4074
4075    int n_fuse = 1;
4076
4077    ggml_metal_buffer_id bid_fuse[2] = { bid_src0, bid_src0 };
4078
4079    // d[0] = norm(a)
4080    // d[1] = mul(d[0], b)
4081    // d[2] = add(d[1], c)
4082    if (use_fusion) {
4083        int n = 1;
4084        const ggml_metal_fusion * fusion = ctx->can_fuse(idx, GGML_METAL_FUSION_FULL, &n);
4085
4086        if (fusion && (fusion->id == GGML_METAL_FUSION_NORM_MUL || fusion->id == GGML_METAL_FUSION_NORM_MUL_ADD)) {
4087            n_fuse = n;
4088
4089            ctx->count_fusions(fusion);
4090
4091            for (int i = 1; i < n_fuse; i++) {
4092                const ggml_tensor * fn = ctx->node(idx + i);
4093
4094                bid_fuse[i - 1] = ggml_metal_get_buffer_id(fn->src[1]);
4095
4096                args.nef1[i] = fn->src[1]->ne[1];
4097                args.nef2[i] = fn->src[1]->ne[2];
4098                args.nef3[i] = fn->src[1]->ne[3];
4099
4100                args.nbf1[i] = fn->src[1]->nb[1];
4101                args.nbf2[i] = fn->src[1]->nb[2];
4102                args.nbf3[i] = fn->src[1]->nb[3];
4103            }
4104
4105            if (debug_fusion > 1) {
4106                if (n_fuse == 2) {
4107                    GGML_LOG_DEBUG("%s: fuse: %s + MUL\n", __func__, ggml_op_name(op->op));
4108                }
4109                if (n_fuse == 3) {
4110                    GGML_LOG_DEBUG("%s: fuse: %s + MUL + ADD\n", __func__, ggml_op_name(op->op));
4111                }
4112            }
4113        }
4114    }
4115
4116    if (n_fuse > 1) {
4117        bid_dst = ggml_metal_get_buffer_id(ctx->node(idx + n_fuse - 1));
4118
4119        for (int i = 1; i < n_fuse; ++i) {
4120            if (!ggml_metal_op_concurrency_check(ctx, ctx->node(idx + i))) {
4121                ggml_metal_op_concurrency_reset(ctx);
4122
4123                break;
4124            }
4125        }
4126    }
4127
4128    auto pipeline = ggml_metal_library_get_pipeline_norm(lib, op, n_fuse);
4129
4130    int nth = 32; // SIMD width
4131
4132    while (nth < args.ne00_t && nth < ggml_metal_pipeline_max_theads_per_threadgroup(pipeline)) {
4133        nth *= 2;
4134    }
4135
4136    nth = std::min(nth, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
4137    nth = std::min(nth, (args.ne00_t + 31)/32*32);
4138
4139    const size_t smem = pipeline.smem;
4140
4141    ggml_metal_encoder_set_pipeline(enc, pipeline);
4142    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4143    ggml_metal_encoder_set_buffer  (enc, bid_src0,    1);
4144    ggml_metal_encoder_set_buffer  (enc, bid_fuse[0], 2);
4145    ggml_metal_encoder_set_buffer  (enc, bid_fuse[1], 3);
4146    ggml_metal_encoder_set_buffer  (enc, bid_dst,     4);
4147
4148    ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
4149
4150    ggml_metal_encoder_dispatch_threadgroups(enc, ne01, ne02, ne03, nth, 1, 1);
4151
4152    return n_fuse;
4153}
4154
4155int ggml_metal_op_rope(ggml_metal_op_t ctx, int idx) {
4156    ggml_tensor * op = ctx->node(idx);
4157
4158    ggml_metal_library_t lib = ctx->lib;
4159    ggml_metal_encoder_t enc = ctx->enc;
4160
4161    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
4162    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
4163    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
4164    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
4165    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
4166    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
4167
4168    // make sure we have one or more position id(ne10) per token(ne02)
4169    GGML_ASSERT(ne10 % ne02 == 0);
4170    GGML_ASSERT(ne10 >= ne02);
4171
4172    const int nth = std::min(1024, ne00);
4173
4174    const int n_past     = ((const int32_t *) op->op_params)[0];
4175    const int n_dims     = ((const int32_t *) op->op_params)[1];
4176  //const int mode       = ((const int32_t *) op->op_params)[2];
4177    // skip 3, n_ctx, used in GLM RoPE, unimplemented in metal
4178    const int n_ctx_orig = ((const int32_t *) op->op_params)[4];
4179
4180    float freq_base;
4181    float freq_scale;
4182    float ext_factor;
4183    float attn_factor;
4184    float beta_fast;
4185    float beta_slow;
4186
4187    memcpy(&freq_base,   (const int32_t *) op->op_params +  5, sizeof(float));
4188    memcpy(&freq_scale,  (const int32_t *) op->op_params +  6, sizeof(float));
4189    memcpy(&ext_factor,  (const int32_t *) op->op_params +  7, sizeof(float));
4190    memcpy(&attn_factor, (const int32_t *) op->op_params +  8, sizeof(float));
4191    memcpy(&beta_fast,   (const int32_t *) op->op_params +  9, sizeof(float));
4192    memcpy(&beta_slow,   (const int32_t *) op->op_params + 10, sizeof(float));
4193
4194    // mrope
4195    const int sect_0 = ((const int32_t *) op->op_params)[11];
4196    const int sect_1 = ((const int32_t *) op->op_params)[12];
4197    const int sect_2 = ((const int32_t *) op->op_params)[13];
4198    const int sect_3 = ((const int32_t *) op->op_params)[14];
4199
4200    const int n_offs = ((const int32_t *) op->op_params)[15];
4201
4202    // when dst aliases src0, the channels outside the rotated window already hold the correct data
4203    const bool inplace = op->data == op->src[0]->data;
4204
4205    ggml_metal_kargs_rope args = {
4206        /*.ne00        =*/ ne00,
4207        /*.ne01        =*/ ne01,
4208        /*.ne02        =*/ ne02,
4209        /*.ne03        =*/ ne03,
4210        /*.nb00        =*/ nb00,
4211        /*.nb01        =*/ nb01,
4212        /*.nb02        =*/ nb02,
4213        /*.nb03        =*/ nb03,
4214        /*.ne0         =*/ ne0,
4215        /*.ne1         =*/ ne1,
4216        /*.ne2         =*/ ne2,
4217        /*.ne3         =*/ ne3,
4218        /*.nb0         =*/ nb0,
4219        /*.nb1         =*/ nb1,
4220        /*.nb2         =*/ nb2,
4221        /*.nb3         =*/ nb3,
4222        /*.n_past      =*/ n_past,
4223        /*.n_dims      =*/ n_dims,
4224        /*.n_offs      =*/ n_offs,
4225        /*.n_ctx_orig  =*/ n_ctx_orig,
4226        /*.freq_base   =*/ freq_base,
4227        /*.freq_scale  =*/ freq_scale,
4228        /*.ext_factor  =*/ ext_factor,
4229        /*.attn_factor =*/ attn_factor,
4230        /*.beta_fast   =*/ beta_fast,
4231        /*.beta_slow   =*/ beta_slow,
4232        /* sect_0      =*/ sect_0,
4233        /* sect_1      =*/ sect_1,
4234        /* sect_2      =*/ sect_2,
4235        /* sect_3      =*/ sect_3,
4236        /* src2        =*/ op->src[2] != nullptr,
4237        /* inplace     =*/ inplace,
4238    };
4239
4240    auto pipeline = ggml_metal_library_get_pipeline_rope(lib, op);
4241
4242    ggml_metal_encoder_set_pipeline(enc, pipeline);
4243    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4244    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
4245    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
4246    if (op->src[2]) {
4247        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[2]), 3);
4248    } else {
4249        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 3);
4250    }
4251    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         4);
4252
4253    ggml_metal_encoder_dispatch_threadgroups(enc, ne01, ne02, ne03, nth, 1, 1);
4254
4255    return 1;
4256}
4257
4258int ggml_metal_op_im2col(ggml_metal_op_t ctx, int idx) {
4259    ggml_tensor * op = ctx->node(idx);
4260
4261    ggml_metal_library_t lib = ctx->lib;
4262    ggml_metal_encoder_t enc = ctx->enc;
4263
4264    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
4265    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
4266    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
4267    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
4268
4269    const int32_t s0 = ((const int32_t *)(op->op_params))[0];
4270    const int32_t s1 = ((const int32_t *)(op->op_params))[1];
4271    const int32_t p0 = ((const int32_t *)(op->op_params))[2];
4272    const int32_t p1 = ((const int32_t *)(op->op_params))[3];
4273    const int32_t d0 = ((const int32_t *)(op->op_params))[4];
4274    const int32_t d1 = ((const int32_t *)(op->op_params))[5];
4275
4276    const bool is_2D = ((const int32_t *)(op->op_params))[6] == 1;
4277
4278    const int32_t N  = op->src[1]->ne[is_2D ? 3 : 2];
4279    const int32_t IC = op->src[1]->ne[is_2D ? 2 : 1];
4280    const int32_t IH = is_2D ? op->src[1]->ne[1] : 1;
4281    const int32_t IW =         op->src[1]->ne[0];
4282
4283    const int32_t KH = is_2D ? op->src[0]->ne[1] : 1;
4284    const int32_t KW =         op->src[0]->ne[0];
4285
4286    const int32_t OH = is_2D ? op->ne[2] : 1;
4287    const int32_t OW =         op->ne[1];
4288
4289    const int32_t CHW = IC * KH * KW;
4290
4291    const uint64_t ofs0 = op->src[1]->nb[is_2D ? 3 : 2] / 4;
4292    const uint64_t ofs1 = op->src[1]->nb[is_2D ? 2 : 1] / 4;
4293
4294    ggml_metal_kargs_im2col args = {
4295        /*.ofs0 =*/ ofs0,
4296        /*.ofs1 =*/ ofs1,
4297        /*.IW   =*/ IW,
4298        /*.IH   =*/ IH,
4299        /*.CHW  =*/ CHW,
4300        /*.s0   =*/ s0,
4301        /*.s1   =*/ s1,
4302        /*.p0   =*/ p0,
4303        /*.p1   =*/ p1,
4304        /*.d0   =*/ d0,
4305        /*.d1   =*/ d1,
4306        /*.N    =*/ N,
4307        /*.KH   =*/ KH,
4308        /*.KW   =*/ KW,
4309        /*.KHW  =*/ KH * KW,
4310    };
4311
4312    auto pipeline = ggml_metal_library_get_pipeline_im2col(lib, op);
4313
4314    if (KH*KW <= ggml_metal_pipeline_max_theads_per_threadgroup(pipeline)) {
4315        const uint64_t ntptg0 = std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline)/(KH*KW), N);
4316
4317        ggml_metal_encoder_set_pipeline(enc, pipeline);
4318        ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4319        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 1);
4320        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
4321
4322        ggml_metal_encoder_dispatch_threadgroups(enc, IC, OH, OW, ntptg0, KH, KW);
4323    } else {
4324        const uint64_t n_threads = std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline), N);
4325        const int64_t  quotient  = N / n_threads + (N % n_threads > 0 ? 1 : 0);
4326
4327        ggml_metal_encoder_set_pipeline(enc, pipeline);
4328        ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4329        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 1);
4330        ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
4331
4332        ggml_metal_encoder_dispatch_threadgroups(enc, quotient * CHW, OH, OW, n_threads, 1, 1);
4333    }
4334
4335    return 1;
4336}
4337
4338int ggml_metal_op_conv_2d(ggml_metal_op_t ctx, int idx) {
4339    ggml_tensor * op = ctx->node(idx);
4340
4341    ggml_metal_library_t lib = ctx->lib;
4342    ggml_metal_encoder_t enc = ctx->enc;
4343
4344    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
4345    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
4346    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
4347    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
4348    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
4349    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
4350
4351    GGML_ASSERT(ggml_is_contiguous(op->src[0]));
4352    GGML_ASSERT(op->src[1]->type == GGML_TYPE_F32);
4353    GGML_ASSERT(op->type == GGML_TYPE_F32);
4354    GGML_ASSERT(op->src[0]->type == GGML_TYPE_F16 || op->src[0]->type == GGML_TYPE_F32);
4355
4356    const int32_t s0 = ((const int32_t *) op->op_params)[0];
4357    const int32_t s1 = ((const int32_t *) op->op_params)[1];
4358    const int32_t p0 = ((const int32_t *) op->op_params)[2];
4359    const int32_t p1 = ((const int32_t *) op->op_params)[3];
4360    const int32_t d0 = ((const int32_t *) op->op_params)[4];
4361    const int32_t d1 = ((const int32_t *) op->op_params)[5];
4362
4363    ggml_metal_kargs_conv_2d args = {
4364        /*.nb00 =*/ nb00,
4365        /*.nb01 =*/ nb01,
4366        /*.nb02 =*/ nb02,
4367        /*.nb03 =*/ nb03,
4368        /*.nb10 =*/ nb10,
4369        /*.nb11 =*/ nb11,
4370        /*.nb12 =*/ nb12,
4371        /*.nb13 =*/ nb13,
4372        /*.nb0  =*/ nb0,
4373        /*.nb1  =*/ nb1,
4374        /*.nb2  =*/ nb2,
4375        /*.nb3  =*/ nb3,
4376        /*.IW   =*/ ne10,
4377        /*.IH   =*/ ne11,
4378        /*.KW   =*/ ne00,
4379        /*.KH   =*/ ne01,
4380        /*.IC   =*/ ne02,
4381        /*.OC   =*/ ne03,
4382        /*.OW   =*/ ne0,
4383        /*.OH   =*/ ne1,
4384        /*.N    =*/ ne3,
4385        /*.s0   =*/ s0,
4386        /*.s1   =*/ s1,
4387        /*.p0   =*/ p0,
4388        /*.p1   =*/ p1,
4389        /*.d0   =*/ d0,
4390        /*.d1   =*/ d1,
4391    };
4392
4393    auto pipeline = ggml_metal_library_get_pipeline_conv_2d(lib, op);
4394
4395    int nth = ggml_metal_pipeline_max_theads_per_threadgroup(pipeline);
4396    nth = std::min(nth, 256);
4397    nth = std::max(nth, 1);
4398
4399    const uint64_t n_out = ggml_nelements(op);
4400
4401    uint64_t tg = (n_out + nth - 1)/nth;
4402    tg = std::max<uint64_t>(tg, 1);
4403    tg = std::min<uint64_t>(tg, (uint64_t) std::numeric_limits<int>::max());
4404
4405    ggml_metal_encoder_set_pipeline(enc, pipeline);
4406    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4407    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
4408    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
4409    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
4410
4411    ggml_metal_encoder_dispatch_threadgroups(enc, tg, 1, 1, nth, 1, 1);
4412
4413    return 1;
4414}
4415
4416int ggml_metal_op_conv_2d_dw(ggml_metal_op_t ctx, int idx) {
4417    ggml_tensor * op = ctx->node(idx);
4418
4419    ggml_metal_library_t lib = ctx->lib;
4420    ggml_metal_encoder_t enc = ctx->enc;
4421
4422    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
4423    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
4424    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
4425    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
4426    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
4427    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
4428
4429    GGML_ASSERT(op->src[1]->type == GGML_TYPE_F32);
4430    GGML_ASSERT(op->type == GGML_TYPE_F32);
4431    GGML_ASSERT(op->src[0]->type == GGML_TYPE_F16 || op->src[0]->type == GGML_TYPE_F32);
4432
4433    const int32_t s0 = ((const int32_t *) op->op_params)[0];
4434    const int32_t s1 = ((const int32_t *) op->op_params)[1];
4435    const int32_t p0 = ((const int32_t *) op->op_params)[2];
4436    const int32_t p1 = ((const int32_t *) op->op_params)[3];
4437    const int32_t d0 = ((const int32_t *) op->op_params)[4];
4438    const int32_t d1 = ((const int32_t *) op->op_params)[5];
4439
4440    ggml_metal_kargs_conv_2d_dw args = {
4441        /*.nb00 =*/ nb00,
4442        /*.nb01 =*/ nb01,
4443        /*.nb02 =*/ nb03,
4444        /*.nb10 =*/ nb10,
4445        /*.nb11 =*/ nb11,
4446        /*.nb12 =*/ nb12,
4447        /*.nb13 =*/ nb13,
4448        /*.nb0  =*/ nb0,
4449        /*.nb1  =*/ nb1,
4450        /*.nb2  =*/ nb2,
4451        /*.nb3  =*/ nb3,
4452        /*.IW   =*/ ne10,
4453        /*.IH   =*/ ne11,
4454        /*.KW   =*/ ne00,
4455        /*.KH   =*/ ne01,
4456        /*.C    =*/ ne12,
4457        /*.OW   =*/ ne0,
4458        /*.OH   =*/ ne1,
4459        /*.N    =*/ ne13,
4460        /*.s0   =*/ s0,
4461        /*.s1   =*/ s1,
4462        /*.p0   =*/ p0,
4463        /*.p1   =*/ p1,
4464        /*.d0   =*/ d0,
4465        /*.d1   =*/ d1,
4466    };
4467
4468    const bool use_tiled = (nb12 < nb10);
4469
4470    auto pipeline = ggml_metal_library_get_pipeline_conv_2d_dw(lib, op, use_tiled);
4471
4472    int nth = ggml_metal_pipeline_max_theads_per_threadgroup(pipeline);
4473    nth = std::min(nth, 256);
4474    nth = std::max(nth, 1);
4475
4476    const int32_t OW = ne0;
4477    const int32_t OH = ne1;
4478    const int32_t C  = ne12;
4479    const int32_t N  = ne13;
4480
4481    const int tg_x = use_tiled ? (C + nth - 1) / nth : (OW + nth - 1) / nth;
4482    const int tg_y = OH;
4483    const int tg_z = use_tiled ? OW * N : C * N;
4484
4485    ggml_metal_encoder_set_pipeline(enc, pipeline);
4486    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4487    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
4488    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
4489    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
4490
4491    ggml_metal_encoder_dispatch_threadgroups(enc, tg_x, tg_y, tg_z, nth, 1, 1);
4492
4493    return 1;
4494}
4495
4496int ggml_metal_op_conv_3d(ggml_metal_op_t ctx, int idx) {
4497    ggml_tensor * op = ctx->node(idx);
4498
4499    ggml_metal_library_t lib = ctx->lib;
4500    ggml_metal_encoder_t enc = ctx->enc;
4501
4502    // 1. Extract standard dimensions and byte strides
4503    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
4504    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
4505    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
4506
4507    // 2. Extract hyperparams from op_params
4508    const int32_t s0 = ((const int32_t *)(op->op_params))[0];
4509    const int32_t s1 = ((const int32_t *)(op->op_params))[1];
4510    const int32_t s2 = ((const int32_t *)(op->op_params))[2];
4511    const int32_t p0 = ((const int32_t *)(op->op_params))[3];
4512    const int32_t p1 = ((const int32_t *)(op->op_params))[4];
4513    const int32_t p2 = ((const int32_t *)(op->op_params))[5];
4514    const int32_t d0 = ((const int32_t *)(op->op_params))[6];
4515    const int32_t d1 = ((const int32_t *)(op->op_params))[7];
4516    const int32_t d2 = ((const int32_t *)(op->op_params))[8];
4517    const int32_t IC = ((const int32_t *)(op->op_params))[9];
4518    const int32_t N  = ((const int32_t *)(op->op_params))[10];
4519    const int32_t OC = ((const int32_t *)(op->op_params))[11];
4520
4521    // 3. Build the parameter struct using the macro-generated variables
4522    ggml_metal_kargs_conv_3d args = {
4523        /*.IW =*/ (int32_t)op->src[1]->ne[0],
4524        /*.IH =*/ (int32_t)op->src[1]->ne[1],
4525        /*.ID =*/ (int32_t)op->src[1]->ne[2],
4526        /*.OW =*/ (int32_t)op->ne[0],
4527        /*.OH =*/ (int32_t)op->ne[1],
4528        /*.OD =*/ (int32_t)op->ne[2],
4529        /*.KW =*/ (int32_t)op->src[0]->ne[0],
4530        /*.KH =*/ (int32_t)op->src[0]->ne[1],
4531        /*.KD =*/ (int32_t)op->src[0]->ne[2],
4532        s0, s1, s2,
4533        p0, p1, p2,
4534        d0, d1, d2,
4535        IC, N, OC,
4536        nb00, nb01, nb02, nb03, // Weight strides
4537        nb10, nb11, nb12, nb13, // Input strides
4538        nb0,  nb1,  nb2,  nb3   // Output strides
4539    };
4540
4541    // 4. Fetch the JIT pipeline
4542    auto pipeline = ggml_metal_library_get_pipeline_conv_3d(lib, op);
4543
4544    // 5. Grid mapping
4545    int nth0 = 32; // Standard SIMD width for Apple Silicon
4546    int nth1 = 1;
4547    int nth2 = 1;
4548
4549    int64_t spatial_volume = args.OW * args.OH * args.OD;
4550
4551    int ntg0 = (spatial_volume + nth0 - 1) / nth0;
4552    int ntg1 = args.OC;
4553    int ntg2 = args.N;
4554
4555    // 6. Bind and Dispatch via the ggml C wrapper
4556    ggml_metal_encoder_set_pipeline(enc, pipeline);
4557    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4558    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
4559    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
4560    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
4561
4562    ggml_metal_encoder_dispatch_threadgroups(enc, ntg0, ntg1, ntg2, nth0, nth1, nth2);
4563
4564    return 1;
4565}
4566
4567int ggml_metal_op_conv_transpose_1d(ggml_metal_op_t ctx, int idx) {
4568    ggml_tensor * op = ctx->node(idx);
4569
4570    ggml_metal_library_t lib = ctx->lib;
4571    ggml_metal_encoder_t enc = ctx->enc;
4572
4573    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
4574    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
4575    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
4576    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
4577    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
4578    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
4579
4580    const int32_t s0 = ((const int32_t *)(op->op_params))[0];
4581
4582    const int32_t IC = op->src[1]->ne[1];
4583    const int32_t IL = op->src[1]->ne[0];
4584
4585    const int32_t K  = op->src[0]->ne[0];
4586
4587    const int32_t OL = op->ne[0];
4588    const int32_t OC = op->ne[1];
4589
4590    ggml_metal_kargs_conv_transpose_1d args = {
4591        /*.IC  =*/ IC,
4592        /*.IL  =*/ IL,
4593        /*.K   =*/ K,
4594        /*.s0  =*/ s0,
4595        /*.nb0 =*/ nb0,
4596        /*.nb1 =*/ nb1,
4597    };
4598
4599    auto pipeline = ggml_metal_library_get_pipeline_conv_transpose_1d(lib, op);
4600
4601    ggml_metal_encoder_set_pipeline(enc, pipeline);
4602    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4603    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
4604    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
4605    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
4606
4607    ggml_metal_encoder_dispatch_threadgroups(enc, OL, OC, 1, 1, 1, 1);
4608
4609    return 1;
4610}
4611
4612int ggml_metal_op_col2im_1d(ggml_metal_op_t ctx, int idx) {
4613    ggml_tensor * op = ctx->node(idx);
4614
4615    ggml_metal_library_t lib = ctx->lib;
4616    ggml_metal_encoder_t enc = ctx->enc;
4617
4618    const int32_t s0 = ((const int32_t *)(op->op_params))[0];
4619    const int32_t OC = ((const int32_t *)(op->op_params))[1];
4620    const int32_t p0 = ((const int32_t *)(op->op_params))[2];
4621
4622    const int32_t K_OC  = (int32_t) op->src[0]->ne[0];
4623    const int32_t T_in  = (int32_t) op->src[0]->ne[1];
4624    const int32_t K     = K_OC / OC;
4625    const int32_t T_out = (int32_t) op->ne[0];
4626
4627    ggml_metal_kargs_col2im_1d args = {
4628        /*.T_in  =*/ T_in,
4629        /*.T_out =*/ T_out,
4630        /*.OC    =*/ OC,
4631        /*.K     =*/ K,
4632        /*.K_OC  =*/ K_OC,
4633        /*.s0    =*/ s0,
4634        /*.p0    =*/ p0,
4635    };
4636
4637    auto pipeline = ggml_metal_library_get_pipeline_col2im_1d(lib, op);
4638
4639    const int total = T_out * OC;
4640    const int nth   = 256;
4641    const int ntg   = (total + nth - 1) / nth;
4642
4643    ggml_metal_encoder_set_pipeline(enc, pipeline);
4644    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4645    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
4646    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
4647
4648    ggml_metal_encoder_dispatch_threadgroups(enc, ntg, 1, 1, nth, 1, 1);
4649
4650    return 1;
4651}
4652
4653// Dispatch the fused snake kernel from the matched mul -> sin -> sqr -> mul -> add chain.
4654// idx points at the leading mul. The caller has validated the chain.
4655int ggml_metal_op_snake_fused(ggml_metal_op_t ctx, int idx) {
4656    ggml_metal_library_t lib = ctx->lib;
4657    ggml_metal_encoder_t enc = ctx->enc;
4658
4659    const ggml_tensor * mul0 = ctx->node(idx + 0);
4660    const ggml_tensor * sqr  = ctx->node(idx + 2);
4661    const ggml_tensor * mul1 = ctx->node(idx + 3);
4662    ggml_tensor *       add  = ctx->node(idx + 4);
4663
4664    const ggml_tensor * x = ggml_are_same_shape(mul0, mul0->src[0]) ? mul0->src[0] : mul0->src[1];
4665    const ggml_tensor * a = (x == mul0->src[0]) ? mul0->src[1] : mul0->src[0];
4666    const ggml_tensor * inv_b = (mul1->src[0] == sqr) ? mul1->src[1] : mul1->src[0];
4667
4668    const int T     = (int) x->ne[0];
4669    const int C     = (int) x->ne[1];
4670    const int total = T * C;
4671
4672    // the encode loop pre-checked the leading mul only, check the rest of the chain
4673    for (int i = 1; i < 5; ++i) {
4674        if (!ggml_metal_op_concurrency_check(ctx, ctx->node(idx + i))) {
4675            ggml_metal_op_concurrency_reset(ctx);
4676
4677            break;
4678        }
4679    }
4680
4681    auto pipeline = ggml_metal_library_get_pipeline_snake(lib, x->type);
4682
4683    ggml_metal_kargs_snake args = {
4684        /*.T =*/ T,
4685        /*.C =*/ C,
4686    };
4687
4688    ggml_metal_encoder_set_pipeline(enc, pipeline);
4689    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4690    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(x),     1);
4691    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(a),     2);
4692    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(inv_b), 3);
4693    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(add),   4);
4694
4695    const int nth = 256;
4696    const int ntg = (total + nth - 1) / nth;
4697    ggml_metal_encoder_dispatch_threadgroups(enc, ntg, 1, 1, nth, 1, 1);
4698
4699    return 5;
4700}
4701
4702int ggml_metal_op_conv_transpose_2d(ggml_metal_op_t ctx, int idx) {
4703    ggml_tensor * op = ctx->node(idx);
4704
4705    ggml_metal_library_t lib = ctx->lib;
4706    ggml_metal_encoder_t enc = ctx->enc;
4707
4708    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
4709    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
4710    GGML_TENSOR_LOCALS( int32_t, ne1, op->src[1], ne);
4711    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
4712    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
4713    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
4714
4715    const int32_t s0 = ((const int32_t *)(op->op_params))[0];
4716
4717    const int32_t IC = op->src[1]->ne[2];
4718    const int32_t IH = op->src[1]->ne[1];
4719    const int32_t IW = op->src[1]->ne[0];
4720
4721    const int32_t KH = op->src[0]->ne[1];
4722    const int32_t KW = op->src[0]->ne[0];
4723
4724    const int32_t OW = op->ne[0];
4725    const int32_t OH = op->ne[1];
4726    const int32_t OC = op->ne[2];
4727    const int32_t N  = op->src[1]->ne[3];
4728
4729    ggml_metal_kargs_conv_transpose_2d args = {
4730        /*.IC  =*/ IC,
4731        /*.IH  =*/ IH,
4732        /*.IW  =*/ IW,
4733        /*.KH  =*/ KH,
4734        /*.KW  =*/ KW,
4735        /*.OC  =*/ OC,
4736        /*.s0  =*/ s0,
4737        /*.nb0 =*/ nb0,
4738        /*.nb1 =*/ nb1,
4739        /*.nb2 =*/ nb2,
4740        /*.nb3 =*/ nb3,
4741    };
4742
4743    auto pipeline = ggml_metal_library_get_pipeline_conv_transpose_2d(lib, op);
4744
4745    ggml_metal_encoder_set_pipeline(enc, pipeline);
4746    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4747    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
4748    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), 2);
4749    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         3);
4750
4751    // Metal requires buffer size to be multiple of 16 bytes
4752    const size_t smem = GGML_PAD(KW * KH * sizeof(float), 16);
4753    ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
4754
4755    ggml_metal_encoder_dispatch_threadgroups(enc, OW, OH, OC * N, KW, KH, 1);
4756
4757    return 1;
4758}
4759
4760int ggml_metal_op_upscale(ggml_metal_op_t ctx, int idx) {
4761    ggml_tensor * op = ctx->node(idx);
4762
4763    ggml_metal_library_t lib = ctx->lib;
4764    ggml_metal_encoder_t enc = ctx->enc;
4765
4766    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
4767    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
4768    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
4769    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
4770
4771    float sf0 = (float)ne0/op->src[0]->ne[0];
4772    float sf1 = (float)ne1/op->src[0]->ne[1];
4773    float sf2 = (float)ne2/op->src[0]->ne[2];
4774    float sf3 = (float)ne3/op->src[0]->ne[3];
4775
4776    const int32_t mode_flags = ggml_get_op_params_i32(op, 0);
4777
4778    float poffs = 0.5f;
4779
4780    if (mode_flags & GGML_SCALE_FLAG_ALIGN_CORNERS) {
4781        poffs = 0.0f;
4782        sf0 = ne0 > 1 && ne00 > 1 ? (float)(ne0 - 1) / (ne00 - 1) : sf0;
4783        sf1 = ne1 > 1 && ne01 > 1 ? (float)(ne1 - 1) / (ne01 - 1) : sf1;
4784    }
4785
4786    ggml_metal_kargs_upscale args = {
4787        /*.ne00  =*/ ne00,
4788        /*.ne01  =*/ ne01,
4789        /*.ne02  =*/ ne02,
4790        /*.ne03  =*/ ne03,
4791        /*.nb00  =*/ nb00,
4792        /*.nb01  =*/ nb01,
4793        /*.nb02  =*/ nb02,
4794        /*.nb03  =*/ nb03,
4795        /*.ne0   =*/ ne0,
4796        /*.ne1   =*/ ne1,
4797        /*.ne2   =*/ ne2,
4798        /*.ne3   =*/ ne3,
4799        /*.nb0   =*/ nb0,
4800        /*.nb1   =*/ nb1,
4801        /*.nb2   =*/ nb2,
4802        /*.nb3   =*/ nb3,
4803        /*.sf0   =*/ sf0,
4804        /*.sf1   =*/ sf1,
4805        /*.sf2   =*/ sf2,
4806        /*.sf3   =*/ sf3,
4807        /*.poffs =*/ poffs,
4808    };
4809
4810    auto pipeline = ggml_metal_library_get_pipeline_upscale(lib, op);
4811
4812    const int nth = std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline), ne0);
4813
4814    ggml_metal_encoder_set_pipeline(enc, pipeline);
4815    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4816    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
4817    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
4818
4819    ggml_metal_encoder_dispatch_threadgroups(enc, ne1, ne2, ne3, nth, 1, 1);
4820
4821    return 1;
4822}
4823
4824int ggml_metal_op_roll(ggml_metal_op_t ctx, int idx) {
4825    ggml_tensor * op = ctx->node(idx);
4826
4827    ggml_metal_library_t lib = ctx->lib;
4828    ggml_metal_encoder_t enc = ctx->enc;
4829
4830    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
4831    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
4832    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
4833    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
4834
4835    const int32_t s0 = ggml_get_op_params_i32(op, 0);
4836    const int32_t s1 = ggml_get_op_params_i32(op, 1);
4837    const int32_t s2 = ggml_get_op_params_i32(op, 2);
4838    const int32_t s3 = ggml_get_op_params_i32(op, 3);
4839
4840    ggml_metal_kargs_roll args = {
4841        /*.ne00 =*/ ne00,
4842        /*.ne01 =*/ ne01,
4843        /*.ne02 =*/ ne02,
4844        /*.ne03 =*/ ne03,
4845        /*.nb00 =*/ nb00,
4846        /*.nb01 =*/ nb01,
4847        /*.nb02 =*/ nb02,
4848        /*.nb03 =*/ nb03,
4849        /*.ne0  =*/ ne0,
4850        /*.ne1  =*/ ne1,
4851        /*.ne2  =*/ ne2,
4852        /*.ne3  =*/ ne3,
4853        /*.nb0  =*/ nb0,
4854        /*.nb1  =*/ nb1,
4855        /*.nb2  =*/ nb2,
4856        /*.nb3  =*/ nb3,
4857        /*.s0   =*/ s0,
4858        /*.s1   =*/ s1,
4859        /*.s2   =*/ s2,
4860        /*.s3   =*/ s3
4861    };
4862
4863    auto pipeline = ggml_metal_library_get_pipeline_roll(lib, op);
4864
4865    const int nth = std::min(1024, ne0);
4866
4867    ggml_metal_encoder_set_pipeline(enc, pipeline);
4868    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4869    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
4870    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
4871
4872    ggml_metal_encoder_dispatch_threadgroups(enc, ne1, ne2, ne3, nth, 1, 1);
4873
4874    return 1;
4875}
4876
4877int ggml_metal_op_pad(ggml_metal_op_t ctx, int idx) {
4878    ggml_tensor * op = ctx->node(idx);
4879
4880    ggml_metal_library_t lib = ctx->lib;
4881    ggml_metal_encoder_t enc = ctx->enc;
4882
4883    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
4884    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
4885    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
4886    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
4887
4888    ggml_metal_kargs_pad args = {
4889        /*.ne00 =*/ ne00,
4890        /*.ne01 =*/ ne01,
4891        /*.ne02 =*/ ne02,
4892        /*.ne03 =*/ ne03,
4893        /*.nb00 =*/ nb00,
4894        /*.nb01 =*/ nb01,
4895        /*.nb02 =*/ nb02,
4896        /*.nb03 =*/ nb03,
4897        /*.ne0  =*/ ne0,
4898        /*.ne1  =*/ ne1,
4899        /*.ne2  =*/ ne2,
4900        /*.ne3  =*/ ne3,
4901        /*.nb0  =*/ nb0,
4902        /*.nb1  =*/ nb1,
4903        /*.nb2  =*/ nb2,
4904        /*.nb3  =*/ nb3
4905    };
4906
4907    auto pipeline = ggml_metal_library_get_pipeline_pad(lib, op);
4908
4909    if (pipeline.c4) {
4910        args.ne00 = ne00/4;
4911        args.ne0  = ne0/4;
4912    }
4913
4914    const int nth_max = MIN(64, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
4915    const int nth = MIN(args.ne0, nth_max);
4916    const int nk0 = (args.ne0 + 1024 - 1)/1024; // note: 1024 is hardcoded in the kernel!
4917
4918    ggml_metal_encoder_set_pipeline(enc, pipeline);
4919    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4920    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
4921    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
4922
4923    ggml_metal_encoder_dispatch_threadgroups(enc, nk0*ne1, ne2, ne3, nth, 1, 1);
4924
4925    return 1;
4926}
4927
4928int ggml_metal_op_pad_reflect_1d(ggml_metal_op_t ctx, int idx) {
4929    ggml_tensor * op = ctx->node(idx);
4930
4931    ggml_metal_library_t lib = ctx->lib;
4932    ggml_metal_encoder_t enc = ctx->enc;
4933
4934    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
4935    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
4936    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
4937    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
4938
4939    ggml_metal_kargs_pad_reflect_1d args = {
4940        /*.ne00 =*/ ne00,
4941        /*.ne01 =*/ ne01,
4942        /*.ne02 =*/ ne02,
4943        /*.ne03 =*/ ne03,
4944        /*.nb00 =*/ nb00,
4945        /*.nb01 =*/ nb01,
4946        /*.nb02 =*/ nb02,
4947        /*.nb03 =*/ nb03,
4948        /*.ne0  =*/ ne0,
4949        /*.ne1  =*/ ne1,
4950        /*.ne2  =*/ ne2,
4951        /*.ne3  =*/ ne3,
4952        /*.nb0  =*/ nb0,
4953        /*.nb1  =*/ nb1,
4954        /*.nb2  =*/ nb2,
4955        /*.nb3  =*/ nb3,
4956        /*.p0 =*/ ((const int32_t *)(op->op_params))[0],
4957        /*.p1 =*/ ((const int32_t *)(op->op_params))[1]
4958    };
4959
4960    auto pipeline = ggml_metal_library_get_pipeline_pad_reflect_1d(lib, op);
4961
4962    const int nth = std::min(1024, ne0);
4963
4964    ggml_metal_encoder_set_pipeline(enc, pipeline);
4965    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
4966    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
4967    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
4968
4969    ggml_metal_encoder_dispatch_threadgroups(enc, ne1, ne2, ne3, nth, 1, 1);
4970
4971    return 1;
4972}
4973
4974int ggml_metal_op_arange(ggml_metal_op_t ctx, int idx) {
4975    ggml_tensor * op = ctx->node(idx);
4976
4977    ggml_metal_library_t lib = ctx->lib;
4978    ggml_metal_encoder_t enc = ctx->enc;
4979
4980    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
4981    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
4982
4983    float start;
4984    float step;
4985
4986    memcpy(&start, ((const int32_t *) op->op_params) + 0, sizeof(float));
4987    memcpy(&step,  ((const int32_t *) op->op_params) + 2, sizeof(float));
4988
4989    ggml_metal_kargs_arange args = {
4990        /*.ne0   =*/ ne0,
4991        /*.start =*/ start,
4992        /*.step  =*/ step
4993    };
4994
4995    const int nth = std::min(1024, ne0);
4996
4997    auto pipeline = ggml_metal_library_get_pipeline_arange(lib, op);
4998
4999    ggml_metal_encoder_set_pipeline(enc, pipeline);
5000    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
5001    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op), 1);
5002
5003    ggml_metal_encoder_dispatch_threadgroups(enc, 1, 1, 1, nth, 1, 1);
5004
5005    return 1;
5006}
5007
5008int ggml_metal_op_timestep_embedding(ggml_metal_op_t ctx, int idx) {
5009    ggml_tensor * op = ctx->node(idx);
5010
5011    ggml_metal_library_t lib = ctx->lib;
5012    ggml_metal_encoder_t enc = ctx->enc;
5013
5014    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
5015    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
5016    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
5017    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
5018
5019    const int dim        = op->op_params[0];
5020    const int max_period = op->op_params[1];
5021
5022    ggml_metal_kargs_timestep_embedding args = {
5023        /*.nb1 =*/ nb1,
5024        /*.dim =*/ dim,
5025        /*.max_period =*/ max_period,
5026    };
5027
5028    auto pipeline = ggml_metal_library_get_pipeline_timestep_embedding(lib, op);
5029
5030    const int nth = std::max(1, std::min(1024, dim/2));
5031
5032    ggml_metal_encoder_set_pipeline(enc, pipeline);
5033    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
5034    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
5035    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
5036
5037    ggml_metal_encoder_dispatch_threadgroups(enc, ne00, 1, 1, nth, 1, 1);
5038
5039    return 1;
5040}
5041
5042int ggml_metal_op_argmax(ggml_metal_op_t ctx, int idx) {
5043    ggml_tensor * op = ctx->node(idx);
5044
5045    ggml_metal_library_t lib = ctx->lib;
5046    ggml_metal_encoder_t enc = ctx->enc;
5047
5048    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
5049    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
5050    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
5051    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
5052
5053    ggml_metal_kargs_argmax args = {
5054        /*.ne00 = */ ne00,
5055        /*.nb01 = */ nb01,
5056    };
5057
5058    auto pipeline = ggml_metal_library_get_pipeline_argmax(lib, op);
5059
5060    const int64_t nrows = ggml_nrows(op->src[0]);
5061
5062    int nth = 32; // SIMD width
5063    while (nth < ne00 && nth*ne01*ne02*ne03 < 256) {
5064        nth *= 2;
5065    }
5066
5067    const size_t smem = pipeline.smem;
5068
5069    ggml_metal_encoder_set_pipeline(enc, pipeline);
5070    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
5071    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
5072    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
5073
5074    ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
5075
5076    ggml_metal_encoder_dispatch_threadgroups(enc, nrows, 1, 1, nth, 1, 1);
5077
5078    return 1;
5079}
5080
5081int ggml_metal_op_argsort(ggml_metal_op_t ctx, int idx) {
5082    ggml_tensor * op = ctx->node(idx);
5083
5084    ggml_metal_library_t lib = ctx->lib;
5085    ggml_metal_encoder_t enc = ctx->enc;
5086
5087    GGML_ASSERT(ggml_is_contiguous_rows(op->src[0]));
5088
5089    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
5090    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
5091    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
5092    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
5093
5094    auto pipeline = ggml_metal_library_get_pipeline_argsort(lib, op);
5095
5096    // bitonic sort requires the number of elements to be power of 2
5097    int nth = 1;
5098    while (nth < ne00 && 2*nth <= ggml_metal_pipeline_max_theads_per_threadgroup(pipeline)) {
5099        nth *= 2;
5100    }
5101
5102    const int npr = (ne00 + nth - 1)/nth;
5103
5104    // Metal kernels require the buffer size to be multiple of 16 bytes
5105    // https://developer.apple.com/documentation/metal/mtlcomputecommandencoder/1443142-setthreadgroupmemorylength
5106    const size_t smem = GGML_PAD(nth*sizeof(int32_t), 16);
5107
5108    ggml_metal_buffer_id bid_src0 = ggml_metal_get_buffer_id(op->src[0]);
5109    ggml_metal_buffer_id bid_dst  = ggml_metal_get_buffer_id(op);
5110
5111    ggml_metal_buffer_id bid_tmp = bid_dst;
5112    bid_tmp.offs += ggml_nbytes(op);
5113
5114    if ((int) ceil(std::log(npr) / std::log(2)) % 2 == 1) {
5115        std::swap(bid_dst, bid_tmp);
5116    }
5117
5118    ggml_metal_kargs_argsort args = {
5119        /*.ne00  =*/ ne00,
5120        /*.ne01  =*/ ne01,
5121        /*.ne02  =*/ ne02,
5122        /*.ne03  =*/ ne03,
5123        /*.nb00  =*/ nb00,
5124        /*.nb01  =*/ nb01,
5125        /*.nb02  =*/ nb02,
5126        /*.nb03  =*/ nb03,
5127        /*.ne0   =*/ ne0,
5128        /*.ne1   =*/ ne1,
5129        /*.ne2   =*/ ne2,
5130        /*.ne3   =*/ ne3,
5131        /*.top_k =*/ nth,
5132    };
5133
5134    ggml_metal_encoder_set_pipeline(enc, pipeline);
5135    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
5136    ggml_metal_encoder_set_buffer  (enc, bid_src0, 1);
5137    ggml_metal_encoder_set_buffer  (enc, bid_dst,  2);
5138
5139    ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
5140
5141    ggml_metal_encoder_dispatch_threadgroups(enc, npr*ne01, ne02, ne03, nth, 1, 1);
5142
5143    auto pipeline_merge = ggml_metal_library_get_pipeline_argsort_merge(lib, op);
5144
5145    int len = nth;
5146
5147    while (len < ne00) {
5148        ggml_metal_op_concurrency_reset(ctx);
5149
5150        ggml_metal_kargs_argsort_merge args_merge = {
5151            /*.ne00  =*/ ne00,
5152            /*.ne01  =*/ ne01,
5153            /*.ne02  =*/ ne02,
5154            /*.ne03  =*/ ne03,
5155            /*.nb00  =*/ nb00,
5156            /*.nb01  =*/ nb01,
5157            /*.nb02  =*/ nb02,
5158            /*.nb03  =*/ nb03,
5159            /*.ne0   =*/ ne0,
5160            /*.ne1   =*/ ne1,
5161            /*.ne2   =*/ ne2,
5162            /*.ne3   =*/ ne3,
5163            /*.top_k =*/ ne00,
5164            /*.len   =*/ len,
5165        };
5166
5167        // merges per row
5168        const int nm = (ne00 + 2*len - 1) / (2*len);
5169
5170        const int nth = std::min(512, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline_merge));
5171
5172        ggml_metal_encoder_set_pipeline(enc, pipeline_merge);
5173        ggml_metal_encoder_set_bytes   (enc, &args_merge, sizeof(args_merge), 0);
5174        ggml_metal_encoder_set_buffer  (enc, bid_src0, 1);
5175        ggml_metal_encoder_set_buffer  (enc, bid_dst,  2);
5176        ggml_metal_encoder_set_buffer  (enc, bid_tmp,  3);
5177
5178        ggml_metal_encoder_dispatch_threadgroups(enc, nm*ne01, ne02, ne03, nth, 1, 1);
5179
5180        std::swap(bid_dst, bid_tmp);
5181
5182        len <<= 1;
5183    }
5184
5185    return 1;
5186}
5187
5188// bitonic-sort + merge fallback: efficient when k is small and there are few rows,
5189// where the single-workgroup-per-row radix-select cannot reach enough parallelism
5190static void ggml_metal_op_top_k_bitonic(ggml_metal_op_t ctx, int idx) {
5191    ggml_tensor * op = ctx->node(idx);
5192
5193    ggml_metal_library_t lib = ctx->lib;
5194    ggml_metal_encoder_t enc = ctx->enc;
5195
5196    GGML_ASSERT(ggml_is_contiguous_rows(op->src[0]));
5197
5198    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
5199    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
5200    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
5201    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
5202
5203    auto pipeline = ggml_metal_library_get_pipeline_top_k(lib, op);
5204
5205    // bitonic sort requires the number of elements to be power of 2
5206    int nth = 1;
5207    while (nth < ne00 && 2*nth <= ggml_metal_pipeline_max_theads_per_threadgroup(pipeline)) {
5208        nth *= 2;
5209    }
5210
5211    // blocks per row
5212    const int npr = (ne00 + nth - 1)/nth;
5213
5214    const size_t smem = GGML_PAD(nth*sizeof(int32_t), 16);
5215
5216    ggml_metal_buffer_id bid_src0 = ggml_metal_get_buffer_id(op->src[0]);
5217    ggml_metal_buffer_id bid_dst  = ggml_metal_get_buffer_id(op);
5218
5219    ggml_metal_buffer_id bid_tmp = bid_dst;
5220    bid_tmp.offs += sizeof(int32_t)*ggml_nelements(op->src[0]);
5221
5222    if ((int) ceil(std::log(npr) / std::log(2)) % 2 == 1) {
5223        std::swap(bid_dst, bid_tmp);
5224    }
5225
5226    const int top_k = ne0;
5227
5228    ggml_metal_kargs_argsort args = {
5229        /*.ne00  =*/ ne00,
5230        /*.ne01  =*/ ne01,
5231        /*.ne02  =*/ ne02,
5232        /*.ne03  =*/ ne03,
5233        /*.nb00  =*/ nb00,
5234        /*.nb01  =*/ nb01,
5235        /*.nb02  =*/ nb02,
5236        /*.nb03  =*/ nb03,
5237        /*.ne0   =*/ ne0,
5238        /*.ne1   =*/ ne1,
5239        /*.ne2   =*/ ne2,
5240        /*.ne3   =*/ ne3,
5241        /*.top_k =*/ std::min(nth, top_k), // for each block, keep just the top_k indices
5242    };
5243
5244    if (npr > 1) {
5245        args.ne0 = (npr - 1)*args.top_k + std::min(ne00 - (npr - 1)*nth, args.top_k);
5246    }
5247
5248    ggml_metal_encoder_set_pipeline(enc, pipeline);
5249    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
5250    ggml_metal_encoder_set_buffer  (enc, bid_src0, 1);
5251    ggml_metal_encoder_set_buffer  (enc, bid_dst,  2);
5252
5253    ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
5254
5255    ggml_metal_encoder_dispatch_threadgroups(enc, npr*ne01, ne02, ne03, nth, 1, 1);
5256
5257    auto pipeline_merge = ggml_metal_library_get_pipeline_top_k_merge(lib, op);
5258
5259    int len = args.top_k;
5260
5261    while (len < args.ne0) {
5262        ggml_metal_op_concurrency_reset(ctx);
5263
5264        // merges per row
5265        const int nm = (args.ne0 + 2*len - 1) / (2*len);
5266
5267        const int nth = std::min(512, std::min(len, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline_merge)));
5268
5269        ggml_metal_kargs_argsort_merge args_merge = {
5270            /*.ne00  =*/ ne00,
5271            /*.ne01  =*/ ne01,
5272            /*.ne02  =*/ ne02,
5273            /*.ne03  =*/ ne03,
5274            /*.nb00  =*/ nb00,
5275            /*.nb01  =*/ nb01,
5276            /*.nb02  =*/ nb02,
5277            /*.nb03  =*/ nb03,
5278            /*.ne0   =*/ args.ne0,
5279            /*.ne1   =*/ ne1,
5280            /*.ne2   =*/ ne2,
5281            /*.ne3   =*/ ne3,
5282            /*.top_k =*/ nm == 1 ? top_k : args.ne0, // the final merge outputs top_k elements
5283            /*.len   =*/ len,
5284        };
5285
5286        ggml_metal_encoder_set_pipeline(enc, pipeline_merge);
5287        ggml_metal_encoder_set_bytes   (enc, &args_merge, sizeof(args_merge), 0);
5288        ggml_metal_encoder_set_buffer  (enc, bid_src0, 1);
5289        ggml_metal_encoder_set_buffer  (enc, bid_dst,  2);
5290        ggml_metal_encoder_set_buffer  (enc, bid_tmp,  3);
5291
5292        ggml_metal_encoder_dispatch_threadgroups(enc, nm*ne01, ne02, ne03, nth, 1, 1);
5293
5294        std::swap(bid_dst, bid_tmp);
5295
5296        len <<= 1;
5297    }
5298}
5299
5300// radix-select: one workgroup per row. Maps each float to an order-preserving unsigned
5301// key, finds the k-th largest via 4 radix-8 histogram passes, then compacts the top-k
5302// indices. Fast for large k and/or many rows.
5303static void ggml_metal_op_top_k_radix(ggml_metal_op_t ctx, int idx) {
5304    ggml_tensor * op = ctx->node(idx);
5305
5306    ggml_metal_library_t lib = ctx->lib;
5307    ggml_metal_encoder_t enc = ctx->enc;
5308
5309    GGML_ASSERT(ggml_is_contiguous_rows(op->src[0]));
5310
5311    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
5312    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
5313
5314    auto pipeline = ggml_metal_library_get_pipeline_top_k_radix(lib, op);
5315
5316    // one workgroup per row; radix-select the k-th largest value
5317    const int nth = std::min(1024, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
5318
5319    ggml_metal_kargs_top_k args = {
5320        /*.ne00  =*/ ne00,
5321        /*.ne01  =*/ ne01,
5322        /*.ne02  =*/ ne02,
5323        /*.ne03  =*/ ne03,
5324        /*.nb01  =*/ nb01,
5325        /*.nb02  =*/ nb02,
5326        /*.nb03  =*/ nb03,
5327        /*.top_k =*/ (int32_t) op->ne[0],
5328    };
5329
5330    // shared memory: 256-entry histogram + bucket/above scalars + output counter
5331    const size_t smem_histo  = GGML_PAD(256*sizeof(uint32_t), 16);
5332    const size_t smem_bucket = GGML_PAD(    sizeof(uint32_t), 16);
5333    const size_t smem_above  = GGML_PAD(    sizeof(uint32_t), 16);
5334    const size_t smem_out    = GGML_PAD(    sizeof(uint32_t), 16);
5335
5336    ggml_metal_encoder_set_pipeline(enc, pipeline);
5337    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
5338    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
5339    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
5340
5341    ggml_metal_encoder_set_threadgroup_memory_size(enc, smem_histo,  0);
5342    ggml_metal_encoder_set_threadgroup_memory_size(enc, smem_bucket, 1);
5343    ggml_metal_encoder_set_threadgroup_memory_size(enc, smem_above,  2);
5344    ggml_metal_encoder_set_threadgroup_memory_size(enc, smem_out,    3);
5345
5346    ggml_metal_encoder_dispatch_threadgroups(enc, ne01, ne02, ne03, nth, 1, 1);
5347}
5348
5349int ggml_metal_op_top_k(ggml_metal_op_t ctx, int idx) {
5350    ggml_tensor * op = ctx->node(idx);
5351
5352    // radix-select has a fixed single-workgroup-per-row cost (~50-60us) that is only
5353    // amortized for long rows, many rows, or a large k; otherwise the bitonic path wins
5354    const int ncols = op->src[0]->ne[0];
5355    const int k     = op->ne[0];
5356    const int nrows = ggml_nrows(op->src[0]);
5357
5358    const bool use_radix =
5359        ncols > 2048 && (k > 64 || (nrows > 4 && ncols >= 8192));
5360
5361    if (use_radix) {
5362        ggml_metal_op_top_k_radix(ctx, idx);
5363    } else {
5364        ggml_metal_op_top_k_bitonic(ctx, idx);
5365    }
5366
5367    return 1;
5368}
5369
5370int ggml_metal_op_tri(ggml_metal_op_t ctx, int idx) {
5371    ggml_tensor * op = ctx->node(idx);
5372
5373    ggml_metal_library_t lib = ctx->lib;
5374    ggml_metal_encoder_t enc = ctx->enc;
5375
5376    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
5377    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
5378    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
5379    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
5380
5381    ggml_metal_kargs_tri args = {
5382        /*.ne00  =*/ ne00,
5383        /*.ne01  =*/ ne01,
5384        /*.ne02  =*/ ne02,
5385        /*.ne03  =*/ ne03,
5386        /*.nb00  =*/ nb00,
5387        /*.nb01  =*/ nb01,
5388        /*.nb02  =*/ nb02,
5389        /*.nb03  =*/ nb03,
5390        /*.ne0   =*/ ne0,
5391        /*.ne1   =*/ ne1,
5392        /*.ne2   =*/ ne2,
5393        /*.ne3   =*/ ne3,
5394        /*.nb0   =*/ nb0,
5395        /*.nb1   =*/ nb1,
5396        /*.nb2   =*/ nb2,
5397        /*.nb3   =*/ nb3,
5398    };
5399
5400    auto pipeline = ggml_metal_library_get_pipeline_tri(lib, op);
5401
5402    int nth = 32; // SIMD width
5403
5404    while (nth < ne00 && nth < ggml_metal_pipeline_max_theads_per_threadgroup(pipeline)) {
5405        nth *= 2;
5406    }
5407
5408    nth = std::min(nth, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
5409    nth = std::min(nth, ne00);
5410
5411    ggml_metal_encoder_set_pipeline(enc, pipeline);
5412    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), 0);
5413    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), 1);
5414    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op),         2);
5415
5416    ggml_metal_encoder_dispatch_threadgroups(enc, ne01, ne02, ne03, nth, 1, 1);
5417
5418    return 1;
5419}
5420
5421int ggml_metal_op_opt_step_adamw(ggml_metal_op_t ctx, int idx) {
5422    ggml_tensor * op = ctx->node(idx);
5423
5424    ggml_metal_library_t lib = ctx->lib;
5425    ggml_metal_encoder_t enc = ctx->enc;
5426
5427    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
5428    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
5429    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
5430    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
5431
5432    auto pipeline = ggml_metal_library_get_pipeline_opt_step_adamw(lib, op);
5433
5434    const int64_t np = ggml_nelements(op->src[0]);
5435    ggml_metal_kargs_opt_step_adamw args = {
5436        /*.np =*/ np,
5437    };
5438
5439    int ida = 0;
5440
5441    ggml_metal_encoder_set_pipeline(enc, pipeline);
5442    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), ida++);
5443    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), ida++);
5444    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), ida++);
5445    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[2]), ida++);
5446    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[3]), ida++);
5447    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[4]), ida++);
5448
5449    const int nth = std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline), ne0);
5450    const int64_t n = (np + nth - 1) / nth;
5451
5452    ggml_metal_encoder_dispatch_threadgroups(enc, n, 1, 1, nth, 1, 1);
5453
5454    return 1;
5455}
5456
5457int ggml_metal_op_opt_step_sgd(ggml_metal_op_t ctx, int idx) {
5458    ggml_tensor * op = ctx->node(idx);
5459
5460    ggml_metal_library_t lib = ctx->lib;
5461    ggml_metal_encoder_t enc = ctx->enc;
5462
5463    GGML_TENSOR_LOCALS( int32_t, ne0, op->src[0], ne);
5464    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
5465    GGML_TENSOR_LOCALS( int32_t, ne,  op,         ne);
5466    GGML_TENSOR_LOCALS(uint64_t, nb,  op,         nb);
5467
5468    auto pipeline = ggml_metal_library_get_pipeline_opt_step_sgd(lib, op);
5469
5470    const int64_t np = ggml_nelements(op->src[0]);
5471    ggml_metal_kargs_opt_step_sgd args = {
5472        /*.np =*/ np,
5473    };
5474
5475    int ida = 0;
5476
5477    ggml_metal_encoder_set_pipeline(enc, pipeline);
5478    ggml_metal_encoder_set_bytes   (enc, &args, sizeof(args), ida++);
5479    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[0]), ida++);
5480    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[1]), ida++);
5481    ggml_metal_encoder_set_buffer  (enc, ggml_metal_get_buffer_id(op->src[2]), ida++);
5482
5483    const int nth = std::min(ggml_metal_pipeline_max_theads_per_threadgroup(pipeline), ne0);
5484    const int64_t n = (np + nth - 1) / nth;
5485
5486    ggml_metal_encoder_dispatch_threadgroups(enc, n, 1, 1, nth, 1, 1);
5487
5488    return 1;
5489}
5490
5491int ggml_metal_op_count_equal(ggml_metal_op_t ctx, int idx) {
5492    ggml_tensor * op = ctx->node(idx);
5493
5494    ggml_metal_library_t lib = ctx->lib;
5495    ggml_metal_encoder_t enc = ctx->enc;
5496
5497    GGML_TENSOR_LOCALS(int32_t,  ne0, op->src[0], ne);
5498    GGML_TENSOR_LOCALS(uint64_t, nb0, op->src[0], nb);
5499    GGML_TENSOR_LOCALS(uint64_t, nb1, op->src[1], nb);
5500
5501    {
5502        ggml_metal_kargs_memset args = { /*.val =*/ 0 };
5503
5504        auto pipeline = ggml_metal_library_get_pipeline_memset(lib, op);
5505
5506        ggml_metal_encoder_set_pipeline(enc, pipeline);
5507        ggml_metal_encoder_set_bytes(enc, &args, sizeof(args), 0);
5508        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op), 1);
5509
5510        ggml_metal_encoder_dispatch_threadgroups(enc, 1, 1, 1, 1, 1, 1);
5511    }
5512
5513    ggml_metal_op_concurrency_reset(ctx);
5514
5515    {
5516        ggml_metal_kargs_count_equal args = {
5517            /*.ne00 =*/ ne00,
5518            /*.ne01 =*/ ne01,
5519            /*.ne02 =*/ ne02,
5520            /*.ne03 =*/ ne03,
5521            /*.nb00 =*/ nb00,
5522            /*.nb01 =*/ nb01,
5523            /*.nb02 =*/ nb02,
5524            /*.nb03 =*/ nb03,
5525            /*.nb10 =*/ nb10,
5526            /*.nb11 =*/ nb11,
5527            /*.nb12 =*/ nb12,
5528            /*.nb13 =*/ nb13,
5529        };
5530
5531        auto pipeline = ggml_metal_library_get_pipeline_count_equal(lib, op);
5532
5533        const size_t smem = pipeline.smem;
5534
5535        const int nth = 32*pipeline.nsg;
5536
5537        GGML_ASSERT(nth <= ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
5538
5539        ggml_metal_encoder_set_pipeline(enc, pipeline);
5540        ggml_metal_encoder_set_bytes(enc, &args, sizeof(args), 0);
5541        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op->src[0]), 1);
5542        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op->src[1]), 2);
5543        ggml_metal_encoder_set_buffer(enc, ggml_metal_get_buffer_id(op), 3);
5544
5545        ggml_metal_encoder_set_threadgroup_memory_size(enc, smem, 0);
5546        ggml_metal_encoder_dispatch_threadgroups(enc, ne01, ne02, ne03, nth, 1, 1);
5547    }
5548
5549    return 1;
5550}