kazutab commited on
Commit
80e5f6d
·
verified ·
1 Parent(s): 7b49da7

Upload folder using huggingface_hub (part 4)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. backend/llama.cpp/ggml/src/ggml-cuda/fwht.cu +101 -0
  2. backend/llama.cpp/ggml/src/ggml-cuda/fwht.cuh +4 -0
  3. backend/llama.cpp/ggml/src/ggml-cuda/gated_delta_net.cu +327 -0
  4. backend/llama.cpp/ggml/src/ggml-cuda/gated_delta_net.cuh +14 -0
  5. backend/llama.cpp/ggml/src/ggml-cuda/getrows.cu +311 -0
  6. backend/llama.cpp/ggml/src/ggml-cuda/getrows.cuh +15 -0
  7. backend/llama.cpp/ggml/src/ggml-cuda/ggml-cuda.cu +0 -0
  8. backend/llama.cpp/ggml/src/ggml-cuda/gla.cu +93 -0
  9. backend/llama.cpp/ggml/src/ggml-cuda/gla.cuh +3 -0
  10. backend/llama.cpp/ggml/src/ggml-cuda/im2col.cu +267 -0
  11. backend/llama.cpp/ggml/src/ggml-cuda/im2col.cuh +6 -0
  12. backend/llama.cpp/ggml/src/ggml-cuda/mean.cu +77 -0
  13. backend/llama.cpp/ggml/src/ggml-cuda/mean.cuh +3 -0
  14. backend/llama.cpp/ggml/src/ggml-cuda/mma.cuh +1456 -0
  15. backend/llama.cpp/ggml/src/ggml-cuda/mmf.cu +191 -0
  16. backend/llama.cpp/ggml/src/ggml-cuda/mmf.cuh +908 -0
  17. backend/llama.cpp/ggml/src/ggml-cuda/mmid.cu +164 -0
  18. backend/llama.cpp/ggml/src/ggml-cuda/mmid.cuh +5 -0
  19. backend/llama.cpp/ggml/src/ggml-cuda/mmq.cu +379 -0
  20. backend/llama.cpp/ggml/src/ggml-cuda/mmq.cuh +0 -0
  21. backend/llama.cpp/ggml/src/ggml-cuda/mmvf.cu +869 -0
  22. backend/llama.cpp/ggml/src/ggml-cuda/mmvf.cuh +14 -0
  23. backend/llama.cpp/ggml/src/ggml-cuda/mmvq.cu +1289 -0
  24. backend/llama.cpp/ggml/src/ggml-cuda/mmvq.cuh +18 -0
  25. backend/llama.cpp/ggml/src/ggml-cuda/norm.cu +698 -0
  26. backend/llama.cpp/ggml/src/ggml-cuda/norm.cuh +18 -0
  27. backend/llama.cpp/ggml/src/ggml-cuda/opt-step-adamw.cu +78 -0
  28. backend/llama.cpp/ggml/src/ggml-cuda/opt-step-adamw.cuh +5 -0
  29. backend/llama.cpp/ggml/src/ggml-cuda/opt-step-sgd.cu +49 -0
  30. backend/llama.cpp/ggml/src/ggml-cuda/opt-step-sgd.cuh +5 -0
  31. backend/llama.cpp/ggml/src/ggml-cuda/out-prod.cu +127 -0
  32. backend/llama.cpp/ggml/src/ggml-cuda/out-prod.cuh +3 -0
  33. backend/llama.cpp/ggml/src/ggml-cuda/pad.cu +106 -0
  34. backend/llama.cpp/ggml/src/ggml-cuda/pad.cuh +5 -0
  35. backend/llama.cpp/ggml/src/ggml-cuda/pad_reflect_1d.cu +91 -0
  36. backend/llama.cpp/ggml/src/ggml-cuda/pad_reflect_1d.cuh +5 -0
  37. backend/llama.cpp/ggml/src/ggml-cuda/pool2d.cu +94 -0
  38. backend/llama.cpp/ggml/src/ggml-cuda/pool2d.cuh +5 -0
  39. backend/llama.cpp/ggml/src/ggml-cuda/quantize.cu +450 -0
  40. backend/llama.cpp/ggml/src/ggml-cuda/quantize.cuh +41 -0
  41. backend/llama.cpp/ggml/src/ggml-cuda/reduce_rows.cuh +43 -0
  42. backend/llama.cpp/ggml/src/ggml-cuda/roll.cu +67 -0
  43. backend/llama.cpp/ggml/src/ggml-cuda/roll.cuh +5 -0
  44. backend/llama.cpp/ggml/src/ggml-cuda/rope.cu +672 -0
  45. backend/llama.cpp/ggml/src/ggml-cuda/rope.cuh +9 -0
  46. backend/llama.cpp/ggml/src/ggml-cuda/scale.cu +37 -0
  47. backend/llama.cpp/ggml/src/ggml-cuda/scale.cuh +5 -0
  48. backend/llama.cpp/ggml/src/ggml-cuda/set-rows.cu +398 -0
  49. backend/llama.cpp/ggml/src/ggml-cuda/set-rows.cuh +7 -0
  50. backend/llama.cpp/ggml/src/ggml-cuda/set.cu +39 -0
backend/llama.cpp/ggml/src/ggml-cuda/fwht.cu ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+ #include "fwht.cuh"
3
+
4
+ template <int N>
5
+ __launch_bounds__(4*ggml_cuda_get_physical_warp_size(), 1)
6
+ __global__ void fwht_cuda(const float * src, float * dst, const int64_t n_rows, const float scale) {
7
+ constexpr int warp_size = ggml_cuda_get_physical_warp_size();
8
+
9
+ const int64_t r = (int64_t) blockIdx.x * blockDim.y + threadIdx.y;
10
+
11
+ if (r >= n_rows) {
12
+ return;
13
+ }
14
+
15
+ src += r * N;
16
+ dst += r * N;
17
+
18
+ static constexpr int el_w = N / warp_size;
19
+ float reg[el_w];
20
+ const int lane = threadIdx.x;
21
+
22
+ ggml_cuda_pdl_sync();
23
+ #pragma unroll
24
+ for (int i = 0; i < el_w; ++i) {
25
+ reg[i] = src[i * warp_size + lane] * scale;
26
+ }
27
+
28
+ #pragma unroll
29
+ for (int h = 1; h < warp_size; h *= 2) {
30
+ #pragma unroll
31
+ for (int j = 0; j < el_w; j++) {
32
+ const float val = reg[j];
33
+ const float val2 = __shfl_xor_sync(0xFFFFFFFF, val, h, warp_size);
34
+
35
+ reg[j] = (lane & h) == 0 ? val + val2 : val2 - val;
36
+ }
37
+ }
38
+
39
+ #pragma unroll
40
+ for (int h = warp_size; h < N; h *= 2) {
41
+ const int step = h / warp_size;
42
+ #pragma unroll
43
+ for (int j = 0; j < el_w; j += 2 * step) {
44
+ #pragma unroll
45
+ for (int k = 0; k < step; k++) {
46
+ const float x = reg[j + k];
47
+ const float y = reg[j + k + step];
48
+
49
+ reg[j + k] = x + y;
50
+ reg[j + k + step] = x - y;
51
+ }
52
+ }
53
+ }
54
+
55
+ #pragma unroll
56
+ for (int i = 0; i < el_w; ++i) {
57
+ dst[i * warp_size + lane] = reg[i];
58
+ }
59
+ }
60
+
61
+ bool ggml_cuda_op_fwht(ggml_backend_cuda_context & ctx, const ggml_tensor * src, ggml_tensor * dst) {
62
+ GGML_ASSERT(ggml_are_same_shape(src, dst));
63
+ if (!ggml_is_contiguous(src) || !ggml_is_contiguous(dst)) {
64
+ return false;
65
+ }
66
+ const int n = src->ne[0];
67
+ const int64_t rows = ggml_nrows(src);
68
+
69
+ const float * src_d = (const float *) src->data;
70
+ float * dst_d = (float *) dst->data;
71
+
72
+ const int warp_size = ggml_cuda_info().devices[ggml_cuda_get_device()].warp_size;
73
+ const int rows_per_block = 4;
74
+
75
+ const int64_t num_blocks = (rows + rows_per_block - 1) / rows_per_block;
76
+
77
+ cudaStream_t stream = ctx.stream();
78
+ dim3 grid_dims(num_blocks, 1, 1);
79
+ dim3 block_dims(warp_size, rows_per_block, 1);
80
+ const ggml_cuda_kernel_launch_params launch_params =
81
+ ggml_cuda_kernel_launch_params(grid_dims, block_dims, 0, stream);
82
+
83
+ const float scale = 1 / sqrtf(n);
84
+
85
+ switch (n) {
86
+ case 64:
87
+ ggml_cuda_kernel_launch(fwht_cuda<64>, launch_params, src_d, dst_d, rows, scale);
88
+ return true;
89
+ case 128:
90
+ ggml_cuda_kernel_launch(fwht_cuda<128>, launch_params, src_d, dst_d, rows, scale);
91
+ return true;
92
+ case 256:
93
+ ggml_cuda_kernel_launch(fwht_cuda<256>, launch_params, src_d, dst_d, rows, scale);
94
+ return true;
95
+ case 512:
96
+ ggml_cuda_kernel_launch(fwht_cuda<512>, launch_params, src_d, dst_d, rows, scale);
97
+ return true;
98
+ default:
99
+ return false;
100
+ }
101
+ }
backend/llama.cpp/ggml/src/ggml-cuda/fwht.cuh ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ // Returns whether the Fast Walsh-Hadamard transform could be used.
4
+ bool ggml_cuda_op_fwht(ggml_backend_cuda_context & ctx, const ggml_tensor * src, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/gated_delta_net.cu ADDED
@@ -0,0 +1,327 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "gated_delta_net.cuh"
2
+ #include "ggml-cuda/common.cuh"
3
+
4
+ template <int S_v, bool KDA, bool keep_rs_t>
5
+ __global__ void __launch_bounds__((ggml_cuda_get_physical_warp_size() < S_v ? ggml_cuda_get_physical_warp_size() : S_v) * 4, 2)
6
+ gated_delta_net_cuda(const float * q,
7
+ const float * k,
8
+ const float * v,
9
+ const float * g,
10
+ const float * beta,
11
+ const float * curr_state,
12
+ float * dst,
13
+ float * state,
14
+ int64_t H,
15
+ int64_t n_tokens,
16
+ int64_t n_seqs,
17
+ int64_t sq1,
18
+ int64_t sq2,
19
+ int64_t sq3,
20
+ int64_t sv1,
21
+ int64_t sv2,
22
+ int64_t sv3,
23
+ int64_t sb1,
24
+ int64_t sb2,
25
+ int64_t sb3,
26
+ const uint3 neqk1_magic,
27
+ const uint3 rq3_magic,
28
+ float scale,
29
+ int64_t state_slot_stride,
30
+ int K) {
31
+ const uint32_t h_idx = blockIdx.x;
32
+ const uint32_t sequence = blockIdx.y;
33
+ // each warp owns one column, using warp-level primitives to reduce across rows
34
+ const int lane = threadIdx.x;
35
+ const int col = blockIdx.z * blockDim.y + threadIdx.y;
36
+
37
+ const uint32_t iq1 = fastmodulo(h_idx, neqk1_magic);
38
+ const uint32_t iq3 = fastdiv(sequence, rq3_magic);
39
+
40
+ float * attn_data = dst;
41
+
42
+ // input state holds s0 only: [S_v, S_v, H, n_seqs] — seq stride is D = H * S_v * S_v.
43
+ // output state layout (per-slot D * n_seqs) — same per-(seq,head) offset as before.
44
+ const int64_t state_in_offset = sequence * H * S_v * S_v + h_idx * S_v * S_v;
45
+ const int64_t state_out_offset = (sequence * H + h_idx) * S_v * S_v;
46
+ state += state_out_offset;
47
+ curr_state += state_in_offset + col * S_v;
48
+ attn_data += (sequence * n_tokens * H + h_idx) * S_v;
49
+
50
+ constexpr int warp_size = ggml_cuda_get_physical_warp_size() < S_v ? ggml_cuda_get_physical_warp_size() : S_v;
51
+ static_assert(S_v % warp_size == 0, "S_v must be a multiple of warp_size");
52
+ constexpr int rows_per_lane = (S_v + warp_size - 1) / warp_size;
53
+ float s_shard[rows_per_lane];
54
+ // state is stored transposed: M[col][i] = S[i][col], row col is contiguous
55
+
56
+ ggml_cuda_pdl_sync();
57
+ #pragma unroll
58
+ for (int r = 0; r < rows_per_lane; r++) {
59
+ const int i = r * warp_size + lane;
60
+ s_shard[r] = curr_state[i];
61
+ }
62
+
63
+ for (int t = 0; t < n_tokens; t++) {
64
+ const float * q_t = q + iq3 * sq3 + t * sq2 + iq1 * sq1;
65
+ const float * k_t = k + iq3 * sq3 + t * sq2 + iq1 * sq1;
66
+ const float * v_t = v + sequence * sv3 + t * sv2 + h_idx * sv1;
67
+
68
+ const int64_t gb_offset = sequence * sb3 + t * sb2 + h_idx * sb1;
69
+ const float * beta_t = beta + gb_offset;
70
+ const float * g_t = g + gb_offset * (KDA ? S_v : 1);
71
+
72
+ const float beta_val = *beta_t;
73
+
74
+ // Cache k and q in registers
75
+ float k_reg[rows_per_lane];
76
+ float q_reg[rows_per_lane];
77
+ #pragma unroll
78
+ for (int r = 0; r < rows_per_lane; r++) {
79
+ const int i = r * warp_size + lane;
80
+ k_reg[r] = k_t[i];
81
+ q_reg[r] = q_t[i];
82
+ }
83
+
84
+ if constexpr (!KDA) {
85
+ const float g_val = expf(*g_t);
86
+
87
+ // kv[col] = (S^T @ k)[col] = sum_i S[i][col] * k[i]
88
+ float kv_shard = 0.0f;
89
+ #pragma unroll
90
+ for (int r = 0; r < rows_per_lane; r++) {
91
+ kv_shard += s_shard[r] * k_reg[r];
92
+ }
93
+ float kv_col = warp_reduce_sum<warp_size>(kv_shard);
94
+
95
+ // delta[col] = (v[col] - g * kv[col]) * beta
96
+ float delta_col = (v_t[col] - g_val * kv_col) * beta_val;
97
+
98
+ // fused: S[i][col] = g * S[i][col] + k[i] * delta[col]
99
+ // attn[col] = (S^T @ q)[col] = sum_i S[i][col] * q[i]
100
+ float attn_partial = 0.0f;
101
+ #pragma unroll
102
+ for (int r = 0; r < rows_per_lane; r++) {
103
+ s_shard[r] = g_val * s_shard[r] + k_reg[r] * delta_col;
104
+ attn_partial += s_shard[r] * q_reg[r];
105
+ }
106
+
107
+ float attn_col = warp_reduce_sum<warp_size>(attn_partial);
108
+
109
+ if (lane == 0) {
110
+ attn_data[col] = attn_col * scale;
111
+ }
112
+ } else {
113
+ // kv[col] = sum_i g[i] * S[i][col] * k[i]
114
+ float kv_shard = 0.0f;
115
+ #pragma unroll
116
+ for (int r = 0; r < rows_per_lane; r++) {
117
+ const int i = r * warp_size + lane;
118
+ kv_shard += expf(g_t[i]) * s_shard[r] * k_reg[r];
119
+ }
120
+
121
+ float kv_col = warp_reduce_sum<warp_size>(kv_shard);
122
+
123
+ // delta[col] = (v[col] - kv[col]) * beta
124
+ float delta_col = (v_t[col] - kv_col) * beta_val;
125
+
126
+ // fused: S[i][col] = g[i] * S[i][col] + k[i] * delta[col]
127
+ // attn[col] = (S^T @ q)[col] = sum_i S[i][col] * q[i]
128
+ float attn_partial = 0.0f;
129
+ #pragma unroll
130
+ for (int r = 0; r < rows_per_lane; r++) {
131
+ const int i = r * warp_size + lane;
132
+ s_shard[r] = expf(g_t[i]) * s_shard[r] + k_reg[r] * delta_col;
133
+ attn_partial += s_shard[r] * q_reg[r];
134
+ }
135
+
136
+ float attn_col = warp_reduce_sum<warp_size>(attn_partial);
137
+
138
+ if (lane == 0) {
139
+ attn_data[col] = attn_col * scale;
140
+ }
141
+ }
142
+
143
+ attn_data += S_v * H;
144
+
145
+ if constexpr (keep_rs_t) {
146
+ // snapshot slot mapping: slot 0 = most recent state, slot s = s tokens back.
147
+ // When n_tokens < K only slots 0..n_tokens-1 are written; older slots are caller-owned.
148
+ const int target_slot = (int) n_tokens - 1 - t;
149
+ if (target_slot >= 0 && target_slot < K) {
150
+ float * curr_state = state + target_slot * state_slot_stride;
151
+ #pragma unroll
152
+ for (int r = 0; r < rows_per_lane; r++) {
153
+ const int i = r * warp_size + lane;
154
+ curr_state[col * S_v + i] = s_shard[r];
155
+ }
156
+ }
157
+ }
158
+ }
159
+
160
+ if constexpr (!keep_rs_t) {
161
+ #pragma unroll
162
+ for (int r = 0; r < rows_per_lane; r++) {
163
+ const int i = r * warp_size + lane;
164
+ state[col * S_v + i] = s_shard[r];
165
+ }
166
+ }
167
+ }
168
+
169
+ template <bool KDA, bool keep_rs_t>
170
+ static void launch_gated_delta_net(
171
+ const float * q_d, const float * k_d, const float * v_d,
172
+ const float * g_d, const float * b_d, const float * s_d,
173
+ float * dst_d, float * state_d,
174
+ int64_t S_v, int64_t H, int64_t n_tokens, int64_t n_seqs,
175
+ int64_t sq1, int64_t sq2, int64_t sq3,
176
+ int64_t sv1, int64_t sv2, int64_t sv3,
177
+ int64_t sb1, int64_t sb2, int64_t sb3,
178
+ int64_t neqk1, int64_t rq3,
179
+ float scale, int64_t state_slot_stride, int K, cudaStream_t stream) {
180
+ //TODO: Add chunked kernel for even faster pre-fill
181
+ const int warp_size = ggml_cuda_info().devices[ggml_cuda_get_device()].warp_size;
182
+ const int num_warps = 4;
183
+ dim3 grid_dims(H, n_seqs, (S_v + num_warps - 1) / num_warps);
184
+ dim3 block_dims(warp_size <= S_v ? warp_size : S_v, num_warps, 1);
185
+
186
+ const uint3 neqk1_magic = init_fastdiv_values(neqk1);
187
+ const uint3 rq3_magic = init_fastdiv_values(rq3);
188
+
189
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(grid_dims, block_dims, 0, stream);
190
+ switch (S_v) {
191
+ case 16:
192
+ ggml_cuda_kernel_launch(gated_delta_net_cuda<16, KDA, keep_rs_t>, launch_params,
193
+ q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d, H,
194
+ n_tokens, n_seqs, sq1, sq2, sq3, sv1, sv2, sv3,
195
+ sb1, sb2, sb3, neqk1_magic, rq3_magic, scale, state_slot_stride, K);
196
+ break;
197
+ case 32:
198
+ ggml_cuda_kernel_launch(gated_delta_net_cuda<32, KDA, keep_rs_t>, launch_params,
199
+ q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d, H,
200
+ n_tokens, n_seqs, sq1, sq2, sq3, sv1, sv2, sv3,
201
+ sb1, sb2, sb3, neqk1_magic, rq3_magic, scale, state_slot_stride, K);
202
+ break;
203
+ case 64: {
204
+ ggml_cuda_kernel_launch(gated_delta_net_cuda<64, KDA, keep_rs_t>, launch_params,
205
+ q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d, H,
206
+ n_tokens, n_seqs, sq1, sq2, sq3, sv1, sv2, sv3,
207
+ sb1, sb2, sb3, neqk1_magic, rq3_magic, scale, state_slot_stride, K);
208
+ break;
209
+ }
210
+ case 128: {
211
+ ggml_cuda_kernel_launch(gated_delta_net_cuda<128, KDA, keep_rs_t>, launch_params,
212
+ q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d, H,
213
+ n_tokens, n_seqs, sq1, sq2, sq3, sv1, sv2, sv3,
214
+ sb1, sb2, sb3, neqk1_magic, rq3_magic, scale, state_slot_stride, K);
215
+ break;
216
+ }
217
+ default:
218
+ GGML_ABORT("fatal error");
219
+ break;
220
+ }
221
+ }
222
+
223
+ static void ggml_cuda_op_gated_delta_net_impl(
224
+ ggml_backend_cuda_context & ctx, ggml_tensor * dst, const ggml_cuda_gated_delta_net_fused_cache * cache) {
225
+ ggml_tensor * src_q = dst->src[0];
226
+ ggml_tensor * src_k = dst->src[1];
227
+ ggml_tensor * src_v = dst->src[2];
228
+ ggml_tensor * src_g = dst->src[3];
229
+ ggml_tensor * src_beta = dst->src[4];
230
+ ggml_tensor * src_state = dst->src[5];
231
+
232
+ GGML_TENSOR_LOCALS(int64_t, neq, src_q, ne);
233
+ GGML_TENSOR_LOCALS(size_t , nbq, src_q, nb);
234
+ GGML_TENSOR_LOCALS(int64_t, nek, src_k, ne);
235
+ GGML_TENSOR_LOCALS(size_t , nbk, src_k, nb);
236
+ GGML_TENSOR_LOCALS(int64_t, nev, src_v, ne);
237
+ GGML_TENSOR_LOCALS(size_t, nbv, src_v, nb);
238
+ GGML_TENSOR_LOCALS(size_t, nbb, src_beta, nb);
239
+
240
+ const int64_t S_v = nev0;
241
+ const int64_t H = nev1;
242
+ const int64_t n_tokens = nev2;
243
+ const int64_t n_seqs = nev3;
244
+
245
+ const bool kda = (src_g->ne[0] == S_v);
246
+
247
+ GGML_ASSERT(neq1 == nek1);
248
+ const int64_t neqk1 = neq1;
249
+
250
+ const int64_t rq3 = nev3 / neq3;
251
+
252
+ const float * q_d = (const float *) src_q->data;
253
+ const float * k_d = (const float *) src_k->data;
254
+ const float * v_d = (const float *) src_v->data;
255
+ const float * g_d = (const float *) src_g->data;
256
+ const float * b_d = (const float *) src_beta->data;
257
+
258
+ const float * s_d = (const float *) src_state->data;
259
+ float * dst_d = (float *) dst->data;
260
+
261
+ GGML_ASSERT(ggml_is_contiguous_rows(src_q));
262
+ GGML_ASSERT(ggml_is_contiguous_rows(src_k));
263
+ GGML_ASSERT(ggml_is_contiguous_rows(src_v));
264
+ GGML_ASSERT(ggml_are_same_stride(src_q, src_k));
265
+ GGML_ASSERT(src_g->ne[0] == 1 || kda);
266
+ GGML_ASSERT(ggml_is_contiguous(src_g));
267
+ GGML_ASSERT(ggml_is_contiguous(src_beta));
268
+ GGML_ASSERT(ggml_is_contiguous(src_state));
269
+
270
+ // strides in floats (beta strides used for both g and beta offset computation)
271
+ const int64_t sq1 = nbq1 / sizeof(float);
272
+ const int64_t sq2 = nbq2 / sizeof(float);
273
+ const int64_t sq3 = nbq3 / sizeof(float);
274
+ const int64_t sv1 = nbv1 / sizeof(float);
275
+ const int64_t sv2 = nbv2 / sizeof(float);
276
+ const int64_t sv3 = nbv3 / sizeof(float);
277
+ const int64_t sb1 = nbb1 / sizeof(float);
278
+ const int64_t sb2 = nbb2 / sizeof(float);
279
+ const int64_t sb3 = nbb3 / sizeof(float);
280
+
281
+ const float scale = 1.0f / sqrtf((float) S_v);
282
+
283
+ cudaStream_t stream = ctx.stream();
284
+
285
+ // K (snapshot slot count) is an op param; state holds s0 only [S_v, S_v, H, n_seqs].
286
+ const int K = ggml_get_op_params_i32(dst, 0);
287
+ const bool keep_rs = K > 1;
288
+
289
+ // recurrent state -> gdn_out tail (after attention scores), or the cache when fusing
290
+ float * state_d = dst_d + S_v * H * n_tokens * n_seqs;
291
+ int64_t state_slot_stride = S_v * S_v * H * n_seqs;
292
+ if (cache != nullptr) {
293
+ state_d = cache->data;
294
+ state_slot_stride = cache->slot_stride;
295
+ }
296
+
297
+ if (kda) {
298
+ if (keep_rs) {
299
+ launch_gated_delta_net<true, true>(q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d,
300
+ S_v, H, n_tokens, n_seqs, sq1, sq2, sq3, sv1, sv2, sv3,
301
+ sb1, sb2, sb3, neqk1, rq3, scale, state_slot_stride, K, stream);
302
+ } else {
303
+ launch_gated_delta_net<true, false>(q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d,
304
+ S_v, H, n_tokens, n_seqs, sq1, sq2, sq3, sv1, sv2, sv3,
305
+ sb1, sb2, sb3, neqk1, rq3, scale, state_slot_stride, K, stream);
306
+ }
307
+ } else {
308
+ if (keep_rs) {
309
+ launch_gated_delta_net<false, true>(q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d,
310
+ S_v, H, n_tokens, n_seqs, sq1, sq2, sq3, sv1, sv2, sv3,
311
+ sb1, sb2, sb3, neqk1, rq3, scale, state_slot_stride, K, stream);
312
+ } else {
313
+ launch_gated_delta_net<false, false>(q_d, k_d, v_d, g_d, b_d, s_d, dst_d, state_d,
314
+ S_v, H, n_tokens, n_seqs, sq1, sq2, sq3, sv1, sv2, sv3,
315
+ sb1, sb2, sb3, neqk1, rq3, scale, state_slot_stride, K, stream);
316
+ }
317
+ }
318
+ }
319
+
320
+ void ggml_cuda_op_gated_delta_net(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
321
+ ggml_cuda_op_gated_delta_net_impl(ctx, dst, nullptr);
322
+ }
323
+
324
+ void ggml_cuda_op_gated_delta_net_fused_cache(
325
+ ggml_backend_cuda_context & ctx, ggml_tensor * dst, ggml_cuda_gated_delta_net_fused_cache cache) {
326
+ ggml_cuda_op_gated_delta_net_impl(ctx, dst, &cache);
327
+ }
backend/llama.cpp/ggml/src/ggml-cuda/gated_delta_net.cuh ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+ #include "ggml.h"
3
+
4
+ // fused-kernel recurrent-state output; strides in elements (per-seq stride is always D, set in-kernel)
5
+ struct ggml_cuda_gated_delta_net_fused_cache {
6
+ float * data; // rollback slot 0
7
+ int64_t slot_stride; // between rollback slots (0 when K==1)
8
+ };
9
+
10
+ void ggml_cuda_op_gated_delta_net(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
11
+
12
+ // same op, but writes the snapshot(s) into the cache instead of dst (see ggml_cuda_try_gdn_cache_fusion)
13
+ void ggml_cuda_op_gated_delta_net_fused_cache(ggml_backend_cuda_context & ctx, ggml_tensor * dst,
14
+ ggml_cuda_gated_delta_net_fused_cache cache);
backend/llama.cpp/ggml/src/ggml-cuda/getrows.cu ADDED
@@ -0,0 +1,311 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "getrows.cuh"
2
+ #include "dequantize.cuh"
3
+ #include "convert.cuh"
4
+
5
+ template<int qk, int qr, dequantize_kernel_t dequantize_kernel, typename dst_t>
6
+ static __global__ void k_get_rows(
7
+ const void * __restrict__ src0, const int32_t * __restrict__ src1, dst_t * __restrict__ dst,
8
+ const int64_t ne00, /*const int64_t ne01, const int64_t ne02, const int64_t ne03,*/
9
+ /*const int64_t ne10,*/ const int64_t ne11, const uint3 ne12_fdv, /*const int64_t ne13,*/
10
+ /*const size_t s0,*/ const size_t s1, const size_t s2, const size_t s3,
11
+ /*const size_t nb00,*/ const size_t nb01, const size_t nb02, const size_t nb03,
12
+ const size_t s10, const size_t s11, const size_t s12/*, const size_t s13*/) {
13
+
14
+ ggml_cuda_pdl_sync();
15
+ for (int64_t z = blockIdx.z; z < ne11*(int64_t)ne12_fdv.z; z += gridDim.z) {
16
+ for (int64_t i00 = 2*(blockIdx.y*blockDim.x + threadIdx.x); i00 < ne00; i00 += gridDim.y*blockDim.x) {
17
+ // The x and y dimensions of the grid are swapped because the maximum allowed grid size for x is higher.
18
+ const int i10 = blockIdx.x;
19
+ const uint2 dm = fast_div_modulo((uint32_t)z, ne12_fdv);
20
+ const int i11 = dm.x;
21
+ const int i12 = dm.y;
22
+
23
+ const int i01 = src1[i10*s10 + i11*s11 + i12*s12];
24
+
25
+ dst_t * dst_row = dst + i10*s1 + i11*s2 + i12*s3;
26
+ const void * src0_row = (const char *) src0 + i01*nb01 + i11*nb02 + i12*nb03;
27
+
28
+ const int ib = i00/qk; // block index
29
+ const int iqs = (i00%qk)/qr; // quant index
30
+ const int iybs = i00 - i00%qk; // dst block start index
31
+ const int y_offset = qr == 1 ? 1 : qk/2;
32
+
33
+ // dequantize
34
+ float2 v;
35
+ dequantize_kernel(src0_row, ib, iqs, v);
36
+
37
+ dst_row[iybs + iqs + 0] = ggml_cuda_cast<dst_t>(v.x);
38
+ dst_row[iybs + iqs + y_offset] = ggml_cuda_cast<dst_t>(v.y);
39
+ }
40
+ }
41
+ }
42
+
43
+ template<typename src0_t, typename dst_t>
44
+ static __global__ void k_get_rows_float(
45
+ const src0_t * src0_ptr, const int32_t * src1_ptr, dst_t * dst_ptr,
46
+ const int64_t ne00, /*const int64_t ne01, const int64_t ne02, const int64_t ne03,*/
47
+ /*const int64_t ne10,*/ const int64_t ne11, const uint3 ne12_fdv, /*const int64_t ne13,*/
48
+ /*const size_t s0,*/ const size_t s1, const size_t s2, const size_t s3,
49
+ /*const size_t nb00,*/ const size_t nb01, const size_t nb02, const size_t nb03,
50
+ const size_t s10, const size_t s11, const size_t s12/*, const size_t s13*/) {
51
+
52
+ ggml_cuda_pdl_lc();
53
+ const src0_t * GGML_CUDA_RESTRICT src0 = src0_ptr;
54
+ const int32_t * GGML_CUDA_RESTRICT src1 = src1_ptr;
55
+ dst_t * GGML_CUDA_RESTRICT dst = dst_ptr;
56
+ ggml_cuda_pdl_sync();
57
+ for (int64_t z = blockIdx.z; z < ne11*(int64_t)ne12_fdv.z; z += gridDim.z) {
58
+ for (int64_t i00 = blockIdx.y*blockDim.x + threadIdx.x; i00 < ne00; i00 += gridDim.y*blockDim.x) {
59
+ // The x and y dimensions of the grid are swapped because the maximum allowed grid size for x is higher.
60
+ const int i10 = blockIdx.x;
61
+ const uint2 dm = fast_div_modulo((uint32_t)z, ne12_fdv);
62
+ const int i11 = dm.x;
63
+ const int i12 = dm.y;
64
+
65
+ if (i00 >= ne00) {
66
+ return;
67
+ }
68
+
69
+ const int i01 = src1[i10*s10 + i11*s11 + i12*s12];
70
+
71
+ dst_t * dst_row = dst + i10*s1 + i11*s2 + i12*s3;
72
+ const src0_t * src0_row = (const src0_t *)((const char *) src0 + i01*nb01 + i11*nb02 + i12*nb03);
73
+
74
+ dst_row[i00] = ggml_cuda_cast<dst_t>(src0_row[i00]);
75
+ }
76
+ }
77
+ }
78
+
79
+ template<typename grad_t, typename dst_t>
80
+ static __global__ void k_get_rows_back_float(
81
+ const grad_t * __restrict__ grad, const int32_t * __restrict__ rows, dst_t * __restrict__ dst,
82
+ const int64_t ncols, const int64_t nrows_grad, const int64_t nrows_dst) {
83
+ const int col = blockIdx.x*blockDim.x + threadIdx.x;
84
+
85
+ if (col >= ncols) {
86
+ return;
87
+ }
88
+
89
+ ggml_cuda_pdl_sync();
90
+
91
+ // grid.y is clamped to the CUDA grid limit, so stride over the destination rows
92
+ for (int64_t dst_row = blockIdx.y; dst_row < nrows_dst; dst_row += gridDim.y) {
93
+ float sum = 0.0f;
94
+
95
+ for (int64_t i = 0; i < nrows_grad; ++i) {
96
+ if (rows[i] != dst_row) {
97
+ continue;
98
+ }
99
+ sum += grad[i*ncols + col];
100
+ }
101
+
102
+ dst[dst_row*ncols + col] = sum;
103
+ }
104
+ }
105
+
106
+ template<int qk, int qr, dequantize_kernel_t dq, typename dst_t>
107
+ static void get_rows_cuda_q(
108
+ const void * src0_d, const int32_t * src1_d, dst_t * dst_d,
109
+ const int64_t ne00, const size_t nb01, const size_t nb02, const size_t nb03,
110
+ const int64_t ne10, const int64_t ne11, const int64_t ne12, const size_t nb10, const size_t nb11, const size_t nb12,
111
+ const size_t nb1, const size_t nb2, const size_t nb3,
112
+ cudaStream_t stream) {
113
+ const dim3 block_dims(CUDA_GET_ROWS_BLOCK_SIZE, 1, 1);
114
+ const int block_num_y = (ne00 + 2*CUDA_GET_ROWS_BLOCK_SIZE - 1) / (2*CUDA_GET_ROWS_BLOCK_SIZE);
115
+ const dim3 block_nums(ne10, MIN(block_num_y, UINT16_MAX), MIN(ne11*ne12, UINT16_MAX));
116
+
117
+ // strides in elements
118
+ // const size_t s0 = nb0 / sizeof(dst_t);
119
+ const size_t s1 = nb1 / sizeof(dst_t);
120
+ const size_t s2 = nb2 / sizeof(dst_t);
121
+ const size_t s3 = nb3 / sizeof(dst_t);
122
+
123
+ const size_t s10 = nb10 / sizeof(int32_t);
124
+ const size_t s11 = nb11 / sizeof(int32_t);
125
+ const size_t s12 = nb12 / sizeof(int32_t);
126
+ // const size_t s13 = nb13 / sizeof(int32_t);
127
+
128
+ GGML_ASSERT(ne00 % 2 == 0);
129
+
130
+ GGML_ASSERT(ne12 > 0);
131
+ GGML_ASSERT(ne11 <= std::numeric_limits<uint32_t>::max() / ne12);
132
+ const uint3 ne12_fdv = init_fastdiv_values(ne12);
133
+
134
+ k_get_rows<qk, qr, dq><<<block_nums, block_dims, 0, stream>>>(
135
+ src0_d, src1_d, dst_d,
136
+ ne00, /*ne01, ne02, ne03,*/
137
+ /*ne10,*/ ne11, ne12_fdv, /*ne13,*/
138
+ /* s0,*/ s1, s2, s3,
139
+ /* nb00,*/ nb01, nb02, nb03,
140
+ s10, s11, s12/*, s13*/);
141
+ }
142
+
143
+ template<typename src0_t, typename dst_t>
144
+ static void get_rows_cuda_float(
145
+ const src0_t * src0_d, const int32_t * src1_d, dst_t * dst_d,
146
+ const int64_t ne00, const size_t nb01, const size_t nb02, const size_t nb03,
147
+ const int64_t ne10, const int64_t ne11, const int64_t ne12, const size_t nb10, const size_t nb11, const size_t nb12,
148
+ const size_t nb1, const size_t nb2, const size_t nb3,
149
+ cudaStream_t stream) {
150
+ const dim3 block_dims(CUDA_GET_ROWS_BLOCK_SIZE, 1, 1);
151
+ const int block_num_y = (ne00 + CUDA_GET_ROWS_BLOCK_SIZE - 1) / CUDA_GET_ROWS_BLOCK_SIZE;
152
+ const dim3 block_nums(ne10, MIN(block_num_y, UINT16_MAX), MIN(ne11*ne12, UINT16_MAX));
153
+
154
+ // strides in elements
155
+ // const size_t s0 = nb0 / sizeof(dst_t);
156
+ const size_t s1 = nb1 / sizeof(dst_t);
157
+ const size_t s2 = nb2 / sizeof(dst_t);
158
+ const size_t s3 = nb3 / sizeof(dst_t);
159
+
160
+ const size_t s10 = nb10 / sizeof(int32_t);
161
+ const size_t s11 = nb11 / sizeof(int32_t);
162
+ const size_t s12 = nb12 / sizeof(int32_t);
163
+ // const size_t s13 = nb13 / sizeof(int32_t);
164
+
165
+ GGML_ASSERT(ne12 > 0);
166
+ GGML_ASSERT(ne11 <= std::numeric_limits<uint32_t>::max() / ne12);
167
+ const uint3 ne12_fdv = init_fastdiv_values(ne12);
168
+
169
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params{block_nums, block_dims, 0, stream};
170
+ ggml_cuda_kernel_launch(k_get_rows_float<src0_t, dst_t>, launch_params,
171
+ src0_d, src1_d, dst_d,
172
+ ne00, /*ne01, ne02, ne03,*/
173
+ /*ne10,*/ ne11, ne12_fdv, /*ne13,*/
174
+ /* s0,*/ s1, s2, s3,
175
+ /* nb00,*/ nb01, nb02, nb03,
176
+ s10, s11, s12/*, s13*/);
177
+ }
178
+
179
+ template <typename dst_t>
180
+ static void ggml_cuda_get_rows_switch_src0_type(
181
+ const void * src0_d, const ggml_type src0_type, const int32_t * src1_d, dst_t * dst_d,
182
+ const int64_t ne00, const size_t nb01, const size_t nb02, const size_t nb03,
183
+ const int64_t ne10, const int64_t ne11, const int64_t ne12, const size_t nb10, const size_t nb11, const size_t nb12,
184
+ const size_t nb1, const size_t nb2, const size_t nb3,
185
+ cudaStream_t stream) {
186
+ switch (src0_type) {
187
+ case GGML_TYPE_F16:
188
+ get_rows_cuda_float((const half *) src0_d, src1_d, dst_d,
189
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
190
+ break;
191
+ case GGML_TYPE_F32:
192
+ get_rows_cuda_float((const float *) src0_d, src1_d, dst_d,
193
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
194
+ break;
195
+ case GGML_TYPE_I32:
196
+ get_rows_cuda_float((const int32_t *) src0_d, src1_d, dst_d,
197
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
198
+ break;
199
+ case GGML_TYPE_BF16:
200
+ get_rows_cuda_float((const nv_bfloat16 *) src0_d, src1_d, dst_d,
201
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
202
+ break;
203
+ case GGML_TYPE_Q1_0:
204
+ get_rows_cuda_q<QK1_0, QR1_0, dequantize_q1_0>(src0_d, src1_d, dst_d,
205
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
206
+ break;
207
+ case GGML_TYPE_Q4_0:
208
+ get_rows_cuda_q<QK4_0, QR4_0, dequantize_q4_0>(src0_d, src1_d, dst_d,
209
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
210
+ break;
211
+ case GGML_TYPE_Q4_1:
212
+ get_rows_cuda_q<QK4_1, QR4_1, dequantize_q4_1>(src0_d, src1_d, dst_d,
213
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
214
+ break;
215
+ case GGML_TYPE_Q5_0:
216
+ get_rows_cuda_q<QK5_0, QR5_0, dequantize_q5_0>(src0_d, src1_d, dst_d,
217
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
218
+ break;
219
+ case GGML_TYPE_Q5_1:
220
+ get_rows_cuda_q<QK5_1, QR5_1, dequantize_q5_1>(src0_d, src1_d, dst_d,
221
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
222
+ break;
223
+ case GGML_TYPE_Q8_0:
224
+ get_rows_cuda_q<QK8_0, QR8_0, dequantize_q8_0>(src0_d, src1_d, dst_d,
225
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
226
+ break;
227
+ default:
228
+ // TODO: k-quants
229
+ GGML_ABORT("%s: unsupported src0 type: %s\n", __func__, ggml_type_name(src0_type));
230
+ break;
231
+ }
232
+ }
233
+
234
+ void get_rows_cuda(
235
+ const void * src0_d, ggml_type src0_type, const int32_t * src1_d, void * dst_d, ggml_type dst_type,
236
+ int64_t ne00, size_t nb01, size_t nb02, size_t nb03,
237
+ int64_t ne10, int64_t ne11, int64_t ne12, size_t nb10, size_t nb11, size_t nb12,
238
+ size_t nb1, size_t nb2, size_t nb3,
239
+ cudaStream_t stream) {
240
+ switch (dst_type) {
241
+ case GGML_TYPE_F32:
242
+ ggml_cuda_get_rows_switch_src0_type(src0_d, src0_type, src1_d, (float *) dst_d,
243
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
244
+ break;
245
+ case GGML_TYPE_I32:
246
+ ggml_cuda_get_rows_switch_src0_type(src0_d, src0_type, src1_d, (int32_t *) dst_d,
247
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
248
+ break;
249
+ case GGML_TYPE_F16:
250
+ ggml_cuda_get_rows_switch_src0_type(src0_d, src0_type, src1_d, (half *) dst_d,
251
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
252
+ break;
253
+ case GGML_TYPE_BF16:
254
+ ggml_cuda_get_rows_switch_src0_type(src0_d, src0_type, src1_d, (nv_bfloat16 *) dst_d,
255
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
256
+ break;
257
+ default:
258
+ GGML_ABORT("%s: unsupported dst type: %s\n", __func__, ggml_type_name(dst_type));
259
+ break;
260
+ }
261
+ }
262
+
263
+ void ggml_cuda_op_get_rows(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
264
+ const ggml_tensor * src0 = dst->src[0];
265
+ const ggml_tensor * src1 = dst->src[1];
266
+
267
+ cudaStream_t stream = ctx.stream();
268
+
269
+ GGML_TENSOR_BINARY_OP_LOCALS
270
+
271
+ GGML_ASSERT(src1->type == GGML_TYPE_I32);
272
+ GGML_ASSERT(ne13 == 1);
273
+
274
+ GGML_ASSERT(src0->nb[0] == ggml_type_size(src0->type));
275
+ GGML_ASSERT(src1->nb[0] == ggml_type_size(src1->type));
276
+ GGML_ASSERT(dst->nb[0] == ggml_type_size(dst->type));
277
+
278
+ get_rows_cuda(src0->data, src0->type, (const int32_t *) src1->data, dst->data, dst->type,
279
+ ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
280
+ }
281
+
282
+ void ggml_cuda_op_get_rows_back(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
283
+ const ggml_tensor * src0 = dst->src[0]; // gradients of forward pass output
284
+ const ggml_tensor * src1 = dst->src[1]; // src1 in forward pass
285
+
286
+ GGML_TENSOR_BINARY_OP_LOCALS
287
+
288
+ const float * src0_d = (const float *) src0->data;
289
+ const int32_t * src1_d = (const int32_t *) src1->data;
290
+ float * dst_d = (float *) dst->data;
291
+
292
+ cudaStream_t stream = ctx.stream();
293
+
294
+ GGML_ASSERT(src0->type == GGML_TYPE_F32);
295
+ GGML_ASSERT(src1->type == GGML_TYPE_I32);
296
+ GGML_ASSERT(dst->type == GGML_TYPE_F32);
297
+
298
+ GGML_ASSERT(ggml_is_contiguous(src0));
299
+ GGML_ASSERT(ggml_is_contiguous(src1));
300
+ GGML_ASSERT(ggml_is_contiguous(dst));
301
+
302
+ GGML_ASSERT(ne02*ne03 == 1);
303
+ GGML_ASSERT(ne12*ne13 == 1);
304
+ GGML_ASSERT(ne2*ne3 == 1);
305
+
306
+ const dim3 block_dims(CUDA_GET_ROWS_BACK_BLOCK_SIZE, 1, 1);
307
+ const int block_num_x = (ne00 + CUDA_GET_ROWS_BACK_BLOCK_SIZE - 1) / CUDA_GET_ROWS_BACK_BLOCK_SIZE;
308
+ const dim3 block_nums(block_num_x, MIN(ne1, (int64_t)UINT16_MAX), 1);
309
+
310
+ k_get_rows_back_float<<<block_nums, block_dims, 0, stream>>>(src0_d, src1_d, dst_d, ne00, ne10, ne1);
311
+ }
backend/llama.cpp/ggml/src/ggml-cuda/getrows.cuh ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ #define CUDA_GET_ROWS_BLOCK_SIZE 256
4
+ #define CUDA_GET_ROWS_BACK_BLOCK_SIZE 256
5
+
6
+ void get_rows_cuda(
7
+ const void * src0_d, ggml_type src0_type, const int32_t * src1_d, void * dst_d, ggml_type dst_type,
8
+ int64_t ne00, size_t nb01, size_t nb02, size_t nb03,
9
+ int64_t ne10, int64_t ne11, int64_t ne12, size_t nb10, size_t nb11, size_t nb12,
10
+ size_t nb1, size_t nb2, size_t nb3,
11
+ cudaStream_t stream);
12
+
13
+ void ggml_cuda_op_get_rows(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
14
+
15
+ void ggml_cuda_op_get_rows_back(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/ggml-cuda.cu ADDED
The diff for this file is too large to render. See raw diff
 
backend/llama.cpp/ggml/src/ggml-cuda/gla.cu ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+ #include "gla.cuh"
3
+
4
+ template<int HEAD_SIZE>
5
+ static __global__ void gated_linear_attn_f32(const int B, const int T, const int C, const int H, const float scale,
6
+ const float * k, const float * v, const float * r, const float * td, const float * s, float * dst) {
7
+ const int tid = threadIdx.x;
8
+ const int bid = blockIdx.x;
9
+
10
+ const int head_size = HEAD_SIZE;
11
+ const int batch_i = bid / H;
12
+ const int head_i = bid % H;
13
+ const int state_size = C * head_size;
14
+ const int n_seq_tokens = T / B;
15
+
16
+ float state[head_size];
17
+ __shared__ float _k[head_size], _r[head_size], _td[head_size];
18
+
19
+ #pragma unroll
20
+ for (int i = 0; i < head_size; i++) {
21
+ state[i] = s[batch_i * state_size + head_i * head_size * head_size + i * head_size + tid];
22
+ }
23
+
24
+ for (int t = batch_i * n_seq_tokens * C + head_i * head_size + tid; t < (batch_i + 1) * n_seq_tokens * C + head_i * head_size + tid; t += C) {
25
+ __syncthreads();
26
+ _k[tid] = k[t];
27
+ _r[tid] = r[t];
28
+ _td[tid] = td[t];
29
+ __syncthreads();
30
+
31
+ const float _v = v[t];
32
+ float y = 0;
33
+ for (int j = 0; j < head_size; j += 4) {
34
+ const float4 & k = (float4 &)(_k[j]);
35
+ const float4 & r = (float4 &)(_r[j]);
36
+ const float4 & td = (float4 &)(_td[j]);
37
+ float4 & s = (float4 &)(state[j]);
38
+ float4 kv;
39
+
40
+ kv.x = k.x * _v;
41
+ kv.y = k.y * _v;
42
+ kv.z = k.z * _v;
43
+ kv.w = k.w * _v;
44
+
45
+ s.x = s.x * td.x + kv.x;
46
+ s.y = s.y * td.y + kv.y;
47
+ s.z = s.z * td.z + kv.z;
48
+ s.w = s.w * td.w + kv.w;
49
+
50
+ y += r.x * s.x;
51
+ y += r.y * s.y;
52
+ y += r.z * s.z;
53
+ y += r.w * s.w;
54
+ }
55
+ dst[t] = y * scale;
56
+ }
57
+
58
+ #pragma unroll
59
+ for (int i = 0; i < head_size; i++) {
60
+ dst[T * C + batch_i * state_size + head_i * head_size * head_size + i * head_size + tid] = state[i];
61
+ }
62
+ }
63
+
64
+ void ggml_cuda_op_gated_linear_attn(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
65
+ const float * k_d = (const float *)dst->src[0]->data;
66
+ const float * v_d = (const float *)dst->src[1]->data;
67
+ const float * r_d = (const float *)dst->src[2]->data;
68
+ const float * td_d = (const float *)dst->src[3]->data;
69
+ const float * s_d = (const float *)dst->src[4]->data;
70
+
71
+ const int64_t B = dst->src[4]->ne[1];
72
+ const int64_t T = dst->src[0]->ne[2];
73
+ const int64_t C = dst->ne[0];
74
+ const int64_t H = dst->src[0]->ne[1];
75
+
76
+ float scale;
77
+ memcpy(&scale, (float*)dst->op_params, sizeof(float));
78
+
79
+ float * dst_d = (float *)dst->data;
80
+
81
+ cudaStream_t stream = ctx.stream();
82
+
83
+ GGML_ASSERT(dst->src[4]->type == GGML_TYPE_F32);
84
+ GGML_ASSERT(C % H == 0);
85
+ GGML_ASSERT(C / H == 64 || C / H == 128);
86
+
87
+
88
+ if (C / H == 64) {
89
+ gated_linear_attn_f32<64><<<B * H, C / H, 0, stream>>>(B, T, C, H, scale, k_d, v_d, r_d, td_d, s_d, dst_d);
90
+ } else {
91
+ gated_linear_attn_f32<128><<<B * H, C / H, 0, stream>>>(B, T, C, H, scale, k_d, v_d, r_d, td_d, s_d, dst_d);
92
+ }
93
+ }
backend/llama.cpp/ggml/src/ggml-cuda/gla.cuh ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ void ggml_cuda_op_gated_linear_attn(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/im2col.cu ADDED
@@ -0,0 +1,267 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "im2col.cuh"
2
+
3
+ #define MAX_GRIDDIM_Y 65535
4
+ #define MAX_GRIDDIM_Z 65535
5
+
6
+ template <typename T>
7
+ static __global__ void im2col_kernel(
8
+ const float * x, T * dst,
9
+ int64_t IC, int64_t IW, int64_t IH, int64_t OH, int64_t OW, int64_t KW, int64_t KH,
10
+ int64_t IC_IH_IW, int64_t IH_IW, int64_t N_OH, int64_t KH_KW, int64_t IC_KH_KW,
11
+ int s0, int s1, int p0, int p1, int d0, int d1) {
12
+ const int64_t i = threadIdx.x + blockIdx.x * blockDim.x;
13
+ if (i >= IC_KH_KW) {
14
+ return;
15
+ }
16
+
17
+ const int64_t iic = i / (KH_KW);
18
+ const int64_t rem = i - iic * KH_KW;
19
+ const int64_t ikh = rem / KW;
20
+ const int64_t ikw = rem - ikh * KW;
21
+
22
+ for (int64_t iow = blockIdx.y; iow < OW; iow += MAX_GRIDDIM_Y) {
23
+ for (int64_t iz = blockIdx.z; iz < N_OH; iz += MAX_GRIDDIM_Z) {
24
+ const int64_t in = iz / OH;
25
+ const int64_t ioh = iz - in * OH;
26
+
27
+ const int64_t iiw = iow * s0 + ikw * d0 - p0;
28
+ const int64_t iih = ioh * s1 + ikh * d1 - p1;
29
+
30
+ const int64_t offset_dst =
31
+ ((in * OH + ioh) * OW + iow) * IC_KH_KW + iic * KH_KW + ikh * KW + ikw;
32
+
33
+ if (iih < 0 || iih >= IH || iiw < 0 || iiw >= IW) {
34
+ dst[offset_dst] = 0.0f;
35
+ } else {
36
+ const int64_t offset_src = iic * IC_IH_IW + in * IH_IW;
37
+ dst[offset_dst] = x[offset_src + iih * IW + iiw];
38
+ }
39
+ }
40
+ }
41
+
42
+ GGML_UNUSED(IC);
43
+ GGML_UNUSED(KH);
44
+ }
45
+
46
+ // im2col: [N, IC, IH, IW] => [N, OH, OW, IC*KH*KW]
47
+ template <typename T>
48
+ static void im2col_cuda(const float * x, T* dst,
49
+ int64_t IW, int64_t IH, int64_t OW, int64_t OH, int64_t KW, int64_t KH, int64_t IC,
50
+ int64_t N, int64_t IC_IH_IW, int64_t IH_IW,
51
+ int s0,int s1,int p0,int p1,int d0,int d1, cudaStream_t stream) {
52
+ const int64_t IC_KH_KW = IC * KH * KW;
53
+ const int64_t num_blocks = (IC_KH_KW + CUDA_IM2COL_BLOCK_SIZE - 1) / CUDA_IM2COL_BLOCK_SIZE;
54
+ const int64_t N_OH = N * OH;
55
+ const int64_t KH_KW = KW*KH;
56
+ dim3 block_nums(num_blocks, MIN(OW, MAX_GRIDDIM_Y), MIN(N_OH, MAX_GRIDDIM_Z));
57
+ im2col_kernel<<<block_nums, MIN(IC_KH_KW, CUDA_IM2COL_BLOCK_SIZE) , 0, stream>>>(x, dst, IC, IW, IH, OH, OW, KW, KH,
58
+ IC_IH_IW, IH_IW, N_OH, KH_KW, IC_KH_KW,
59
+ s0, s1, p0, p1, d0, d1);
60
+ }
61
+
62
+ static void im2col_cuda_f16(const float * x, half * dst,
63
+ int64_t IW, int64_t IH, int64_t OW, int64_t OH, int64_t KW, int64_t KH, int64_t IC,
64
+ int64_t N, int64_t IC_IH_IW, int64_t IH_IW,
65
+ int s0,int s1,int p0,int p1,int d0,int d1, cudaStream_t stream) {
66
+
67
+ im2col_cuda<half>(x, dst, IW, IH, OW, OH, KW, KH, IC, N, IC_IH_IW, IH_IW, s0, s1, p0, p1, d0, d1, stream);
68
+ }
69
+
70
+ static void im2col_cuda_f32(const float * x, float * dst,
71
+ int64_t IW, int64_t IH, int64_t OW, int64_t OH, int64_t KW, int64_t KH, int64_t IC,
72
+ int64_t N, int64_t IC_IH_IW, int64_t IH_IW,
73
+ int s0,int s1,int p0,int p1,int d0,int d1, cudaStream_t stream) {
74
+
75
+ im2col_cuda<float>(x, dst, IW, IH, OW, OH, KW, KH, IC, N, IC_IH_IW, IH_IW, s0, s1, p0, p1, d0, d1, stream);
76
+ }
77
+
78
+ void ggml_cuda_op_im2col(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
79
+ const ggml_tensor * src0 = dst->src[0];
80
+ const ggml_tensor * src1 = dst->src[1];
81
+ const float * src1_d = (const float *)src1->data;
82
+ float * dst_d = (float *)dst->data;
83
+ cudaStream_t stream = ctx.stream();
84
+
85
+ GGML_ASSERT(src1->type == GGML_TYPE_F32);
86
+ GGML_ASSERT( dst->type == GGML_TYPE_F16 || dst->type == GGML_TYPE_F32);
87
+
88
+ const int32_t s0 = ((const int32_t*)(dst->op_params))[0];
89
+ const int32_t s1 = ((const int32_t*)(dst->op_params))[1];
90
+ const int32_t p0 = ((const int32_t*)(dst->op_params))[2];
91
+ const int32_t p1 = ((const int32_t*)(dst->op_params))[3];
92
+ const int32_t d0 = ((const int32_t*)(dst->op_params))[4];
93
+ const int32_t d1 = ((const int32_t*)(dst->op_params))[5];
94
+
95
+ const bool is_2D = ((const int32_t*)(dst->op_params))[6] == 1;
96
+
97
+ const int64_t IC = src1->ne[is_2D ? 2 : 1];
98
+ const int64_t IH = is_2D ? src1->ne[1] : 1;
99
+ const int64_t IW = src1->ne[0];
100
+
101
+ const int64_t KH = is_2D ? src0->ne[1] : 1;
102
+ const int64_t KW = src0->ne[0];
103
+
104
+ const int64_t OH = is_2D ? dst->ne[2] : 1;
105
+ const int64_t OW = dst->ne[1];
106
+
107
+ const int64_t IC_IH_IW = src1->nb[is_2D ? 2 : 1] / 4; // nb is byte offset, src is type float32
108
+ const int64_t N = src1->ne[is_2D ? 3 : 2];
109
+ const int64_t IH_IW = src1->nb[is_2D ? 3 : 2] / 4; // nb is byte offset, src is type float32
110
+
111
+ if(dst->type == GGML_TYPE_F16) {
112
+ im2col_cuda_f16(src1_d, (half *) dst_d, IW, IH, OW, OH, KW, KH, IC, N, IC_IH_IW, IH_IW, s0, s1, p0, p1, d0, d1, stream);
113
+ } else {
114
+ im2col_cuda_f32(src1_d, (float *) dst_d, IW, IH, OW, OH, KW, KH, IC, N, IC_IH_IW, IH_IW, s0, s1, p0, p1, d0, d1, stream);
115
+ }
116
+ }
117
+
118
+ // [N*IC, ID, IH, IW] => [N*OD, OH, OW, IC * KD * KH * KW]
119
+ template <typename T>
120
+ static __global__ void im2col_3d_kernel(
121
+ const float * src, T * dst,
122
+ int64_t N, int64_t IC, int64_t ID, int64_t IH, int64_t IW, int64_t OC,
123
+ int64_t KD, int64_t KH, int64_t KW, int64_t OD, int64_t OH, int64_t OW,
124
+ int64_t OH_OW, int64_t KD_KH_KW, int64_t ID_IH_IW, int64_t KH_KW, int64_t IH_IW, int64_t IC_ID_IH_IW,
125
+ int64_t IC_KD_KH_KW, int64_t OW_KD_KH_KW, int64_t OD_OH_OW_IC_KD_KH_KW, int64_t OH_OW_IC_KD_KH_KW,
126
+ int64_t OW_IC_KD_KH_KW, int64_t N_OD_OH, int64_t OD_OH,
127
+ int64_t stride_q, int64_t stride_z, int64_t stride_y, int64_t stride_x,
128
+ int s0, int s1, int s2, int p0, int p1, int p2, int d0, int d1, int d2) {
129
+ const int64_t i = threadIdx.x + blockIdx.x * blockDim.x;
130
+ if (i >= IC_KD_KH_KW) {
131
+ return;
132
+ }
133
+ GGML_UNUSED(N); GGML_UNUSED(OC); GGML_UNUSED(OH_OW); GGML_UNUSED(OD); GGML_UNUSED(OW); GGML_UNUSED(KD); GGML_UNUSED(KH);
134
+ GGML_UNUSED(ID_IH_IW); GGML_UNUSED(IH_IW); GGML_UNUSED(IC_ID_IH_IW); GGML_UNUSED(OW_KD_KH_KW);
135
+
136
+ const int64_t iic = i / KD_KH_KW;
137
+ const int64_t ikd = (i - iic * KD_KH_KW) / KH_KW;
138
+ const int64_t ikh = (i - iic * KD_KH_KW - ikd * KH_KW) / KW;
139
+ const int64_t ikw = i % KW;
140
+
141
+ for (int64_t iow = blockIdx.y; iow < OW; iow += MAX_GRIDDIM_Y) {
142
+ for (int64_t iz = blockIdx.z; iz < N_OD_OH; iz += MAX_GRIDDIM_Z) {
143
+ const int64_t in = iz / OD_OH;
144
+ const int64_t iod = (iz - in*OD_OH) / OH;
145
+ const int64_t ioh = iz % OH;
146
+
147
+ const int64_t iiw = iow * s0 + ikw * d0 - p0;
148
+ const int64_t iih = ioh * s1 + ikh * d1 - p1;
149
+ const int64_t iid = iod * s2 + ikd * d2 - p2;
150
+
151
+ const int64_t offset_dst = in*OD_OH_OW_IC_KD_KH_KW + iod*OH_OW_IC_KD_KH_KW + ioh*OW_IC_KD_KH_KW + iow*IC_KD_KH_KW + iic*KD_KH_KW + ikd * KH_KW + ikh*KW + ikw;
152
+
153
+ if (iih < 0 || iih >= IH || iiw < 0 || iiw >= IW || iid < 0 || iid >= ID) {
154
+ dst[offset_dst] = 0.0f;
155
+ } else {
156
+ const int64_t offset_src = ((in * IC + iic) * stride_q) + (iid * stride_z) + (iih * stride_y) + (iiw * stride_x);
157
+ dst[offset_dst] = src[offset_src];
158
+ }
159
+ }
160
+ }
161
+ }
162
+
163
+ // [N*IC, ID, IH, IW] => [N*OD, OH, OW, IC * KD * KH * KW]
164
+ template <typename T>
165
+ static void im2col_3d_cuda(const float * src, T* dst,
166
+ int64_t N, int64_t IC, int64_t ID, int64_t IH, int64_t IW, int64_t OC,
167
+ int64_t KD, int64_t KH, int64_t KW, int64_t OD, int64_t OH, int64_t OW,
168
+ int64_t stride_q, int64_t stride_z, int64_t stride_y, int64_t stride_x,
169
+ int s0, int s1, int s2, int p0, int p1, int p2, int d0, int d1, int d2, cudaStream_t stream) {
170
+ const int64_t OH_OW = OH*OW;
171
+ const int64_t KD_KH_KW = KD*KH*KW;
172
+ const int64_t ID_IH_IW = ID*IH*IW;
173
+ const int64_t KH_KW = KH*KW;
174
+ const int64_t IH_IW = IH*IW;
175
+ const int64_t IC_KD_KH_KW = IC*KD*KH*KW;
176
+ const int64_t OW_KD_KH_KW = OW*KD*KH*KW;
177
+ const int64_t N_OD_OH = N*OD*OH;
178
+ const int64_t OD_OH = OD*OH;
179
+ const int64_t IC_ID_IH_IW = IC*ID*IH*IW;
180
+ const int64_t OD_OH_OW_IC_KD_KH_KW = OD*OH*OW*IC*KD*KH*KW;
181
+ const int64_t OH_OW_IC_KD_KH_KW = OH*OW*IC*KD*KH*KW;
182
+ const int64_t OW_IC_KD_KH_KW = OW*IC*KD*KH*KW;
183
+ const int64_t num_blocks = (IC_KD_KH_KW + CUDA_IM2COL_BLOCK_SIZE - 1) / CUDA_IM2COL_BLOCK_SIZE;
184
+ dim3 block_nums(num_blocks, MIN(OW, MAX_GRIDDIM_Y), MIN(N_OD_OH, MAX_GRIDDIM_Z));
185
+ im2col_3d_kernel<<<block_nums, MIN(IC_KD_KH_KW, CUDA_IM2COL_BLOCK_SIZE) , 0, stream>>>(src, dst, N, IC, ID, IH, IW, OC, KD, KH, KW, OD, OH, OW,
186
+ OH_OW, KD_KH_KW, ID_IH_IW, KH_KW, IH_IW, IC_ID_IH_IW,
187
+ IC_KD_KH_KW, OW_KD_KH_KW, OD_OH_OW_IC_KD_KH_KW,
188
+ OH_OW_IC_KD_KH_KW, OW_IC_KD_KH_KW, N_OD_OH, OD_OH,
189
+ stride_q, stride_z, stride_y, stride_x,
190
+ s0, s1, s2, p0, p1, p2, d0, d1, d2);
191
+ }
192
+
193
+ static void im2col_3d_cuda_f16(const float * src, half * dst,
194
+ int64_t N, int64_t IC, int64_t ID, int64_t IH, int64_t IW, int64_t OC,
195
+ int64_t KD, int64_t KH, int64_t KW, int64_t OD, int64_t OH, int64_t OW,
196
+ int64_t stride_q, int64_t stride_z, int64_t stride_y, int64_t stride_x,
197
+ int s0, int s1, int s2, int p0, int p1, int p2, int d0, int d1, int d2, cudaStream_t stream) {
198
+
199
+ im2col_3d_cuda<half>(src, dst, N, IC, ID, IH, IW, OC, KD, KH, KW, OD, OH, OW,
200
+ stride_q, stride_z, stride_y, stride_x,
201
+ s0, s1, s2, p0, p1, p2, d0, d1, d2, stream);
202
+ }
203
+
204
+ static void im2col_3d_cuda_f32(const float * src, float * dst,
205
+ int64_t N, int64_t IC, int64_t ID, int64_t IH, int64_t IW, int64_t OC,
206
+ int64_t KD, int64_t KH, int64_t KW, int64_t OD, int64_t OH, int64_t OW,
207
+ int64_t stride_q, int64_t stride_z, int64_t stride_y, int64_t stride_x,
208
+ int s0, int s1, int s2, int p0, int p1, int p2, int d0, int d1, int d2, cudaStream_t stream) {
209
+
210
+ im2col_3d_cuda<float>(src, dst, N, IC, ID, IH, IW, OC, KD, KH, KW, OD, OH, OW,
211
+ stride_q, stride_z, stride_y, stride_x,
212
+ s0, s1, s2, p0, p1, p2, d0, d1, d2, stream);
213
+ }
214
+
215
+ void ggml_cuda_op_im2col_3d(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
216
+ const ggml_tensor * src0 = dst->src[0];
217
+ const ggml_tensor * src1 = dst->src[1];
218
+ const float * src1_d = (const float *)src1->data;
219
+ float * dst_d = (float *)dst->data;
220
+ cudaStream_t stream = ctx.stream();
221
+
222
+ GGML_ASSERT(src1->type == GGML_TYPE_F32);
223
+ GGML_ASSERT( dst->type == GGML_TYPE_F16 || dst->type == GGML_TYPE_F32);
224
+
225
+ GGML_TENSOR_BINARY_OP_LOCALS
226
+
227
+ const int32_t s0 = ((const int32_t *)(dst->op_params))[0];
228
+ const int32_t s1 = ((const int32_t *)(dst->op_params))[1];
229
+ const int32_t s2 = ((const int32_t *)(dst->op_params))[2];
230
+ const int32_t p0 = ((const int32_t *)(dst->op_params))[3];
231
+ const int32_t p1 = ((const int32_t *)(dst->op_params))[4];
232
+ const int32_t p2 = ((const int32_t *)(dst->op_params))[5];
233
+ const int32_t d0 = ((const int32_t *)(dst->op_params))[6];
234
+ const int32_t d1 = ((const int32_t *)(dst->op_params))[7];
235
+ const int32_t d2 = ((const int32_t *)(dst->op_params))[8];
236
+ const int32_t IC = ((const int32_t *)(dst->op_params))[9];
237
+
238
+ const int64_t N = ne13 / IC;
239
+ const int64_t ID = ne12;
240
+ const int64_t IH = ne11;
241
+ const int64_t IW = ne10;
242
+
243
+ const int64_t OC = ne03 / IC;
244
+ const int64_t KD = ne02;
245
+ const int64_t KH = ne01;
246
+ const int64_t KW = ne00;
247
+
248
+ const int64_t OD = ne3 / N;
249
+ const int64_t OH = ne2;
250
+ const int64_t OW = ne1;
251
+
252
+ const size_t es = ggml_element_size(src1);
253
+ const int64_t stride_x = src1->nb[0] / es;
254
+ const int64_t stride_y = src1->nb[1] / es;
255
+ const int64_t stride_z = src1->nb[2] / es;
256
+ const int64_t stride_q = src1->nb[3] / es;
257
+
258
+ if(dst->type == GGML_TYPE_F16) {
259
+ im2col_3d_cuda_f16(src1_d, (half *) dst_d, N, IC, ID, IH, IW, OC, KD, KH, KW, OD, OH, OW,
260
+ stride_q, stride_z, stride_y, stride_x,
261
+ s0, s1, s2, p0, p1, p2, d0, d1, d2, stream);
262
+ } else {
263
+ im2col_3d_cuda_f32(src1_d, (float *) dst_d, N, IC, ID, IH, IW, OC, KD, KH, KW, OD, OH, OW,
264
+ stride_q, stride_z, stride_y, stride_x,
265
+ s0, s1, s2, p0, p1, p2, d0, d1, d2, stream);
266
+ }
267
+ }
backend/llama.cpp/ggml/src/ggml-cuda/im2col.cuh ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ #define CUDA_IM2COL_BLOCK_SIZE 256
4
+
5
+ void ggml_cuda_op_im2col(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
6
+ void ggml_cuda_op_im2col_3d(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/mean.cu ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "mean.cuh"
2
+ #include "reduce_rows.cuh"
3
+
4
+ #ifdef GGML_CUDA_USE_CUB
5
+ #include <cub/cub.cuh>
6
+ using namespace cub;
7
+ #endif // GGML_CUDA_USE_CUB
8
+
9
+ template <typename T> __global__ void divide_by_count(T * result, size_t count) {
10
+ *result /= static_cast<T>(count);
11
+ }
12
+
13
+ void ggml_cuda_op_mean(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
14
+ const ggml_tensor * src0 = dst->src[0];
15
+ const float * src0_d = (const float *) src0->data;
16
+ float * dst_d = (float *) dst->data;
17
+ cudaStream_t stream = ctx.stream();
18
+
19
+ GGML_ASSERT(src0->type == GGML_TYPE_F32);
20
+ GGML_ASSERT(dst->type == GGML_TYPE_F32);
21
+ GGML_ASSERT(ggml_is_contiguous(src0));
22
+
23
+ const int64_t ncols = src0->ne[0];
24
+ const int64_t nrows = ggml_nrows(src0);
25
+
26
+ // Special case for reducing vectors
27
+ #ifdef GGML_CUDA_USE_CUB
28
+ #ifdef USE_CUDA_GRAPH
29
+ cudaStreamCaptureStatus iscapturing;
30
+ CUDA_CHECK(cudaStreamIsCapturing(stream, &iscapturing));
31
+ #endif // USE_CUDA_GRAPH
32
+ if ((nrows == 1) &&
33
+ #ifdef USE_CUDA_GRAPH
34
+ // Determine if CUDA graphs are effectively disabled for this context
35
+ // (no graph instance exists and we're not capturing, OR graphs are explicitly enabled)
36
+ (((ncols > 65536) &&
37
+ (((!ctx.any_cuda_graph_has_instance()) && (iscapturing == cudaStreamCaptureStatusNone)) ||
38
+ ctx.any_cuda_graph_enabled())) ||
39
+ // CUDA graphs are enabled - use lower threshold
40
+ ((ncols > 32768) &&
41
+ !(((!ctx.any_cuda_graph_has_instance()) && (iscapturing == cudaStreamCaptureStatusNone)) ||
42
+ ctx.any_cuda_graph_enabled())))) {
43
+ #else
44
+ (ncols > 65536)) {
45
+ #endif // USE_CUDA_GRAPH
46
+ // Single row - use device-wide reduction
47
+ size_t tmp_size = 0;
48
+ ggml_cuda_pool & pool = ctx.pool();
49
+
50
+ DeviceReduce::Sum(nullptr, tmp_size, src0_d, dst_d, ncols, stream);
51
+
52
+ ggml_cuda_pool_alloc<uint8_t> tmp_alloc(pool, tmp_size);
53
+ DeviceReduce::Sum(tmp_alloc.ptr, tmp_size, src0_d, dst_d, ncols, stream);
54
+
55
+ // Divide by ncols
56
+ divide_by_count<float><<<1, 1, 0, stream>>>(dst_d, ncols);
57
+ return;
58
+ }
59
+ #endif // GGML_CUDA_USE_CUB
60
+
61
+ const dim3 block_nums(nrows, 1, 1);
62
+
63
+ const int id = ggml_cuda_get_device();
64
+ const int nsm = ggml_cuda_info().devices[id].nsm;
65
+
66
+ // Heuristic for block size selection to optimize occupancy.
67
+ // See discussion in: https://github.com/ggml-org/llama.cpp/pull/15132
68
+ if ((nrows / nsm) < 2) {
69
+ const dim3 block_dims(512, 1, 1);
70
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(block_nums, block_dims, 0, stream);
71
+ ggml_cuda_kernel_launch(reduce_rows_f32</*norm=*/true>, launch_params, src0_d, dst_d, ncols);
72
+ } else {
73
+ const dim3 block_dims(ncols < 1024 ? 32 : 128, 1, 1);
74
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(block_nums, block_dims, 0, stream);
75
+ ggml_cuda_kernel_launch(reduce_rows_f32</*norm=*/true>, launch_params, src0_d, dst_d, ncols);
76
+ }
77
+ }
backend/llama.cpp/ggml/src/ggml-cuda/mean.cuh ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ void ggml_cuda_op_mean(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/mma.cuh ADDED
@@ -0,0 +1,1456 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma once
2
+ // This file contains primitives that expose the tensor core PTX instructions for CUDA code.
3
+ // The primitives can be used in a similar way as the nvcuda::wmma interface but with a well-defined memory layout.
4
+ // The documentation for the PTX instructions can be found under:
5
+ // https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#matrix-multiply-accumulate-operation-using-mma-instruction
6
+ //
7
+ // Like with nvcuda::wmma there are three types of matrix tiles: A, B, and C with A @ B = C.
8
+ // A is a row-major matrix with shape M x K.
9
+ // B is a column-major matrix with shape K x N.
10
+ // C is a column-major matrix with shape M x N.
11
+ // A, B, and C are represented using the same fundamental data type: a row-major matrix with I rows and J columns.
12
+ // Note that J is measured in physical 32 bit elements instead of logical elements.
13
+ // The methods get_i and get_j can be used to get the physical 32 bit index of the lth element of a thread within a tile.
14
+ // All matrix tiles have ne physical 32 bit elements per warp.
15
+ //
16
+ // As described in the PTX documentation, all pointers for load_ldmatrix must be to shared memory and aligned to 16 bytes.
17
+ // The API in this file also assumes that the pointers for load_generic are aligned to 16 bytes, unaligned pointers are considered undefined behavior.
18
+
19
+ #include "common.cuh"
20
+
21
+ // On Volta each warp is doing 4 8x8 mma operations in parallel.
22
+ // The basic memory layout for a 32x8 output tile is to stack 4 input tiles in I direction and to mirror the B tile.
23
+ // However, the i indices in this file are by default permuted to simplify the index calculations.
24
+ // #define GGML_CUDA_MMA_NO_VOLTA_PERM
25
+
26
+ #if CUDART_VERSION >= 11080
27
+
28
+ static __device__ __forceinline__ int ggml_cuda_movmatrix(const int x) {
29
+ int ret = 0;
30
+
31
+ #ifdef TURING_MMA_AVAILABLE
32
+ asm("movmatrix.sync.aligned.m8n8.trans.b16 %0, %1;"
33
+ : "=r"(ret) : "r"(x));
34
+ #else
35
+ GGML_UNUSED(x);
36
+ NO_DEVICE_CODE;
37
+ #endif // defined(TURING_MMA_AVAILABLE)
38
+ return ret;
39
+ }
40
+
41
+ #else
42
+
43
+ static __device__ __forceinline__ int ggml_cuda_movmatrix(const int x) {
44
+ // Imagine transposing row-major matrix to column-major matrix.
45
+ const int src_i_low = 2 * (threadIdx.x % 4);
46
+ const int src_i_high = src_i_low + 1;
47
+ const int src_j = threadIdx.x / 4;
48
+
49
+ const int src_laneid_low = src_i_low * 4 + src_j / 2;
50
+ const int src_laneid_high = src_i_high * 4 + src_j / 2;
51
+
52
+ const int shift_low = ((src_j + 0) % 2) * 16;
53
+ const int shift_high = ((src_j + 1) % 2) * 16;
54
+
55
+ const int ret_low = (__shfl_sync(0xFFFFFFFF, x, src_laneid_low, WARP_SIZE) >> shift_low) & 0x0000FFFF;
56
+ const int ret_high = (__shfl_sync(0xFFFFFFFF, x, src_laneid_high, WARP_SIZE) << shift_high) & 0xFFFF0000;
57
+
58
+ return ret_low | ret_high;
59
+ }
60
+
61
+ #endif // CUDART_VERSION >= 11080
62
+
63
+ static __device__ __forceinline__ half2 ggml_cuda_movmatrix(const half2 x) {
64
+ half2 ret;
65
+ *((int *) &ret) = ggml_cuda_movmatrix(*((const int *) &x));
66
+ return ret;
67
+ }
68
+
69
+ namespace ggml_cuda_mma {
70
+
71
+ // Some architectures like Volta or CDNA3 perform multiple matrix multiplications per warp in parallel,
72
+ // effectively the warp is being split into subgroups of threads that each perform a single mma instruction.
73
+ // In those cases the data can be split in different ways across the warp.
74
+ enum data_layout {
75
+ // By default the data uses the I direction as its major dimension and the J direction as its minor dimension.
76
+ // For the A/C matrices this means I major == row major, J major == column major.
77
+ // For the B matrix this means I major == column major, J major == row major.
78
+ // MIRRORED == Each data value is held exactly once per thread subgroup.
79
+ DATA_LAYOUT_I_MAJOR = 0, // Always used for Turing, Ampere, Ada Lovelace, consumer Blackwell, matrix A&B for RDNA4 and CDNA.
80
+ DATA_LAYOUT_J_MAJOR = 10, // Matrix C for CDNA and RDNA4, int and float matrix C for RDNA3.
81
+ DATA_LAYOUT_I_MAJOR_MIRRORED = 20, // Volta, matrix A&B for RDNA3.
82
+ DATA_LAYOUT_J_MAJOR_MIRRORED = 30,
83
+ DATA_LAYOUT_I_MAJOR_SCRAMBLED = 40, // Scrambled matrix C for faster transposition (RDNA4/CDNA), convert to float to unscramble.
84
+ };
85
+ // Implemented mma combinations are:
86
+ // - (I_MAJOR, I_MAJOR) -> I_MAJOR
87
+ // - (I_MAJOR, I_MAJOR_MIRRORED) -> I_MAJOR
88
+ // - (I_MAJOR, J_MAJOR_MIRRORED) -> I_MAJOR
89
+
90
+ static constexpr __device__ data_layout get_input_data_layout() {
91
+ #if defined(RDNA3) || defined(VOLTA_MMA_AVAILABLE)
92
+ return DATA_LAYOUT_I_MAJOR_MIRRORED;
93
+ #else
94
+ return DATA_LAYOUT_I_MAJOR;
95
+ #endif // defined(RDNA3) || defined(VOLTA_MMA_AVAILABLE)
96
+ }
97
+
98
+ template <int I_, int J_, typename T, data_layout ds_=DATA_LAYOUT_I_MAJOR>
99
+ struct tile {};
100
+
101
+ template <int I_, int J_, typename T>
102
+ struct tile<I_, J_, T, DATA_LAYOUT_I_MAJOR> {
103
+ static constexpr int I = I_;
104
+ static constexpr int J = J_;
105
+ static constexpr data_layout dl = DATA_LAYOUT_I_MAJOR;
106
+
107
+ #if defined(AMD_MFMA_AVAILABLE)
108
+ static constexpr int ne = I * J / 64;
109
+ T x[ne] = {0};
110
+
111
+ static constexpr __device__ bool supported() {
112
+ if (I == 16 && J == 8) return true;
113
+ if (I == 32 && J == 4) return true;
114
+ if (I == 16 && J == 16) return true;
115
+ if (I == 32 && J == 32) return true;
116
+ return false;
117
+ }
118
+
119
+ static __device__ __forceinline__ int get_i(const int l) {
120
+ if constexpr (I == 16 && J == 4) {
121
+ return threadIdx.x % 16;
122
+ } else if constexpr (I == 16 && J == 8) {
123
+ return threadIdx.x % 16;
124
+ } else if constexpr (I == 32 && J == 4) {
125
+ return threadIdx.x % 32;
126
+ } else if constexpr (I == 16 && J == 16) {
127
+ return threadIdx.x % 16;
128
+ } else if constexpr (I == 32 && J == 32) {
129
+ return threadIdx.x % 32;
130
+ } else {
131
+ NO_DEVICE_CODE;
132
+ return -1;
133
+ }
134
+ }
135
+
136
+ static __device__ __forceinline__ int get_j(const int l) {
137
+ if constexpr (I == 16 && J == 4) {
138
+ return threadIdx.x / 16;
139
+ } else if constexpr (I == 16 && J == 8) {
140
+ return 2 * (threadIdx.x / 16) + l;
141
+ } else if constexpr (I == 32 && J == 4) {
142
+ return 2 * (threadIdx.x / 32) + l;
143
+ } else if constexpr (I == 16 && J == 16) {
144
+ return 4 * (threadIdx.x / 16) + l;
145
+ } else if constexpr (I == 32 && J == 32) {
146
+ return 4 * (threadIdx.x / 32) + 8 * (l / 4) + (l % 4);
147
+ } else {
148
+ NO_DEVICE_CODE;
149
+ return -1;
150
+ }
151
+ }
152
+ #elif defined(VOLTA_MMA_AVAILABLE)
153
+ static constexpr int ne = I * J / 32;
154
+ T x[ne] = {0};
155
+
156
+ static constexpr __device__ bool supported() {
157
+ if (I == 32 && J == 8) return true;
158
+ return false;
159
+ }
160
+
161
+ static __device__ __forceinline__ int get_i(const int l) {
162
+ if constexpr (I == 32 && J == 8) {
163
+ #ifdef GGML_CUDA_MMA_NO_VOLTA_PERM
164
+ return (((threadIdx.x % 16) / 4) * 8) + ((threadIdx.x / 16) * 4) + (l & 2) + (threadIdx.x % 2);
165
+ #else
166
+ return (l & 2) + (threadIdx.x & ~2);
167
+ #endif // GGML_CUDA_MMA_NO_VOLTA_PERM
168
+ } else {
169
+ NO_DEVICE_CODE;
170
+ return -1;
171
+ }
172
+ }
173
+
174
+ static __device__ __forceinline__ int get_j(const int l) {
175
+ if constexpr (I == 32 && J == 8) {
176
+ return (threadIdx.x & 2) + (l & (4 + 1));
177
+ } else {
178
+ NO_DEVICE_CODE;
179
+ return -1;
180
+ }
181
+ }
182
+ #elif defined(AMD_WMMA_AVAILABLE)
183
+ static constexpr int ne = I * J / 32;
184
+ T x[ne] = {0};
185
+
186
+ static constexpr __device__ bool supported() {
187
+ if (I == 16 && J == 16) return true;
188
+ if (I == 16 && J == 8) return true;
189
+ if (I == 16 && J == 4) return true;
190
+ return false;
191
+ }
192
+
193
+ static __device__ __forceinline__ int get_i(const int l) {
194
+ if constexpr (supported()) {
195
+ return threadIdx.x % 16;
196
+ } else {
197
+ NO_DEVICE_CODE;
198
+ return -1;
199
+ }
200
+ }
201
+
202
+ static __device__ __forceinline__ int get_j(const int l) {
203
+ if constexpr (I == 16 && J == 16) {
204
+ #if defined(RDNA3)
205
+ if constexpr (std::is_same_v<T, float> || std::is_same_v<T, int>) {
206
+ // matrix C
207
+ return 2 * l + (threadIdx.x / 16);
208
+ } else {
209
+ // matrix A&B
210
+ return l;
211
+ }
212
+ #else
213
+ // matrix C is the transposed matrix A&B on RDNA4
214
+ return ne * (threadIdx.x / 16) + l;
215
+ #endif // defined(RDNA3)
216
+ } else if constexpr (I == 16 && J == 8) {
217
+ // mmq input for RDNA4
218
+ return ne * (threadIdx.x / 16) + l;
219
+ } else if constexpr (I == 16 && J == 4) {
220
+ return ne * (threadIdx.x / 16) + l;
221
+ } else {
222
+ NO_DEVICE_CODE;
223
+ return -1;
224
+ }
225
+ }
226
+ #else
227
+ static constexpr int ne = I * J / 32;
228
+ T x[ne] = {0};
229
+
230
+ static constexpr __device__ bool supported() {
231
+ if (I == 8 && J == 4) return true;
232
+ if (I == 8 && J == 8) return true;
233
+ if (I == 16 && J == 8) return true;
234
+ if (I == 16 && J == 16) return true;
235
+ if (I == 32 && J == 8) return true;
236
+ return false;
237
+ }
238
+
239
+ static __device__ __forceinline__ int get_i(const int l) {
240
+ if constexpr (I == 8 && J == 4) {
241
+ return threadIdx.x / 4;
242
+ } else if constexpr (I == 8 && J == 8) {
243
+ return threadIdx.x / 4;
244
+ } else if constexpr (I == 16 && J == 8) {
245
+ return ((l / 2) * 8) + (threadIdx.x / 4);
246
+ } else if constexpr (I == 16 && J == 16) {
247
+ return (((l / 2) % 2) * 8) + (threadIdx.x / 4);
248
+ } else if constexpr (I == 32 && J == 8) {
249
+ return tile<16, 8, T>::get_i(l); // Memory layout simply repeated with same pattern in i direction.
250
+ } else {
251
+ NO_DEVICE_CODE;
252
+ return -1;
253
+ }
254
+ }
255
+
256
+ static __device__ __forceinline__ int get_j(const int l) {
257
+ if constexpr (I == 8 && J == 4) {
258
+ return threadIdx.x % 4;
259
+ } else if constexpr (I == 8 && J == 8) {
260
+ return (l * 4) + (threadIdx.x % 4);
261
+ } else if constexpr (I == 16 && J == 8) {
262
+ return ((threadIdx.x % 4) * 2) + (l % 2);
263
+ } else if constexpr (I == 16 && J == 16) {
264
+ return ((l / 4) * 8) + ((threadIdx.x % 4) * 2) + (l % 2);
265
+ } else if constexpr (I == 32 && J == 8) {
266
+ return tile<16, 8, T>::get_j(l); // Memory layout simply repeated with same pattern in i direction.
267
+ } else {
268
+ NO_DEVICE_CODE;
269
+ return -1;
270
+ }
271
+ }
272
+ #endif // defined(GGML_USE_HIP)
273
+ };
274
+
275
+ template <int I_, int J_>
276
+ struct tile<I_, J_, half2, DATA_LAYOUT_I_MAJOR> {
277
+ static constexpr int I = I_;
278
+ static constexpr int J = J_;
279
+ static constexpr data_layout dl = DATA_LAYOUT_I_MAJOR;
280
+
281
+ #if defined(VOLTA_MMA_AVAILABLE)
282
+ static constexpr int ne = I * J / WARP_SIZE;
283
+ half2 x[ne] = {{0.0f, 0.0f}};
284
+
285
+ static constexpr __device__ bool supported() {
286
+ if (I == 32 && J == 4) return true;
287
+ return false;
288
+ }
289
+
290
+ static __device__ __forceinline__ int get_i(const int l) {
291
+ if constexpr (I == 32 && J == 4) {
292
+ #ifdef GGML_CUDA_MMA_NO_VOLTA_PERM
293
+ return (((threadIdx.x % 16) / 4) * 8) + ((threadIdx.x / 16) * 4) + (threadIdx.x % 4);
294
+ #else
295
+ return threadIdx.x;
296
+ #endif // GGML_CUDA_MMA_NO_VOLTA_PERM
297
+ } else {
298
+ NO_DEVICE_CODE;
299
+ return -1;
300
+ }
301
+ }
302
+
303
+ static __device__ __forceinline__ int get_j(const int l) {
304
+ if constexpr (I == 32 && J == 4) {
305
+ return l;
306
+ } else {
307
+ NO_DEVICE_CODE;
308
+ return -1;
309
+ }
310
+ }
311
+ #elif defined(AMD_WMMA_AVAILABLE)
312
+ static constexpr int ne = I * J / 32;
313
+ half2 x[ne] = {{0.0f, 0.0f}};
314
+
315
+ static constexpr __device__ bool supported() {
316
+ if (I == 16 && J == 8) return true;
317
+ if (I == 16 && J == 16) return true;
318
+ if (I == 32 && J == 8) return true;
319
+ return false;
320
+ }
321
+
322
+ static __device__ __forceinline__ int get_i(const int l) {
323
+ if constexpr (I == 16 && J == 8) {
324
+ return threadIdx.x % 16;
325
+ } else if constexpr (I == 16 && J == 16) {
326
+ return threadIdx.x % 16;
327
+ } else if constexpr (I == 32 && J == 8) {
328
+ return (threadIdx.x % 16) * 2 + l / (ne/2);
329
+ } else {
330
+ NO_DEVICE_CODE;
331
+ return -1;
332
+ }
333
+ }
334
+
335
+ static __device__ __forceinline__ int get_j(const int l) {
336
+ if constexpr (I == 16 && J == 8) {
337
+ return (threadIdx.x / 16) * ne + l;
338
+ } else if constexpr (I == 16 && J == 16) {
339
+ #ifdef RDNA3
340
+ return l*2 + (threadIdx.x / 16);
341
+ #else
342
+ return (threadIdx.x / 16) * ne + l;
343
+ #endif // RDNA3
344
+ } else if constexpr (I == 32 && J == 8) {
345
+ return (threadIdx.x / 16) * (ne/2) + l % (ne/2);
346
+ } else {
347
+ NO_DEVICE_CODE;
348
+ return -1;
349
+ }
350
+ }
351
+ #elif defined(AMD_MFMA_AVAILABLE)
352
+ static constexpr int ne = I * J / 64;
353
+ half2 x[ne] = {{0.0f, 0.0f}};
354
+
355
+ static constexpr __device__ bool supported() {
356
+ if (I == 16 && J == 8) return true;
357
+ if (I == 16 && J == 16) return true;
358
+ if (I == 32 && J == 8) return true;
359
+ return false;
360
+ }
361
+
362
+ static __device__ __forceinline__ int get_i(const int l) {
363
+ if constexpr (I == 16 && J == 8) {
364
+ return threadIdx.x % 16;
365
+ } else if constexpr (I == 16 && J == 16) {
366
+ return threadIdx.x % 16;
367
+ } else if constexpr (I == 32 && J == 8) {
368
+ return (threadIdx.x % 16) * 2 + l / (ne/2);
369
+ } else {
370
+ NO_DEVICE_CODE;
371
+ return -1;
372
+ }
373
+ }
374
+
375
+ static __device__ __forceinline__ int get_j(const int l) {
376
+ if constexpr (I == 16 && J == 8) {
377
+ return (threadIdx.x / 16) * ne + l;
378
+ } else if constexpr (I == 16 && J == 16) {
379
+ return (threadIdx.x / 16) * ne + l;
380
+ } else if constexpr (I == 32 && J == 8) {
381
+ return (threadIdx.x / 16) * (ne/2) + l % (ne/2);
382
+ } else {
383
+ NO_DEVICE_CODE;
384
+ return -1;
385
+ }
386
+ }
387
+ #else
388
+ static constexpr int ne = I * J / WARP_SIZE;
389
+ half2 x[ne] = {{0.0f, 0.0f}};
390
+
391
+ static constexpr __device__ bool supported() {
392
+ if (I == 8 && J == 4) return true;
393
+ if (I == 8 && J == 8) return true;
394
+ if (I == 16 && J == 8) return true;
395
+ if (I == 16 && J == 16) return true;
396
+ if (I == 32 && J == 8) return true;
397
+ return false;
398
+ }
399
+
400
+ static __device__ __forceinline__ int get_i(const int l) {
401
+ if constexpr (I == 8 && J == 8) {
402
+ return threadIdx.x / 4;
403
+ } else if constexpr (I == 16 && J == 4) {
404
+ return (l * 8) + (threadIdx.x / 4);
405
+ } else if constexpr (I == 16 && J == 8) {
406
+ return ((l % 2) * 8) + (threadIdx.x / 4);
407
+ } else if constexpr (I == 32 && J == 8) {
408
+ return ((l / 4) * 16) + ((l % 2) * 8) + (threadIdx.x / 4);
409
+ } else {
410
+ NO_DEVICE_CODE;
411
+ return -1;
412
+ }
413
+ }
414
+
415
+ static __device__ __forceinline__ int get_j(const int l) {
416
+ if constexpr (I == 8 && J == 8) {
417
+ return (l * 4) + (threadIdx.x % 4);
418
+ } else if constexpr (I == 16 && J == 4) {
419
+ return threadIdx.x % 4;
420
+ } else if constexpr (I == 16 && J == 8) {
421
+ return ((l / 2) * 4) + (threadIdx.x % 4);
422
+ } else if constexpr (I == 32 && J == 8) {
423
+ return ((l & 2) * 2) + (threadIdx.x % 4);
424
+ } else {
425
+ NO_DEVICE_CODE;
426
+ return -1;
427
+ }
428
+ }
429
+ #endif // defined(VOLTA_MMA_AVAILABLE)
430
+ };
431
+
432
+ template <int I_, int J_>
433
+ struct tile<I_, J_, nv_bfloat162, DATA_LAYOUT_I_MAJOR> {
434
+ static constexpr int I = I_;
435
+ static constexpr int J = J_;
436
+ static constexpr data_layout dl = DATA_LAYOUT_I_MAJOR;
437
+
438
+ #if defined(AMD_WMMA_AVAILABLE)
439
+ static constexpr int ne = tile<I_, J_, half2, DATA_LAYOUT_I_MAJOR>::ne;
440
+ nv_bfloat162 x[ne] = {{0.0f, 0.0f}};
441
+
442
+ static constexpr __device__ bool supported() {
443
+ return tile<I_, J_, half2, DATA_LAYOUT_I_MAJOR>::supported();
444
+ }
445
+
446
+ static __device__ __forceinline__ int get_i(const int l) {
447
+ return tile<I_, J_, half2, DATA_LAYOUT_I_MAJOR>::get_i(l);
448
+ }
449
+
450
+ static __device__ __forceinline__ int get_j(const int l) {
451
+ return tile<I_, J_, half2, DATA_LAYOUT_I_MAJOR>::get_j(l);
452
+ }
453
+ #elif defined(AMD_MFMA_AVAILABLE)
454
+ static constexpr int ne = tile<I_, J_, half2, DATA_LAYOUT_I_MAJOR>::ne;
455
+ nv_bfloat162 x[ne] = {{0.0f, 0.0f}};
456
+
457
+ static constexpr __device__ bool supported() {
458
+ return tile<I_, J_, half2, DATA_LAYOUT_I_MAJOR>::supported();
459
+ }
460
+
461
+ static __device__ __forceinline__ int get_i(const int l) {
462
+ return tile<I_, J_, half2, DATA_LAYOUT_I_MAJOR>::get_i(l);
463
+ }
464
+
465
+ static __device__ __forceinline__ int get_j(const int l) {
466
+ return tile<I_, J_, half2, DATA_LAYOUT_I_MAJOR>::get_j(l);
467
+ }
468
+ #else
469
+ static constexpr int ne = I * J / WARP_SIZE;
470
+ nv_bfloat162 x[ne] = {{0.0f, 0.0f}};
471
+
472
+ static constexpr __device__ bool supported() {
473
+ if (I == 8 && J == 8) return true;
474
+ if (I == 16 && J == 4) return true;
475
+ if (I == 16 && J == 8) return true;
476
+ return false;
477
+ }
478
+
479
+ static __device__ __forceinline__ int get_i(const int l) {
480
+ if constexpr (I == 8 && J == 8) {
481
+ return threadIdx.x / 4;
482
+ } else if constexpr (I == 16 && J == 4) {
483
+ return (l * 8) + (threadIdx.x / 4);
484
+ } else if constexpr (I == 16 && J == 8) {
485
+ return ((l % 2) * 8) + (threadIdx.x / 4);
486
+ } else {
487
+ NO_DEVICE_CODE;
488
+ return -1;
489
+ }
490
+ }
491
+
492
+ static __device__ __forceinline__ int get_j(const int l) {
493
+ if constexpr (I == 8 && J == 8) {
494
+ return (l * 4) + (threadIdx.x % 4);
495
+ } else if constexpr (I == 16 && J == 4) {
496
+ return threadIdx.x % 4;
497
+ } else if constexpr (I == 16 && J == 8) {
498
+ return ((l / 2) * 4) + (threadIdx.x % 4);
499
+ } else {
500
+ NO_DEVICE_CODE;
501
+ return -1;
502
+ }
503
+ }
504
+ #endif // defined(AMD_WMMA_AVAILABLE)
505
+ };
506
+
507
+ template <int I_, int J_, typename T>
508
+ struct tile<I_, J_, T, DATA_LAYOUT_J_MAJOR> {
509
+ static constexpr int I = I_;
510
+ static constexpr int J = J_;
511
+ static constexpr data_layout dl = DATA_LAYOUT_J_MAJOR;
512
+
513
+ static constexpr int ne = tile<I_, J_, T, DATA_LAYOUT_I_MAJOR>::ne;
514
+ T x[ne] = {0};
515
+
516
+ static constexpr __device__ bool supported() {
517
+ return tile<I_, J_, T, DATA_LAYOUT_I_MAJOR>::supported();
518
+ }
519
+
520
+ static __device__ __forceinline__ int get_i(const int l) {
521
+ return tile<I_, J_, T, DATA_LAYOUT_I_MAJOR>::get_j(l);
522
+ }
523
+
524
+ static __device__ __forceinline__ int get_j(const int l) {
525
+ return tile<I_, J_, T, DATA_LAYOUT_I_MAJOR>::get_i(l);
526
+ }
527
+ };
528
+
529
+ template <int I_, int J_, typename T>
530
+ struct tile<I_, J_, T, DATA_LAYOUT_I_MAJOR_MIRRORED> {
531
+ static constexpr int I = I_;
532
+ static constexpr int J = J_;
533
+ static constexpr data_layout dl = DATA_LAYOUT_I_MAJOR_MIRRORED;
534
+
535
+ // RDNA3
536
+ static constexpr int ne = I * J / 32 * 2;
537
+
538
+ T x[ne] = {0};
539
+
540
+ static constexpr __device__ bool supported() {
541
+ if (I == 16 && J == 16) return true;
542
+ if (I == 16 && J == 8) return true;
543
+ if (I == 16 && J == 4) return true;
544
+ if (I == 32 && J == 8) return true;
545
+ return false;
546
+ }
547
+
548
+ static __device__ __forceinline__ int get_i(const int l) {
549
+ if constexpr (I == 16) {
550
+ return threadIdx.x % 16;
551
+ } else if constexpr (I == 32) {
552
+ return (threadIdx.x % 16) * 2 + l / (ne/2);
553
+ } else {
554
+ NO_DEVICE_CODE;
555
+ return -1;
556
+ }
557
+ }
558
+
559
+ static __device__ __forceinline__ int get_j(const int l) {
560
+ if constexpr (I == 16) {
561
+ return l;
562
+ } else if constexpr (I == 32) {
563
+ return l % (ne/2);
564
+ } else {
565
+ NO_DEVICE_CODE;
566
+ return -1;
567
+ }
568
+ }
569
+ };
570
+
571
+ template <int I_, int J_>
572
+ struct tile<I_, J_, half2, DATA_LAYOUT_I_MAJOR_MIRRORED> {
573
+ static constexpr int I = I_;
574
+ static constexpr int J = J_;
575
+ static constexpr data_layout dl = DATA_LAYOUT_I_MAJOR_MIRRORED;
576
+ #if defined(RDNA3)
577
+ static constexpr int ne = tile<I_, J_, float, DATA_LAYOUT_I_MAJOR_MIRRORED>::ne;
578
+
579
+ half2 x[ne] = {{0.0f, 0.0f}};
580
+
581
+ static constexpr __device__ bool supported() {
582
+ return tile<I_, J_, float, DATA_LAYOUT_I_MAJOR_MIRRORED>::supported();
583
+ }
584
+
585
+ static __device__ __forceinline__ int get_i(const int l) {
586
+ return tile<I_, J_, float, DATA_LAYOUT_I_MAJOR_MIRRORED>::get_i(l);
587
+ }
588
+
589
+ static __device__ __forceinline__ int get_j(const int l) {
590
+ return tile<I_, J_, float, DATA_LAYOUT_I_MAJOR_MIRRORED>::get_j(l);
591
+ }
592
+ #else // Volta
593
+ static constexpr int ne = I * J / (WARP_SIZE/4);
594
+
595
+ half2 x[ne] = {{0.0f, 0.0f}};
596
+
597
+ static constexpr __device__ bool supported() {
598
+ if (I == 8 && J == 4) return true;
599
+ return false;
600
+ }
601
+
602
+ static __device__ __forceinline__ int get_i(const int /*l*/) {
603
+ if constexpr (I == 8 && J == 4) {
604
+ return ((threadIdx.x / 16) * 4) + (threadIdx.x % 4);
605
+ } else {
606
+ NO_DEVICE_CODE;
607
+ return -1;
608
+ }
609
+ }
610
+
611
+ static __device__ __forceinline__ int get_j(const int l) {
612
+ if constexpr (I == 8 && J == 4) {
613
+ return l;
614
+ } else {
615
+ NO_DEVICE_CODE;
616
+ return -1;
617
+ }
618
+ }
619
+ #endif // defined(RDNA3)
620
+ };
621
+
622
+ template <int I_, int J_>
623
+ struct tile<I_, J_, nv_bfloat162, DATA_LAYOUT_I_MAJOR_MIRRORED> {
624
+ static constexpr int I = I_;
625
+ static constexpr int J = J_;
626
+ static constexpr data_layout dl = DATA_LAYOUT_I_MAJOR_MIRRORED;
627
+ static constexpr int ne = tile<I_, J_, float, DATA_LAYOUT_I_MAJOR_MIRRORED>::ne;
628
+
629
+ nv_bfloat162 x[ne] = {{0.0f, 0.0f}};
630
+
631
+ static constexpr __device__ bool supported() {
632
+ return tile<I_, J_, float, DATA_LAYOUT_I_MAJOR_MIRRORED>::supported();
633
+ }
634
+
635
+ static __device__ __forceinline__ int get_i(const int l) {
636
+ return tile<I_, J_, float, DATA_LAYOUT_I_MAJOR_MIRRORED>::get_i(l);
637
+ }
638
+
639
+ static __device__ __forceinline__ int get_j(const int l) {
640
+ return tile<I_, J_, float, DATA_LAYOUT_I_MAJOR_MIRRORED>::get_j(l);
641
+ }
642
+ };
643
+
644
+ template <int I_, int J_>
645
+ struct tile<I_, J_, half2, DATA_LAYOUT_J_MAJOR_MIRRORED> {
646
+ static constexpr int I = I_;
647
+ static constexpr int J = J_;
648
+ static constexpr data_layout dl = DATA_LAYOUT_J_MAJOR_MIRRORED;
649
+ static constexpr int ne = I * J / (WARP_SIZE/4);
650
+
651
+ half2 x[ne] = {{0.0f, 0.0f}};
652
+
653
+ static constexpr __device__ bool supported() {
654
+ if (I == 8 && J == 4) return true;
655
+ return false;
656
+ }
657
+
658
+ static __device__ __forceinline__ int get_i(const int l) {
659
+ if constexpr (I == 8 && J == 4) {
660
+ return ((l / 2) * 4) + (threadIdx.x % 4);
661
+ } else {
662
+ NO_DEVICE_CODE;
663
+ return -1;
664
+ }
665
+ }
666
+
667
+ static __device__ __forceinline__ int get_j(const int l) {
668
+ if constexpr (I == 8 && J == 4) {
669
+ return ((threadIdx.x / 16) * 2) + (l % 2);
670
+ } else {
671
+ NO_DEVICE_CODE;
672
+ return -1;
673
+ }
674
+ }
675
+ };
676
+
677
+ template <int I_, int J_>
678
+ struct tile<I_, J_, half2, DATA_LAYOUT_I_MAJOR_SCRAMBLED> {
679
+ static constexpr int I = I_;
680
+ static constexpr int J = J_;
681
+ static constexpr data_layout dl = DATA_LAYOUT_I_MAJOR_SCRAMBLED;
682
+
683
+ static constexpr int ne = I * J / ggml_cuda_get_physical_warp_size();
684
+ half2 x[ne] = {{0.0f, 0.0f}};
685
+
686
+ static constexpr __device__ bool supported() {
687
+ if (I == 16 && J == 16) return true;
688
+ return false;
689
+ }
690
+
691
+ static __device__ __forceinline__ int get_i(const int l) {
692
+ return tile<I_, J_, half2, DATA_LAYOUT_I_MAJOR>::get_i(l);
693
+ }
694
+ };
695
+
696
+ static __device__ __forceinline__ tile<16, 16, half2, DATA_LAYOUT_I_MAJOR> unscramble(const tile<16, 16, half2, DATA_LAYOUT_I_MAJOR_SCRAMBLED> & t) {
697
+ #if defined(AMD_MFMA_AVAILABLE) || (defined(AMD_WMMA_AVAILABLE) && defined(RDNA4))
698
+ tile<16, 16, half2, DATA_LAYOUT_I_MAJOR> ret;
699
+ #pragma unroll
700
+ for (int l0 = 0; l0 < t.ne/2; ++l0) {
701
+ ret.x[2*l0 + 0] = __lows2half2(t.x[l0], t.x[l0 + t.ne/2]);
702
+ ret.x[2*l0 + 1] = __highs2half2(t.x[l0], t.x[l0 + t.ne/2]);
703
+ }
704
+ return ret;
705
+ #else
706
+ NO_DEVICE_CODE;
707
+ GGML_UNUSED(t);
708
+ #endif // defined(AMD_MFMA_AVAILABLE) || (defined(AMD_WMMA_AVAILABLE) && defined(RDNA4))
709
+ }
710
+
711
+ #if defined(TURING_MMA_AVAILABLE)
712
+ template <int I, int J>
713
+ static __device__ __forceinline__ tile<I, J/2, half2> get_half2(const tile<I, J, float> & tile_float) {
714
+ tile<I, J/2, half2> ret;
715
+ #pragma unroll
716
+ for (int l0 = 0; l0 < tile_float.ne; l0 += 2) {
717
+ ret.x[l0/2] = make_half2(tile_float.x[l0 + 0], tile_float.x[l0 + 1]);
718
+ }
719
+ return ret;
720
+ }
721
+
722
+ static __device__ __forceinline__ tile<8, 8, half2> get_transposed(const tile<16, 4, half2> & t) {
723
+ tile<8, 8, half2> ret;
724
+ ret.x[0] = ggml_cuda_movmatrix(t.x[0]);
725
+ ret.x[1] = ggml_cuda_movmatrix(t.x[1]);
726
+
727
+ return ret;
728
+ }
729
+ #elif defined(AMD_WMMA_AVAILABLE) && defined(RDNA3)
730
+ static __device__ __forceinline__ tile<16, 8, half2, DATA_LAYOUT_I_MAJOR_MIRRORED> get_half2(
731
+ const tile<16, 16, float, DATA_LAYOUT_I_MAJOR> & tile_float) {
732
+ tile<16, 8, half2, DATA_LAYOUT_I_MAJOR_MIRRORED> ret;
733
+ #pragma unroll
734
+ for (int l = 0; l < tile_float.ne; ++l) {
735
+ float tmp[2];
736
+ int i = threadIdx.x / 16;
737
+ tmp[i] = tile_float.x[l];
738
+ i ^= 1;
739
+ tmp[i] = __shfl_xor_sync(0xFFFFFFFF, tile_float.x[l], 16, WARP_SIZE);
740
+ ret.x[l] = make_half2(tmp[0], tmp[1]);
741
+ }
742
+ return ret;
743
+ }
744
+ #elif defined(AMD_WMMA_AVAILABLE) || defined(AMD_MFMA_AVAILABLE)
745
+ template <int I, int J>
746
+ static __device__ __forceinline__ tile<I, J/2, half2> get_half2(const tile<I, J, float> & tile_float) {
747
+ tile<I, J/2, half2> ret;
748
+ #pragma unroll
749
+ for (int l0 = 0; l0 < tile_float.ne; l0 += 2) {
750
+ ret.x[l0/2] = make_half2(tile_float.x[l0 + 0], tile_float.x[l0 + 1]);
751
+ }
752
+ return ret;
753
+ }
754
+
755
+ static __device__ __forceinline__ tile<8, 8, half2> get_transposed(const tile<16, 4, half2> & t) {
756
+ NO_DEVICE_CODE;
757
+ return tile<8, 8, half2>{};
758
+ }
759
+ #else // Volta
760
+ template <int I, int J>
761
+ static __device__ __forceinline__ tile<I, J/2, half2> get_half2(const tile<I, J, float> & tile_float) {
762
+ tile<I, J/2, half2> ret;
763
+ #pragma unroll
764
+ for (int l0 = 0; l0 < tile_float.ne; l0 += 4) {
765
+ ret.x[l0/2 + 0] = make_half2(tile_float.x[l0 + 0], tile_float.x[l0 + 1]);
766
+ ret.x[l0/2 + 1] = make_half2(tile_float.x[l0 + 2], tile_float.x[l0 + 3]);
767
+
768
+ // On Volta FP16 and FP32 tiles have a different memory layout,
769
+ // for the conversion threads with an offset of 2 need to exchange half their values:
770
+ ret.x[l0/2 + (((threadIdx.x % 4) / 2) ^ 1)] = __shfl_xor_sync(
771
+ 0xFFFFFFFF, ret.x[l0/2 + (((threadIdx.x % 4) / 2) ^ 1)], 2, WARP_SIZE);
772
+ }
773
+ return ret;
774
+ }
775
+ #endif // defined(TURING_MMA_AVAILABLE)
776
+
777
+ template <int I, int J, typename T, data_layout dl>
778
+ static __device__ __forceinline__ void load_generic(tile<I, J, T, dl> & t, const T * __restrict__ xs0, const int stride) {
779
+ #pragma unroll
780
+ for (int l = 0; l < t.ne; ++l) {
781
+ t.x[l] = xs0[t.get_i(l)*stride + t.get_j(l)];
782
+ }
783
+ }
784
+
785
+ template <typename T>
786
+ static __device__ __forceinline__ void load_ldmatrix(
787
+ tile<8, 8, T> & t, const T * __restrict__ xs0, const int stride) {
788
+ #ifdef TURING_MMA_AVAILABLE
789
+ int * xi = (int *) t.x;
790
+ const int * xs = (const int *) xs0 + (threadIdx.x % t.I) * stride + ((threadIdx.x / t.I) * (t.J / 2)) % t.J;
791
+ asm volatile("ldmatrix.sync.aligned.m8n8.x2.b16 {%0, %1}, [%2];"
792
+ : "=r"(xi[0]), "=r"(xi[1])
793
+ : "l"(xs));
794
+ #else
795
+ GGML_UNUSED_VARS(t, xs0, stride);
796
+ NO_DEVICE_CODE;
797
+ #endif // TURING_MMA_AVAILABLE
798
+ }
799
+
800
+ template <typename T, data_layout dl>
801
+ static __device__ __forceinline__ void load_ldmatrix(
802
+ tile<16, 4, T, dl> & t, const T * __restrict__ xs0, const int stride) {
803
+ #ifdef TURING_MMA_AVAILABLE
804
+ int * xi = (int *) t.x;
805
+ const int * xs = (const int *) xs0 + (threadIdx.x % t.I) * stride;
806
+ asm volatile("ldmatrix.sync.aligned.m8n8.x2.b16 {%0, %1}, [%2];"
807
+ : "=r"(xi[0]), "=r"(xi[1])
808
+ : "l"(xs));
809
+ #elif defined(AMD_WMMA_AVAILABLE)
810
+ #ifdef RDNA3
811
+ static_assert(dl == DATA_LAYOUT_I_MAJOR_MIRRORED, "bad data layout");
812
+ static_assert(sizeof(t.x) == 16, "bad ne");
813
+ ggml_cuda_memcpy_1<8>(t.x + 0, xs0 + t.get_i(0)*stride + 0);
814
+ ggml_cuda_memcpy_1<8>(t.x + 2, xs0 + t.get_i(0)*stride + 2);
815
+ #else
816
+ static_assert(dl == DATA_LAYOUT_I_MAJOR, "bad data layout");
817
+ static_assert(sizeof(t.x) == 8, "bad ne");
818
+ ggml_cuda_memcpy_1<8>(t.x, xs0 + t.get_i(0)*stride + t.get_j(0));
819
+ #endif // RDNA3
820
+ #elif defined(AMD_MFMA_AVAILABLE)
821
+ static_assert(sizeof(t.x) == 4, "bad ne");
822
+ ggml_cuda_memcpy_1<4>(t.x, xs0 + t.get_i(0)*stride + t.get_j(0));
823
+ #else
824
+ GGML_UNUSED_VARS(t, xs0, stride);
825
+ NO_DEVICE_CODE;
826
+ #endif // TURING_MMA_AVAILABLE
827
+ }
828
+
829
+ template <typename T, data_layout dl>
830
+ static __device__ __forceinline__ void load_ldmatrix(
831
+ tile<16, 8, T, dl> & t, const T * __restrict__ xs0, const int stride) {
832
+ #if defined(TURING_MMA_AVAILABLE)
833
+ int * xi = (int * ) t.x;
834
+ const int * xs = (const int *) xs0 + (threadIdx.x % t.I) * stride + (threadIdx.x / t.I) * (t.J / 2);
835
+ asm volatile("ldmatrix.sync.aligned.m8n8.x4.b16 {%0, %1, %2, %3}, [%4];"
836
+ : "=r"(xi[0]), "=r"(xi[1]), "=r"(xi[2]), "=r"(xi[3])
837
+ : "l"(xs));
838
+ #elif defined(VOLTA_MMA_AVAILABLE)
839
+ ggml_cuda_memcpy_1<4*sizeof(T)>(t.x + 0, xs0 + t.get_i(0)*stride + 0);
840
+ ggml_cuda_memcpy_1<4*sizeof(T)>(t.x + 4, xs0 + t.get_i(4)*stride + 4);
841
+ #elif defined(AMD_WMMA_AVAILABLE)
842
+ #ifdef RDNA3
843
+ static_assert(dl == DATA_LAYOUT_I_MAJOR_MIRRORED, "bad data layout");
844
+ static_assert(sizeof(t.x) == 32, "bad ne");
845
+ ggml_cuda_memcpy_1<16>(t.x + 0, xs0 + t.get_i(0)*stride + 0);
846
+ ggml_cuda_memcpy_1<16>(t.x + 4, xs0 + t.get_i(0)*stride + 4);
847
+ #else
848
+ static_assert(dl == DATA_LAYOUT_I_MAJOR, "bad data layout");
849
+ static_assert(sizeof(t.x) == 16, "bad ne");
850
+ ggml_cuda_memcpy_1<16>(t.x, xs0 + t.get_i(0)*stride + t.get_j(0));
851
+ #endif // RDNA3
852
+ #elif defined(AMD_MFMA_AVAILABLE)
853
+ static_assert(sizeof(t.x) == 8, "bad ne");
854
+ ggml_cuda_memcpy_1<8>(t.x, xs0 + t.get_i(0)*stride + t.get_j(0));
855
+ #else
856
+ GGML_UNUSED_VARS(t, xs0, stride);
857
+ NO_DEVICE_CODE;
858
+ #endif // TURING_MMA_AVAILABLE
859
+ }
860
+
861
+ static __device__ __forceinline__ void load_ldmatrix(
862
+ tile<8, 4, half2, DATA_LAYOUT_I_MAJOR_MIRRORED> & t, const half2 * __restrict__ xs0, const int stride) {
863
+ ggml_cuda_memcpy_1<4*sizeof(half2)>(t.x, xs0 + t.get_i(0)*stride);
864
+ }
865
+
866
+ static __device__ __forceinline__ void load_ldmatrix(
867
+ tile<8, 4, half2, DATA_LAYOUT_J_MAJOR_MIRRORED> & t, const half2 * __restrict__ xs0, const int stride) {
868
+ #pragma unroll
869
+ for (int l0 = 0; l0 < t.ne; l0 += 2) {
870
+ ggml_cuda_memcpy_1<2*sizeof(half2)>(t.x + l0, xs0 + t.get_i(l0)*stride + t.get_j(l0));
871
+ }
872
+ }
873
+
874
+ static __device__ __forceinline__ void load_ldmatrix(
875
+ tile<32, 4, half2> & t, const half2 * __restrict__ xs0, const int stride) {
876
+ #if defined(VOLTA_MMA_AVAILABLE)
877
+ ggml_cuda_memcpy_1<4*sizeof(half2)>(t.x, xs0 + t.get_i(0)*stride);
878
+ #else
879
+ GGML_UNUSED_VARS(t, xs0, stride);
880
+ NO_DEVICE_CODE;
881
+ #endif // defined(VOLTA_MMA_AVAILABLE)
882
+ }
883
+
884
+ template <int I, typename T, data_layout dl>
885
+ static __device__ __forceinline__ void load_ldmatrix_trans(
886
+ tile<I, 8, T, dl> & t, const T * __restrict__ xs0, const int stride) {
887
+ #ifdef TURING_MMA_AVAILABLE
888
+ static_assert(I == 16, "bad tile width");
889
+ static_assert(dl == DATA_LAYOUT_I_MAJOR, "bad data layout");
890
+ int * xi = (int *) t.x;
891
+ const int * xs = (const int *) xs0 + (threadIdx.x % t.I) * stride + (threadIdx.x / t.I) * (t.J / 2);
892
+ asm volatile("ldmatrix.sync.aligned.m8n8.x4.trans.b16 {%0, %1, %2, %3}, [%4];"
893
+ : "=r"(xi[0]), "=r"(xi[2]), "=r"(xi[1]), "=r"(xi[3])
894
+ : "l"(xs));
895
+ #elif defined(AMD_MFMA_AVAILABLE) || defined(AMD_WMMA_AVAILABLE)
896
+ static_assert(dl == DATA_LAYOUT_I_MAJOR || dl == DATA_LAYOUT_I_MAJOR_MIRRORED, "bad data layout");
897
+ if constexpr (I == 32) {
898
+ #pragma unroll
899
+ for (int l0 = 0; l0 < t.ne/2; ++l0) {
900
+ const half2 tmp0 = xs0[(2*t.get_j(l0) + 0)*stride + t.get_i(l0)/2];
901
+ const half2 tmp1 = xs0[(2*t.get_j(l0) + 1)*stride + t.get_i(l0)/2];
902
+
903
+ t.x[l0] = __lows2half2(tmp0, tmp1);
904
+ t.x[l0 + t.ne/2] = __highs2half2(tmp0, tmp1);
905
+ }
906
+ } else {
907
+ half * xh = (half *) t.x;
908
+ #pragma unroll
909
+ for (int l = 0; l < t.ne; ++l) {
910
+ xh[2*l + 0] = ((const half *) xs0)[(2*t.get_j(l) + 0)*(2*stride) + t.get_i(l)];
911
+ xh[2*l + 1] = ((const half *) xs0)[(2*t.get_j(l) + 1)*(2*stride) + t.get_i(l)];
912
+ }
913
+ }
914
+ #else
915
+ GGML_UNUSED_VARS(t, xs0, stride);
916
+ NO_DEVICE_CODE;
917
+ #endif // TURING_MMA_AVAILABLE
918
+ }
919
+
920
+ static __device__ __forceinline__ void mma(
921
+ tile<16, 8, int> & D, const tile<16, 4, int> & A, const tile<8, 4, int> & B) {
922
+ #ifdef TURING_MMA_AVAILABLE
923
+ #if __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
924
+ asm("mma.sync.aligned.m16n8k16.row.col.s32.s8.s8.s32 {%0, %1, %2, %3}, {%4, %5}, {%6}, {%0, %1, %2, %3};"
925
+ : "+r"(D.x[0]), "+r"(D.x[1]), "+r"(D.x[2]), "+r"(D.x[3])
926
+ : "r"(A.x[0]), "r"(A.x[1]), "r"(B.x[0]));
927
+ #else
928
+ // On Turing m16n8k16 mma is not available, use 2x m8n8k16 mma instead:
929
+ asm("mma.sync.aligned.m8n8k16.row.col.s32.s8.s8.s32 {%0, %1}, {%2}, {%3}, {%0, %1};"
930
+ : "+r"(D.x[0]), "+r"(D.x[1])
931
+ : "r"(A.x[0]), "r"(B.x[0]));
932
+ asm("mma.sync.aligned.m8n8k16.row.col.s32.s8.s8.s32 {%0, %1}, {%2}, {%3}, {%0, %1};"
933
+ : "+r"(D.x[2]), "+r"(D.x[3])
934
+ : "r"(A.x[1]), "r"(B.x[0]));
935
+ #endif // __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
936
+ #else
937
+ GGML_UNUSED_VARS(D, A, B);
938
+ NO_DEVICE_CODE;
939
+ #endif // TURING_MMA_AVAILABLE
940
+ }
941
+
942
+ static __device__ __forceinline__ void mma(
943
+ tile<16, 8, int> & D, const tile<16, 8, int> & A, const tile<8, 8, int> & B) {
944
+ #ifdef TURING_MMA_AVAILABLE
945
+ #if __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
946
+ asm("mma.sync.aligned.m16n8k32.row.col.s32.s8.s8.s32 {%0, %1, %2, %3}, {%4, %5, %6, %7}, {%8, %9}, {%0, %1, %2, %3};"
947
+ : "+r"(D.x[0]), "+r"(D.x[1]), "+r"(D.x[2]), "+r"(D.x[3])
948
+ : "r"(A.x[0]), "r"(A.x[1]), "r"(A.x[2]), "r"(A.x[3]), "r"(B.x[0]), "r"(B.x[1]));
949
+ #else
950
+ // On Turing m16n8k32 mma is not available, use 4x m8n8k16 mma instead:
951
+ asm("mma.sync.aligned.m8n8k16.row.col.s32.s8.s8.s32 {%0, %1}, {%2}, {%3}, {%0, %1};"
952
+ : "+r"(D.x[0]), "+r"(D.x[1])
953
+ : "r"(A.x[0]), "r"(B.x[0]));
954
+ asm("mma.sync.aligned.m8n8k16.row.col.s32.s8.s8.s32 {%0, %1}, {%2}, {%3}, {%0, %1};"
955
+ : "+r"(D.x[2]), "+r"(D.x[3])
956
+ : "r"(A.x[1]), "r"(B.x[0]));
957
+ asm("mma.sync.aligned.m8n8k16.row.col.s32.s8.s8.s32 {%0, %1}, {%2}, {%3}, {%0, %1};"
958
+ : "+r"(D.x[0]), "+r"(D.x[1])
959
+ : "r"(A.x[2]), "r"(B.x[1]));
960
+ asm("mma.sync.aligned.m8n8k16.row.col.s32.s8.s8.s32 {%0, %1}, {%2}, {%3}, {%0, %1};"
961
+ : "+r"(D.x[2]), "+r"(D.x[3])
962
+ : "r"(A.x[3]), "r"(B.x[1]));
963
+ #endif // __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
964
+ #else
965
+ GGML_UNUSED_VARS(D, A, B);
966
+ NO_DEVICE_CODE;
967
+ #endif // TURING_MMA_AVAILABLE
968
+ }
969
+
970
+ static __device__ __forceinline__ void mma(
971
+ tile<16, 4, half2> & D, const tile<16, 8, half2> & A, const tile<8, 8, half2> & B) {
972
+ #ifdef TURING_MMA_AVAILABLE
973
+ const int * Axi = (const int *) A.x;
974
+ const int * Bxi = (const int *) B.x;
975
+ int * Dxi = (int *) D.x;
976
+ #if __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
977
+ asm("mma.sync.aligned.m16n8k16.row.col.f16.f16.f16.f16 {%0, %1}, {%2, %3, %4, %5}, {%6, %7}, {%0, %1};"
978
+ : "+r"(Dxi[0]), "+r"(Dxi[1])
979
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[0]), "r"(Bxi[1]));
980
+ #else
981
+ // On Turing m16n8k16 mma is not available, use 2x m8n8k8 mma instead:
982
+ asm("mma.sync.aligned.m16n8k8.row.col.f16.f16.f16.f16 {%0, %1}, {%2, %3}, {%4}, {%0, %1};"
983
+ : "+r"(Dxi[0]), "+r"(Dxi[1])
984
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Bxi[0]));
985
+ asm("mma.sync.aligned.m16n8k8.row.col.f16.f16.f16.f16 {%0, %1}, {%2, %3}, {%4}, {%0, %1};"
986
+ : "+r"(Dxi[0]), "+r"(Dxi[1])
987
+ : "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[1]));
988
+ #endif // __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
989
+ #else
990
+ GGML_UNUSED_VARS(D, A, B);
991
+ NO_DEVICE_CODE;
992
+ #endif // TURING_MMA_AVAILABLE
993
+ }
994
+
995
+ static __device__ __forceinline__ void mma(
996
+ tile<16, 8, half2> & D, const tile<16, 8, half2> & A, const tile<16, 8, half2> & B) {
997
+ #ifdef TURING_MMA_AVAILABLE
998
+ const int * Axi = (const int *) A.x;
999
+ const int * Bxi = (const int *) B.x;
1000
+ int * Dxi = (int *) D.x;
1001
+ #if __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
1002
+ asm("mma.sync.aligned.m16n8k16.row.col.f16.f16.f16.f16 {%0, %1}, {%2, %3, %4, %5}, {%6, %7}, {%0, %1};"
1003
+ : "+r"(Dxi[0]), "+r"(Dxi[1])
1004
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[0]), "r"(Bxi[2]));
1005
+ asm("mma.sync.aligned.m16n8k16.row.col.f16.f16.f16.f16 {%0, %1}, {%2, %3, %4, %5}, {%6, %7}, {%0, %1};"
1006
+ : "+r"(Dxi[2]), "+r"(Dxi[3])
1007
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[1]), "r"(Bxi[3]));
1008
+ #else
1009
+ // On Turing m16n8k16 mma is not available, use 4x m8n8k8 mma instead:
1010
+ asm("mma.sync.aligned.m16n8k8.row.col.f16.f16.f16.f16 {%0, %1}, {%2, %3}, {%4}, {%0, %1};"
1011
+ : "+r"(Dxi[0]), "+r"(Dxi[1])
1012
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Bxi[0]));
1013
+ asm("mma.sync.aligned.m16n8k8.row.col.f16.f16.f16.f16 {%0, %1}, {%2, %3}, {%4}, {%0, %1};"
1014
+ : "+r"(Dxi[0]), "+r"(Dxi[1])
1015
+ : "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[2]));
1016
+ asm("mma.sync.aligned.m16n8k8.row.col.f16.f16.f16.f16 {%0, %1}, {%2, %3}, {%4}, {%0, %1};"
1017
+ : "+r"(Dxi[2]), "+r"(Dxi[3])
1018
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Bxi[1]));
1019
+ asm("mma.sync.aligned.m16n8k8.row.col.f16.f16.f16.f16 {%0, %1}, {%2, %3}, {%4}, {%0, %1};"
1020
+ : "+r"(Dxi[2]), "+r"(Dxi[3])
1021
+ : "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[3]));
1022
+ #endif // __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
1023
+ #elif defined(AMD_WMMA_AVAILABLE)
1024
+ #if defined(RDNA4)
1025
+ using halfx8_t = __attribute__((ext_vector_type(8))) _Float16;
1026
+ halfx8_t& acc_frag = reinterpret_cast<halfx8_t&>(D.x[0]);
1027
+ const halfx8_t& a_frag = reinterpret_cast<const halfx8_t&>(A.x[0]);
1028
+ const halfx8_t& b_frag = reinterpret_cast<const halfx8_t&>(B.x[0]);
1029
+ acc_frag = __builtin_amdgcn_wmma_f16_16x16x16_f16_w32_gfx12(a_frag, b_frag, acc_frag);
1030
+ #else
1031
+ GGML_UNUSED_VARS(D, A, B);
1032
+ NO_DEVICE_CODE;
1033
+ #endif // defined(RDNA4)
1034
+ #elif defined(AMD_MFMA_AVAILABLE)
1035
+ // MFMA: FP16 input, FP32 accumulate, convert back to half2.
1036
+ using halfx4_t = __attribute__((ext_vector_type(4))) _Float16;
1037
+ using floatx4_t = __attribute__((ext_vector_type(4))) float;
1038
+
1039
+ // Convert existing half2 accumulator to float for MFMA:
1040
+ floatx4_t acc_f32;
1041
+ {
1042
+ const halfx4_t acc_h = reinterpret_cast<const halfx4_t&>(D.x[0]);
1043
+ #pragma unroll
1044
+ for (int i = 0; i < 4; ++i) {
1045
+ acc_f32[i] = (float)acc_h[i];
1046
+ }
1047
+ }
1048
+
1049
+ const halfx4_t& a_frag = reinterpret_cast<const halfx4_t&>(A.x[0]);
1050
+ const halfx4_t& b_frag = reinterpret_cast<const halfx4_t&>(B.x[0]);
1051
+ acc_f32 = __builtin_amdgcn_mfma_f32_16x16x16f16(a_frag, b_frag, acc_f32, 0, 0, 0);
1052
+
1053
+ // Convert back to half2:
1054
+ {
1055
+ halfx4_t result_h;
1056
+ #pragma unroll
1057
+ for (int i = 0; i < 4; ++i) {
1058
+ result_h[i] = (_Float16)acc_f32[i];
1059
+ }
1060
+ reinterpret_cast<halfx4_t&>(D.x[0]) = result_h;
1061
+ }
1062
+ #else
1063
+ GGML_UNUSED_VARS(D, A, B);
1064
+ NO_DEVICE_CODE;
1065
+ #endif // TURING_MMA_AVAILABLE
1066
+ }
1067
+
1068
+ static __device__ __forceinline__ void mma(
1069
+ tile<16, 16, half2, DATA_LAYOUT_I_MAJOR_SCRAMBLED> & D, const tile<32, 8, half2, DATA_LAYOUT_I_MAJOR> & A,
1070
+ const tile<16, 8, half2, DATA_LAYOUT_I_MAJOR> & B) {
1071
+ #if defined(AMD_MFMA_AVAILABLE) || (defined(AMD_WMMA_AVAILABLE) && defined(RDNA4))
1072
+ tile<16, 8, half2> * D16 = (tile<16, 8, half2> *) &D;
1073
+ const tile<16, 8, half2> * A16 = (const tile<16, 8, half2> *) &A;
1074
+ mma(D16[0], A16[0], B);
1075
+ mma(D16[1], A16[1], B);
1076
+ #else
1077
+ GGML_UNUSED_VARS(D, A, B);
1078
+ NO_DEVICE_CODE;
1079
+ #endif // defined(AMD_MFMA_AVAILABLE) || defined(AMD_WMMA_AVAILABLE) && defined(RDNA4)
1080
+ }
1081
+
1082
+ template <data_layout dl_ab, data_layout dl_d>
1083
+ static __device__ __forceinline__ void mma(
1084
+ tile<16, 8, float, dl_d> & D, const tile<16, 8, float, dl_ab> & A, const tile<8, 8, float, dl_ab> & B) {
1085
+ #ifdef AMPERE_MMA_AVAILABLE
1086
+ const int * Axi = (const int *) A.x;
1087
+ const int * Bxi = (const int *) B.x;
1088
+ int * Dxi = (int *) D.x;
1089
+ asm("mma.sync.aligned.m16n8k8.row.col.f32.tf32.tf32.f32 {%0, %1, %2, %3}, {%4, %5, %6, %7}, {%8, %9}, {%0, %1, %2, %3};"
1090
+ : "+r"(Dxi[0]), "+r"(Dxi[1]), "+r"(Dxi[2]), "+r"(Dxi[3])
1091
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[0]), "r"(Bxi[1]));
1092
+ #else
1093
+ GGML_UNUSED_VARS(D, A, B);
1094
+ NO_DEVICE_CODE;
1095
+ #endif // AMPERE_MMA_AVAILABLE
1096
+ }
1097
+
1098
+ template <data_layout dl_ab, data_layout dl_d>
1099
+ static __device__ __forceinline__ void mma(
1100
+ tile<16, 16, float, dl_d> & D, const tile<16, 8, float, dl_ab> & A, const tile<16, 8, float, dl_ab> & B) {
1101
+ #ifdef AMD_MFMA_AVAILABLE
1102
+ using floatx4_t = __attribute__((ext_vector_type(4))) float;
1103
+ floatx4_t& acc_frag = reinterpret_cast<floatx4_t&>(D.x[0]);
1104
+ #if defined(CDNA3)
1105
+ using floatx2_t = __attribute__((ext_vector_type(2))) float;
1106
+ const floatx2_t& a_frag = reinterpret_cast<const floatx2_t&>(A.x[0]);
1107
+ const floatx2_t& b_frag = reinterpret_cast<const floatx2_t&>(B.x[0]);
1108
+ acc_frag = __builtin_amdgcn_mfma_f32_16x16x8_xf32(a_frag, b_frag, acc_frag, 0, 0, 0);
1109
+ #elif defined(CDNA4) || defined(CDNA2) || defined(CDNA1)
1110
+ // CDNA4 (gfx950) does not support xf32 MFMA, use f32 path like CDNA2/CDNA1
1111
+ #pragma unroll
1112
+ for (int i = 0; i < 2; ++i) {
1113
+ acc_frag = __builtin_amdgcn_mfma_f32_16x16x4f32(A.x[i], B.x[i], acc_frag, 0, 0, 0);
1114
+ }
1115
+ #else
1116
+ GGML_UNUSED_VARS(D, A, B);
1117
+ NO_DEVICE_CODE;
1118
+ #endif // defined(CDNA3)
1119
+ #else
1120
+ GGML_UNUSED_VARS(D, A, B);
1121
+ NO_DEVICE_CODE;
1122
+ #endif // AMD_MFMA_AVAILABLE
1123
+ }
1124
+
1125
+ template <ggml_type type>
1126
+ static __device__ __forceinline__ void mma_block_scaled_fp4(tile<16, 8, float> & D,
1127
+ const tile<16, 8, int> & A,
1128
+ const tile<8, 8, int> & B,
1129
+ uint32_t a_scale,
1130
+ uint32_t b_scale) {
1131
+ #ifdef BLACKWELL_MMA_AVAILABLE
1132
+ const int * Axi = (const int *) A.x;
1133
+ const int * Bxi = (const int *) B.x;
1134
+ float * Dxi = (float *) D.x;
1135
+
1136
+ if constexpr (type == GGML_TYPE_MXFP4) {
1137
+ asm volatile(
1138
+ "mma.sync.aligned.kind::mxf4.block_scale.scale_vec::2X.m16n8k64.row.col.f32.e2m1.e2m1.f32.ue8m0 "
1139
+ "{%0, %1, %2, %3}, {%4, %5, %6, %7}, {%8, %9}, {%0, %1, %2, %3}, "
1140
+ "%10, {0, 0}, %11, {0, 0};"
1141
+ : "+f"(Dxi[0]), "+f"(Dxi[1]), "+f"(Dxi[2]), "+f"(Dxi[3])
1142
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[0]), "r"(Bxi[1]), "r"(a_scale), "r"(b_scale));
1143
+ } else {
1144
+ asm volatile(
1145
+ "mma.sync.aligned.kind::mxf4nvf4.block_scale.scale_vec::4X.m16n8k64.row.col.f32.e2m1.e2m1.f32.ue4m3 "
1146
+ "{%0, %1, %2, %3}, {%4, %5, %6, %7}, {%8, %9}, {%0, %1, %2, %3}, "
1147
+ "%10, {0, 0}, %11, {0, 0};"
1148
+ : "+f"(Dxi[0]), "+f"(Dxi[1]), "+f"(Dxi[2]), "+f"(Dxi[3])
1149
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[0]), "r"(Bxi[1]), "r"(a_scale), "r"(b_scale));
1150
+ }
1151
+ #else
1152
+ GGML_UNUSED_VARS(D, A, B, a_scale, b_scale);
1153
+ #endif // BLACKWELL_MMA_AVAILABLE
1154
+ }
1155
+
1156
+ static __device__ __forceinline__ void mma(
1157
+ tile<16, 8, float> & D, const tile<16, 8, half2> & A, const tile<8, 8, half2> & B) {
1158
+ #ifdef TURING_MMA_AVAILABLE
1159
+ const int * Axi = (const int *) A.x;
1160
+ const int * Bxi = (const int *) B.x;
1161
+ int * Dxi = (int *) D.x;
1162
+ #if __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
1163
+ asm("mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32 {%0, %1, %2, %3}, {%4, %5, %6, %7}, {%8, %9}, {%0, %1, %2, %3};"
1164
+ : "+r"(Dxi[0]), "+r"(Dxi[1]), "+r"(Dxi[2]), "+r"(Dxi[3])
1165
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[0]), "r"(Bxi[1]));
1166
+ #else
1167
+ // On Turing m16n8k16 mma is not available, use 2x m8n8k8 mma instead:
1168
+ asm("mma.sync.aligned.m16n8k8.row.col.f32.f16.f16.f32 {%0, %1, %2, %3}, {%4, %5}, {%6}, {%0, %1, %2, %3};"
1169
+ : "+r"(Dxi[0]), "+r"(Dxi[1]), "+r"(Dxi[2]), "+r"(Dxi[3])
1170
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Bxi[0]));
1171
+ asm("mma.sync.aligned.m16n8k8.row.col.f32.f16.f16.f32 {%0, %1, %2, %3}, {%4, %5}, {%6}, {%0, %1, %2, %3};"
1172
+ : "+r"(Dxi[0]), "+r"(Dxi[1]), "+r"(Dxi[2]), "+r"(Dxi[3])
1173
+ : "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[1]));
1174
+ #endif // __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
1175
+ #else
1176
+ GGML_UNUSED_VARS(D, A, B);
1177
+ NO_DEVICE_CODE;
1178
+ #endif // TURING_MMA_AVAILABLE
1179
+ }
1180
+
1181
+ static __device__ __forceinline__ void mma(
1182
+ tile<16, 8, float> & D, const tile<16, 8, nv_bfloat162> & A, const tile<8, 8, nv_bfloat162> & B) {
1183
+ #ifdef AMPERE_MMA_AVAILABLE
1184
+ const int * Axi = (const int *) A.x;
1185
+ const int * Bxi = (const int *) B.x;
1186
+ int * Dxi = (int *) D.x;
1187
+ asm("mma.sync.aligned.m16n8k16.row.col.f32.bf16.bf16.f32 {%0, %1, %2, %3}, {%4, %5, %6, %7}, {%8, %9}, {%0, %1, %2, %3};"
1188
+ : "+r"(Dxi[0]), "+r"(Dxi[1]), "+r"(Dxi[2]), "+r"(Dxi[3])
1189
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[0]), "r"(Bxi[1]));
1190
+ #else
1191
+ GGML_UNUSED_VARS(D, A, B);
1192
+ NO_DEVICE_CODE;
1193
+ #endif // AMPERE_MMA_AVAILABLE
1194
+ }
1195
+
1196
+ template <data_layout dl_ab, data_layout dl_d>
1197
+ static __device__ __forceinline__ void mma(
1198
+ tile<16, 16, float, dl_d> & D, const tile<16, 8, half2, dl_ab> & A, const tile<16, 8, half2, dl_ab> & B) {
1199
+ #ifdef TURING_MMA_AVAILABLE
1200
+ const int * Axi = (const int *) A.x;
1201
+ const int * Bxi = (const int *) B.x;
1202
+ int * Dxi = (int *) D.x;
1203
+ #if __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
1204
+ asm("mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32 {%0, %1, %2, %3}, {%4, %5, %6, %7}, {%8, %9}, {%0, %1, %2, %3};"
1205
+ : "+r"(Dxi[0]), "+r"(Dxi[1]), "+r"(Dxi[2]), "+r"(Dxi[3])
1206
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[0]), "r"(Bxi[2]));
1207
+ asm("mma.sync.aligned.m16n8k16.row.col.f32.f16.f16.f32 {%0, %1, %2, %3}, {%4, %5, %6, %7}, {%8, %9}, {%0, %1, %2, %3};"
1208
+ : "+r"(Dxi[4]), "+r"(Dxi[5]), "+r"(Dxi[6]), "+r"(Dxi[7])
1209
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[1]), "r"(Bxi[3]));
1210
+ #else
1211
+ // On Turing m16n8k16 mma is not available, use 4x m8n8k8 mma instead:
1212
+ asm("mma.sync.aligned.m16n8k8.row.col.f32.f16.f16.f32 {%0, %1, %2, %3}, {%4, %5}, {%6}, {%0, %1, %2, %3};"
1213
+ : "+r"(Dxi[0]), "+r"(Dxi[1]), "+r"(Dxi[2]), "+r"(Dxi[3])
1214
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Bxi[0]));
1215
+ asm("mma.sync.aligned.m16n8k8.row.col.f32.f16.f16.f32 {%0, %1, %2, %3}, {%4, %5}, {%6}, {%0, %1, %2, %3};"
1216
+ : "+r"(Dxi[0]), "+r"(Dxi[1]), "+r"(Dxi[2]), "+r"(Dxi[3])
1217
+ : "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[2]));
1218
+ asm("mma.sync.aligned.m16n8k8.row.col.f32.f16.f16.f32 {%0, %1, %2, %3}, {%4, %5}, {%6}, {%0, %1, %2, %3};"
1219
+ : "+r"(Dxi[4]), "+r"(Dxi[5]), "+r"(Dxi[6]), "+r"(Dxi[7])
1220
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Bxi[1]));
1221
+ asm("mma.sync.aligned.m16n8k8.row.col.f32.f16.f16.f32 {%0, %1, %2, %3}, {%4, %5}, {%6}, {%0, %1, %2, %3};"
1222
+ : "+r"(Dxi[4]), "+r"(Dxi[5]), "+r"(Dxi[6]), "+r"(Dxi[7])
1223
+ : "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[3]));
1224
+ #endif // __CUDA_ARCH__ >= GGML_CUDA_CC_AMPERE
1225
+ #elif defined(AMD_WMMA_AVAILABLE)
1226
+ #if defined(RDNA4)
1227
+ using halfx8_t = __attribute__((ext_vector_type(8))) _Float16;
1228
+ using floatx8_t = __attribute__((ext_vector_type(8))) float;
1229
+ floatx8_t& acc_frag = reinterpret_cast<floatx8_t&>(D.x[0]);
1230
+ const halfx8_t& a_frag = reinterpret_cast<const halfx8_t&>(A.x[0]);
1231
+ const halfx8_t& b_frag = reinterpret_cast<const halfx8_t&>(B.x[0]);
1232
+ acc_frag = __builtin_amdgcn_wmma_f32_16x16x16_f16_w32_gfx12(a_frag, b_frag, acc_frag);
1233
+ #elif defined(RDNA3)
1234
+ using halfx16_t = __attribute__((ext_vector_type(16))) _Float16;
1235
+ using floatx8_t = __attribute__((ext_vector_type(8))) float;
1236
+ floatx8_t& acc_frag = reinterpret_cast<floatx8_t&>(D.x[0]);
1237
+ const halfx16_t& a_frag = reinterpret_cast<const halfx16_t&>(A.x[0]);
1238
+ const halfx16_t& b_frag = reinterpret_cast<const halfx16_t&>(B.x[0]);
1239
+ acc_frag = __builtin_amdgcn_wmma_f32_16x16x16_f16_w32(a_frag, b_frag, acc_frag);
1240
+ #else
1241
+ GGML_UNUSED_VARS(D, A, B);
1242
+ NO_DEVICE_CODE;
1243
+ #endif // RDNA4
1244
+ #elif defined(AMD_MFMA_AVAILABLE)
1245
+ using halfx4_t = __attribute__((ext_vector_type(4))) _Float16;
1246
+ using floatx4_t = __attribute__((ext_vector_type(4))) float;
1247
+ floatx4_t& acc_frag = reinterpret_cast<floatx4_t&>(D.x[0]);
1248
+ const halfx4_t& a_frag = reinterpret_cast<const halfx4_t&>(A.x[0]);
1249
+ const halfx4_t& b_frag = reinterpret_cast<const halfx4_t&>(B.x[0]);
1250
+ acc_frag = __builtin_amdgcn_mfma_f32_16x16x16f16(a_frag, b_frag, acc_frag, 0, 0, 0);
1251
+ #else
1252
+ GGML_UNUSED_VARS(D, A, B);
1253
+ NO_DEVICE_CODE;
1254
+ #endif // TURING_MMA_AVAILABLE
1255
+ }
1256
+
1257
+ template <data_layout dl_ab, data_layout dl_d>
1258
+ static __device__ __forceinline__ void mma(
1259
+ tile<16, 16, float, dl_d> & D, const tile<16, 8, nv_bfloat162, dl_ab> & A, const tile<16, 8, nv_bfloat162, dl_ab> & B) {
1260
+ #if defined(AMD_WMMA_AVAILABLE)
1261
+ #if defined(RDNA4)
1262
+ using bf16x8_t = __attribute__((ext_vector_type(8))) __bf16;
1263
+ using floatx8_t = __attribute__((ext_vector_type(8))) float;
1264
+ floatx8_t& acc_frag = reinterpret_cast<floatx8_t&>(D.x[0]);
1265
+ const bf16x8_t& a_frag = reinterpret_cast<const bf16x8_t&>(A.x[0]);
1266
+ const bf16x8_t& b_frag = reinterpret_cast<const bf16x8_t&>(B.x[0]);
1267
+ acc_frag = __builtin_amdgcn_wmma_f32_16x16x16_bf16_w32_gfx12(a_frag, b_frag, acc_frag);
1268
+ #elif defined(RDNA3)
1269
+ using bf16x16_t = __attribute__((ext_vector_type(16))) __bf16;
1270
+ using floatx8_t = __attribute__((ext_vector_type(8))) float;
1271
+ floatx8_t& acc_frag = reinterpret_cast<floatx8_t&>(D.x[0]);
1272
+ const bf16x16_t& a_frag = reinterpret_cast<const bf16x16_t&>(A.x[0]);
1273
+ const bf16x16_t& b_frag = reinterpret_cast<const bf16x16_t&>(B.x[0]);
1274
+ acc_frag = __builtin_amdgcn_wmma_f32_16x16x16_bf16_w32(a_frag, b_frag, acc_frag);
1275
+ #else
1276
+ GGML_UNUSED_VARS(D, A, B);
1277
+ NO_DEVICE_CODE;
1278
+ #endif // defined(RDNA4)
1279
+ #elif defined(AMD_MFMA_AVAILABLE)
1280
+ using floatx4_t = __attribute__((ext_vector_type(4))) float;
1281
+ floatx4_t& acc_frag = reinterpret_cast<floatx4_t&>(D.x[0]);
1282
+ #if defined(CDNA4) || defined(CDNA3) || defined(CDNA2)
1283
+ using bf16x4_t = __attribute__((ext_vector_type(4))) __bf16;
1284
+ const bf16x4_t& a_frag = reinterpret_cast<const bf16x4_t&>(A.x[0]);
1285
+ const bf16x4_t& b_frag = reinterpret_cast<const bf16x4_t&>(B.x[0]);
1286
+ acc_frag = __builtin_amdgcn_mfma_f32_16x16x16bf16_1k(a_frag, b_frag, acc_frag, 0, 0, 0);
1287
+ #elif defined(CDNA1)
1288
+ #pragma unroll
1289
+ for (int i = 0; i < 2; ++i) {
1290
+ using bf16x2_t = __attribute__((ext_vector_type(2))) __bf16;
1291
+ const bf16x2_t& a_frag = reinterpret_cast<const bf16x2_t&>(A.x[i]);
1292
+ const bf16x2_t& b_frag = reinterpret_cast<const bf16x2_t&>(B.x[i]);
1293
+ acc_frag = __builtin_amdgcn_mfma_f32_16x16x8bf16(a_frag, b_frag, acc_frag, 0, 0, 0);
1294
+ }
1295
+ #else
1296
+ GGML_UNUSED_VARS(D, A, B);
1297
+ NO_DEVICE_CODE;
1298
+ #endif // defined(CDNA3) || defined(CDNA2)
1299
+ #else
1300
+ GGML_UNUSED_VARS(D, A, B);
1301
+ NO_DEVICE_CODE;
1302
+ #endif // defined(AMD_WMMA_AVAILABLE)
1303
+ }
1304
+
1305
+ template <data_layout dl_d, data_layout dl_ab>
1306
+ static __device__ __forceinline__ void mma(
1307
+ tile<16, 16, int, dl_d> & D, const tile<16, 8, int, dl_ab> & A, const tile<16, 8, int, dl_ab> & B) {
1308
+ #if defined(AMD_MFMA_AVAILABLE)
1309
+ using int32x4_t = __attribute__((__vector_size__(4 * sizeof(int)))) int;
1310
+ int32x4_t * acc = (int32x4_t *) D.x;
1311
+ #if defined(CDNA4) || defined(CDNA3)
1312
+ acc[0] = __builtin_amdgcn_mfma_i32_16x16x32_i8(((int64_t *) A.x)[0], ((int64_t *) B.x)[0], acc[0], 0, 0, 0);
1313
+ #elif defined(CDNA2) || defined(CDNA1)
1314
+ acc[0] = __builtin_amdgcn_mfma_i32_16x16x16i8(A.x[0], B.x[0], acc[0], 0, 0, 0);
1315
+ acc[0] = __builtin_amdgcn_mfma_i32_16x16x16i8(A.x[1], B.x[1], acc[0], 0, 0, 0);
1316
+ #endif // defined(CDNA4) || defined(CDNA3)
1317
+ #elif defined(AMD_WMMA_AVAILABLE)
1318
+ using int32x8_t = __attribute__((__vector_size__(8 * sizeof(int)))) int;
1319
+ int32x8_t * acc = (int32x8_t *) D.x;
1320
+ #if defined(RDNA4)
1321
+ using int32x2_t = __attribute__((__vector_size__(2 * sizeof(int)))) int;
1322
+ int32x2_t * a_vec = (int32x2_t *) A.x;
1323
+ int32x2_t * b_vec = (int32x2_t *) B.x;
1324
+ acc[0] = __builtin_amdgcn_wmma_i32_16x16x16_iu8_w32_gfx12(true, a_vec[0], true, b_vec[0], acc[0], true);
1325
+ acc[0] = __builtin_amdgcn_wmma_i32_16x16x16_iu8_w32_gfx12(true, a_vec[1], true, b_vec[1], acc[0], true);
1326
+ #elif defined(RDNA3)
1327
+ using int32x4_t = __attribute__((__vector_size__(4 * sizeof(int)))) int;
1328
+ int32x4_t * a_vec = (int32x4_t *) A.x;
1329
+ int32x4_t * b_vec = (int32x4_t *) B.x;
1330
+ acc[0] = __builtin_amdgcn_wmma_i32_16x16x16_iu8_w32(true, a_vec[0], true, b_vec[0], acc[0], true);
1331
+ acc[0] = __builtin_amdgcn_wmma_i32_16x16x16_iu8_w32(true, a_vec[1], true, b_vec[1], acc[0], true);
1332
+ #endif // RDNA4
1333
+ #else
1334
+ GGML_UNUSED_VARS(D, A, B);
1335
+ NO_DEVICE_CODE;
1336
+ #endif // AMD_MFMA_AVAILABLE
1337
+ }
1338
+
1339
+ static __device__ __forceinline__ void mma(
1340
+ tile<32, 32, int> & D, const tile<32, 4, int> & A, const tile<32, 4, int> & B) {
1341
+ #if defined(AMD_MFMA_AVAILABLE)
1342
+ using int32x16_t = __attribute__((__vector_size__(16 * sizeof(int)))) int;
1343
+ int32x16_t * acc = (int32x16_t *) D.x;
1344
+ #if defined(CDNA4) || defined(CDNA3)
1345
+ acc[0] = __builtin_amdgcn_mfma_i32_32x32x16_i8(((int64_t *) A.x)[0], ((int64_t *) B.x)[0], acc[0], 0, 0, 0);
1346
+ #elif defined(CDNA2) || defined(CDNA1)
1347
+ acc[0] = __builtin_amdgcn_mfma_i32_32x32x8i8(A.x[0], B.x[0], acc[0], 0, 0, 0);
1348
+ acc[0] = __builtin_amdgcn_mfma_i32_32x32x8i8(A.x[1], B.x[1], acc[0], 0, 0, 0);
1349
+ #endif // defined(CDNA4) || defined(CDNA3)
1350
+
1351
+ #else
1352
+ GGML_UNUSED_VARS(D, A, B);
1353
+ NO_DEVICE_CODE;
1354
+ #endif // AMD_MFMA_AVAILABLE
1355
+ }
1356
+
1357
+ template <typename T1, typename T2, int J, int K>
1358
+ static __device__ __forceinline__ void mma(
1359
+ tile<32, J, T1> & D, const tile<32, K, T2> & A, const tile<J, K, T2> & B) {
1360
+ tile <16, J, T1> * D16 = reinterpret_cast< tile<16, J, T1> *>(&D);
1361
+ const tile<16, K, T2> * A16 = reinterpret_cast<const tile<16, K, T2> *>(&A);
1362
+ mma(D16[0], A16[0], B);
1363
+ mma(D16[1], A16[1], B);
1364
+ }
1365
+
1366
+ static __device__ __forceinline__ void mma(
1367
+ tile<32, 8, float> & D, const tile<32, 4, half2> & A, const tile<8, 4, half2, DATA_LAYOUT_I_MAJOR_MIRRORED> & B) {
1368
+ #if defined(VOLTA_MMA_AVAILABLE)
1369
+ const int * Axi = (const int *) A.x;
1370
+ const int * Bxi = (const int *) B.x;
1371
+ int * Dxi = (int *) D.x;
1372
+ asm("mma.sync.aligned.m8n8k4.row.col.f32.f16.f16.f32 "
1373
+ "{%0, %1, %2, %3, %4, %5, %6, %7}, {%8, %9}, {%10, %11}, {%0, %1, %2, %3, %4, %5, %6, %7};"
1374
+ : "+r"(Dxi[0]), "+r"(Dxi[1]), "+r"(Dxi[2]), "+r"(Dxi[3]), "+r"(Dxi[4]), "+r"(Dxi[5]), "+r"(Dxi[6]), "+r"(Dxi[7])
1375
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Bxi[0]), "r"(Bxi[1]));
1376
+ asm("mma.sync.aligned.m8n8k4.row.col.f32.f16.f16.f32 "
1377
+ "{%0, %1, %2, %3, %4, %5, %6, %7}, {%8, %9}, {%10, %11}, {%0, %1, %2, %3, %4, %5, %6, %7};"
1378
+ : "+r"(Dxi[0]), "+r"(Dxi[1]), "+r"(Dxi[2]), "+r"(Dxi[3]), "+r"(Dxi[4]), "+r"(Dxi[5]), "+r"(Dxi[6]), "+r"(Dxi[7])
1379
+ : "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[2]), "r"(Bxi[3]));
1380
+ #else
1381
+ GGML_UNUSED_VARS(D, A, B);
1382
+ NO_DEVICE_CODE;
1383
+ #endif // defined(VOLTA_MMA_AVAILABLE)
1384
+ }
1385
+
1386
+ static __device__ __forceinline__ void mma(
1387
+ tile<32, 4, half2> & D, const tile<32, 4, half2> & A, const tile<8, 4, half2, DATA_LAYOUT_J_MAJOR_MIRRORED> & B) {
1388
+ #if defined(VOLTA_MMA_AVAILABLE)
1389
+ const int * Axi = (const int *) A.x;
1390
+ const int * Bxi = (const int *) B.x;
1391
+ int * Dxi = (int *) D.x;
1392
+ asm("mma.sync.aligned.m8n8k4.row.row.f16.f16.f16.f16 "
1393
+ "{%0, %1, %2, %3}, {%4, %5}, {%6, %7}, {%0, %1, %2, %3};"
1394
+ : "+r"(Dxi[0]), "+r"(Dxi[1]), "+r"(Dxi[2]), "+r"(Dxi[3])
1395
+ : "r"(Axi[0]), "r"(Axi[1]), "r"(Bxi[0]), "r"(Bxi[1]));
1396
+ asm("mma.sync.aligned.m8n8k4.row.row.f16.f16.f16.f16 "
1397
+ "{%0, %1, %2, %3}, {%4, %5}, {%6, %7}, {%0, %1, %2, %3};"
1398
+ : "+r"(Dxi[0]), "+r"(Dxi[1]), "+r"(Dxi[2]), "+r"(Dxi[3])
1399
+ : "r"(Axi[2]), "r"(Axi[3]), "r"(Bxi[2]), "r"(Bxi[3]));
1400
+ #else
1401
+ GGML_UNUSED_VARS(D, A, B);
1402
+ NO_DEVICE_CODE;
1403
+ #endif // defined(VOLTA_MMA_AVAILABLE)
1404
+ }
1405
+
1406
+ static __device__ __forceinline__ void mma(
1407
+ tile<16, 16, half2, DATA_LAYOUT_I_MAJOR> & D, const tile<32, 8, half2, DATA_LAYOUT_I_MAJOR_MIRRORED> & A,
1408
+ const tile<16, 8, half2, DATA_LAYOUT_I_MAJOR_MIRRORED> & B) {
1409
+ #if defined(AMD_WMMA_AVAILABLE) && defined(RDNA3)
1410
+ using halfx16_t = __attribute__((ext_vector_type(16))) _Float16;
1411
+ halfx16_t * xD = (halfx16_t *) D.x;
1412
+ const halfx16_t * xA = (const halfx16_t *) A.x;
1413
+ const halfx16_t * xB = (const halfx16_t *) B.x;
1414
+ xD[0] = __builtin_amdgcn_wmma_f16_16x16x16_f16_w32(xA[0], xB[0], xD[0], /*opsel =*/ 0);
1415
+ xD[0] = __builtin_amdgcn_wmma_f16_16x16x16_f16_w32(xA[1], xB[0], xD[0], /*opsel =*/ 1);
1416
+ #else
1417
+ GGML_UNUSED_VARS(D, A, B);
1418
+ NO_DEVICE_CODE;
1419
+ #endif // TURING_MMA_AVAILABLE
1420
+ }
1421
+
1422
+ template <data_layout dl_d, data_layout dl_ab>
1423
+ static __device__ __forceinline__ void mma(
1424
+ tile<16, 16, int, dl_d> & D, const tile<16, 4, int, dl_ab> & A, const tile<16, 4, int, dl_ab> & B) {
1425
+ #if defined(AMD_MFMA_AVAILABLE)
1426
+ using int32x4_t = __attribute__((__vector_size__(4 * sizeof(int)))) int;
1427
+ int32x4_t * acc = (int32x4_t *) D.x;
1428
+ #if defined(CDNA4) || defined(CDNA3)
1429
+ const int64_t xA = uint32_t(A.x[0]);
1430
+ const int64_t xB = uint32_t(B.x[0]);
1431
+ acc[0] = __builtin_amdgcn_mfma_i32_16x16x32_i8(xA, xB, acc[0], 0, 0, 0);
1432
+ #elif defined(CDNA2) || defined(CDNA1)
1433
+ acc[0] = __builtin_amdgcn_mfma_i32_16x16x16i8(A.x[0], B.x[0], acc[0], 0, 0, 0);
1434
+ #endif // defined(CDNA4) || defined(CDNA3)
1435
+ #elif defined(AMD_WMMA_AVAILABLE)
1436
+ using int32x8_t = __attribute__((__vector_size__(8 * sizeof(int)))) int;
1437
+ int32x8_t * acc = (int32x8_t *) D.x;
1438
+ #if defined(RDNA4)
1439
+ using int32x2_t = __attribute__((__vector_size__(2 * sizeof(int)))) int;
1440
+ int32x2_t * a_vec = (int32x2_t *) A.x;
1441
+ int32x2_t * b_vec = (int32x2_t *) B.x;
1442
+ acc[0] = __builtin_amdgcn_wmma_i32_16x16x16_iu8_w32_gfx12(true, a_vec[0], true, b_vec[0], acc[0], false);
1443
+ #elif defined(RDNA3)
1444
+ using int32x4_t = __attribute__((__vector_size__(4 * sizeof(int)))) int;
1445
+ int32x4_t * a_vec = (int32x4_t *) A.x;
1446
+ int32x4_t * b_vec = (int32x4_t *) B.x;
1447
+ acc[0] = __builtin_amdgcn_wmma_i32_16x16x16_iu8_w32(true, a_vec[0], true, b_vec[0], acc[0], false);
1448
+ #endif // RDNA4
1449
+ #else
1450
+ GGML_UNUSED(D);
1451
+ GGML_UNUSED(A);
1452
+ GGML_UNUSED(B);
1453
+ NO_DEVICE_CODE;
1454
+ #endif // AMD_WMMA_AVAILABLE
1455
+ }
1456
+ }
backend/llama.cpp/ggml/src/ggml-cuda/mmf.cu ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "ggml.h"
2
+ #include "mmf.cuh"
3
+ #include "mmid.cuh"
4
+
5
+ static __forceinline__ int mmf_get_rows_per_block(const int cc) {
6
+ if (GGML_CUDA_CC_IS_CDNA(cc)) {
7
+ return MMF_ROWS_PER_BLOCK_CDNA;
8
+ } else {
9
+ return MMF_ROWS_PER_BLOCK;
10
+ }
11
+ }
12
+
13
+ void ggml_cuda_mul_mat_f(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, const ggml_tensor * ids, ggml_tensor * dst) {
14
+ GGML_ASSERT( src1->type == GGML_TYPE_F32);
15
+ GGML_ASSERT(!ids || ids->type == GGML_TYPE_I32);
16
+ GGML_ASSERT( dst->type == GGML_TYPE_F32);
17
+
18
+
19
+ GGML_TENSOR_BINARY_OP_LOCALS;
20
+
21
+ const size_t ts_src0 = ggml_type_size(src0->type);
22
+ const size_t ts_src1 = ggml_type_size(src1->type);
23
+ const size_t ts_dst = ggml_type_size(dst->type);
24
+
25
+ GGML_ASSERT(ne13 == ne3);
26
+
27
+ GGML_ASSERT( nb00 == ts_src0);
28
+ GGML_ASSERT( nb10 == ts_src1);
29
+ GGML_ASSERT(!ids || ids->nb[0] == ggml_type_size(ids->type));
30
+ GGML_ASSERT( nb0 == ts_dst);
31
+
32
+ const float * src1_d = (const float *) src1->data;
33
+ const int32_t * ids_d = ids ? (const int32_t *) ids->data : nullptr;
34
+ float * dst_d = (float *) dst->data;
35
+
36
+ const int64_t s01 = src0->nb[1] / ts_src0;
37
+ const int64_t s11 = src1->nb[1] / ts_src1;
38
+ const int64_t s1 = dst->nb[1] / ts_dst;
39
+ const int64_t s02 = src0->nb[2] / ts_src0;
40
+ const int64_t s12 = src1->nb[2] / ts_src1;
41
+ const int64_t s2 = dst->nb[2] / ts_dst;
42
+ const int64_t s03 = src0->nb[3] / ts_src0;
43
+ const int64_t s13 = src1->nb[3] / ts_src1;
44
+ const int64_t s3 = dst->nb[3] / ts_dst;
45
+
46
+ const int64_t ids_s0 = ids ? ids->nb[0] / ggml_type_size(ids->type) : 0;
47
+ const int64_t ids_s1 = ids ? ids->nb[1] / ggml_type_size(ids->type) : 0;
48
+
49
+ mmf_ids_data ids_info{};
50
+ mmf_ids_data * ids_info_ptr = nullptr;
51
+ ggml_cuda_pool_alloc<int32_t> ids_src_compact_dev;
52
+ ggml_cuda_pool_alloc<int32_t> ids_dst_compact_dev;
53
+ ggml_cuda_pool_alloc<int32_t> expert_bounds_dev;
54
+
55
+ // For MUL_MAT_ID the memory layout is different than for MUL_MAT:
56
+ const int64_t ncols_dst = ids ? ne2 : ne1;
57
+ const int64_t nchannels_dst = ids ? ne1 : ne2;
58
+
59
+ const int64_t stride_col_dst = ids ? s2 : s1;
60
+ const int64_t stride_col_y = ids ? s12 : s11;
61
+ const int64_t stride_channel_dst = ids ? s1 : s2;
62
+
63
+ int64_t stride_channel_y = ids ? s11 : s12;
64
+ int64_t nchannels_y = ids ? ne11 : ne12;
65
+
66
+ //mul_mat_id: handle broadcast
67
+ if (ids && nchannels_y == 1) {
68
+ stride_channel_y = 0;
69
+ nchannels_y = ids->ne[0];
70
+ }
71
+
72
+ if (ids && ncols_dst > 16) {
73
+ const int64_t n_expert_used = ids->ne[0];
74
+ const int64_t n_experts = ne02;
75
+ const int64_t n_tokens = ne12;
76
+ const int64_t ne_get_rows = n_tokens * n_expert_used;
77
+
78
+ ids_src_compact_dev.alloc(ctx.pool(), ne_get_rows);
79
+ ids_dst_compact_dev.alloc(ctx.pool(), ne_get_rows);
80
+ expert_bounds_dev.alloc(ctx.pool(), n_experts + 1);
81
+
82
+ const int si1 = static_cast<int>(ids_s1);
83
+ const int sis1 = static_cast<int>(src1->nb[2] / src1->nb[1]);
84
+
85
+ GGML_ASSERT(sis1 > 0);
86
+
87
+ ggml_cuda_launch_mm_ids_helper(ids_d, ids_src_compact_dev.get(), ids_dst_compact_dev.get(), expert_bounds_dev.get(),
88
+ static_cast<int>(n_experts), static_cast<int>(n_tokens), static_cast<int>(n_expert_used), static_cast<int>(ne11), si1, sis1, ctx.stream());
89
+ CUDA_CHECK(cudaGetLastError());
90
+
91
+ ids_info.ids_src_compact = ids_src_compact_dev.get();
92
+ ids_info.ids_dst_compact = ids_dst_compact_dev.get();
93
+ ids_info.expert_bounds_dev = expert_bounds_dev.get();
94
+ ids_info.n_experts = static_cast<int>(n_experts);
95
+ ids_info.sis1 = sis1;
96
+ ids_info_ptr = &ids_info;
97
+ }
98
+
99
+ const int device = ggml_cuda_get_device();
100
+ const int cc = ggml_cuda_info().devices[device].cc;
101
+ const int rows_per_block = mmf_get_rows_per_block(cc);
102
+
103
+ switch (src0->type) {
104
+ case GGML_TYPE_F32: {
105
+ const float * src0_d = (const float *) src0->data;
106
+ constexpr int vals_per_T = 1;
107
+ mul_mat_f_switch_rows_per_block<float>(
108
+ rows_per_block, src0_d, src1_d, ids_d, dst_d, ne00/vals_per_T, ne01, ncols_dst, s01/vals_per_T, stride_col_y/vals_per_T, stride_col_dst,
109
+ ids_s0, ids_s1, ne02, nchannels_y, nchannels_dst, s02/vals_per_T, stride_channel_y, stride_channel_dst,
110
+ ne03, ne3, s03/vals_per_T, s13, s3, ctx.stream(), ids_info_ptr);
111
+ } break;
112
+ case GGML_TYPE_F16: {
113
+ const half2 * src0_d = (const half2 *) src0->data;
114
+ constexpr int vals_per_T = 2;
115
+ mul_mat_f_switch_rows_per_block<half2>(
116
+ rows_per_block, src0_d, src1_d, ids_d, dst_d, ne00/vals_per_T, ne01, ncols_dst, s01/vals_per_T, stride_col_y/vals_per_T, stride_col_dst,
117
+ ids_s0, ids_s1, ne02, nchannels_y, nchannels_dst, s02/vals_per_T, stride_channel_y, stride_channel_dst,
118
+ ne03, ne3, s03/vals_per_T, s13, s3, ctx.stream(), ids_info_ptr);
119
+ } break;
120
+ case GGML_TYPE_BF16: {
121
+ const nv_bfloat162 * src0_d = (const nv_bfloat162 *) src0->data;
122
+ constexpr int vals_per_T = 2;
123
+ mul_mat_f_switch_rows_per_block<nv_bfloat162>(
124
+ rows_per_block, src0_d, src1_d, ids_d, dst_d, ne00/vals_per_T, ne01, ncols_dst, s01/vals_per_T, stride_col_y/vals_per_T, stride_col_dst,
125
+ ids_s0, ids_s1, ne02, nchannels_y, nchannels_dst, s02/vals_per_T, stride_channel_y, stride_channel_dst,
126
+ ne03, ne3, s03/vals_per_T, s13, s3, ctx.stream(), ids_info_ptr);
127
+ } break;
128
+ default:
129
+ GGML_ABORT("unsupported type: %s", ggml_type_name(src0->type));
130
+ }
131
+ }
132
+
133
+ bool ggml_cuda_should_use_mmf(enum ggml_type type, int cc, int warp_size, const int64_t * src0_ne,
134
+ const size_t * src0_nb, const int src1_ncols, bool mul_mat_id) {
135
+ if (ggml_is_quantized(type)) {
136
+ return false;
137
+ }
138
+
139
+ const size_t ts = ggml_type_size(type);
140
+ if (src0_ne[0] % (warp_size * (4/ts)) != 0) {
141
+ return false;
142
+ }
143
+
144
+ if (src0_nb[0] != ts) {
145
+ return false;
146
+ }
147
+
148
+ // Pointers not aligned to the size of half2/nv_bfloat162/float2 would result in a crash:
149
+ for (size_t i = 1; i < GGML_MAX_DIMS; ++i) {
150
+ if (src0_nb[i] % (2*ts) != 0) {
151
+ return false;
152
+ }
153
+ }
154
+ if (src0_ne[1] % mmf_get_rows_per_block(cc) != 0) {
155
+ return false;
156
+ }
157
+
158
+ if (GGML_CUDA_CC_IS_CDNA3(cc) && type == GGML_TYPE_BF16) {
159
+ return false;
160
+ }
161
+
162
+ if (mul_mat_id) {
163
+ if (src0_ne[1] <= 1024 && src1_ncols > 512) {
164
+ return false;
165
+ } else if(src0_ne[1] > 1024 && src1_ncols > 128) {
166
+ return false;
167
+ }
168
+ } else {
169
+ if (GGML_CUDA_CC_IS_RDNA3_0(cc) && src1_ncols > 8) {
170
+ return false;
171
+ } else if (GGML_CUDA_CC_IS_CDNA2(cc) && (type == GGML_TYPE_F16 || type == GGML_TYPE_BF16)) {
172
+ //TODO: truse CDNA2 as CDNA1, tune the perf when CDNA2 is available.
173
+ return false;
174
+ } else if (GGML_CUDA_CC_IS_CDNA1(cc) && (type == GGML_TYPE_F16 || type == GGML_TYPE_BF16)) {
175
+ return false;
176
+ } else if (src1_ncols > 16) {
177
+ return false;
178
+ }
179
+ }
180
+
181
+ switch (type) {
182
+ case GGML_TYPE_F32:
183
+ return ampere_mma_available(cc) || amd_mfma_available(cc);
184
+ case GGML_TYPE_F16:
185
+ return volta_mma_available(cc) || turing_mma_available(cc) || amd_wmma_available(cc) || amd_mfma_available(cc);
186
+ case GGML_TYPE_BF16:
187
+ return ampere_mma_available(cc) || amd_wmma_available(cc) || amd_mfma_available(cc);
188
+ default:
189
+ return false;
190
+ }
191
+ }
backend/llama.cpp/ggml/src/ggml-cuda/mmf.cuh ADDED
@@ -0,0 +1,908 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma once
2
+
3
+ #include "mma.cuh"
4
+ #include "common.cuh"
5
+ #include "convert.cuh"
6
+
7
+ using namespace ggml_cuda_mma;
8
+
9
+ #define MMF_ROWS_PER_BLOCK 32
10
+ #define MMF_ROWS_PER_BLOCK_CDNA 64
11
+
12
+ static __forceinline__ int64_t mmf_get_max_block_size(int cc) {
13
+ if (GGML_CUDA_CC_IS_CDNA(cc)) {
14
+ return 512;
15
+ } else {
16
+ return 256;
17
+ }
18
+ }
19
+
20
+ static __forceinline__ int mmf_get_padding(int cc) {
21
+ if (GGML_CUDA_CC_IS_CDNA(cc)) {
22
+ return 2;
23
+ } else {
24
+ return 4;
25
+ }
26
+ }
27
+
28
+ static constexpr __device__ int mmf_get_padding() {
29
+ #if defined(AMD_MFMA_AVAILABLE)
30
+ return 2;
31
+ #else
32
+ return 4;
33
+ #endif // defined(AMD_MFMA_AVAILABLE)
34
+ }
35
+
36
+ struct mmf_ids_data {
37
+ const int32_t * ids_src_compact = nullptr;
38
+ const int32_t * ids_dst_compact = nullptr;
39
+ const int32_t * expert_bounds_dev = nullptr;
40
+ int n_experts = 0;
41
+ int sis1 = 0;
42
+ };
43
+
44
+ void ggml_cuda_mul_mat_f(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, const ggml_tensor * ids, ggml_tensor * dst);
45
+
46
+ bool ggml_cuda_should_use_mmf(enum ggml_type type, int cc, int warp_size, const int64_t * scr0_ne, const size_t * src0_nb, const int src1_ncols, bool mul_mat_id);
47
+
48
+ template <typename T, int rows_per_block, int cols_per_block, int nwarps, bool has_ids>
49
+ __launch_bounds__(ggml_cuda_get_physical_warp_size()*nwarps, 1)
50
+ static __global__ void mul_mat_f(
51
+ const T * __restrict__ x, const float * __restrict__ y, const int32_t * __restrict__ ids, float * __restrict__ dst,
52
+ const int ncols, const int ncols_dst_total, const int nchannels_dst, const int stride_row, const int stride_col_y, const int stride_col_dst,
53
+ const int stride_col_id, const int stride_row_id,
54
+ const int channel_ratio, const int stride_channel_x, const int stride_channel_y, const int stride_channel_dst,
55
+ const int sample_ratio, const int stride_sample_x, const int stride_sample_y, const int stride_sample_dst) {
56
+ // TODO: handle this in a consistent and simpler way after AMD MFMA support has been added
57
+ #if defined(VOLTA_MMA_AVAILABLE) || defined(TURING_MMA_AVAILABLE) || defined(AMD_WMMA_AVAILABLE) || defined(AMD_MFMA_AVAILABLE)
58
+ #if defined(AMD_WMMA_AVAILABLE)
59
+ if constexpr (!(std::is_same_v<T, half2> || std::is_same_v<T, nv_bfloat162>) || rows_per_block != MMF_ROWS_PER_BLOCK) {NO_DEVICE_CODE;} else {
60
+ typedef tile<16, 8, T, get_input_data_layout()> tile_A;
61
+ typedef tile<16, 8, T, get_input_data_layout()> tile_B;
62
+ typedef tile<16, 16, float, DATA_LAYOUT_J_MAJOR> tile_C;
63
+ #elif defined(AMD_MFMA_AVAILABLE)
64
+ if constexpr (rows_per_block != MMF_ROWS_PER_BLOCK_CDNA) {NO_DEVICE_CODE;} else {
65
+ typedef tile<16, 8, T, DATA_LAYOUT_I_MAJOR> tile_A;
66
+ typedef tile<16, 8, T, DATA_LAYOUT_I_MAJOR> tile_B;
67
+ typedef tile<16, 16, float, DATA_LAYOUT_J_MAJOR> tile_C;
68
+ #else
69
+ #ifdef VOLTA_MMA_AVAILABLE
70
+ if constexpr (!std::is_same_v<T, half2> || rows_per_block != MMF_ROWS_PER_BLOCK) {NO_DEVICE_CODE;} else {
71
+ typedef tile<32, 4, T, DATA_LAYOUT_I_MAJOR> tile_A;
72
+ typedef tile< 8, 4, T, DATA_LAYOUT_I_MAJOR_MIRRORED> tile_B;
73
+ typedef tile<32, 8, float, DATA_LAYOUT_I_MAJOR> tile_C;
74
+ #else
75
+ if constexpr (rows_per_block != MMF_ROWS_PER_BLOCK) {NO_DEVICE_CODE;} else {
76
+ typedef tile<16, 8, T> tile_A;
77
+ typedef tile<8, 8, T> tile_B;
78
+ typedef tile<16, 8, float> tile_C;
79
+ #endif // VOLTA_MMA_AVAILABLE
80
+ #endif // defined(AMD_WMMA_AVAILABLE)
81
+ if constexpr (!tile_A::supported() || !tile_B::supported() || !tile_C::supported()) {
82
+ NO_DEVICE_CODE;
83
+ return;
84
+ }
85
+
86
+ constexpr int warp_size = ggml_cuda_get_physical_warp_size();
87
+ constexpr int tile_k_padded = warp_size + mmf_get_padding();
88
+ constexpr int ntA = rows_per_block / tile_A::I;
89
+ constexpr int ntB = (cols_per_block + tile_B::I - 1) / tile_B::I;
90
+
91
+ const int row0 = blockIdx.x * rows_per_block;
92
+
93
+ int expert_idx = 0;
94
+ [[maybe_unused]] int col_base = 0;
95
+
96
+ const int channel_dst = has_ids ? 0 : blockIdx.y;
97
+
98
+ if constexpr (has_ids) {
99
+ // experts + tiles of ncols_dst are packed in the y dimension
100
+ int col_tiles = (ncols_dst_total + cols_per_block - 1) / cols_per_block;
101
+ const int nchannels_x = gridDim.y / col_tiles;
102
+ const int tile_idx = blockIdx.y / nchannels_x;
103
+ expert_idx = blockIdx.y - tile_idx * nchannels_x;
104
+ col_base = tile_idx * cols_per_block;
105
+ }
106
+
107
+ const int channel_x = has_ids ? expert_idx : (channel_dst / channel_ratio);
108
+ const int channel_y = channel_dst;
109
+ const int sample_dst = blockIdx.z;
110
+ const int sample_x = sample_dst / sample_ratio;
111
+ const int sample_y = sample_dst;
112
+
113
+ x += int64_t(sample_x) *stride_sample_x + channel_x *stride_channel_x + row0*stride_row ;
114
+ y += int64_t(sample_y) *stride_sample_y + (has_ids ? 0 : channel_y *stride_channel_y);
115
+ dst += int64_t(sample_dst)*stride_sample_dst + (has_ids ? 0 : channel_dst*stride_channel_dst);
116
+
117
+ if constexpr (has_ids) {
118
+ constexpr int y_stride_scale = std::is_same_v<T, float> ? 1 : 2;
119
+ const int64_t col_offset = col_base;
120
+ y += col_offset * stride_col_y * y_stride_scale;
121
+ dst += col_offset * stride_col_dst;
122
+ ids += col_offset * stride_row_id;
123
+ }
124
+
125
+ [[maybe_unused]] const float2 * y2 = (const float2 *) y;
126
+
127
+ extern __shared__ char data_mmv[];
128
+
129
+ char * shmem_base = data_mmv;
130
+ [[maybe_unused]] int * slot_map = (int *) shmem_base;
131
+ char * compute_base = has_ids ? (shmem_base + GGML_PAD(cols_per_block, 16) * sizeof(int)) : shmem_base;
132
+
133
+ tile_C C[ntA][ntB];
134
+
135
+ T * tile_xy = (T *) compute_base + threadIdx.y*(tile_A::I * tile_k_padded);
136
+
137
+ if constexpr (has_ids) {
138
+ int found = 0;
139
+
140
+ for (int j0 = 0; j0 < cols_per_block; j0 += nwarps) {
141
+ const int j = j0 + threadIdx.y;
142
+
143
+ if (threadIdx.x == 0) {
144
+ slot_map[j] = -1;
145
+ }
146
+
147
+ if (col_base + j >= ncols_dst_total) {
148
+ continue;
149
+ }
150
+
151
+ const int32_t * __restrict__ id_row = ids + j*stride_row_id;
152
+
153
+ for (int k = threadIdx.x; k < nchannels_dst; k += warp_size) {
154
+ int match = id_row[k*stride_col_id] == expert_idx;
155
+
156
+ if (match) {
157
+ slot_map[j] = k;
158
+ found = 1;
159
+ break;
160
+ }
161
+ }
162
+ }
163
+
164
+ if (!__syncthreads_or(found)) {
165
+ return;
166
+ }
167
+ }
168
+
169
+
170
+ for (int col = threadIdx.y*warp_size + threadIdx.x; col < ncols; col += nwarps*warp_size) {
171
+ tile_A A[ntA][warp_size / tile_A::J];
172
+ #pragma unroll
173
+ for (int itA = 0; itA < ntA; ++itA) {
174
+ #pragma unroll
175
+ for (int i = 0; i < tile_A::I; ++i) {
176
+ tile_xy[i*tile_k_padded + threadIdx.x] = x[(itA*tile_A::I + i)*stride_row + col];
177
+ }
178
+ #pragma unroll
179
+ for (int k0 = 0; k0 < warp_size; k0 += tile_A::J) {
180
+ load_ldmatrix(A[itA][k0/tile_A::J], tile_xy + k0, tile_k_padded);
181
+ }
182
+ }
183
+
184
+ #pragma unroll
185
+ for (int itB = 0; itB < ntB; ++itB) {
186
+ if constexpr (std::is_same_v<T, float>) {
187
+ #pragma unroll
188
+ for (int j0 = 0; j0 < tile_B::I; ++j0) {
189
+ const int j = j0 + itB*tile_B::I;
190
+
191
+ if constexpr (!has_ids) {
192
+ tile_xy[j0*tile_k_padded + threadIdx.x] = j < cols_per_block ? y[j*stride_col_y + col] : 0.0f;
193
+ } else {
194
+ const bool valid = j < cols_per_block && (col_base + j) < ncols_dst_total && slot_map[j] >= 0;
195
+ tile_xy[j0*tile_k_padded + threadIdx.x] = valid ? y[slot_map[j]*stride_channel_y + j*stride_col_y + col] : 0.0f;
196
+ }
197
+ }
198
+ } else if constexpr (std::is_same_v<T, half2> || std::is_same_v<T, nv_bfloat162>) {
199
+ #pragma unroll
200
+ for (int j0 = 0; j0 < tile_B::I; ++j0) {
201
+ const int j = j0 + itB*tile_B::I;
202
+
203
+ if constexpr (!has_ids) {
204
+ const float2 tmp = j < cols_per_block ? y2[j*stride_col_y + col] : make_float2(0.0f, 0.0f);
205
+ tile_xy[j0*tile_k_padded + threadIdx.x] = ggml_cuda_cast<T>(tmp);
206
+ } else {
207
+ const bool valid = j < cols_per_block && (col_base + j) < ncols_dst_total && slot_map[j] >= 0;
208
+ float2 tmp = valid ? *(const float2*) &y[slot_map[j]*stride_channel_y + 2*(j*stride_col_y + col)] : make_float2(0.0f, 0.0f);
209
+ tile_xy[j0*tile_k_padded + threadIdx.x] = ggml_cuda_cast<T>(tmp);
210
+ }
211
+ }
212
+ } else {
213
+ static_assert(std::is_same_v<T, void>, "unsupported type");
214
+ }
215
+ #pragma unroll
216
+ for (int k0 = 0; k0 < warp_size; k0 += tile_B::J) {
217
+ tile_B B;
218
+ load_ldmatrix(B, tile_xy + k0, tile_k_padded);
219
+ #pragma unroll
220
+ for (int itA = 0; itA < ntA; ++itA) {
221
+ mma(C[itA][itB], A[itA][k0/tile_B::J], B);
222
+ }
223
+ }
224
+ }
225
+ }
226
+
227
+ float * buf_iw = (float *) compute_base;
228
+ constexpr int kiw = nwarps*rows_per_block + mmf_get_padding();
229
+
230
+ if (nwarps > 1) {
231
+ __syncthreads();
232
+ }
233
+ #pragma unroll
234
+ for (int itB = 0; itB < ntB; ++itB) {
235
+ #pragma unroll
236
+ for (int itA = 0; itA < ntA; ++itA) {
237
+ #pragma unroll
238
+ for (int l = 0; l < tile_C::ne; ++l) {
239
+ const int i = threadIdx.y*rows_per_block + itA*tile_C::I + tile_C::get_i(l);
240
+ const int j = itB*tile_C::J + tile_C::get_j(l);
241
+ buf_iw[j*kiw + i] = C[itA][itB].x[l];
242
+ }
243
+ }
244
+ }
245
+
246
+ if (nwarps > 1) {
247
+ __syncthreads();
248
+ }
249
+
250
+ #pragma unroll
251
+ for (int j0 = 0; j0 < cols_per_block; j0 += nwarps) {
252
+ const int j = j0 + threadIdx.y;
253
+
254
+ if (j0 + nwarps > cols_per_block && j >= cols_per_block) {
255
+ return;
256
+ }
257
+
258
+ float sum[rows_per_block/warp_size] = {0.0f};
259
+ static_assert((rows_per_block % warp_size) == 0, "rows_per_block must be a multiple of warp_size.");
260
+ #pragma unroll
261
+ for (int i0 = 0; i0 < nwarps*rows_per_block; i0 += rows_per_block) {
262
+ #pragma unroll
263
+ for (int i1 = 0; i1 < sizeof(sum)/sizeof(sum[0]); ++i1) {
264
+ const int i = i0 + i1*warp_size + threadIdx.x;
265
+
266
+ sum[i1] += buf_iw[j*kiw + i];
267
+ }
268
+ }
269
+
270
+ if constexpr (!has_ids) {
271
+ #pragma unroll
272
+ for (int i0 = 0; i0 < sizeof(sum)/sizeof(sum[0]); ++i0) {
273
+ dst[j*stride_col_dst + row0 + i0*warp_size + threadIdx.x] = sum[i0];
274
+ }
275
+ } else {
276
+ const int slot = (j < cols_per_block) ? slot_map[j] : -1;
277
+ if (slot >= 0 && (col_base + j) < ncols_dst_total) {
278
+ #pragma unroll
279
+ for (int i0 = 0; i0 < sizeof(sum)/sizeof(sum[0]); ++i0) {
280
+ dst[slot*stride_channel_dst + j*stride_col_dst + row0 + i0*warp_size + threadIdx.x] = sum[i0];
281
+ }
282
+ }
283
+ }
284
+ }
285
+ }
286
+ #else
287
+ GGML_UNUSED_VARS(x, y, ids, dst,
288
+ ncols, ncols_dst_total, nchannels_dst, stride_row, stride_col_y, stride_col_dst,
289
+ stride_col_id, stride_row_id,
290
+ channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
291
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst);
292
+ NO_DEVICE_CODE;
293
+ #endif // defined(VOLTA_MMA_AVAILABLE) || defined(TURING_MMA_AVAILABLE) || defined(AMD_WMMA_AVAILABLE) || defined(AMD_MFMA_AVAILABLE)
294
+ }
295
+
296
+ //This kernel is for larger batch sizes of mul_mat_id
297
+ template <typename T, int rows_per_block, int cols_per_block, int nwarps>
298
+ __launch_bounds__(ggml_cuda_get_physical_warp_size()*nwarps, 1)
299
+ static __global__ void mul_mat_f_ids(
300
+ const T * __restrict__ x, const float * __restrict__ y,
301
+ const int32_t * __restrict__ ids_src_compact, const int32_t * __restrict__ ids_dst_compact,
302
+ const int32_t * __restrict__ expert_bounds, float * __restrict__ dst,
303
+ const int ncols, const int ncols_dst_total, const int nchannels_dst, const int stride_row, const int stride_col_y, const int stride_col_dst,
304
+ const int channel_ratio, const int stride_channel_x, const int stride_channel_y, const int stride_channel_dst,
305
+ const int sample_ratio, const int stride_sample_x, const int stride_sample_y, const int stride_sample_dst,
306
+ const uint3 sis1_fd, const uint3 nch_fd) {
307
+ // TODO: handle this in a consistent and simpler way after AMD MFMA support has been added
308
+ #if defined(VOLTA_MMA_AVAILABLE) || defined(TURING_MMA_AVAILABLE) || defined(AMD_WMMA_AVAILABLE) || defined(AMD_MFMA_AVAILABLE)
309
+ #if defined(AMD_WMMA_AVAILABLE)
310
+ if constexpr (!(std::is_same_v<T, half2> || std::is_same_v<T, nv_bfloat162>) || rows_per_block != MMF_ROWS_PER_BLOCK) {NO_DEVICE_CODE;} else {
311
+ typedef tile<16, 8, T, get_input_data_layout()> tile_A;
312
+ typedef tile<16, 8, T, get_input_data_layout()> tile_B;
313
+ typedef tile<16, 16, float, DATA_LAYOUT_J_MAJOR> tile_C;
314
+ #elif defined(AMD_MFMA_AVAILABLE)
315
+ if constexpr (rows_per_block != MMF_ROWS_PER_BLOCK_CDNA) {NO_DEVICE_CODE;} else {
316
+ typedef tile<16, 8, T, DATA_LAYOUT_I_MAJOR> tile_A;
317
+ typedef tile<16, 8, T, DATA_LAYOUT_I_MAJOR> tile_B;
318
+ typedef tile<16, 16, float, DATA_LAYOUT_J_MAJOR> tile_C;
319
+ #else
320
+ #ifdef VOLTA_MMA_AVAILABLE
321
+ if constexpr (!std::is_same_v<T, half2> || rows_per_block != MMF_ROWS_PER_BLOCK) {NO_DEVICE_CODE;} else {
322
+ typedef tile<32, 4, T, DATA_LAYOUT_I_MAJOR> tile_A;
323
+ typedef tile< 8, 4, T, DATA_LAYOUT_I_MAJOR_MIRRORED> tile_B;
324
+ typedef tile<32, 8, float, DATA_LAYOUT_I_MAJOR> tile_C;
325
+ #else
326
+ if constexpr (rows_per_block != MMF_ROWS_PER_BLOCK) {NO_DEVICE_CODE;} else {
327
+ typedef tile<16, 8, T> tile_A;
328
+ typedef tile<8, 8, T> tile_B;
329
+ typedef tile<16, 8, float> tile_C;
330
+ #endif // VOLTA_MMA_AVAILABLE
331
+ #endif // defined(AMD_WMMA_AVAILABLE)
332
+ if constexpr (!tile_A::supported() || !tile_B::supported() || !tile_C::supported()) {
333
+ NO_DEVICE_CODE;
334
+ return;
335
+ }
336
+
337
+
338
+ constexpr int warp_size = ggml_cuda_get_physical_warp_size();
339
+ constexpr int tile_k_padded = warp_size + mmf_get_padding();
340
+ constexpr int ntA = rows_per_block / tile_A::I;
341
+ constexpr int ntB = (cols_per_block + tile_B::I - 1) / tile_B::I;
342
+
343
+ const int row0 = blockIdx.x * rows_per_block;
344
+
345
+ const int expert_idx = blockIdx.y;
346
+ const int expert_start = expert_bounds[expert_idx];
347
+ const int expert_end = expert_bounds[expert_idx + 1];
348
+ const int ncols_expert = expert_end - expert_start;
349
+
350
+ const int tiles_for_expert = (ncols_expert + cols_per_block - 1) / cols_per_block;
351
+ const int tile_idx = blockIdx.z;
352
+ if (tile_idx >= tiles_for_expert) {
353
+ return;
354
+ }
355
+
356
+ const int col_base = tile_idx * cols_per_block;
357
+
358
+ GGML_UNUSED(channel_ratio);
359
+
360
+ const int channel_x = expert_idx;
361
+ const int sample_dst = 0;
362
+ const int sample_x = sample_dst / sample_ratio;
363
+ const int sample_y = sample_dst;
364
+
365
+ x += int64_t(sample_x) *stride_sample_x + channel_x *stride_channel_x + row0*stride_row;
366
+ y += int64_t(sample_y) *stride_sample_y;
367
+ dst += int64_t(sample_dst)*stride_sample_dst;
368
+
369
+ const int32_t * ids_src_expert = ids_src_compact + expert_start;
370
+ const int32_t * ids_dst_expert = ids_dst_compact + expert_start;
371
+
372
+ extern __shared__ char data_mmv[];
373
+ char * compute_base = data_mmv;
374
+
375
+ //const float2 * y2 = (const float2 *) y;
376
+
377
+ tile_C C[ntA][ntB];
378
+
379
+ T * tile_xy = (T *) compute_base + threadIdx.y*(tile_A::I * tile_k_padded);
380
+
381
+ for (int col = threadIdx.y*warp_size + threadIdx.x; col < ncols; col += nwarps*warp_size) {
382
+ tile_A A[ntA][warp_size / tile_A::J];
383
+ #pragma unroll
384
+ for (int itA = 0; itA < ntA; ++itA) {
385
+ #pragma unroll
386
+ for (int i = 0; i < tile_A::I; ++i) {
387
+ tile_xy[i*tile_k_padded + threadIdx.x] = x[(itA*tile_A::I + i)*stride_row + col];
388
+ }
389
+ #pragma unroll
390
+ for (int k0 = 0; k0 < warp_size; k0 += tile_A::J) {
391
+ load_ldmatrix(A[itA][k0/tile_A::J], tile_xy + k0, tile_k_padded);
392
+ }
393
+ }
394
+
395
+ if constexpr (std::is_same_v<T, float>) {
396
+ float vals_buf[2][tile_B::I];
397
+ auto gather_tile = [&](int tile_idx_local, float *vals) {
398
+ #pragma unroll
399
+ for (int j0 = 0; j0 < tile_B::I; ++j0) {
400
+ const int j = j0 + tile_idx_local*tile_B::I;
401
+ const int global_j = col_base + j;
402
+ float val = 0.0f;
403
+ if (j < cols_per_block && global_j < ncols_expert) {
404
+ const int src_entry = ids_src_expert[global_j];
405
+ const uint2 qrm = fast_div_modulo((uint32_t) src_entry, sis1_fd);
406
+ const int token = (int) qrm.x;
407
+ const int channel = (int) qrm.y;
408
+ if (token < ncols_dst_total) {
409
+ val = y[channel*stride_channel_y + token*stride_col_y + col];
410
+ }
411
+ }
412
+ vals[j0] = val;
413
+ }
414
+ };
415
+
416
+ gather_tile(0, vals_buf[0]);
417
+
418
+ int curr_buf = 0;
419
+ int next_buf = 1;
420
+ #pragma unroll
421
+ for (int itB = 0; itB < ntB; ++itB) {
422
+ #pragma unroll
423
+ for (int j0 = 0; j0 < tile_B::I; ++j0) {
424
+ tile_xy[j0*tile_k_padded + threadIdx.x] = vals_buf[curr_buf][j0];
425
+ }
426
+
427
+ if (itB + 1 < ntB) {
428
+ gather_tile(itB + 1, vals_buf[next_buf]);
429
+ }
430
+
431
+ #pragma unroll
432
+ for (int k0 = 0; k0 < warp_size; k0 += tile_B::J) {
433
+ tile_B B;
434
+ load_ldmatrix(B, tile_xy + k0, tile_k_padded);
435
+ #pragma unroll
436
+ for (int itA = 0; itA < ntA; ++itA) {
437
+ mma(C[itA][itB], A[itA][k0/tile_B::J], B);
438
+ }
439
+ }
440
+
441
+ if (itB + 1 < ntB) {
442
+ curr_buf ^= 1;
443
+ next_buf ^= 1;
444
+ }
445
+ }
446
+ } else if constexpr (std::is_same_v<T, half2> || std::is_same_v<T, nv_bfloat162>) {
447
+ float2 vals_buf[2][tile_B::I];
448
+ auto gather_tile = [&](int tile_idx_local, float2 *vals) {
449
+ #pragma unroll
450
+ for (int j0 = 0; j0 < tile_B::I; ++j0) {
451
+ const int j = j0 + tile_idx_local*tile_B::I;
452
+ const int global_j = col_base + j;
453
+ float2 tmp = make_float2(0.0f, 0.0f);
454
+ if (j < cols_per_block && global_j < ncols_expert) {
455
+ const int src_entry = ids_src_expert[global_j];
456
+ const uint2 qrm = fast_div_modulo((uint32_t) src_entry, sis1_fd);
457
+ const int token = (int) qrm.x;
458
+ const int channel = (int) qrm.y;
459
+ if (token < ncols_dst_total) {
460
+ tmp = *(const float2*) &y[channel*stride_channel_y + 2*(token*stride_col_y + col)];
461
+ }
462
+ }
463
+ vals[j0] = tmp;
464
+ }
465
+ };
466
+
467
+ if (ntB > 0) {
468
+ gather_tile(0, vals_buf[0]);
469
+ }
470
+
471
+ int curr_buf = 0;
472
+ int next_buf = 1;
473
+ #pragma unroll
474
+ for (int itB = 0; itB < ntB; ++itB) {
475
+ #pragma unroll
476
+ for (int j0 = 0; j0 < tile_B::I; ++j0) {
477
+ const float2 tmp = vals_buf[curr_buf][j0];
478
+ tile_xy[j0*tile_k_padded + threadIdx.x] = ggml_cuda_cast<T>(tmp);
479
+ }
480
+
481
+ if (itB + 1 < ntB) {
482
+ gather_tile(itB + 1, vals_buf[next_buf]);
483
+ }
484
+
485
+ #pragma unroll
486
+ for (int k0 = 0; k0 < warp_size; k0 += tile_B::J) {
487
+ tile_B B;
488
+ load_ldmatrix(B, tile_xy + k0, tile_k_padded);
489
+ #pragma unroll
490
+ for (int itA = 0; itA < ntA; ++itA) {
491
+ mma(C[itA][itB], A[itA][k0/tile_B::J], B);
492
+ }
493
+ }
494
+
495
+ if (itB + 1 < ntB) {
496
+ curr_buf ^= 1;
497
+ next_buf ^= 1;
498
+ }
499
+ }
500
+ } else {
501
+ static_assert(std::is_same_v<T, void>, "unsupported type");
502
+ }
503
+ }
504
+
505
+ float * buf_iw = (float *) compute_base;
506
+ constexpr int kiw = nwarps*rows_per_block + mmf_get_padding();
507
+
508
+ if (nwarps > 1) {
509
+ __syncthreads();
510
+ }
511
+ #pragma unroll
512
+ for (int itB = 0; itB < ntB; ++itB) {
513
+ #pragma unroll
514
+ for (int itA = 0; itA < ntA; ++itA) {
515
+ #pragma unroll
516
+ for (int l = 0; l < tile_C::ne; ++l) {
517
+ const int i = threadIdx.y*rows_per_block + itA*tile_C::I + tile_C::get_i(l);
518
+ const int j = itB*tile_C::J + tile_C::get_j(l);
519
+ buf_iw[j*kiw + i] = C[itA][itB].x[l];
520
+ }
521
+ }
522
+ }
523
+
524
+ if (nwarps > 1) {
525
+ __syncthreads();
526
+ }
527
+
528
+ #pragma unroll
529
+ for (int j0 = 0; j0 < cols_per_block; j0 += nwarps) {
530
+ const int j = j0 + threadIdx.y;
531
+
532
+ if (j0 + nwarps > cols_per_block && j >= cols_per_block) {
533
+ return;
534
+ }
535
+
536
+ float sum[rows_per_block/warp_size] = {0.0f};
537
+ static_assert((rows_per_block % warp_size) == 0, "rows_per_block must be a multiple of warp_size.");
538
+ #pragma unroll
539
+ for (int i0 = 0; i0 < nwarps*rows_per_block; i0 += rows_per_block) {
540
+ #pragma unroll
541
+ for (int i1 = 0; i1 < sizeof(sum)/sizeof(sum[0]); ++i1) {
542
+ const int i = i0 + i1*warp_size + threadIdx.x;
543
+
544
+ sum[i1] += buf_iw[j * kiw + i];
545
+ }
546
+ }
547
+
548
+ const int global_j = col_base + j;
549
+ if (j < cols_per_block && global_j < ncols_expert && nchannels_dst > 0) {
550
+ const int dst_entry = ids_dst_expert[global_j];
551
+ const uint2 qrm = fast_div_modulo((uint32_t) dst_entry, nch_fd);
552
+ const int token = (int) qrm.x;
553
+ if (token < ncols_dst_total) {
554
+ const int slot = (int) qrm.y;
555
+ #pragma unroll
556
+ for (int i0 = 0; i0 < sizeof(sum)/sizeof(sum[0]); ++i0) {
557
+ dst[slot * stride_channel_dst + token * stride_col_dst + row0 + i0*warp_size + threadIdx.x] = sum[i0];
558
+ }
559
+ }
560
+ }
561
+ }
562
+ }
563
+ #else
564
+ GGML_UNUSED_VARS(x, y, ids_src_compact, ids_dst_compact, expert_bounds, dst,
565
+ ncols, ncols_dst_total, nchannels_dst, stride_row, stride_col_y, stride_col_dst,
566
+ channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
567
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, sis1_fd, nch_fd);
568
+ NO_DEVICE_CODE;
569
+ #endif // defined(VOLTA_MMA_AVAILABLE) || defined(TURING_MMA_AVAILABLE) || defined(AMD_WMMA_AVAILABLE) || defined(AMD_MFMA_AVAILABLE)
570
+ }
571
+
572
+ template<typename T, int rows_per_block, int cols_per_block, int nwarps>
573
+ static inline void mul_mat_f_switch_ids(
574
+ const T * x, const float * y, const int32_t * ids, float * dst,
575
+ const int64_t ncols_x, const int64_t ncols_dst, const int64_t nchannels_dst,
576
+ const int64_t stride_row, const int64_t stride_col_y, const int64_t stride_col_dst,
577
+ const int64_t stride_col_id, const int64_t stride_row_id,
578
+ const int64_t channel_ratio, const int64_t stride_channel_x, const int64_t stride_channel_y, const int64_t stride_channel_dst,
579
+ const int64_t sample_ratio, const int64_t stride_sample_x, const int64_t stride_sample_y, const int64_t stride_sample_dst,
580
+ const dim3 & block_nums, const dim3 & block_dims, const int nbytes_shared_total, cudaStream_t stream,
581
+ const mmf_ids_data * ids_data) {
582
+ const bool has_ids_data = ids_data && ids_data->ids_src_compact;
583
+
584
+ // Use the compact-ids kernel only for larger tiles; for small ncols_dst (< 16)
585
+ // we prefer the normal mul_mat_f path with has_ids=true.
586
+ if (has_ids_data && ncols_dst > 16) {
587
+ const int max_tiles = (int) ((ncols_dst + cols_per_block - 1) / cols_per_block);
588
+ if (max_tiles == 0) {
589
+ return;
590
+ }
591
+ dim3 block_nums_ids(block_nums.x, ids_data->n_experts, max_tiles);
592
+
593
+ const uint3 sis1_fd = ids_data->sis1 > 0 ? init_fastdiv_values((uint32_t) ids_data->sis1) : make_uint3(0, 0, 1);
594
+ const uint3 nch_fd = init_fastdiv_values((uint32_t) nchannels_dst);
595
+
596
+ mul_mat_f_ids<T, rows_per_block, cols_per_block, nwarps><<<block_nums_ids, block_dims, nbytes_shared_total, stream>>>
597
+ (x, y, ids_data->ids_src_compact, ids_data->ids_dst_compact, ids_data->expert_bounds_dev, dst,
598
+ ncols_x, ncols_dst, nchannels_dst, stride_row, stride_col_y, stride_col_dst,
599
+ channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
600
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst,
601
+ sis1_fd, nch_fd);
602
+ } else if (ids) {
603
+ const int64_t col_tiles = (ncols_dst + cols_per_block - 1) / cols_per_block;
604
+ dim3 block_nums_ids = block_nums;
605
+ block_nums_ids.y *= col_tiles;
606
+
607
+ mul_mat_f<T, rows_per_block, cols_per_block, nwarps, true><<<block_nums_ids, block_dims, nbytes_shared_total, stream>>>
608
+ (x, y, ids, dst, ncols_x, ncols_dst, nchannels_dst, stride_row, stride_col_y, stride_col_dst,
609
+ stride_col_id, stride_row_id, channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
610
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst);
611
+ } else {
612
+ mul_mat_f<T, rows_per_block, cols_per_block, nwarps, false><<<block_nums, block_dims, nbytes_shared_total, stream>>>
613
+ (x, y, ids, dst, ncols_x, cols_per_block, nchannels_dst, stride_row, stride_col_y, stride_col_dst,
614
+ stride_col_id, stride_row_id, channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
615
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst);
616
+ }
617
+ }
618
+
619
+ template <typename T, int rows_per_block, int cols_per_block>
620
+ void mul_mat_f_cuda(
621
+ const T * x, const float * y, const int32_t * ids, float * dst,
622
+ const int64_t ncols_x, const int64_t nrows_x, const int64_t ncols_dst,
623
+ const int64_t stride_row, const int64_t stride_col_y, const int64_t stride_col_dst,
624
+ const int64_t stride_col_id, const int64_t stride_row_id,
625
+ const int64_t nchannels_x, const int64_t nchannels_y, const int64_t nchannels_dst,
626
+ const int64_t stride_channel_x, const int64_t stride_channel_y, const int64_t stride_channel_dst, const int64_t nsamples_x,
627
+ const int64_t nsamples_dst, const int64_t stride_sample_x, const int64_t stride_sample_y, const int64_t stride_sample_dst,
628
+ cudaStream_t stream, const mmf_ids_data * ids_data) {
629
+ typedef tile<16, 8, T> tile_A_16;
630
+ typedef tile<32, 8, T> tile_A_32;
631
+ typedef tile<16, 8, T> tile_B_16;
632
+ typedef tile< 8, 8, T> tile_B_8;
633
+
634
+ GGML_ASSERT(ncols_x % 2 == 0);
635
+ GGML_ASSERT(stride_row % 2 == 0);
636
+ GGML_ASSERT(stride_col_y % 2 == 0);
637
+ GGML_ASSERT(ids || nchannels_dst % nchannels_x == 0);
638
+ GGML_ASSERT( nsamples_dst % nsamples_x == 0);
639
+ const int64_t channel_ratio = nchannels_dst / nchannels_x;
640
+ const int64_t sample_ratio = nsamples_dst / nsamples_x;
641
+
642
+ const int device = ggml_cuda_get_device();
643
+ const int cc = ggml_cuda_info().devices[device].cc;
644
+ const int warp_size = ggml_cuda_info().devices[device].warp_size;
645
+
646
+ int64_t nwarps_best = 1;
647
+ int64_t niter_best = (ncols_x + warp_size*2 - 1) / (warp_size*2);
648
+ int64_t max_block_size = mmf_get_max_block_size(cc);
649
+ for (int64_t nwarps = 2; nwarps <= max_block_size/warp_size; nwarps++) {
650
+ const int64_t niter = (ncols_x + nwarps*warp_size*2 - 1) / (nwarps*warp_size*2);
651
+ if (niter < niter_best) {
652
+ niter_best = niter;
653
+ nwarps_best = nwarps;
654
+ }
655
+ }
656
+
657
+ const int nbytes_shared_iter = nwarps_best * (volta_mma_available(cc) ? tile_A_32::I : tile_A_16::I) * (warp_size + mmf_get_padding(cc)) * 4;
658
+ const int nbytes_cols_per_block_pad = (amd_wmma_available(cc) || amd_mfma_available(cc)) ? tile_B_16::I : tile_B_8::I;
659
+ const int nbytes_shared_combine = GGML_PAD(cols_per_block, nbytes_cols_per_block_pad) * (nwarps_best*rows_per_block + mmf_get_padding(cc)) * 4;
660
+ const int nbytes_shared = std::max(nbytes_shared_iter, nbytes_shared_combine);
661
+ const int nbytes_slotmap = ids ? GGML_PAD(cols_per_block, 16) * sizeof(int) : 0;
662
+ const int nbytes_shared_total = nbytes_shared + nbytes_slotmap;
663
+ const int64_t grid_y = ids ? nchannels_x : nchannels_dst;
664
+
665
+ const dim3 block_nums(nrows_x/rows_per_block, grid_y, nsamples_dst);
666
+ const dim3 block_dims(warp_size, nwarps_best, 1);
667
+
668
+ switch (nwarps_best) {
669
+ case 1: {
670
+ mul_mat_f_switch_ids<T, rows_per_block, cols_per_block, 1>(
671
+ x, y, ids, dst, ncols_x, ncols_dst, nchannels_dst, stride_row, stride_col_y, stride_col_dst,
672
+ stride_col_id, stride_row_id, channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
673
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, block_nums, block_dims, nbytes_shared_total, stream,
674
+ ids_data);
675
+ } break;
676
+ case 2: {
677
+ mul_mat_f_switch_ids<T, rows_per_block, cols_per_block, 2>(
678
+ x, y, ids, dst, ncols_x, ncols_dst, nchannels_dst, stride_row, stride_col_y, stride_col_dst,
679
+ stride_col_id, stride_row_id, channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
680
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, block_nums, block_dims, nbytes_shared_total, stream,
681
+ ids_data);
682
+ } break;
683
+ case 3: {
684
+ mul_mat_f_switch_ids<T, rows_per_block, cols_per_block, 3>(
685
+ x, y, ids, dst, ncols_x, ncols_dst, nchannels_dst, stride_row, stride_col_y, stride_col_dst,
686
+ stride_col_id, stride_row_id, channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
687
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, block_nums, block_dims, nbytes_shared_total, stream,
688
+ ids_data);
689
+ } break;
690
+ case 4: {
691
+ mul_mat_f_switch_ids<T, rows_per_block, cols_per_block, 4>(
692
+ x, y, ids, dst, ncols_x, ncols_dst, nchannels_dst, stride_row, stride_col_y, stride_col_dst,
693
+ stride_col_id, stride_row_id, channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
694
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, block_nums, block_dims, nbytes_shared_total, stream,
695
+ ids_data);
696
+ } break;
697
+ case 5: {
698
+ mul_mat_f_switch_ids<T, rows_per_block, cols_per_block, 5>(
699
+ x, y, ids, dst, ncols_x, ncols_dst, nchannels_dst, stride_row, stride_col_y, stride_col_dst,
700
+ stride_col_id, stride_row_id, channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
701
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, block_nums, block_dims, nbytes_shared_total, stream,
702
+ ids_data);
703
+ } break;
704
+ case 6: {
705
+ mul_mat_f_switch_ids<T, rows_per_block, cols_per_block, 6>(
706
+ x, y, ids, dst, ncols_x, ncols_dst, nchannels_dst, stride_row, stride_col_y, stride_col_dst,
707
+ stride_col_id, stride_row_id, channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
708
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, block_nums, block_dims, nbytes_shared_total, stream,
709
+ ids_data);
710
+ } break;
711
+ case 7: {
712
+ mul_mat_f_switch_ids<T, rows_per_block, cols_per_block, 7>(
713
+ x, y, ids, dst, ncols_x, ncols_dst, nchannels_dst, stride_row, stride_col_y, stride_col_dst,
714
+ stride_col_id, stride_row_id, channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
715
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, block_nums, block_dims, nbytes_shared_total, stream,
716
+ ids_data);
717
+ } break;
718
+ case 8: {
719
+ mul_mat_f_switch_ids<T, rows_per_block, cols_per_block, 8>(
720
+ x, y, ids, dst, ncols_x, ncols_dst, nchannels_dst, stride_row, stride_col_y, stride_col_dst,
721
+ stride_col_id, stride_row_id, channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
722
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, block_nums, block_dims, nbytes_shared_total, stream,
723
+ ids_data);
724
+ } break;
725
+ default: {
726
+ GGML_ABORT("fatal error");
727
+ } break;
728
+ }
729
+
730
+ GGML_UNUSED_VARS(nchannels_y);
731
+ }
732
+
733
+ template <typename T, int rows_per_block>
734
+ static void mul_mat_f_switch_cols_per_block(
735
+ const T * x, const float * y, const int32_t * ids, float * dst,
736
+ const int64_t ncols_x, const int64_t nrows_x, const int64_t ncols_dst,
737
+ const int64_t stride_row, const int64_t stride_col_y, const int64_t stride_col_dst,
738
+ const int64_t stride_col_id, const int stride_row_id,
739
+ const int64_t nchannels_x, const int64_t nchannels_y, const int64_t nchannels_dst,
740
+ const int64_t stride_channel_x, const int64_t stride_channel_y, const int64_t stride_channel_dst, const int64_t nsamples_x,
741
+ const int64_t nsamples_dst, const int64_t stride_sample_x, const int64_t stride_sample_y, const int64_t stride_sample_dst,
742
+ cudaStream_t stream, const mmf_ids_data * ids_data) {
743
+
744
+ const int ncols_case = (ids && ncols_dst > 16) ? 16 : ncols_dst;
745
+
746
+ GGML_ASSERT(ids || ncols_dst <= 16);
747
+
748
+ switch (ncols_case) {
749
+ case 1: {
750
+ mul_mat_f_cuda<T, rows_per_block, 1>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
751
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
752
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
753
+ } break;
754
+ case 2: {
755
+ mul_mat_f_cuda<T, rows_per_block, 2>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
756
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
757
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
758
+ } break;
759
+ case 3: {
760
+ mul_mat_f_cuda<T, rows_per_block, 3>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
761
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
762
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
763
+ } break;
764
+ case 4: {
765
+ mul_mat_f_cuda<T, rows_per_block, 4>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
766
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
767
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
768
+ } break;
769
+ case 5: {
770
+ mul_mat_f_cuda<T, rows_per_block, 5>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
771
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
772
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
773
+ } break;
774
+ case 6: {
775
+ mul_mat_f_cuda<T, rows_per_block, 6>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
776
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
777
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
778
+ } break;
779
+ case 7: {
780
+ mul_mat_f_cuda<T, rows_per_block, 7>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
781
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
782
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
783
+ } break;
784
+ case 8: {
785
+ mul_mat_f_cuda<T, rows_per_block, 8>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
786
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
787
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
788
+ } break;
789
+ case 9: {
790
+ mul_mat_f_cuda<T, rows_per_block, 9>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
791
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
792
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
793
+ } break;
794
+ case 10: {
795
+ mul_mat_f_cuda<T, rows_per_block, 10>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
796
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
797
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
798
+ } break;
799
+ case 11: {
800
+ mul_mat_f_cuda<T, rows_per_block, 11>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
801
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
802
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
803
+ } break;
804
+ case 12: {
805
+ mul_mat_f_cuda<T, rows_per_block, 12>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
806
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
807
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
808
+ } break;
809
+ case 13: {
810
+ mul_mat_f_cuda<T, rows_per_block, 13>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
811
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
812
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
813
+ } break;
814
+ case 14: {
815
+ mul_mat_f_cuda<T, rows_per_block, 14>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
816
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
817
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
818
+ } break;
819
+ case 15: {
820
+ mul_mat_f_cuda<T, rows_per_block, 15>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
821
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
822
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
823
+ } break;
824
+ case 16: {
825
+ mul_mat_f_cuda<T, rows_per_block, 16>(x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
826
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
827
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
828
+ } break;
829
+ default: {
830
+ GGML_ABORT("fatal error");
831
+ } break;
832
+ }
833
+ }
834
+
835
+ template <typename T>
836
+ static void mul_mat_f_switch_rows_per_block(
837
+ const int rows_per_block, const T * x, const float * y, const int32_t * ids, float * dst,
838
+ const int64_t ncols_x, const int64_t nrows_x, const int64_t ncols_dst,
839
+ const int64_t stride_row, const int64_t stride_col_y, const int64_t stride_col_dst,
840
+ const int64_t stride_col_id, const int stride_row_id,
841
+ const int64_t nchannels_x, const int64_t nchannels_y, const int64_t nchannels_dst,
842
+ const int64_t stride_channel_x, const int64_t stride_channel_y, const int64_t stride_channel_dst, const int64_t nsamples_x,
843
+ const int64_t nsamples_dst, const int64_t stride_sample_x, const int64_t stride_sample_y, const int64_t stride_sample_dst,
844
+ cudaStream_t stream, const mmf_ids_data * ids_data) {
845
+ switch (rows_per_block) {
846
+ case MMF_ROWS_PER_BLOCK: {
847
+ mul_mat_f_switch_cols_per_block<T, MMF_ROWS_PER_BLOCK>(
848
+ x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
849
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
850
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
851
+ } break;
852
+ case MMF_ROWS_PER_BLOCK_CDNA: {
853
+ mul_mat_f_switch_cols_per_block<T, MMF_ROWS_PER_BLOCK_CDNA>(
854
+ x, y, ids, dst, ncols_x, nrows_x, ncols_dst, stride_row, stride_col_y, stride_col_dst,
855
+ stride_col_id, stride_row_id, nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
856
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, stream, ids_data);
857
+ } break;
858
+ default:
859
+ GGML_ABORT("unsupported rows_per_block: %i", rows_per_block);
860
+ }
861
+ }
862
+
863
+ #define DECL_MMF_CASE_HELPER(T, nrows_dst, ncols_dst) \
864
+ template void mul_mat_f_cuda<T, nrows_dst, ncols_dst>( \
865
+ const T * x, const float * y, const int32_t * ids, float * dst, \
866
+ const int64_t ncols_x, const int64_t nrows_x, int64_t ncols_dst_total, const int64_t stride_row, const int64_t stride_col_y, const int64_t stride_col_dst, \
867
+ const int64_t stride_col_id, const int64_t stride_row_id, \
868
+ const int64_t nchannels_x, const int64_t nchannels_y, const int64_t nchannels_dst, \
869
+ const int64_t stride_channel_x, const int64_t stride_channel_y, const int64_t stride_channel_dst, const int64_t nsamples_x,\
870
+ const int64_t nsamples_dst, const int64_t stride_sample_x, const int64_t stride_sample_y, const int64_t stride_sample_dst, \
871
+ cudaStream_t stream, const mmf_ids_data * ids_data);
872
+
873
+ #if !defined(GGML_USE_MUSA)
874
+ #define DECL_MMF_CASE_EXTERN(ncols_dst) \
875
+ extern DECL_MMF_CASE_HELPER(float, MMF_ROWS_PER_BLOCK, ncols_dst) \
876
+ extern DECL_MMF_CASE_HELPER(half2, MMF_ROWS_PER_BLOCK, ncols_dst) \
877
+ extern DECL_MMF_CASE_HELPER(nv_bfloat162, MMF_ROWS_PER_BLOCK, ncols_dst) \
878
+ extern DECL_MMF_CASE_HELPER(float, MMF_ROWS_PER_BLOCK_CDNA, ncols_dst) \
879
+ extern DECL_MMF_CASE_HELPER(half2, MMF_ROWS_PER_BLOCK_CDNA, ncols_dst) \
880
+ extern DECL_MMF_CASE_HELPER(nv_bfloat162, MMF_ROWS_PER_BLOCK_CDNA, ncols_dst)
881
+
882
+ #define DECL_MMF_CASE(ncols_dst) \
883
+ DECL_MMF_CASE_HELPER(float, MMF_ROWS_PER_BLOCK, ncols_dst) \
884
+ DECL_MMF_CASE_HELPER(half2, MMF_ROWS_PER_BLOCK, ncols_dst) \
885
+ DECL_MMF_CASE_HELPER(nv_bfloat162, MMF_ROWS_PER_BLOCK, ncols_dst) \
886
+ DECL_MMF_CASE_HELPER(float, MMF_ROWS_PER_BLOCK_CDNA, ncols_dst) \
887
+ DECL_MMF_CASE_HELPER(half2, MMF_ROWS_PER_BLOCK_CDNA, ncols_dst) \
888
+ DECL_MMF_CASE_HELPER(nv_bfloat162, MMF_ROWS_PER_BLOCK_CDNA, ncols_dst)
889
+
890
+ DECL_MMF_CASE_EXTERN(1);
891
+ DECL_MMF_CASE_EXTERN(2);
892
+ DECL_MMF_CASE_EXTERN(3);
893
+ DECL_MMF_CASE_EXTERN(4);
894
+ DECL_MMF_CASE_EXTERN(5);
895
+ DECL_MMF_CASE_EXTERN(6);
896
+ DECL_MMF_CASE_EXTERN(7);
897
+ DECL_MMF_CASE_EXTERN(8);
898
+ DECL_MMF_CASE_EXTERN(9);
899
+ DECL_MMF_CASE_EXTERN(10);
900
+ DECL_MMF_CASE_EXTERN(11);
901
+ DECL_MMF_CASE_EXTERN(12);
902
+ DECL_MMF_CASE_EXTERN(13);
903
+ DECL_MMF_CASE_EXTERN(14);
904
+ DECL_MMF_CASE_EXTERN(15);
905
+ DECL_MMF_CASE_EXTERN(16);
906
+ #else
907
+ #define DECL_MMF_CASE(ncols_dst)
908
+ #endif
backend/llama.cpp/ggml/src/ggml-cuda/mmid.cu ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+ #include "mmid.cuh"
3
+
4
+ // To reduce shared memory use, store "it" and "iex_used" with 22/10 bits each.
5
+ struct mm_ids_helper_store {
6
+ uint32_t data;
7
+
8
+ __device__ mm_ids_helper_store(const uint32_t it, const uint32_t iex_used) {
9
+ data = (it & 0x003FFFFF) | (iex_used << 22);
10
+ }
11
+
12
+ __device__ uint32_t it() const {
13
+ return data & 0x003FFFFF;
14
+ }
15
+
16
+ __device__ uint32_t iex_used() const {
17
+ return data >> 22;
18
+ }
19
+ };
20
+ static_assert(sizeof(mm_ids_helper_store) == 4, "unexpected size for mm_ids_helper_store");
21
+
22
+ // Helper function for mul_mat_id, converts ids to a more convenient format.
23
+ // ids_src1 describes how to permute the flattened column indices of src1 in order to get a compact src1 tensor sorted by expert.
24
+ // ids_dst describes the same mapping but for the dst tensor.
25
+ // The upper and lower bounds for the ith expert in the compact src1 tensor are stored in expert_bounds[i:i+1].
26
+ template <int n_expert_used_template>
27
+ __launch_bounds__(ggml_cuda_get_physical_warp_size(), 1)
28
+ static __global__ void mm_ids_helper(
29
+ const int32_t * __restrict__ ids, int32_t * __restrict__ ids_src1, int32_t * __restrict__ ids_dst, int32_t * __restrict__ expert_bounds,
30
+ const int n_tokens, const int n_expert_used_var, const int nchannels_y, const int si1, const int sis1) {
31
+ constexpr int warp_size = ggml_cuda_get_physical_warp_size();
32
+ const int n_expert_used = n_expert_used_template == 0 ? n_expert_used_var : n_expert_used_template;
33
+ const int expert = blockIdx.x;
34
+
35
+ extern __shared__ char data_mm_ids_helper[];
36
+ mm_ids_helper_store * store = (mm_ids_helper_store *) data_mm_ids_helper;
37
+
38
+ int nex_prev = 0; // Number of columns for experts with a lower index.
39
+ int it_compact = 0; // Running index for the compact slice of this expert.
40
+
41
+ if constexpr (n_expert_used_template == 0) {
42
+ // Generic implementation:
43
+ for (int it = 0; it < n_tokens; ++it) {
44
+ int iex_used = -1; // The index at which the expert is used, if any.
45
+ for (int iex = threadIdx.x; iex < n_expert_used; iex += warp_size) {
46
+ const int expert_used = ids[it*si1 + iex];
47
+ nex_prev += expert_used < expert;
48
+ if (expert_used == expert) {
49
+ iex_used = iex;
50
+ }
51
+ }
52
+
53
+ if (iex_used != -1) {
54
+ store[it_compact] = mm_ids_helper_store(it, iex_used);
55
+ }
56
+
57
+ if (warp_reduce_any<warp_size>(iex_used != -1)) {
58
+ it_compact++;
59
+ }
60
+ }
61
+ } else {
62
+ // Implementation optimized for specific numbers of experts used:
63
+ static_assert(n_expert_used == 6 || warp_size % n_expert_used == 0, "bad n_expert_used");
64
+ const int neu_padded = n_expert_used == 6 ? 8 : n_expert_used; // Padded to next higher power of 2.
65
+ for (int it0 = 0; it0 < n_tokens; it0 += warp_size/neu_padded) {
66
+ const int it = it0 + threadIdx.x / neu_padded;
67
+
68
+ const int iex = threadIdx.x % neu_padded; // The index at which the expert is used, if any.
69
+ const int expert_used = (neu_padded == n_expert_used || iex < n_expert_used) && it < n_tokens ?
70
+ ids[it*si1 + iex] : INT_MAX;
71
+ const int iex_used = expert_used == expert ? iex : -1;
72
+ nex_prev += expert_used < expert;
73
+
74
+ // Whether the threads at this token position have used the expert:
75
+ const int it_compact_add_self = warp_reduce_any<neu_padded>(iex_used != -1);
76
+
77
+ // Do a scan over threads at lower token positions in warp to get the correct index for writing data:
78
+ int it_compact_add_lower = 0;
79
+ #pragma unroll
80
+ for (int offset = neu_padded; offset < warp_size; offset += neu_padded) {
81
+ const int tmp = __shfl_up_sync(0xFFFFFFFF, it_compact_add_self, offset, warp_size);
82
+ if (threadIdx.x >= static_cast<unsigned int>(offset)) {
83
+ it_compact_add_lower += tmp;
84
+ }
85
+ }
86
+
87
+ if (iex_used != -1) {
88
+ store[it_compact + it_compact_add_lower] = mm_ids_helper_store(it, iex_used);
89
+ }
90
+
91
+ // The thread with the highest index in the warp always has the sum over the whole warp, use it to increment all threads:
92
+ it_compact += __shfl_sync(0xFFFFFFFF, it_compact_add_lower + it_compact_add_self, warp_size - 1, warp_size);
93
+ }
94
+ }
95
+ nex_prev = warp_reduce_sum<warp_size>(nex_prev);
96
+
97
+ for (int itc = threadIdx.x; itc < it_compact; itc += warp_size) {
98
+ const mm_ids_helper_store store_it = store[itc];
99
+ const int it = store_it.it();
100
+ const int iex_used = store_it.iex_used();
101
+ ids_src1[nex_prev + itc] = it*sis1 + iex_used % nchannels_y;
102
+ ids_dst [nex_prev + itc] = it*n_expert_used + iex_used;
103
+ }
104
+
105
+ if (threadIdx.x != 0) {
106
+ return;
107
+ }
108
+
109
+ expert_bounds[expert] = nex_prev;
110
+
111
+ if (expert < static_cast<int>(gridDim.x) - 1) {
112
+ return;
113
+ }
114
+
115
+ expert_bounds[gridDim.x] = nex_prev + it_compact;
116
+ }
117
+
118
+ template <int n_expert_used_template>
119
+ static void launch_mm_ids_helper(
120
+ const int32_t * __restrict__ ids, int32_t * __restrict__ ids_src1, int32_t * __restrict__ ids_dst, int32_t * __restrict__ expert_bounds,
121
+ const int n_experts, const int n_tokens, const int n_expert_used_var, const int nchannels_y, const int si1, const int sis1, cudaStream_t stream) {
122
+ GGML_ASSERT(n_tokens < (1 << 22) && "too few bits in mm_ids_helper_store");
123
+ GGML_ASSERT(n_expert_used_var < (1 << 10) && "too few bits in mm_ids_helper_store");
124
+
125
+ const int id = ggml_cuda_get_device();
126
+ const int warp_size = ggml_cuda_info().devices[id].warp_size;
127
+ const size_t smpbo = ggml_cuda_info().devices[id].smpbo;
128
+ CUDA_SET_SHARED_MEMORY_LIMIT(mm_ids_helper<n_expert_used_template>, smpbo);
129
+
130
+ const dim3 num_blocks(n_experts, 1, 1);
131
+ const dim3 block_size(warp_size, 1, 1);
132
+ const size_t nbytes_shared = n_tokens*sizeof(mm_ids_helper_store);
133
+ GGML_ASSERT(nbytes_shared <= smpbo);
134
+ mm_ids_helper<n_expert_used_template><<<num_blocks, block_size, nbytes_shared, stream>>>
135
+ (ids, ids_src1, ids_dst, expert_bounds, n_tokens, n_expert_used_var, nchannels_y, si1, sis1);
136
+ }
137
+
138
+ void ggml_cuda_launch_mm_ids_helper(
139
+ const int32_t * __restrict__ ids, int32_t * __restrict__ ids_src1, int32_t * __restrict__ ids_dst, int32_t * __restrict__ expert_bounds,
140
+ const int n_experts, const int n_tokens, const int n_expert_used, const int nchannels_y, const int si1, const int sis1, cudaStream_t stream) {
141
+ switch (n_expert_used) {
142
+ case 2:
143
+ launch_mm_ids_helper< 2>(ids, ids_src1, ids_dst, expert_bounds, n_experts, n_tokens, n_expert_used, nchannels_y, si1, sis1, stream);
144
+ break;
145
+ case 4:
146
+ launch_mm_ids_helper< 4>(ids, ids_src1, ids_dst, expert_bounds, n_experts, n_tokens, n_expert_used, nchannels_y, si1, sis1, stream);
147
+ break;
148
+ case 6:
149
+ launch_mm_ids_helper< 6>(ids, ids_src1, ids_dst, expert_bounds, n_experts, n_tokens, n_expert_used, nchannels_y, si1, sis1, stream);
150
+ break;
151
+ case 8:
152
+ launch_mm_ids_helper< 8>(ids, ids_src1, ids_dst, expert_bounds, n_experts, n_tokens, n_expert_used, nchannels_y, si1, sis1, stream);
153
+ break;
154
+ case 16:
155
+ launch_mm_ids_helper<16>(ids, ids_src1, ids_dst, expert_bounds, n_experts, n_tokens, n_expert_used, nchannels_y, si1, sis1, stream);
156
+ break;
157
+ case 32:
158
+ launch_mm_ids_helper<32>(ids, ids_src1, ids_dst, expert_bounds, n_experts, n_tokens, n_expert_used, nchannels_y, si1, sis1, stream);
159
+ break;
160
+ default:
161
+ launch_mm_ids_helper< 0>(ids, ids_src1, ids_dst, expert_bounds, n_experts, n_tokens, n_expert_used, nchannels_y, si1, sis1, stream);
162
+ break;
163
+ }
164
+ }
backend/llama.cpp/ggml/src/ggml-cuda/mmid.cuh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #pragma once
2
+
3
+ void ggml_cuda_launch_mm_ids_helper(
4
+ const int32_t * ids, int32_t * ids_src1, int32_t * ids_dst, int32_t * expert_bounds,
5
+ int n_experts, int n_tokens, int n_expert_used, int nchannels_y, int si1, int sis1, cudaStream_t stream);
backend/llama.cpp/ggml/src/ggml-cuda/mmq.cu ADDED
@@ -0,0 +1,379 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+ #include "mmq.cuh"
3
+ #include "quantize.cuh"
4
+ #include "mmid.cuh"
5
+
6
+ static void ggml_cuda_mul_mat_q_switch_type(ggml_backend_cuda_context & ctx, const mmq_args & args, cudaStream_t stream) {
7
+ switch (args.type_x) {
8
+ case GGML_TYPE_Q1_0:
9
+ mul_mat_q_case<GGML_TYPE_Q1_0>(ctx, args, stream);
10
+ break;
11
+ case GGML_TYPE_Q4_0:
12
+ mul_mat_q_case<GGML_TYPE_Q4_0>(ctx, args, stream);
13
+ break;
14
+ case GGML_TYPE_Q4_1:
15
+ mul_mat_q_case<GGML_TYPE_Q4_1>(ctx, args, stream);
16
+ break;
17
+ case GGML_TYPE_Q5_0:
18
+ mul_mat_q_case<GGML_TYPE_Q5_0>(ctx, args, stream);
19
+ break;
20
+ case GGML_TYPE_Q5_1:
21
+ mul_mat_q_case<GGML_TYPE_Q5_1>(ctx, args, stream);
22
+ break;
23
+ case GGML_TYPE_Q8_0:
24
+ mul_mat_q_case<GGML_TYPE_Q8_0>(ctx, args, stream);
25
+ break;
26
+ case GGML_TYPE_MXFP4:
27
+ mul_mat_q_case<GGML_TYPE_MXFP4>(ctx, args, stream);
28
+ break;
29
+ case GGML_TYPE_NVFP4:
30
+ mul_mat_q_case<GGML_TYPE_NVFP4>(ctx, args, stream);
31
+ break;
32
+ case GGML_TYPE_Q2_K:
33
+ mul_mat_q_case<GGML_TYPE_Q2_K>(ctx, args, stream);
34
+ break;
35
+ case GGML_TYPE_Q3_K:
36
+ mul_mat_q_case<GGML_TYPE_Q3_K>(ctx, args, stream);
37
+ break;
38
+ case GGML_TYPE_Q4_K:
39
+ mul_mat_q_case<GGML_TYPE_Q4_K>(ctx, args, stream);
40
+ break;
41
+ case GGML_TYPE_Q5_K:
42
+ mul_mat_q_case<GGML_TYPE_Q5_K>(ctx, args, stream);
43
+ break;
44
+ case GGML_TYPE_Q6_K:
45
+ mul_mat_q_case<GGML_TYPE_Q6_K>(ctx, args, stream);
46
+ break;
47
+ case GGML_TYPE_IQ2_XXS:
48
+ mul_mat_q_case<GGML_TYPE_IQ2_XXS>(ctx, args, stream);
49
+ break;
50
+ case GGML_TYPE_IQ2_XS:
51
+ mul_mat_q_case<GGML_TYPE_IQ2_XS>(ctx, args, stream);
52
+ break;
53
+ case GGML_TYPE_IQ2_S:
54
+ mul_mat_q_case<GGML_TYPE_IQ2_S>(ctx, args, stream);
55
+ break;
56
+ case GGML_TYPE_IQ3_XXS:
57
+ mul_mat_q_case<GGML_TYPE_IQ3_XXS>(ctx, args, stream);
58
+ break;
59
+ case GGML_TYPE_IQ3_S:
60
+ mul_mat_q_case<GGML_TYPE_IQ3_S>(ctx, args, stream);
61
+ break;
62
+ case GGML_TYPE_IQ1_S:
63
+ mul_mat_q_case<GGML_TYPE_IQ1_S>(ctx, args, stream);
64
+ break;
65
+ case GGML_TYPE_IQ4_XS:
66
+ mul_mat_q_case<GGML_TYPE_IQ4_XS>(ctx, args, stream);
67
+ break;
68
+ case GGML_TYPE_IQ4_NL:
69
+ mul_mat_q_case<GGML_TYPE_IQ4_NL>(ctx, args, stream);
70
+ break;
71
+ default:
72
+ GGML_ABORT("fatal error");
73
+ break;
74
+ }
75
+ }
76
+
77
+ void ggml_cuda_mul_mat_q(
78
+ ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, const ggml_tensor * ids, ggml_tensor * dst) {
79
+ GGML_ASSERT( src1->type == GGML_TYPE_F32);
80
+ GGML_ASSERT( dst->type == GGML_TYPE_F32);
81
+ GGML_ASSERT(!ids || ids->type == GGML_TYPE_I32); // Optional, used for batched GGML_MUL_MAT_ID.
82
+
83
+ GGML_TENSOR_BINARY_OP_LOCALS;
84
+
85
+ cudaStream_t stream = ctx.stream();
86
+ const int cc = ggml_cuda_info().devices[ggml_cuda_get_device()].cc;
87
+
88
+ const size_t ts_src0 = ggml_type_size(src0->type);
89
+ const size_t ts_src1 = ggml_type_size(src1->type);
90
+ const size_t ts_dst = ggml_type_size(dst->type);
91
+
92
+ GGML_ASSERT( nb00 == ts_src0);
93
+ GGML_ASSERT( nb10 == ts_src1);
94
+ GGML_ASSERT( nb0 == ts_dst);
95
+ GGML_ASSERT(!ids || ids->nb[0] == ggml_type_size(ids->type));
96
+
97
+ const char * src0_d = (const char *) src0->data;
98
+ const float * src1_d = (const float *) src1->data;
99
+ float * dst_d = (float *) dst->data;
100
+
101
+ // If src0 is a temporary compute buffer, clear any potential padding.
102
+ if (ggml_backend_buffer_get_usage(src0->buffer) == GGML_BACKEND_BUFFER_USAGE_COMPUTE) {
103
+ const size_t size_data = ggml_nbytes(src0);
104
+ const size_t size_alloc = ggml_backend_buffer_get_alloc_size(src0->buffer, src0);
105
+ if (size_alloc > size_data) {
106
+ GGML_ASSERT(ggml_is_contiguously_allocated(src0));
107
+ GGML_ASSERT(!src0->view_src);
108
+ CUDA_CHECK(cudaMemsetAsync((char *) src0->data + size_data, 0, size_alloc - size_data, stream));
109
+ }
110
+ }
111
+
112
+ const int64_t ne10_padded = GGML_PAD(ne10, MATRIX_ROW_PADDING);
113
+
114
+ const int64_t s01 = src0->nb[1] / ts_src0;
115
+ const int64_t s1 = dst->nb[1] / ts_dst;
116
+ const int64_t s02 = src0->nb[2] / ts_src0;
117
+ const int64_t s2 = dst->nb[2] / ts_dst;
118
+ const int64_t s03 = src0->nb[3] / ts_src0;
119
+ const int64_t s3 = dst->nb[3] / ts_dst;
120
+
121
+ const bool use_stream_k = (GGML_CUDA_CC_IS_NVIDIA(cc) && ggml_cuda_highest_compiled_arch(cc) >= GGML_CUDA_CC_VOLTA)
122
+ || GGML_CUDA_CC_IS_CDNA(cc);
123
+
124
+ // TODO: tighter pool buffer size vs q8 path
125
+ const bool use_native_fp4 = blackwell_mma_available(cc) && (src0->type == GGML_TYPE_MXFP4 || src0->type == GGML_TYPE_NVFP4);
126
+
127
+ if (!ids) {
128
+ const size_t nbytes_src1_q8_1 = ne13*ne12 * ne11*ne10_padded * sizeof(block_q8_1)/QK8_1 +
129
+ get_mmq_x_max_host(cc)*sizeof(block_q8_1_mmq);
130
+ ggml_cuda_pool_alloc<char> src1_q8_1(ctx.pool(), nbytes_src1_q8_1);
131
+
132
+ {
133
+ const int64_t s11 = src1->nb[1] / ts_src1;
134
+ const int64_t s12 = src1->nb[2] / ts_src1;
135
+ const int64_t s13 = src1->nb[3] / ts_src1;
136
+ if (use_native_fp4) {
137
+ static_assert(sizeof(block_fp4_mmq) == 4 * sizeof(block_q8_1));
138
+ quantize_mmq_fp4_cuda(src1_d, nullptr, src1_q8_1.get(), src0->type, ne10, s11, s12, s13, ne10_padded,
139
+ ne11, ne12, ne13, stream);
140
+
141
+ } else {
142
+ quantize_mmq_q8_1_cuda(src1_d, nullptr, src1_q8_1.get(), src0->type, ne10, s11, s12, s13, ne10_padded,
143
+ ne11, ne12, ne13, stream);
144
+ }
145
+ CUDA_CHECK(cudaGetLastError());
146
+ }
147
+
148
+ // Stride depends on quantization format
149
+ const int64_t s12 = use_native_fp4 ?
150
+ ne11 * ne10_padded * sizeof(block_fp4_mmq) / (QK_K * sizeof(int)) : // block_fp4_mmq holds 256 values
151
+ ne11 * ne10_padded * sizeof(block_q8_1) / (QK8_1 * sizeof(int));
152
+ const int64_t s13 = ne12*s12;
153
+
154
+ const mmq_args args = {
155
+ src0_d, src0->type, (const int *) src1_q8_1.ptr, nullptr, nullptr, dst_d,
156
+ ne00, ne01, ne1, s01, ne11, s1,
157
+ ne02, ne12, s02, s12, s2,
158
+ ne03, ne13, s03, s13, s3,
159
+ use_stream_k, ne1};
160
+ ggml_cuda_mul_mat_q_switch_type(ctx, args, stream);
161
+ return;
162
+ }
163
+
164
+ GGML_ASSERT(ne13 == 1);
165
+ GGML_ASSERT(nb12 % nb11 == 0);
166
+ GGML_ASSERT(nb2 % nb1 == 0);
167
+
168
+ const int64_t n_expert_used = ids->ne[0];
169
+ const int64_t ne_get_rows = ne12 * n_expert_used;
170
+ GGML_ASSERT(ne1 == n_expert_used);
171
+
172
+ ggml_cuda_pool_alloc<int32_t> ids_src1(ctx.pool(), ne_get_rows);
173
+ ggml_cuda_pool_alloc<int32_t> ids_dst(ctx.pool(), ne_get_rows);
174
+ ggml_cuda_pool_alloc<int32_t> expert_bounds(ctx.pool(), ne02 + 1);
175
+
176
+ {
177
+ GGML_ASSERT(ids->nb[0] == ggml_element_size(ids));
178
+ const int si1 = ids->nb[1] / ggml_element_size(ids);
179
+ const int sis1 = nb12 / nb11;
180
+
181
+ ggml_cuda_launch_mm_ids_helper((const int32_t *) ids->data, ids_src1.get(), ids_dst.get(), expert_bounds.get(),
182
+ ne02, ne12, n_expert_used, ne11, si1, sis1, stream);
183
+ CUDA_CHECK(cudaGetLastError());
184
+ }
185
+
186
+ const size_t nbytes_src1_q8_1 = ne12*n_expert_used*ne10_padded * sizeof(block_q8_1)/QK8_1 +
187
+ get_mmq_x_max_host(cc)*sizeof(block_q8_1_mmq);
188
+ ggml_cuda_pool_alloc<char> src1_q8_1(ctx.pool(), nbytes_src1_q8_1);
189
+
190
+ const int64_t ne11_flat = ne12*n_expert_used;
191
+ const int64_t ne12_flat = 1;
192
+ const int64_t ne13_flat = 1;
193
+
194
+ {
195
+ const int64_t s11 = src1->nb[1] / ts_src1;
196
+ const int64_t s12 = src1->nb[2] / ts_src1;
197
+ const int64_t s13 = src1->nb[3] / ts_src1;
198
+
199
+ if (use_native_fp4) {
200
+ quantize_mmq_fp4_cuda(src1_d, ids_src1.get(), src1_q8_1.get(), src0->type, ne10, s11, s12, s13,
201
+ ne10_padded, ne11_flat, ne12_flat, ne13_flat, stream);
202
+ } else {
203
+ quantize_mmq_q8_1_cuda(src1_d, ids_src1.get(), src1_q8_1.get(), src0->type, ne10, s11, s12, s13,
204
+ ne10_padded, ne11_flat, ne12_flat, ne13_flat, stream);
205
+ }
206
+ CUDA_CHECK(cudaGetLastError());
207
+ }
208
+
209
+ static_assert(QK_K == 8 * QK_MXFP4, "QK_K needs to be 8 * QK_MXFP4");
210
+ const int64_t s12 = use_native_fp4 ? ne11 * ne10_padded * sizeof(block_fp4_mmq) / (QK_K * sizeof(int)) :
211
+ ne11 * ne10_padded * sizeof(block_q8_1) / (QK8_1 * sizeof(int));
212
+ const int64_t s13 = ne12*s12;
213
+
214
+ // Note that ne02 is used instead of ne12 because the number of y channels determines the z dimension of the CUDA grid.
215
+ const mmq_args args = {
216
+ src0_d, src0->type, (const int *) src1_q8_1.get(), ids_dst.get(), expert_bounds.get(), dst_d,
217
+ ne00, ne01, ne_get_rows, s01, ne_get_rows, s1,
218
+ ne02, ne02, s02, s12, s2,
219
+ ne03, ne13, s03, s13, s3,
220
+ use_stream_k, ne12};
221
+
222
+ ggml_cuda_mul_mat_q_switch_type(ctx, args, stream);
223
+ }
224
+
225
+ void ggml_cuda_op_mul_mat_q(
226
+ ggml_backend_cuda_context & ctx,
227
+ const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst, const char * src0_dd_i, const float * src1_ddf_i,
228
+ const char * src1_ddq_i, float * dst_dd_i, const int64_t row_low, const int64_t row_high, const int64_t src1_ncols,
229
+ const int64_t src1_padded_row_size, cudaStream_t stream) {
230
+
231
+ const int64_t ne00 = src0->ne[0];
232
+
233
+ const int64_t ne10 = src1->ne[0];
234
+ const int64_t ne11 = src1->ne[1];
235
+ GGML_ASSERT(ne10 % QK8_1 == 0);
236
+
237
+ const int64_t ne0 = dst->ne[0];
238
+
239
+ const int64_t row_diff = row_high - row_low;
240
+ const int64_t stride01 = ne00 / ggml_blck_size(src0->type);
241
+
242
+ const int id = ggml_cuda_get_device();
243
+ const int cc = ggml_cuda_info().devices[id].cc;
244
+
245
+ // the main device has a larger memory buffer to hold the results from all GPUs
246
+ // nrows_dst == nrows of the matrix that the kernel writes into
247
+ const int64_t nrows_dst = id == ctx.device ? ne0 : row_diff;
248
+
249
+ // The stream-k decomposition is only faster for recent NVIDIA GPUs.
250
+ // Also its fixup needs to allocate a temporary buffer in the memory pool.
251
+ // There are multiple parallel CUDA streams for src1_ncols != ne11 which would introduce a race condition for this buffer.
252
+ const bool use_stream_k = ((GGML_CUDA_CC_IS_NVIDIA(cc) && ggml_cuda_highest_compiled_arch(cc) >= GGML_CUDA_CC_VOLTA)
253
+ || GGML_CUDA_CC_IS_CDNA(cc))
254
+ && src1_ncols == ne11;
255
+ const mmq_args args = {
256
+ src0_dd_i, src0->type, (const int *) src1_ddq_i, nullptr, nullptr, dst_dd_i,
257
+ ne00, row_diff, src1_ncols, stride01, ne11, nrows_dst,
258
+ 1, 1, 0, 0, 0,
259
+ 1, 1, 0, 0, 0,
260
+ use_stream_k, src1_ncols};
261
+
262
+ ggml_cuda_mul_mat_q_switch_type(ctx, args, stream);
263
+
264
+ GGML_UNUSED_VARS(src1, dst, src1_ddf_i, src1_padded_row_size);
265
+ }
266
+
267
+ bool ggml_cuda_should_use_mmq(enum ggml_type type, int cc, int64_t ne11, int64_t n_experts) {
268
+ #ifdef GGML_CUDA_FORCE_CUBLAS
269
+ return false;
270
+ #endif // GGML_CUDA_FORCE_CUBLAS
271
+
272
+ bool mmq_supported;
273
+
274
+ switch (type) {
275
+ case GGML_TYPE_Q1_0:
276
+ case GGML_TYPE_Q4_0:
277
+ case GGML_TYPE_Q4_1:
278
+ case GGML_TYPE_Q5_0:
279
+ case GGML_TYPE_Q5_1:
280
+ case GGML_TYPE_Q8_0:
281
+ case GGML_TYPE_MXFP4:
282
+ case GGML_TYPE_NVFP4:
283
+ case GGML_TYPE_Q2_K:
284
+ case GGML_TYPE_Q3_K:
285
+ case GGML_TYPE_Q4_K:
286
+ case GGML_TYPE_Q5_K:
287
+ case GGML_TYPE_Q6_K:
288
+ case GGML_TYPE_IQ2_XXS:
289
+ case GGML_TYPE_IQ2_XS:
290
+ case GGML_TYPE_IQ2_S:
291
+ case GGML_TYPE_IQ3_XXS:
292
+ case GGML_TYPE_IQ3_S:
293
+ case GGML_TYPE_IQ1_S:
294
+ case GGML_TYPE_IQ4_XS:
295
+ case GGML_TYPE_IQ4_NL:
296
+ mmq_supported = true;
297
+ break;
298
+ default:
299
+ mmq_supported = false;
300
+ break;
301
+ }
302
+
303
+ if (!mmq_supported) {
304
+ return false;
305
+ }
306
+
307
+ if (turing_mma_available(cc)) {
308
+ return true;
309
+ }
310
+
311
+ if (ggml_cuda_highest_compiled_arch(cc) < GGML_CUDA_CC_DP4A) {
312
+ return false;
313
+ }
314
+
315
+ #ifdef GGML_CUDA_FORCE_MMQ
316
+ return true;
317
+ #endif //GGML_CUDA_FORCE_MMQ
318
+
319
+ if (GGML_CUDA_CC_IS_NVIDIA(cc)) {
320
+ return !fp16_mma_hardware_available(cc) || ne11 < MMQ_DP4A_MAX_BATCH_SIZE;
321
+ }
322
+
323
+ if (amd_mfma_available(cc)) {
324
+ // As of ROCM 7.0 rocblas/tensile performs very poorly on CDNA3 and hipblaslt (via ROCBLAS_USE_HIPBLASLT)
325
+ // performs better but is currently suffering from a crash on this architecture.
326
+ // TODO: Revisit when hipblaslt is fixed on CDNA3
327
+ if (GGML_CUDA_CC_IS_CDNA3(cc)) {
328
+ return true;
329
+ }
330
+ if (n_experts > 64 || ne11 <= 128) {
331
+ return true;
332
+ }
333
+ if (type == GGML_TYPE_Q4_0 || type == GGML_TYPE_Q4_1 || type == GGML_TYPE_Q5_0 || type == GGML_TYPE_Q5_1) {
334
+ return true;
335
+ }
336
+ if (ne11 <= 256 && (type == GGML_TYPE_Q4_K || type == GGML_TYPE_Q5_K)) {
337
+ return true;
338
+ }
339
+ return false;
340
+ }
341
+
342
+ if (amd_wmma_available(cc)) {
343
+ if (GGML_CUDA_CC_IS_RDNA3(cc)) {
344
+ // High expert counts are almost always better on MMQ due to
345
+ // the synchronization overhead in the cuBLAS/hipBLAS path:
346
+ // https://github.com/ggml-org/llama.cpp/pull/18202
347
+ if (n_experts >= 64) {
348
+ return true;
349
+ }
350
+
351
+ // For some quantization types MMQ can have lower peak TOPS than hipBLAS
352
+ // so it's only faster for sufficiently small batch sizes:
353
+ switch (type) {
354
+ case GGML_TYPE_Q2_K:
355
+ return ne11 <= 128;
356
+ case GGML_TYPE_Q6_K:
357
+ return ne11 <= (GGML_CUDA_CC_IS_RDNA3_0(cc) ? 128 : 256);
358
+ case GGML_TYPE_IQ2_XS:
359
+ case GGML_TYPE_IQ2_S:
360
+ return GGML_CUDA_CC_IS_RDNA3_5(cc) || ne11 <= 128;
361
+ default:
362
+ return true;
363
+ }
364
+ }
365
+
366
+ // For RDNA4 MMQ is consistently faster than dequantization + hipBLAS:
367
+ // https://github.com/ggml-org/llama.cpp/pull/18537#issuecomment-3706422301
368
+ return true;
369
+ }
370
+
371
+ // gfx900 (Vega 10) lacks native dp4a, loses to dequant + hipBLAS
372
+ // for dense matrices; keep MMQ only for MoE, where the
373
+ // hipBLAS path is much slower.
374
+ if (cc == GGML_CUDA_CC_VEGA) {
375
+ return n_experts > 0;
376
+ }
377
+
378
+ return (!GGML_CUDA_CC_IS_CDNA(cc)) || ne11 < MMQ_DP4A_MAX_BATCH_SIZE;
379
+ }
backend/llama.cpp/ggml/src/ggml-cuda/mmq.cuh ADDED
The diff for this file is too large to render. See raw diff
 
backend/llama.cpp/ggml/src/ggml-cuda/mmvf.cu ADDED
@@ -0,0 +1,869 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "ggml.h"
2
+ #include "common.cuh"
3
+ #include "unary.cuh"
4
+ #include "mmvf.cuh"
5
+ #include "convert.cuh"
6
+
7
+ template <typename T, typename type_acc, int ncols_dst, int block_size, bool has_fusion = false, bool is_multi_token_id = false>
8
+ static __global__ void mul_mat_vec_f(
9
+ const T * x_ptr, const float * y_ptr, const int32_t * ids_ptr, const ggml_cuda_mm_fusion_args_device fusion, float * dst_ptr,
10
+ const int ncols2, const uint3 nchannels_y, const int stride_row, const int stride_col_y2, const int stride_col_dst,
11
+ const uint3 channel_ratio, const int stride_channel_x, const int stride_channel_y, const int stride_channel_dst,
12
+ const uint3 sample_ratio, const int stride_sample_x, const int stride_sample_y, const int stride_sample_dst,
13
+ const int ids_stride) {
14
+ const T * GGML_CUDA_RESTRICT x = x_ptr;
15
+ const float * GGML_CUDA_RESTRICT y = y_ptr;
16
+ const int32_t * GGML_CUDA_RESTRICT ids = ids_ptr;
17
+ float * GGML_CUDA_RESTRICT dst = dst_ptr;
18
+ const int row = blockIdx.x;
19
+ // for MUL_MAT_ID - blockIdx.y = n_expert_used, blockIdx.z = ncols_dst (tokens)
20
+ const int channel_dst = blockIdx.y;
21
+ const int tid = threadIdx.x;
22
+
23
+ int token_idx;
24
+ int channel_x;
25
+ int channel_y;
26
+ int sample_dst;
27
+
28
+ ggml_cuda_pdl_sync();
29
+ if constexpr (is_multi_token_id) {
30
+ // Multi-token MUL_MAT_ID path, adding these in the normal path causes a perf regression for n_tokens=1 case
31
+ token_idx = blockIdx.z;
32
+ channel_x = ids[channel_dst + token_idx * ids_stride];
33
+ channel_y = fastmodulo(channel_dst, nchannels_y);
34
+ sample_dst = 0;
35
+ } else {
36
+ token_idx = ids ? blockIdx.z : 0;
37
+ channel_x = ids ? ids[blockIdx.y + token_idx * ids_stride] : fastdiv((uint32_t) channel_dst, channel_ratio);
38
+ channel_y = ids ? fastmodulo(blockIdx.y, nchannels_y) : channel_dst;
39
+ sample_dst = ids ? 0 : blockIdx.z;
40
+ }
41
+
42
+ const int sample_x = fastdiv((uint32_t) sample_dst, sample_ratio);
43
+ const int sample_y = sample_dst;
44
+
45
+ constexpr int warp_size = ggml_cuda_get_physical_warp_size();
46
+
47
+ x += int64_t(sample_x) *stride_sample_x + channel_x *stride_channel_x + row*stride_row;
48
+ y += int64_t(sample_y) *stride_sample_y + channel_y *stride_channel_y;
49
+ dst += int64_t(sample_dst)*stride_sample_dst + channel_dst*stride_channel_dst;
50
+ if constexpr (is_multi_token_id) {
51
+ y += token_idx*stride_col_y2*2;
52
+ dst += token_idx*stride_col_dst;
53
+ }
54
+
55
+ bool use_gate = false;
56
+ bool use_bias = false;
57
+ bool use_gate_bias = false;
58
+ ggml_glu_op glu_op = ggml_glu_op::GGML_GLU_OP_SWIGLU;
59
+ const T * gate_x = nullptr;
60
+ const float * x_bias = nullptr;
61
+ const float * gate_bias = nullptr;
62
+
63
+ if constexpr (has_fusion) {
64
+ use_gate = fusion.gate != nullptr;
65
+ use_bias = fusion.x_bias != nullptr;
66
+ use_gate_bias = fusion.gate_bias != nullptr;
67
+ glu_op = fusion.glu_op;
68
+
69
+ if (use_gate) {
70
+ gate_x = static_cast<const T *>(fusion.gate);
71
+ }
72
+ if (use_bias) {
73
+ x_bias = static_cast<const float *>(fusion.x_bias);
74
+ }
75
+ if (use_gate_bias) {
76
+ gate_bias = static_cast<const float *>(fusion.gate_bias);
77
+ use_gate_bias = use_gate;
78
+ } else {
79
+ use_gate_bias = false;
80
+ }
81
+ }
82
+
83
+ if (use_gate) {
84
+ gate_x += int64_t(sample_x) *stride_sample_x + channel_x *stride_channel_x + row*stride_row;
85
+ }
86
+
87
+ if constexpr (has_fusion) {
88
+ const int channel_bias = ids ? channel_x : channel_dst;
89
+ if (use_bias) {
90
+ x_bias += int64_t(sample_dst)*stride_sample_dst + channel_bias*stride_channel_dst;
91
+ }
92
+ if (use_gate_bias) {
93
+ gate_bias += int64_t(sample_dst)*stride_sample_dst + channel_bias*stride_channel_dst;
94
+ }
95
+ }
96
+
97
+ const float2 * y2 = (const float2 *) y;
98
+
99
+ extern __shared__ char data_mmv[];
100
+ float * buf_iw = (float *) data_mmv;
101
+ [[maybe_unused]] float * buf_iw_gate = nullptr;
102
+ if constexpr (has_fusion) {
103
+ buf_iw_gate = (float *) (data_mmv + warp_size*sizeof(float));
104
+ }
105
+
106
+ if (block_size > warp_size) {
107
+ if (tid < warp_size) {
108
+ buf_iw[tid] = 0.0f;
109
+ if constexpr (has_fusion) {
110
+ if (use_gate) {
111
+ buf_iw_gate[tid] = 0.0f;
112
+ }
113
+ }
114
+ }
115
+ __syncthreads();
116
+ }
117
+
118
+ float sumf[ncols_dst] = {0.0f};
119
+ float sumf_gate[ncols_dst];
120
+ if constexpr (has_fusion) {
121
+ #pragma unroll
122
+ for (int j = 0; j < ncols_dst; ++j) {
123
+ sumf_gate[j] = 0.0f;
124
+ }
125
+ }
126
+
127
+ if constexpr (std::is_same_v<T, float>) {
128
+ const float2 * x2 = (const float2 *) x;
129
+ [[maybe_unused]] const float2 * gate_x2 = nullptr;
130
+ if constexpr (has_fusion) {
131
+ if (use_gate) {
132
+ gate_x2 = (const float2 *) gate_x;
133
+ }
134
+ }
135
+
136
+ for (int col2 = tid; col2 < ncols2; col2 += block_size) {
137
+ const float2 tmpx = x2[col2];
138
+ float2 tmpx_gate = make_float2(0.0f, 0.0f);
139
+ if constexpr (has_fusion) {
140
+ if (use_gate) {
141
+ tmpx_gate = gate_x2[col2];
142
+ }
143
+ }
144
+
145
+ #pragma unroll
146
+ for (int j = 0; j < ncols_dst; ++j) {
147
+ const float2 tmpy = y2[j*stride_col_y2 + col2];
148
+ ggml_cuda_mad(sumf[j], tmpx.x, tmpy.x);
149
+ ggml_cuda_mad(sumf[j], tmpx.y, tmpy.y);
150
+
151
+ if constexpr (has_fusion) {
152
+ if (use_gate) {
153
+ ggml_cuda_mad(sumf_gate[j], tmpx_gate.x, tmpy.x);
154
+ ggml_cuda_mad(sumf_gate[j], tmpx_gate.y, tmpy.y);
155
+ }
156
+ }
157
+ }
158
+ }
159
+ } else if constexpr (std::is_same_v<T, half>) {
160
+ const half2 * x2 = (const half2 *) x;
161
+ [[maybe_unused]] const half2 * gate_x2 = nullptr;
162
+ if constexpr (has_fusion) {
163
+ if (use_gate) {
164
+ gate_x2 = (const half2 *) gate_x;
165
+ }
166
+ }
167
+
168
+ if (std::is_same_v<type_acc, float>) {
169
+ for (int col2 = tid; col2 < ncols2; col2 += block_size) {
170
+ const float2 tmpx = __half22float2(x2[col2]);
171
+ float2 tmpx_gate = make_float2(0.0f, 0.0f);
172
+ if constexpr (has_fusion) {
173
+ if (use_gate) {
174
+ tmpx_gate = __half22float2(gate_x2[col2]);
175
+ }
176
+ }
177
+ #pragma unroll
178
+ for (int j = 0; j < ncols_dst; ++j) {
179
+ const float2 tmpy = y2[j*stride_col_y2 + col2];
180
+ ggml_cuda_mad(sumf[j], tmpx.x, tmpy.x);
181
+ ggml_cuda_mad(sumf[j], tmpx.y, tmpy.y);
182
+
183
+ if constexpr (has_fusion) {
184
+ if (use_gate) {
185
+ ggml_cuda_mad(sumf_gate[j], tmpx_gate.x, tmpy.x);
186
+ ggml_cuda_mad(sumf_gate[j], tmpx_gate.y, tmpy.y);
187
+ }
188
+ }
189
+ }
190
+ }
191
+ } else {
192
+ #ifdef FP16_AVAILABLE
193
+ half2 sumh2[ncols_dst] = {{0.0f, 0.0f}};
194
+ half2 sumh2_gate[ncols_dst] = {{0.0f, 0.0f}};
195
+
196
+ for (int col2 = tid; col2 < ncols2; col2 += block_size) {
197
+ const half2 tmpx = x2[col2];
198
+ half2 tmpx_gate = make_half2(0.0f, 0.0f);
199
+ if constexpr (has_fusion) {
200
+ if (use_gate) {
201
+ tmpx_gate = gate_x2[col2];
202
+ }
203
+ }
204
+ #pragma unroll
205
+ for (int j = 0; j < ncols_dst; ++j) {
206
+ const float2 tmpy = y2[j*stride_col_y2 + col2];
207
+ sumh2[j] += tmpx * make_half2(tmpy.x, tmpy.y);
208
+
209
+ if constexpr (has_fusion) {
210
+ if (use_gate) {
211
+ sumh2_gate[j] += tmpx_gate * make_half2(tmpy.x, tmpy.y);
212
+ }
213
+ }
214
+ }
215
+ }
216
+
217
+ #pragma unroll
218
+ for (int j = 0; j < ncols_dst; ++j) {
219
+ sumf[j] = __low2float(sumh2[j]) + __high2float(sumh2[j]);
220
+ }
221
+
222
+ if constexpr (has_fusion) {
223
+ if (use_gate) {
224
+ #pragma unroll
225
+ for (int j = 0; j < ncols_dst; ++j) {
226
+ sumf_gate[j] = __low2float(sumh2_gate[j]) + __high2float(sumh2_gate[j]);
227
+ }
228
+ }
229
+ }
230
+ #else
231
+ NO_DEVICE_CODE;
232
+ #endif // FP16_AVAILABLE
233
+ }
234
+ } else if constexpr (std::is_same_v<T, nv_bfloat16>) {
235
+ //TODO: add support for ggml_cuda_mad for hip_bfloat162
236
+ #if defined(GGML_USE_HIP)
237
+ const int * x2 = (const int *) x;
238
+ const int * gate_x2 = nullptr;
239
+ if constexpr (has_fusion) {
240
+ if (use_gate) {
241
+ gate_x2 = (const int *) gate_x;
242
+ }
243
+ }
244
+ for (int col2 = tid; col2 < ncols2; col2 += block_size) {
245
+ const int tmpx = x2[col2];
246
+ int tmpx_gate = 0;
247
+ if constexpr (has_fusion) {
248
+ if (use_gate) {
249
+ tmpx_gate = gate_x2[col2];
250
+ }
251
+ }
252
+ #pragma unroll
253
+ for (int j = 0; j < ncols_dst; ++j) {
254
+ const float2 tmpy = y2[j*stride_col_y2 + col2];
255
+ const float tmpx0 = ggml_cuda_cast<float>(reinterpret_cast<const nv_bfloat16 *>(&tmpx)[0]);
256
+ const float tmpx1 = ggml_cuda_cast<float>(reinterpret_cast<const nv_bfloat16 *>(&tmpx)[1]);
257
+ ggml_cuda_mad(sumf[j], tmpx0, tmpy.x);
258
+ ggml_cuda_mad(sumf[j], tmpx1, tmpy.y);
259
+
260
+ if constexpr (has_fusion) {
261
+ if (use_gate) {
262
+ const float tmpx0_gate = ggml_cuda_cast<float>(reinterpret_cast<const nv_bfloat16 *>(&tmpx_gate)[0]);
263
+ const float tmpx1_gate = ggml_cuda_cast<float>(reinterpret_cast<const nv_bfloat16 *>(&tmpx_gate)[1]);
264
+ ggml_cuda_mad(sumf_gate[j], tmpx0_gate, tmpy.x);
265
+ ggml_cuda_mad(sumf_gate[j], tmpx1_gate, tmpy.y);
266
+ }
267
+ }
268
+ }
269
+ }
270
+ #else
271
+ const nv_bfloat162 * x2 = (const nv_bfloat162 *) x;
272
+ [[maybe_unused]] const nv_bfloat162 * gate_x2 = nullptr;
273
+ if constexpr (has_fusion) {
274
+ if (use_gate) {
275
+ gate_x2 = (const nv_bfloat162 *) gate_x;
276
+ }
277
+ }
278
+ for (int col2 = tid; col2 < ncols2; col2 += block_size) {
279
+ const nv_bfloat162 tmpx = x2[col2];
280
+ [[maybe_unused]] nv_bfloat162 tmpx_gate;
281
+ if constexpr (has_fusion) {
282
+ if (use_gate) {
283
+ tmpx_gate = gate_x2[col2];
284
+ }
285
+ }
286
+ #pragma unroll
287
+ for (int j = 0; j < ncols_dst; ++j) {
288
+ const float2 tmpy = y2[j*stride_col_y2 + col2];
289
+ ggml_cuda_mad(sumf[j], tmpx.x, tmpy.x);
290
+ ggml_cuda_mad(sumf[j], tmpx.y, tmpy.y);
291
+
292
+ if constexpr (has_fusion) {
293
+ if (use_gate) {
294
+ ggml_cuda_mad(sumf_gate[j], tmpx_gate.x, tmpy.x);
295
+ ggml_cuda_mad(sumf_gate[j], tmpx_gate.y, tmpy.y);
296
+ }
297
+ }
298
+ }
299
+ }
300
+ #endif
301
+ } else {
302
+ static_assert(std::is_same_v<T, void>, "unsupported type");
303
+ }
304
+
305
+ ggml_cuda_pdl_lc();
306
+ #pragma unroll
307
+ for (int j = 0; j < ncols_dst; ++j) {
308
+ sumf[j] = warp_reduce_sum<warp_size>(sumf[j]);
309
+
310
+ if constexpr (has_fusion) {
311
+ if (use_gate) {
312
+ sumf_gate[j] = warp_reduce_sum<warp_size>(sumf_gate[j]);
313
+ }
314
+ }
315
+
316
+ if (block_size > warp_size) {
317
+ buf_iw[tid/warp_size] = sumf[j];
318
+ if constexpr (has_fusion) {
319
+ if (use_gate) {
320
+ buf_iw_gate[tid/warp_size] = sumf_gate[j];
321
+ }
322
+ }
323
+ __syncthreads();
324
+ if (tid < warp_size) {
325
+ sumf[j] = buf_iw[tid];
326
+ sumf[j] = warp_reduce_sum<warp_size>(sumf[j]);
327
+ if constexpr (has_fusion) {
328
+ if (use_gate) {
329
+ sumf_gate[j] = buf_iw_gate[tid];
330
+ sumf_gate[j] = warp_reduce_sum<warp_size>(sumf_gate[j]);
331
+ }
332
+ }
333
+ }
334
+
335
+ if (j < ncols_dst) {
336
+ __syncthreads();
337
+ }
338
+ }
339
+ }
340
+
341
+ if (tid >= ncols_dst) {
342
+ return;
343
+ }
344
+
345
+ float value = sumf[tid];
346
+
347
+ if constexpr (has_fusion) {
348
+ if (use_bias) {
349
+ value += x_bias[tid*stride_col_dst + row];
350
+ }
351
+
352
+ if (use_gate) {
353
+ float gate_value = sumf_gate[tid];
354
+ if (use_gate_bias) {
355
+ gate_value += gate_bias[tid*stride_col_dst + row];
356
+ }
357
+ switch (glu_op) {
358
+ case GGML_GLU_OP_SWIGLU:
359
+ value *= ggml_cuda_op_silu_single(gate_value);
360
+ break;
361
+ case GGML_GLU_OP_GEGLU:
362
+ value *= ggml_cuda_op_gelu_single(gate_value);
363
+ break;
364
+ case GGML_GLU_OP_SWIGLU_OAI: {
365
+ value = ggml_cuda_op_swiglu_oai_single(gate_value, value);
366
+ break;
367
+ }
368
+ default:
369
+ break;
370
+ }
371
+ }
372
+ }
373
+
374
+ dst[tid*stride_col_dst + row] = value;
375
+
376
+ if constexpr (!has_fusion) {
377
+ GGML_UNUSED_VARS(use_gate, use_bias, use_gate_bias, glu_op, gate_x, x_bias, gate_bias, sumf_gate);
378
+ }
379
+ }
380
+
381
+ template<typename T, typename type_acc, int ncols_dst, int block_size, bool is_multi_token_id = false>
382
+ static void mul_mat_vec_f_switch_fusion(
383
+ const T * x, const float * y, const int32_t * ids, const ggml_cuda_mm_fusion_args_device fusion, float * dst,
384
+ const int64_t ncols, const uint3 nchannels_y,
385
+ const int64_t stride_row, const int64_t stride_col_y, const int64_t stride_col_dst,
386
+ const uint3 channel_ratio, const int stride_channel_x, const int stride_channel_y, const int stride_channel_dst,
387
+ const uint3 sample_ratio, const int stride_sample_x, const int stride_sample_y, const int stride_sample_dst,
388
+ const dim3 & block_dims, const dim3 & block_nums, const int nbytes_shared, const int ids_stride, const cudaStream_t stream) {
389
+
390
+ const ggml_cuda_kernel_launch_params launch_params = {block_nums, block_dims, nbytes_shared, stream};
391
+
392
+ const bool has_fusion = fusion.gate != nullptr || fusion.x_bias != nullptr || fusion.gate_bias != nullptr;
393
+ if constexpr (ncols_dst == 1) {
394
+ if (has_fusion) {
395
+ ggml_cuda_kernel_launch(mul_mat_vec_f<T, type_acc, ncols_dst, block_size, true, is_multi_token_id>, launch_params,
396
+ x, y, ids, fusion, dst, ncols, nchannels_y, stride_row, stride_col_y, stride_col_dst,
397
+ channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
398
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride);
399
+ return;
400
+ }
401
+ }
402
+
403
+ GGML_ASSERT(!has_fusion && "fusion only supported for ncols_dst=1");
404
+
405
+ ggml_cuda_kernel_launch(mul_mat_vec_f<T, type_acc, ncols_dst, block_size, false, is_multi_token_id>, launch_params,
406
+ x, y, ids, fusion, dst, ncols, nchannels_y, stride_row, stride_col_y, stride_col_dst,
407
+ channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
408
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride);
409
+
410
+ }
411
+
412
+ template <typename T, typename type_acc, int ncols_dst, bool is_multi_token_id = false>
413
+ void launch_mul_mat_vec_f_cuda(
414
+ const T * x, const float * y, const int32_t * ids, const ggml_cuda_mm_fusion_args_device fusion, float * dst,
415
+ const int64_t ncols, const int64_t nrows,
416
+ const int64_t stride_row, const int64_t stride_col_y, const int64_t stride_col_dst,
417
+ const int64_t nchannels_x, const int64_t nchannels_y, const int64_t nchannels_dst,
418
+ const int64_t stride_channel_x, const int64_t stride_channel_y, const int64_t stride_channel_dst, const int64_t nsamples_x,
419
+ const int64_t nsamples_dst, const int64_t stride_sample_x, const int64_t stride_sample_y, const int64_t stride_sample_dst,
420
+ const int64_t nsamples_or_ntokens, const int64_t ids_stride, cudaStream_t stream) {
421
+ GGML_ASSERT(ncols % 2 == 0);
422
+ GGML_ASSERT(stride_row % 2 == 0);
423
+ GGML_ASSERT(stride_col_y % 2 == 0);
424
+ GGML_ASSERT(ids || nchannels_dst % nchannels_x == 0);
425
+ GGML_ASSERT( nsamples_dst % nsamples_x == 0);
426
+ const uint3 nchannels_y_fd = ids ? init_fastdiv_values(nchannels_y) : make_uint3(0, 0, 0);
427
+ const uint3 channel_ratio_fd = ids ? make_uint3(0, 0, 0) : init_fastdiv_values(nchannels_dst / nchannels_x);
428
+ const uint3 sample_ratio_fd = init_fastdiv_values(nsamples_dst / nsamples_x);
429
+
430
+ const int device = ggml_cuda_get_device();
431
+ const int warp_size = ggml_cuda_info().devices[device].warp_size;
432
+
433
+ int64_t block_size_best = warp_size;
434
+ int64_t niter_best = (ncols + 2*warp_size - 1) / (2*warp_size);
435
+ int64_t max_block_size = 256;
436
+ if(ggml_cuda_info().devices[device].cc > GGML_CUDA_CC_OFFSET_AMD && ggml_cuda_info().devices[device].cc < GGML_CUDA_CC_RDNA1) {
437
+ max_block_size = 128;
438
+ }
439
+ for (int64_t block_size = 2*warp_size; block_size <= max_block_size; block_size += warp_size) {
440
+ const int64_t niter = (ncols + 2*block_size - 1) / (2*block_size);
441
+ if (niter < niter_best) {
442
+ niter_best = niter;
443
+ block_size_best = block_size;
444
+ }
445
+ }
446
+
447
+ const bool has_fusion = fusion.gate != nullptr || fusion.x_bias != nullptr || fusion.gate_bias != nullptr;
448
+
449
+ const int nbytes_shared = warp_size*sizeof(float) + (has_fusion ? warp_size*sizeof(float) : 0);
450
+ const dim3 block_nums(nrows, nchannels_dst, nsamples_or_ntokens);
451
+ const dim3 block_dims(block_size_best, 1, 1);
452
+ switch (block_size_best) {
453
+ case 32: {
454
+ mul_mat_vec_f_switch_fusion<T, type_acc, ncols_dst, 32, is_multi_token_id>
455
+ (x, y, ids, fusion, dst, ncols/2, nchannels_y_fd, stride_row, stride_col_y/2, stride_col_dst,
456
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
457
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, block_dims, block_nums, nbytes_shared, ids_stride, stream);
458
+ } break;
459
+ case 64: {
460
+ mul_mat_vec_f_switch_fusion<T, type_acc, ncols_dst, 64, is_multi_token_id>
461
+ (x, y, ids, fusion, dst, ncols/2, nchannels_y_fd, stride_row, stride_col_y/2, stride_col_dst,
462
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
463
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, block_dims, block_nums, nbytes_shared, ids_stride, stream);
464
+ } break;
465
+ case 96: {
466
+ mul_mat_vec_f_switch_fusion<T, type_acc, ncols_dst, 96, is_multi_token_id>
467
+ (x, y, ids, fusion, dst, ncols/2, nchannels_y_fd, stride_row, stride_col_y/2, stride_col_dst,
468
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
469
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, block_dims, block_nums, nbytes_shared, ids_stride, stream);
470
+ } break;
471
+ case 128: {
472
+ mul_mat_vec_f_switch_fusion<T, type_acc, ncols_dst, 128, is_multi_token_id>
473
+ (x, y, ids, fusion, dst, ncols/2, nchannels_y_fd, stride_row, stride_col_y/2, stride_col_dst,
474
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
475
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, block_dims, block_nums, nbytes_shared, ids_stride, stream);
476
+ } break;
477
+ case 160: {
478
+ mul_mat_vec_f_switch_fusion<T, type_acc, ncols_dst, 160, is_multi_token_id>
479
+ (x, y, ids, fusion, dst, ncols/2, nchannels_y_fd, stride_row, stride_col_y/2, stride_col_dst,
480
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
481
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, block_dims, block_nums, nbytes_shared, ids_stride, stream);
482
+ } break;
483
+ case 192: {
484
+ mul_mat_vec_f_switch_fusion<T, type_acc, ncols_dst, 192, is_multi_token_id>
485
+ (x, y, ids, fusion, dst, ncols/2, nchannels_y_fd, stride_row, stride_col_y/2, stride_col_dst,
486
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
487
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, block_dims, block_nums, nbytes_shared, ids_stride, stream);
488
+ } break;
489
+ case 224: {
490
+ mul_mat_vec_f_switch_fusion<T, type_acc, ncols_dst, 224, is_multi_token_id>
491
+ (x, y, ids, fusion, dst, ncols/2, nchannels_y_fd, stride_row, stride_col_y/2, stride_col_dst,
492
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
493
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, block_dims, block_nums, nbytes_shared, ids_stride, stream);
494
+ } break;
495
+ case 256: {
496
+ mul_mat_vec_f_switch_fusion<T, type_acc, ncols_dst, 256, is_multi_token_id>
497
+ (x, y, ids, fusion, dst, ncols/2, nchannels_y_fd, stride_row, stride_col_y/2, stride_col_dst,
498
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
499
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, block_dims, block_nums, nbytes_shared, ids_stride, stream);
500
+ } break;
501
+ default: {
502
+ GGML_ABORT("fatal error");
503
+ } break;
504
+ }
505
+ }
506
+
507
+ template <typename T, typename type_acc>
508
+ static void mul_mat_vec_f_cuda_switch_ncols_dst(
509
+ const T * x, const float * y, const int32_t * ids, const ggml_cuda_mm_fusion_args_device fusion, float * dst,
510
+ const int64_t ncols, const int64_t nrows, const int64_t ncols_dst,
511
+ const int64_t stride_row, const int64_t stride_col_y, const int64_t stride_col_dst,
512
+ const int64_t nchannels_x, const int64_t nchannels_y, const int64_t nchannels_dst,
513
+ const int64_t stride_channel_x, const int64_t stride_channel_y, const int64_t stride_channel_dst, const int64_t nsamples_x,
514
+ const int64_t nsamples_dst, const int64_t stride_sample_x, const int64_t stride_sample_y, const int64_t stride_sample_dst,
515
+ const int64_t ids_stride, cudaStream_t stream) {
516
+
517
+ const bool has_ids = ids != nullptr;
518
+
519
+ if (has_ids && ncols_dst > 1) {
520
+ // Multi-token MUL_MAT_ID path only - single-token goes through regular path below
521
+ constexpr int c_ncols_dst = 1;
522
+ launch_mul_mat_vec_f_cuda<T, type_acc, c_ncols_dst, true>
523
+ (x, y, ids, fusion, dst, ncols, nrows, stride_row, stride_col_y, stride_col_dst,
524
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y,
525
+ stride_channel_dst, nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst,
526
+ ncols_dst, ids_stride, stream);
527
+ return;
528
+ }
529
+
530
+ if (has_ids) {
531
+ // Single-token MUL_MAT_ID path
532
+ constexpr int c_ncols_dst = 1;
533
+ launch_mul_mat_vec_f_cuda<T, type_acc, c_ncols_dst>
534
+ (x, y, ids, fusion, dst, ncols, nrows, stride_row, stride_col_y, stride_col_dst,
535
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y,
536
+ stride_channel_dst, nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst,
537
+ ncols_dst, ids_stride, stream);
538
+ return;
539
+ }
540
+
541
+ switch (ncols_dst) {
542
+ case 1:
543
+ launch_mul_mat_vec_f_cuda<T, type_acc, 1>
544
+ (x, y, ids, fusion, dst, ncols, nrows, stride_row, stride_col_y, stride_col_dst,
545
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y,
546
+ stride_channel_dst, nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst,
547
+ nsamples_dst, ids_stride, stream);
548
+ break;
549
+ case 2:
550
+ launch_mul_mat_vec_f_cuda<T, type_acc, 2>
551
+ (x, y, ids, fusion, dst, ncols, nrows, stride_row, stride_col_y, stride_col_dst,
552
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y,
553
+ stride_channel_dst, nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst,
554
+ nsamples_dst, ids_stride, stream);
555
+ break;
556
+ case 3:
557
+ launch_mul_mat_vec_f_cuda<T, type_acc, 3>
558
+ (x, y, ids, fusion, dst, ncols, nrows, stride_row, stride_col_y, stride_col_dst,
559
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y,
560
+ stride_channel_dst, nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst,
561
+ nsamples_dst, ids_stride, stream);
562
+ break;
563
+ case 4:
564
+ launch_mul_mat_vec_f_cuda<T, type_acc, 4>
565
+ (x, y, ids, fusion, dst, ncols, nrows, stride_row, stride_col_y, stride_col_dst,
566
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y,
567
+ stride_channel_dst, nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst,
568
+ nsamples_dst, ids_stride, stream);
569
+ break;
570
+ case 5:
571
+ launch_mul_mat_vec_f_cuda<T, type_acc, 5>
572
+ (x, y, ids, fusion, dst, ncols, nrows, stride_row, stride_col_y, stride_col_dst,
573
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y,
574
+ stride_channel_dst, nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst,
575
+ nsamples_dst, ids_stride, stream);
576
+ break;
577
+ case 6:
578
+ launch_mul_mat_vec_f_cuda<T, type_acc, 6>
579
+ (x, y, ids, fusion, dst, ncols, nrows, stride_row, stride_col_y, stride_col_dst,
580
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y,
581
+ stride_channel_dst, nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst,
582
+ nsamples_dst, ids_stride, stream);
583
+ break;
584
+ case 7:
585
+ launch_mul_mat_vec_f_cuda<T, type_acc, 7>
586
+ (x, y, ids, fusion, dst, ncols, nrows, stride_row, stride_col_y, stride_col_dst,
587
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y,
588
+ stride_channel_dst, nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst,
589
+ nsamples_dst, ids_stride, stream);
590
+ break;
591
+ case 8:
592
+ launch_mul_mat_vec_f_cuda<T, type_acc, 8>
593
+ (x, y, ids, fusion, dst, ncols, nrows, stride_row, stride_col_y, stride_col_dst,
594
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y,
595
+ stride_channel_dst, nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst,
596
+ nsamples_dst, ids_stride, stream);
597
+ break;
598
+ default:
599
+ GGML_ABORT("fatal error");
600
+ break;
601
+ }
602
+ }
603
+
604
+ template<typename T>
605
+ static void mul_mat_vec_f_cuda(
606
+ const T * x, const float * y, const int32_t * ids, const ggml_cuda_mm_fusion_args_device fusion, float * dst,
607
+ const int64_t ncols, const int64_t nrows, const int64_t ncols_dst,
608
+ const int64_t stride_row, const int64_t stride_col_y, const int stride_col_dst,
609
+ const int64_t nchannels_x, const int64_t nchannels_y, const int64_t nchannels_dst,
610
+ const int64_t stride_channel_x, const int64_t stride_channel_y, const int64_t stride_channel_dst, const int64_t nsamples_x,
611
+ const int64_t nsamples_dst, const int64_t stride_sample_x, const int64_t stride_sample_y, const int64_t stride_sample_dst,
612
+ const int64_t ids_stride, enum ggml_prec prec, cudaStream_t stream) {
613
+
614
+ if constexpr(std::is_same_v<T, half>) {
615
+ if (prec == GGML_PREC_DEFAULT) {
616
+ mul_mat_vec_f_cuda_switch_ncols_dst<T, half>
617
+ (x, y, ids, fusion, dst, ncols, nrows, ncols_dst, stride_row, stride_col_y, stride_col_dst,
618
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y,
619
+ stride_channel_dst, nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
620
+ return;
621
+ }
622
+ }
623
+ mul_mat_vec_f_cuda_switch_ncols_dst<T, float>
624
+ (x, y, ids, fusion, dst, ncols, nrows, ncols_dst, stride_row, stride_col_y, stride_col_dst,
625
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y,
626
+ stride_channel_dst, nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
627
+ }
628
+
629
+ void ggml_cuda_mul_mat_vec_f(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, const ggml_tensor * ids, ggml_tensor * dst,
630
+ const ggml_cuda_mm_fusion_args_host * fusion) {
631
+ GGML_ASSERT( src1->type == GGML_TYPE_F32);
632
+ GGML_ASSERT(!ids || ids->type == GGML_TYPE_I32);
633
+ GGML_ASSERT( dst->type == GGML_TYPE_F32);
634
+
635
+ GGML_TENSOR_BINARY_OP_LOCALS;
636
+
637
+ const size_t ts_src0 = ggml_type_size(src0->type);
638
+ const size_t ts_src1 = ggml_type_size(src1->type);
639
+ const size_t ts_dst = ggml_type_size(dst->type);
640
+
641
+ GGML_ASSERT(!ids || ne12 <= MMVF_MAX_BATCH_SIZE);
642
+ GGML_ASSERT(ne13 == ne3);
643
+
644
+ GGML_ASSERT( nb00 == ts_src0);
645
+ GGML_ASSERT( nb10 == ts_src1);
646
+ GGML_ASSERT(!ids || ids->nb[0] == ggml_type_size(ids->type));
647
+ GGML_ASSERT( nb0 == ts_dst);
648
+
649
+ const int cc = ggml_cuda_info().devices[ggml_cuda_get_device()].cc;
650
+ const enum ggml_prec prec = fast_fp16_available(cc) ? ggml_prec(dst->op_params[0]) : GGML_PREC_F32;
651
+
652
+ const float * src1_d = (const float *) src1->data;
653
+ const int32_t * ids_d = ids ? (const int32_t *) ids->data : nullptr;
654
+ float * dst_d = (float *) dst->data;
655
+
656
+ ggml_cuda_mm_fusion_args_device fusion_local{};
657
+
658
+ if (fusion) {
659
+ GGML_ASSERT( !ids || dst->ne[2] == 1);
660
+ GGML_ASSERT( ids || dst->ne[1] == 1);
661
+ if (fusion->x_bias) {
662
+ GGML_ASSERT(fusion->x_bias->type == GGML_TYPE_F32);
663
+ GGML_ASSERT(fusion->x_bias->ne[0] == dst->ne[0]);
664
+ GGML_ASSERT(!ids || fusion->x_bias->ne[1] == src0->ne[2]);
665
+ fusion_local.x_bias = fusion->x_bias->data;
666
+ }
667
+ if (fusion->gate) {
668
+ GGML_ASSERT(fusion->gate->type == src0->type && ggml_are_same_stride(fusion->gate, src0));
669
+ fusion_local.gate = fusion->gate->data;
670
+ }
671
+ if (fusion->gate_bias) {
672
+ GGML_ASSERT(fusion->gate_bias->type == GGML_TYPE_F32);
673
+ GGML_ASSERT(fusion->gate_bias->ne[0] == dst->ne[0]);
674
+ GGML_ASSERT(!ids || fusion->gate_bias->ne[1] == src0->ne[2]);
675
+ fusion_local.gate_bias = fusion->gate_bias->data;
676
+ }
677
+ fusion_local.glu_op = fusion->glu_op;
678
+ }
679
+
680
+ const int64_t s01 = src0->nb[1] / ts_src0;
681
+ const int64_t s11 = src1->nb[1] / ts_src1;
682
+ const int64_t s1 = dst->nb[1] / ts_dst;
683
+ const int64_t s02 = src0->nb[2] / ts_src0;
684
+ const int64_t s12 = src1->nb[2] / ts_src1;
685
+ const int64_t s2 = dst->nb[2] / ts_dst;
686
+ const int64_t s03 = src0->nb[3] / ts_src0;
687
+ const int64_t s13 = src1->nb[3] / ts_src1;
688
+ const int64_t s3 = dst->nb[3] / ts_dst;
689
+
690
+ // For MUL_MAT_ID the memory layout is different than for MUL_MAT:
691
+ const int64_t ncols_dst = ids ? ne2 : ne1;
692
+ const int64_t nchannels_y = ids ? ne11 : ne12;
693
+ const int64_t nchannels_dst = ids ? ne1 : ne2;
694
+ const int64_t stride_col_dst = ids ? s2 : s1;
695
+ const int64_t stride_col_y = ids ? s12 : s11;
696
+ const int64_t stride_channel_dst = ids ? s1 : s2;
697
+ const int64_t stride_channel_y = ids ? s11 : s12;
698
+
699
+ const int64_t ids_stride = ids ? ids->nb[1] / ggml_type_size(ids->type) : 0;
700
+
701
+ switch (src0->type) {
702
+ case GGML_TYPE_F32: {
703
+ const float * src0_d = (const float *) src0->data;
704
+ mul_mat_vec_f_cuda(src0_d, src1_d, ids_d, fusion_local, dst_d, ne00, ne01, ncols_dst, s01, stride_col_y, stride_col_dst,
705
+ ne02, nchannels_y, nchannels_dst, s02, stride_channel_y, stride_channel_dst,
706
+ ne03, ne3, s03, s13, s3, ids_stride, prec, ctx.stream());
707
+ } break;
708
+ case GGML_TYPE_F16: {
709
+ const half * src0_d = (const half *) src0->data;
710
+ mul_mat_vec_f_cuda(src0_d, src1_d, ids_d, fusion_local, dst_d, ne00, ne01, ncols_dst, s01, stride_col_y, stride_col_dst,
711
+ ne02, nchannels_y, nchannels_dst, s02, stride_channel_y, stride_channel_dst,
712
+ ne03, ne3, s03, s13, s3, ids_stride, prec, ctx.stream());
713
+ } break;
714
+ case GGML_TYPE_BF16: {
715
+ const nv_bfloat16 * src0_d = (const nv_bfloat16 *) src0->data;
716
+ mul_mat_vec_f_cuda(src0_d, src1_d, ids_d, fusion_local, dst_d, ne00, ne01, ncols_dst, s01, stride_col_y, stride_col_dst,
717
+ ne02, nchannels_y, nchannels_dst, s02, stride_channel_y, stride_channel_dst,
718
+ ne03, ne3, s03, s13, s3, ids_stride, prec, ctx.stream());
719
+ } break;
720
+ default:
721
+ GGML_ABORT("unsupported type: %s", ggml_type_name(src0->type));
722
+ }
723
+ }
724
+
725
+ void ggml_cuda_op_mul_mat_vec_f(
726
+ ggml_backend_cuda_context & ctx,
727
+ const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst, const char * src0_dd_i, const float * src1_ddf_i,
728
+ const char * src1_ddq_i, float * dst_dd_i, const int64_t row_low, const int64_t row_high, const int64_t src1_ncols,
729
+ const int64_t src1_padded_row_size, cudaStream_t stream) {
730
+
731
+ GGML_ASSERT(src1->type == GGML_TYPE_F32);
732
+ GGML_ASSERT(dst->type == GGML_TYPE_F32);
733
+
734
+ const int64_t ne00 = src0->ne[0];
735
+ const int64_t ne10 = src1->ne[0];
736
+ const int64_t ne0 = dst->ne[0];
737
+ const int64_t row_diff = row_high - row_low;
738
+
739
+ const int id = ggml_cuda_get_device();
740
+ const int cc = ggml_cuda_info().devices[id].cc;
741
+ const enum ggml_prec prec = fast_fp16_available(cc) ? ggml_prec(dst->op_params[0]) : GGML_PREC_F32;
742
+
743
+ // ggml_cuda_op provides single, contiguous matrices
744
+ const int64_t stride_row = ne00;
745
+ const int64_t stride_col_y = ne10;
746
+ const int64_t stride_col_dst = id == ctx.device ? ne0 : row_diff; // main device has larger memory buffer
747
+ const int64_t nchannels_x = 1;
748
+ const int64_t nchannels_y = 1;
749
+ const int64_t nchannels_dst = 1;
750
+ const int64_t stride_channel_x = 0;
751
+ const int64_t stride_channel_y = 0;
752
+ const int64_t stride_channel_dst = 0;
753
+ const int64_t nsamples_x = 1;
754
+ const int64_t nsamples_dst = 1;
755
+ const int64_t stride_sample_x = 0;
756
+ const int64_t stride_sample_y = 0;
757
+ const int64_t stride_sample_dst = 0;
758
+
759
+ ggml_cuda_mm_fusion_args_device empty{};
760
+ switch (src0->type) {
761
+ case GGML_TYPE_F32: {
762
+ const float * src0_d = (const float *) src0_dd_i;
763
+ mul_mat_vec_f_cuda(src0_d, src1_ddf_i, nullptr, empty, dst_dd_i, ne00, row_diff, src1_ncols, stride_row, stride_col_y, stride_col_dst,
764
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
765
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, 0, prec, stream);
766
+ } break;
767
+ case GGML_TYPE_F16: {
768
+ const half * src0_d = (const half *) src0_dd_i;
769
+ mul_mat_vec_f_cuda(src0_d, src1_ddf_i, nullptr, empty, dst_dd_i, ne00, row_diff, src1_ncols, stride_row, stride_col_y, stride_col_dst,
770
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
771
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, 0, prec, stream);
772
+ } break;
773
+ case GGML_TYPE_BF16: {
774
+ const nv_bfloat16 * src0_d = (const nv_bfloat16 *) src0_dd_i;
775
+ mul_mat_vec_f_cuda(src0_d, src1_ddf_i, nullptr, empty, dst_dd_i, ne00, row_diff, src1_ncols, stride_row, stride_col_y, stride_col_dst,
776
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
777
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, 0, prec, stream);
778
+ } break;
779
+ default:
780
+ GGML_ABORT("unsupported type: %s", ggml_type_name(src0->type));
781
+ }
782
+
783
+ GGML_UNUSED_VARS(ctx, src1, dst, src1_ddq_i, src1_ncols, src1_padded_row_size);
784
+ }
785
+
786
+ bool ggml_cuda_should_use_mmvf(enum ggml_type type, int cc, const int64_t * src0_ne, const size_t * src0_nb, int64_t ne11) {
787
+ if (src0_ne[0] % 2 != 0) {
788
+ return false;
789
+ }
790
+
791
+ const size_t ts = ggml_type_size(type);
792
+ if (src0_nb[0] != ts) {
793
+ return false;
794
+ }
795
+
796
+ // Pointers not aligned to the size of half2/nv_bfloat162/float2 would result in a crash:
797
+ for (size_t i = 1; i < GGML_MAX_DIMS; ++i) {
798
+ if (src0_nb[i] % (2*ts) != 0) {
799
+ return false;
800
+ }
801
+ }
802
+
803
+ switch (type) {
804
+ case GGML_TYPE_F32:
805
+ if (GGML_CUDA_CC_IS_NVIDIA(cc)) {
806
+ if (ampere_mma_available(cc)) {
807
+ return ne11 <= 3;
808
+ }
809
+ if (cc >= GGML_CUDA_CC_TURING) {
810
+ return ne11 <= 4;
811
+ }
812
+ return ne11 <= 3;
813
+ } else if (GGML_CUDA_CC_IS_AMD(cc)) {
814
+ if (fp32_mma_hardware_available(cc)) {
815
+ return ne11 <= 3;
816
+ }
817
+ return ne11 <= 8;
818
+ }
819
+ return ne11 <= 8;
820
+ case GGML_TYPE_F16:
821
+ if (GGML_CUDA_CC_IS_NVIDIA(cc)) {
822
+ const bool src0_small = (src0_ne[1] <= 512 || src0_ne[2]*src0_ne[3] == 1);
823
+ if (ampere_mma_available(cc)) {
824
+ return src0_small && ne11 == 1;
825
+ }
826
+ if (cc >= GGML_CUDA_CC_ADA_LOVELACE) {
827
+ return src0_small && ne11 <= 4;
828
+ }
829
+ if (fp16_mma_hardware_available(cc)) {
830
+ return src0_small && ne11 <= 3;
831
+ }
832
+ return ne11 <= 8;
833
+ } else if (GGML_CUDA_CC_IS_AMD(cc)) {
834
+ if (fp16_mma_hardware_available(cc)) {
835
+ if (GGML_CUDA_CC_IS_RDNA3(cc)) {
836
+ return ne11 <= 3;
837
+ }
838
+ if (GGML_CUDA_CC_IS_RDNA4(cc)) {
839
+ return ne11 <= 5;
840
+ }
841
+ return ne11 <= 2;
842
+ }
843
+ return ne11 <= 8;
844
+ }
845
+ return ne11 <= 8;
846
+ case GGML_TYPE_BF16:
847
+ if (GGML_CUDA_CC_IS_NVIDIA(cc)) {
848
+ const bool src0_small = (src0_ne[1] <= 512 || src0_ne[2]*src0_ne[3] == 1);
849
+ if (ampere_mma_available(cc)) {
850
+ return src0_small && ne11 == 1;
851
+ }
852
+ if (cc >= GGML_CUDA_CC_ADA_LOVELACE) {
853
+ return src0_small && ne11 <= 4;
854
+ }
855
+ if (bf16_mma_hardware_available(cc)) {
856
+ return src0_small && ne11 <= 3;
857
+ }
858
+ return ne11 <= 8;
859
+ } else if (GGML_CUDA_CC_IS_AMD(cc)) {
860
+ if (bf16_mma_hardware_available(cc)) {
861
+ return ne11 <= 3;
862
+ }
863
+ return ne11 <= 8;
864
+ }
865
+ return ne11 <= 8;
866
+ default:
867
+ return false;
868
+ }
869
+ }
backend/llama.cpp/ggml/src/ggml-cuda/mmvf.cuh ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ #define MMVF_MAX_BATCH_SIZE 8 // Max. batch size for which to use MMVF kernels.
4
+
5
+ void ggml_cuda_mul_mat_vec_f(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, const ggml_tensor * ids, ggml_tensor * dst,
6
+ const ggml_cuda_mm_fusion_args_host * fusion = nullptr);
7
+
8
+ void ggml_cuda_op_mul_mat_vec_f(
9
+ ggml_backend_cuda_context & ctx,
10
+ const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst, const char * src0_dd_i, const float * src1_ddf_i,
11
+ const char * src1_ddq_i, float * dst_dd_i, const int64_t row_low, const int64_t row_high, const int64_t src1_ncols,
12
+ const int64_t src1_padded_row_size, cudaStream_t stream);
13
+
14
+ bool ggml_cuda_should_use_mmvf(enum ggml_type type, int cc, const int64_t * src0_ne, const size_t * src0_nb, int64_t ne11);
backend/llama.cpp/ggml/src/ggml-cuda/mmvq.cu ADDED
@@ -0,0 +1,1289 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "mmvq.cuh"
2
+ #include "quantize.cuh"
3
+ #include "unary.cuh"
4
+ #include "vecdotq.cuh"
5
+
6
+ #include <cstdint>
7
+
8
+ typedef float (*vec_dot_q_cuda_t)(const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs);
9
+
10
+ static constexpr __device__ vec_dot_q_cuda_t get_vec_dot_q_cuda(ggml_type type) {
11
+ switch (type) {
12
+ case GGML_TYPE_Q1_0: return vec_dot_q1_0_q8_1;
13
+ case GGML_TYPE_Q4_0: return vec_dot_q4_0_q8_1;
14
+ case GGML_TYPE_Q4_1: return vec_dot_q4_1_q8_1;
15
+ case GGML_TYPE_Q5_0: return vec_dot_q5_0_q8_1;
16
+ case GGML_TYPE_Q5_1: return vec_dot_q5_1_q8_1;
17
+ case GGML_TYPE_Q8_0: return vec_dot_q8_0_q8_1;
18
+ case GGML_TYPE_MXFP4: return vec_dot_mxfp4_q8_1;
19
+ case GGML_TYPE_NVFP4: return vec_dot_nvfp4_q8_1;
20
+ case GGML_TYPE_Q2_K: return vec_dot_q2_K_q8_1;
21
+ case GGML_TYPE_Q3_K: return vec_dot_q3_K_q8_1;
22
+ case GGML_TYPE_Q4_K: return vec_dot_q4_K_q8_1;
23
+ case GGML_TYPE_Q5_K: return vec_dot_q5_K_q8_1;
24
+ case GGML_TYPE_Q6_K: return vec_dot_q6_K_q8_1;
25
+ case GGML_TYPE_IQ2_XXS: return vec_dot_iq2_xxs_q8_1;
26
+ case GGML_TYPE_IQ2_XS: return vec_dot_iq2_xs_q8_1;
27
+ case GGML_TYPE_IQ2_S: return vec_dot_iq2_s_q8_1;
28
+ case GGML_TYPE_IQ3_XXS: return vec_dot_iq3_xxs_q8_1;
29
+ case GGML_TYPE_IQ1_S: return vec_dot_iq1_s_q8_1;
30
+ case GGML_TYPE_IQ1_M: return vec_dot_iq1_m_q8_1;
31
+ case GGML_TYPE_IQ4_NL: return vec_dot_iq4_nl_q8_1;
32
+ case GGML_TYPE_IQ4_XS: return vec_dot_iq4_xs_q8_1;
33
+ case GGML_TYPE_IQ3_S: return vec_dot_iq3_s_q8_1;
34
+ default: return nullptr;
35
+ }
36
+ }
37
+
38
+ static constexpr __host__ __device__ int get_vdr_mmvq(ggml_type type) {
39
+ switch (type) {
40
+ case GGML_TYPE_Q1_0: return VDR_Q1_0_Q8_1_MMVQ;
41
+ case GGML_TYPE_Q4_0: return VDR_Q4_0_Q8_1_MMVQ;
42
+ case GGML_TYPE_Q4_1: return VDR_Q4_1_Q8_1_MMVQ;
43
+ case GGML_TYPE_Q5_0: return VDR_Q5_0_Q8_1_MMVQ;
44
+ case GGML_TYPE_Q5_1: return VDR_Q5_1_Q8_1_MMVQ;
45
+ case GGML_TYPE_Q8_0: return VDR_Q8_0_Q8_1_MMVQ;
46
+ case GGML_TYPE_MXFP4: return VDR_MXFP4_Q8_1_MMVQ;
47
+ case GGML_TYPE_NVFP4: return VDR_NVFP4_Q8_1_MMVQ;
48
+ case GGML_TYPE_Q2_K: return VDR_Q2_K_Q8_1_MMVQ;
49
+ case GGML_TYPE_Q3_K: return VDR_Q3_K_Q8_1_MMVQ;
50
+ case GGML_TYPE_Q4_K: return VDR_Q4_K_Q8_1_MMVQ;
51
+ case GGML_TYPE_Q5_K: return VDR_Q5_K_Q8_1_MMVQ;
52
+ case GGML_TYPE_Q6_K: return VDR_Q6_K_Q8_1_MMVQ;
53
+ case GGML_TYPE_IQ2_XXS: return VDR_IQ2_XXS_Q8_1_MMVQ;
54
+ case GGML_TYPE_IQ2_XS: return VDR_IQ2_XS_Q8_1_MMVQ;
55
+ case GGML_TYPE_IQ2_S: return VDR_IQ2_S_Q8_1_MMVQ;
56
+ case GGML_TYPE_IQ3_XXS: return VDR_IQ3_XXS_Q8_1_MMVQ;
57
+ case GGML_TYPE_IQ3_S: return VDR_IQ3_S_Q8_1_MMVQ;
58
+ case GGML_TYPE_IQ4_NL: return VDR_IQ4_NL_Q8_1_MMVQ;
59
+ case GGML_TYPE_IQ4_XS: return VDR_IQ4_XS_Q8_1_MMVQ;
60
+ default: return 1;
61
+ }
62
+ }
63
+
64
+ enum mmvq_parameter_table_id {
65
+ MMVQ_PARAMETERS_GENERIC = 0,
66
+ MMVQ_PARAMETERS_TURING,
67
+ MMVQ_PARAMETERS_GCN,
68
+ MMVQ_PARAMETERS_RDNA2,
69
+ MMVQ_PARAMETERS_RDNA3_0,
70
+ MMVQ_PARAMETERS_RDNA4
71
+ };
72
+
73
+ static constexpr __device__ mmvq_parameter_table_id get_device_table_id() {
74
+ #if defined(RDNA4)
75
+ return MMVQ_PARAMETERS_RDNA4;
76
+ #elif defined(RDNA3_0)
77
+ return MMVQ_PARAMETERS_RDNA3_0;
78
+ #elif defined(RDNA2) || defined(RDNA3_5)
79
+ return MMVQ_PARAMETERS_RDNA2;
80
+ #elif defined(GCN) || defined(CDNA)
81
+ return MMVQ_PARAMETERS_GCN;
82
+ #elif defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= GGML_CUDA_CC_TURING && __CUDA_ARCH__ < GGML_CUDA_CC_AMPERE
83
+ return MMVQ_PARAMETERS_TURING;
84
+ #else
85
+ return MMVQ_PARAMETERS_GENERIC;
86
+ #endif
87
+ }
88
+
89
+ static __host__ mmvq_parameter_table_id get_device_table_id(int cc) {
90
+ if (GGML_CUDA_CC_IS_RDNA4(cc)) {
91
+ return MMVQ_PARAMETERS_RDNA4;
92
+ }
93
+ if (GGML_CUDA_CC_IS_RDNA3_0(cc)) {
94
+ return MMVQ_PARAMETERS_RDNA3_0;
95
+ }
96
+ if (GGML_CUDA_CC_IS_RDNA2(cc) || GGML_CUDA_CC_IS_RDNA3_5(cc)) {
97
+ return MMVQ_PARAMETERS_RDNA2;
98
+ }
99
+ if (GGML_CUDA_CC_IS_GCN(cc) || GGML_CUDA_CC_IS_CDNA(cc)) {
100
+ return MMVQ_PARAMETERS_GCN;
101
+ }
102
+ if (GGML_CUDA_CC_IS_NVIDIA(cc) && ggml_cuda_highest_compiled_arch(cc) >= GGML_CUDA_CC_TURING && ggml_cuda_highest_compiled_arch(cc) < GGML_CUDA_CC_AMPERE) {
103
+ return MMVQ_PARAMETERS_TURING;
104
+ }
105
+ return MMVQ_PARAMETERS_GENERIC;
106
+ }
107
+
108
+ // Per-architecture maximum batch size for which MMVQ should be used for MUL_MAT_ID.
109
+ // Returns a value <= MMVQ_MAX_BATCH_SIZE. Default is MMVQ_MAX_BATCH_SIZE.
110
+ // Check https://github.com/ggml-org/llama.cpp/pull/20905#issuecomment-4145835627 for details
111
+
112
+ static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_pascal_older(ggml_type type) {
113
+ switch (type) {
114
+ case GGML_TYPE_IQ1_S: return 6;
115
+ case GGML_TYPE_IQ1_M: return 6;
116
+ case GGML_TYPE_IQ2_S: return 4;
117
+ case GGML_TYPE_IQ2_XS: return 5;
118
+ case GGML_TYPE_IQ2_XXS: return 5;
119
+ case GGML_TYPE_IQ3_S: return 4;
120
+ case GGML_TYPE_IQ3_XXS: return 4;
121
+ case GGML_TYPE_IQ4_NL: return 6;
122
+ case GGML_TYPE_IQ4_XS: return 5;
123
+ case GGML_TYPE_MXFP4: return 4;
124
+ case GGML_TYPE_NVFP4: return 4;
125
+ case GGML_TYPE_Q2_K: return 4;
126
+ case GGML_TYPE_Q3_K: return 4;
127
+ case GGML_TYPE_Q4_0: return 6;
128
+ case GGML_TYPE_Q4_1: return 6;
129
+ case GGML_TYPE_Q4_K: return 5;
130
+ case GGML_TYPE_Q5_0: return 6;
131
+ case GGML_TYPE_Q5_1: return 6;
132
+ case GGML_TYPE_Q5_K: return 5;
133
+ case GGML_TYPE_Q6_K: return 4;
134
+ case GGML_TYPE_Q8_0: return 4;
135
+ default: return MMVQ_MAX_BATCH_SIZE;
136
+ }
137
+ }
138
+
139
+ static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_turing_plus(ggml_type type) {
140
+ switch (type) {
141
+ case GGML_TYPE_IQ2_S: return 7;
142
+ case GGML_TYPE_IQ3_S: return 6;
143
+ case GGML_TYPE_IQ3_XXS: return 7;
144
+ case GGML_TYPE_MXFP4: return 7;
145
+ case GGML_TYPE_NVFP4: return 8;
146
+ case GGML_TYPE_Q2_K: return 7;
147
+ case GGML_TYPE_Q3_K: return 5;
148
+ default: return MMVQ_MAX_BATCH_SIZE;
149
+ }
150
+ }
151
+
152
+ static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_gcn(ggml_type type) {
153
+ switch (type) {
154
+ case GGML_TYPE_IQ1_S: return 5;
155
+ case GGML_TYPE_IQ1_M: return 5;
156
+ case GGML_TYPE_IQ2_S: return 4;
157
+ case GGML_TYPE_IQ2_XS: return 4;
158
+ case GGML_TYPE_IQ2_XXS: return 4;
159
+ case GGML_TYPE_IQ3_S: return 4;
160
+ case GGML_TYPE_IQ3_XXS: return 4;
161
+ case GGML_TYPE_IQ4_NL: return 6;
162
+ case GGML_TYPE_IQ4_XS: return 4;
163
+ case GGML_TYPE_Q2_K: return 4;
164
+ case GGML_TYPE_Q3_K: return 4;
165
+ case GGML_TYPE_Q4_0: return 5;
166
+ case GGML_TYPE_Q4_1: return 5;
167
+ case GGML_TYPE_Q4_K: return 4;
168
+ case GGML_TYPE_Q5_K: return 4;
169
+ case GGML_TYPE_Q6_K: return 4;
170
+ case GGML_TYPE_Q8_0: return 4;
171
+ default: return MMVQ_MAX_BATCH_SIZE;
172
+ }
173
+ }
174
+
175
+ static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_cdna(ggml_type type) {
176
+ switch (type) {
177
+ case GGML_TYPE_IQ2_S: return 5;
178
+ case GGML_TYPE_IQ2_XS: return 5;
179
+ case GGML_TYPE_IQ2_XXS: return 5;
180
+ case GGML_TYPE_IQ3_S: return 4;
181
+ case GGML_TYPE_IQ3_XXS: return 5;
182
+ default: return MMVQ_MAX_BATCH_SIZE;
183
+ }
184
+ }
185
+
186
+ static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_rdna1_rdna2(ggml_type type) {
187
+ switch (type) {
188
+ case GGML_TYPE_IQ2_S: return 4;
189
+ case GGML_TYPE_IQ2_XS: return 4;
190
+ case GGML_TYPE_IQ2_XXS: return 4;
191
+ case GGML_TYPE_IQ3_S: return 4;
192
+ case GGML_TYPE_IQ3_XXS: return 4;
193
+ case GGML_TYPE_Q2_K: return 7;
194
+ case GGML_TYPE_Q3_K: return 4;
195
+ case GGML_TYPE_Q4_K: return 5;
196
+ case GGML_TYPE_Q5_K: return 6;
197
+ case GGML_TYPE_Q6_K: return 5;
198
+ default: return MMVQ_MAX_BATCH_SIZE;
199
+ }
200
+ }
201
+
202
+ static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_rdna3(ggml_type type) {
203
+ switch (type) {
204
+ case GGML_TYPE_IQ1_S: return 6;
205
+ case GGML_TYPE_IQ1_M: return 6;
206
+ case GGML_TYPE_IQ2_S: return 4;
207
+ case GGML_TYPE_IQ2_XS: return 4;
208
+ case GGML_TYPE_IQ2_XXS: return 4;
209
+ case GGML_TYPE_IQ3_S: return 4;
210
+ case GGML_TYPE_IQ3_XXS: return 4;
211
+ case GGML_TYPE_IQ4_NL: return 6;
212
+ case GGML_TYPE_IQ4_XS: return 6;
213
+ case GGML_TYPE_Q4_K: return 4;
214
+ case GGML_TYPE_Q5_K: return 4;
215
+ case GGML_TYPE_Q6_K: return 4;
216
+ default: return MMVQ_MAX_BATCH_SIZE;
217
+ }
218
+ }
219
+
220
+ static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_rdna4(ggml_type type) {
221
+ switch (type) {
222
+ case GGML_TYPE_IQ1_S: return 7;
223
+ case GGML_TYPE_IQ1_M: return 7;
224
+ case GGML_TYPE_IQ2_S: return 4;
225
+ case GGML_TYPE_IQ2_XS: return 4;
226
+ case GGML_TYPE_IQ2_XXS: return 4;
227
+ case GGML_TYPE_IQ3_S: return 4;
228
+ case GGML_TYPE_IQ3_XXS: return 4;
229
+ case GGML_TYPE_IQ4_NL: return 7;
230
+ case GGML_TYPE_IQ4_XS: return 5;
231
+ case GGML_TYPE_MXFP4: return 5;
232
+ case GGML_TYPE_NVFP4: return 5;
233
+ case GGML_TYPE_Q3_K: return 4;
234
+ case GGML_TYPE_Q4_0: return 7;
235
+ case GGML_TYPE_Q4_1: return 7;
236
+ case GGML_TYPE_Q4_K: return 4;
237
+ case GGML_TYPE_Q5_0: return 7;
238
+ case GGML_TYPE_Q5_1: return 7;
239
+ case GGML_TYPE_Q5_K: return 5;
240
+ case GGML_TYPE_Q6_K: return 5;
241
+ case GGML_TYPE_Q8_0: return 7;
242
+ default: return MMVQ_MAX_BATCH_SIZE;
243
+ }
244
+ }
245
+
246
+ // Host function: returns the max batch size for the current arch+type at runtime.
247
+ int get_mmvq_mmid_max_batch(ggml_type type, int cc) {
248
+ // NVIDIA: Volta, Ada Lovelace, and Blackwell always use MMVQ for MUL_MAT_ID.
249
+ if (GGML_CUDA_CC_IS_NVIDIA(cc)) {
250
+ if (cc == GGML_CUDA_CC_VOLTA || cc >= GGML_CUDA_CC_ADA_LOVELACE) {
251
+ return MMVQ_MAX_BATCH_SIZE;
252
+ }
253
+ if (cc >= GGML_CUDA_CC_TURING) {
254
+ return get_mmvq_mmid_max_batch_turing_plus(type);
255
+ }
256
+ return get_mmvq_mmid_max_batch_pascal_older(type);
257
+ }
258
+
259
+ // AMD
260
+ if (GGML_CUDA_CC_IS_AMD(cc)) {
261
+ if (GGML_CUDA_CC_IS_RDNA4(cc)) {
262
+ return get_mmvq_mmid_max_batch_rdna4(type);
263
+ }
264
+ if (GGML_CUDA_CC_IS_RDNA3(cc)) {
265
+ return get_mmvq_mmid_max_batch_rdna3(type);
266
+ }
267
+ if (GGML_CUDA_CC_IS_RDNA1(cc) || GGML_CUDA_CC_IS_RDNA2(cc)) {
268
+ return get_mmvq_mmid_max_batch_rdna1_rdna2(type);
269
+ }
270
+ if (GGML_CUDA_CC_IS_CDNA(cc)) {
271
+ return get_mmvq_mmid_max_batch_cdna(type);
272
+ }
273
+ if (GGML_CUDA_CC_IS_GCN(cc)) {
274
+ return get_mmvq_mmid_max_batch_gcn(type);
275
+ }
276
+ }
277
+ return MMVQ_MAX_BATCH_SIZE;
278
+ }
279
+
280
+ bool ggml_cuda_should_use_mmvq(enum ggml_type type, int cc, int64_t ne11) {
281
+ if (!ggml_is_quantized(type)) {
282
+ return false;
283
+ }
284
+ if (GGML_CUDA_CC_IS_CDNA(cc)) {
285
+ if (GGML_CUDA_CC_IS_CDNA1(cc)) {
286
+ switch (type) {
287
+ case GGML_TYPE_Q4_0:
288
+ case GGML_TYPE_Q4_1:
289
+ return ne11 <= 7;
290
+ case GGML_TYPE_Q5_1:
291
+ return ne11 <= 7;
292
+ case GGML_TYPE_Q8_0:
293
+ return ne11 <= 6;
294
+ case GGML_TYPE_Q2_K:
295
+ return ne11 <= 4;
296
+ case GGML_TYPE_Q3_K:
297
+ return ne11 <= 3;
298
+ case GGML_TYPE_Q4_K:
299
+ return ne11 <= 2;
300
+ case GGML_TYPE_Q5_K:
301
+ return ne11 <= 3;
302
+ case GGML_TYPE_Q6_K:
303
+ return ne11 <= 4;
304
+ case GGML_TYPE_IQ1_S:
305
+ return ne11 <= 5;
306
+ case GGML_TYPE_IQ2_XXS:
307
+ case GGML_TYPE_IQ3_S:
308
+ case GGML_TYPE_IQ4_XS:
309
+ return ne11 <= 6;
310
+ default:
311
+ return ne11 <= MMVQ_MAX_BATCH_SIZE;
312
+ }
313
+ }
314
+ switch (type) { // tuned for CDNA2
315
+ case GGML_TYPE_Q2_K:
316
+ return ne11 <= 5;
317
+ case GGML_TYPE_Q3_K:
318
+ case GGML_TYPE_Q4_K:
319
+ case GGML_TYPE_Q5_K:
320
+ return ne11 <= 3;
321
+ case GGML_TYPE_Q6_K:
322
+ return ne11 <= 5;
323
+ default:
324
+ return ne11 <= MMVQ_MAX_BATCH_SIZE;
325
+ }
326
+ }
327
+ return ne11 <= MMVQ_MAX_BATCH_SIZE;
328
+ }
329
+
330
+ // Device constexpr: returns the max batch size for the current arch+type at compile time.
331
+ template <ggml_type type>
332
+ static constexpr __device__ int get_mmvq_mmid_max_batch_for_device() {
333
+ #if defined(RDNA4)
334
+ return get_mmvq_mmid_max_batch_rdna4(type);
335
+ #elif defined(RDNA3)
336
+ return get_mmvq_mmid_max_batch_rdna3(type);
337
+ #elif defined(RDNA2) || defined(RDNA1)
338
+ return get_mmvq_mmid_max_batch_rdna1_rdna2(type);
339
+ #elif defined(CDNA)
340
+ return get_mmvq_mmid_max_batch_cdna(type);
341
+ #elif defined(GCN)
342
+ return get_mmvq_mmid_max_batch_gcn(type);
343
+ #elif defined(__CUDA_ARCH__) && (__CUDA_ARCH__ == GGML_CUDA_CC_VOLTA || __CUDA_ARCH__ >= GGML_CUDA_CC_ADA_LOVELACE)
344
+ return MMVQ_MAX_BATCH_SIZE;
345
+ #elif defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= GGML_CUDA_CC_TURING
346
+ return get_mmvq_mmid_max_batch_turing_plus(type);
347
+ #else
348
+ return get_mmvq_mmid_max_batch_pascal_older(type);
349
+ #endif
350
+ }
351
+
352
+ static constexpr __host__ __device__ int calc_nwarps(ggml_type type, int ncols_dst, mmvq_parameter_table_id table_id) {
353
+ if (table_id == MMVQ_PARAMETERS_GENERIC) {
354
+ switch (ncols_dst) {
355
+ case 1:
356
+ case 2:
357
+ case 3:
358
+ case 4:
359
+ return 4;
360
+ case 5:
361
+ case 6:
362
+ case 7:
363
+ case 8:
364
+ return 2;
365
+ default:
366
+ return 1;
367
+ }
368
+ } else if (table_id == MMVQ_PARAMETERS_GCN) {
369
+ switch (ncols_dst) {
370
+ case 1:
371
+ case 2:
372
+ case 3:
373
+ case 4:
374
+ return 2;
375
+ case 5:
376
+ case 6:
377
+ case 7:
378
+ case 8:
379
+ default:
380
+ return 1;
381
+ }
382
+ }
383
+ if (table_id == MMVQ_PARAMETERS_RDNA4) {
384
+ // nwarps=8 benefits types with simple vec_dot on RDNA4 (ncols_dst=1).
385
+ // Types with complex vec_dot (Q3_K, IQ2_*, IQ3_*) regress due to register
386
+ // pressure and lookup table contention at higher thread counts.
387
+ if (ncols_dst == 1) {
388
+ switch (type) {
389
+ case GGML_TYPE_Q4_0:
390
+ case GGML_TYPE_Q4_1:
391
+ case GGML_TYPE_Q5_0:
392
+ case GGML_TYPE_Q5_1:
393
+ case GGML_TYPE_Q8_0:
394
+ case GGML_TYPE_Q2_K:
395
+ case GGML_TYPE_Q4_K:
396
+ case GGML_TYPE_Q5_K:
397
+ case GGML_TYPE_Q6_K:
398
+ case GGML_TYPE_IQ4_NL:
399
+ case GGML_TYPE_IQ4_XS:
400
+ return 8;
401
+ default:
402
+ return 1;
403
+ }
404
+ }
405
+ return 1;
406
+ }
407
+ if (table_id == MMVQ_PARAMETERS_RDNA3_0) {
408
+ // RDNA3 (W7900): stricter whitelist than RDNA4.
409
+ // Q2_K / Q5_K / IQ4_XS regress in full quant sweeps.
410
+ if (ncols_dst == 1) {
411
+ switch (type) {
412
+ case GGML_TYPE_Q4_0:
413
+ case GGML_TYPE_Q4_1:
414
+ case GGML_TYPE_Q5_0:
415
+ case GGML_TYPE_Q5_1:
416
+ case GGML_TYPE_Q8_0:
417
+ return 8;
418
+ case GGML_TYPE_Q6_K:
419
+ return 2;
420
+ case GGML_TYPE_IQ4_NL:
421
+ return 8;
422
+ default:
423
+ return 1;
424
+ }
425
+ }
426
+ return 1;
427
+ }
428
+ if (table_id == MMVQ_PARAMETERS_TURING) {
429
+ if (ncols_dst == 1) {
430
+ switch (type) {
431
+ case GGML_TYPE_Q2_K:
432
+ case GGML_TYPE_Q3_K:
433
+ case GGML_TYPE_Q4_K:
434
+ case GGML_TYPE_Q5_K:
435
+ case GGML_TYPE_Q6_K:
436
+ return 2;
437
+ default:
438
+ return 4;
439
+ }
440
+ }
441
+ switch (ncols_dst) {
442
+ case 2:
443
+ case 3:
444
+ case 4:
445
+ return 4;
446
+ case 5:
447
+ case 6:
448
+ case 7:
449
+ case 8:
450
+ return 2;
451
+ default:
452
+ return 1;
453
+ }
454
+ }
455
+ return 1;
456
+ }
457
+
458
+ static constexpr __host__ __device__ int calc_rows_per_block(int ncols_dst, int table_id, bool small_k = false, int nwarps = 1) {
459
+ if (table_id == MMVQ_PARAMETERS_GENERIC || table_id == MMVQ_PARAMETERS_GCN || table_id == MMVQ_PARAMETERS_TURING) {
460
+ switch (ncols_dst) {
461
+ case 1:
462
+ return small_k ? nwarps : 1;
463
+ case 2:
464
+ case 3:
465
+ case 4:
466
+ case 5:
467
+ case 6:
468
+ case 7:
469
+ case 8:
470
+ return 2;
471
+ default:
472
+ return 1;
473
+ }
474
+ }
475
+ return 1;
476
+ }
477
+
478
+ template <ggml_type type, int ncols_dst, bool has_fusion, bool small_k = false>
479
+ __launch_bounds__(calc_nwarps(type, ncols_dst, get_device_table_id())*ggml_cuda_get_physical_warp_size(), 1)
480
+ static __global__ void mul_mat_vec_q(
481
+ const void * vx_ptr, const void * vy_ptr, const int32_t * ids_ptr, const ggml_cuda_mm_fusion_args_device fusion, float * dst_ptr,
482
+ const uint32_t ncols_x, const uint3 nchannels_y, const uint32_t stride_row_x, const uint32_t stride_col_y,
483
+ const uint32_t stride_col_dst, const uint3 channel_ratio, const uint32_t stride_channel_x,
484
+ const uint32_t stride_channel_y, const uint32_t stride_channel_dst, const uint3 sample_ratio,
485
+ const uint32_t stride_sample_x, const uint32_t stride_sample_y, const uint32_t stride_sample_dst,
486
+ const uint32_t ids_stride) {
487
+ const void * GGML_CUDA_RESTRICT vx = vx_ptr;
488
+ const void * GGML_CUDA_RESTRICT vy = vy_ptr;
489
+ const int32_t * GGML_CUDA_RESTRICT ids = ids_ptr;
490
+ float * GGML_CUDA_RESTRICT dst = dst_ptr;
491
+
492
+ constexpr int qk = ggml_cuda_type_traits<type>::qk;
493
+ constexpr int qi = ggml_cuda_type_traits<type>::qi;
494
+ constexpr int vdr = get_vdr_mmvq(type);
495
+ constexpr mmvq_parameter_table_id table_id = get_device_table_id();
496
+ constexpr int nwarps = calc_nwarps(type, ncols_dst, table_id);
497
+ constexpr int rows_per_cuda_block = calc_rows_per_block(ncols_dst, table_id, small_k, nwarps);
498
+ constexpr int warp_size = ggml_cuda_get_physical_warp_size();
499
+
500
+ constexpr vec_dot_q_cuda_t vec_dot_q_cuda = get_vec_dot_q_cuda(type);
501
+
502
+ const int tid = warp_size*threadIdx.y + threadIdx.x;
503
+ const int row0 = rows_per_cuda_block*blockIdx.x;
504
+ const int blocks_per_row_x = ncols_x / qk;
505
+ constexpr int blocks_per_iter = vdr * nwarps*warp_size / qi;
506
+
507
+ const uint32_t channel_dst = blockIdx.y;
508
+
509
+ uint32_t channel_x;
510
+ uint32_t channel_y;
511
+ uint32_t sample_dst;
512
+
513
+ ggml_cuda_pdl_sync();
514
+ channel_x = ncols_dst == 1 && ids ? ids[channel_dst] : fastdiv(channel_dst, channel_ratio);
515
+ channel_y = ncols_dst == 1 && ids ? fastmodulo(channel_dst, nchannels_y) : channel_dst;
516
+ sample_dst = blockIdx.z;
517
+
518
+ const uint32_t sample_x = fastdiv(sample_dst, sample_ratio);
519
+ const uint32_t sample_y = sample_dst;
520
+
521
+ bool use_gate = false;
522
+ bool use_bias = false;
523
+ bool use_gate_bias = false;
524
+ bool use_scale = false;
525
+ bool use_gate_scale = false;
526
+ [[maybe_unused]] const void * vgate = nullptr;
527
+ const float * x_bias = nullptr;
528
+ const float * gate_bias = nullptr;
529
+ const float * x_scale = nullptr;
530
+ const float * gate_scale = nullptr;
531
+ ggml_glu_op active_glu;
532
+
533
+ if constexpr (has_fusion) {
534
+ use_gate = fusion.gate != nullptr;
535
+ use_bias = fusion.x_bias != nullptr;
536
+ use_gate_bias = fusion.gate_bias != nullptr && use_gate;
537
+ vgate = fusion.gate;
538
+ x_bias = (const float *) fusion.x_bias;
539
+ gate_bias = (const float *) fusion.gate_bias;
540
+ active_glu = fusion.glu_op;
541
+ if constexpr (type == GGML_TYPE_NVFP4) {
542
+ use_scale = fusion.x_scale != nullptr;
543
+ use_gate_scale = fusion.gate_scale != nullptr && use_gate;
544
+ x_scale = (const float *) fusion.x_scale;
545
+ gate_scale = (const float *) fusion.gate_scale;
546
+ }
547
+ }
548
+
549
+
550
+ [[maybe_unused]] float x_biases[ncols_dst] = { 0.0f };
551
+ [[maybe_unused]] float gate_biases[ncols_dst] = { 0.0f };
552
+ [[maybe_unused]] float x_scales = 1.0f;
553
+ [[maybe_unused]] float gate_scales = 1.0f;
554
+ if constexpr (has_fusion) {
555
+ // 1. Hide latency by prefetching bias, gates and scales here
556
+ // 2. load only on threads that won't die after partial sum calculation
557
+ const uint32_t channel_bias = ids ? channel_x : channel_dst;
558
+ if (threadIdx.x < rows_per_cuda_block && threadIdx.y == 0 &&
559
+ (rows_per_cuda_block == 1 || uint32_t(row0 + threadIdx.x) < stride_col_dst)) {
560
+ if (use_bias) {
561
+ x_bias = x_bias + sample_dst * stride_sample_dst + channel_bias * stride_channel_dst + row0;
562
+ #pragma unroll
563
+ for (int j = 0; j < ncols_dst; ++j) {
564
+ x_biases[j] = x_bias[j * stride_col_dst + threadIdx.x];
565
+ }
566
+ }
567
+ if (use_gate_bias) {
568
+ gate_bias = gate_bias + sample_dst * stride_sample_dst + channel_bias * stride_channel_dst + row0;
569
+ #pragma unroll
570
+ for (int j = 0; j < ncols_dst; ++j) {
571
+ gate_biases[j] = gate_bias[j * stride_col_dst + threadIdx.x];
572
+ }
573
+ }
574
+ if constexpr (type == GGML_TYPE_NVFP4) {
575
+ if (use_scale) {
576
+ x_scales = x_scale[ids ? channel_x : 0];
577
+ }
578
+ if (use_gate_scale) {
579
+ gate_scales = gate_scale[ids ? channel_x : 0];
580
+ }
581
+ }
582
+ }
583
+ }
584
+
585
+ // partial sum for each thread
586
+ float tmp[ncols_dst][rows_per_cuda_block] = {{0.0f}};
587
+ float tmp_gate[ncols_dst][rows_per_cuda_block] = {{0.0f}};
588
+
589
+ const block_q8_1 * y = ((const block_q8_1 *) vy) + sample_y*stride_sample_y + channel_y*stride_channel_y;
590
+ const int kbx_offset = sample_x*stride_sample_x + channel_x*stride_channel_x + row0*stride_row_x;
591
+
592
+ for (int kbx = tid / (qi/vdr); kbx < blocks_per_row_x; kbx += blocks_per_iter) {
593
+ const int kby = kbx * (qk/QK8_1); // y block index that aligns with kbx
594
+
595
+ // x block quant index when casting the quants to int
596
+ const int kqs = vdr * (tid % (qi/vdr));
597
+
598
+ #pragma unroll
599
+ for (int j = 0; j < ncols_dst; ++j) {
600
+ #pragma unroll
601
+ for (int i = 0; i < rows_per_cuda_block; ++i) {
602
+ tmp[j][i] += vec_dot_q_cuda(
603
+ vx, &y[j*stride_col_y + kby], kbx_offset + i*stride_row_x + kbx, kqs);
604
+ if constexpr (has_fusion) {
605
+ if (use_gate) {
606
+ tmp_gate[j][i] += vec_dot_q_cuda(
607
+ vgate, &y[j*stride_col_y + kby], kbx_offset + i*stride_row_x + kbx, kqs);
608
+ }
609
+ }
610
+ }
611
+ }
612
+ }
613
+
614
+ __shared__ float tmp_shared[nwarps-1 > 0 ? nwarps-1 : 1][ncols_dst][rows_per_cuda_block][warp_size];
615
+ [[maybe_unused]] __shared__ float tmp_shared_gate[(has_fusion && (nwarps-1 > 0)) ? nwarps-1 : 1][ncols_dst][rows_per_cuda_block][warp_size];
616
+
617
+ if (threadIdx.y > 0) {
618
+ #pragma unroll
619
+ for (int j = 0; j < ncols_dst; ++j) {
620
+ #pragma unroll
621
+ for (int i = 0; i < rows_per_cuda_block; ++i) {
622
+ tmp_shared[threadIdx.y-1][j][i][threadIdx.x] = tmp[j][i];
623
+ if constexpr (has_fusion) {
624
+ if (use_gate) {
625
+ tmp_shared_gate[threadIdx.y-1][j][i][threadIdx.x] = tmp_gate[j][i];
626
+ }
627
+ }
628
+ }
629
+ }
630
+ }
631
+ __syncthreads();
632
+ if (threadIdx.y > 0) {
633
+ return;
634
+ }
635
+
636
+ dst += sample_dst*stride_sample_dst + channel_dst*stride_channel_dst + row0;
637
+
638
+ // sum up partial sums and write back result
639
+ #pragma unroll
640
+ for (int j = 0; j < ncols_dst; ++j) {
641
+ #pragma unroll
642
+ for (int i = 0; i < rows_per_cuda_block; ++i) {
643
+ #pragma unroll
644
+ for (int l = 0; l < nwarps-1; ++l) {
645
+ tmp[j][i] += tmp_shared[l][j][i][threadIdx.x];
646
+ if constexpr (has_fusion) {
647
+ if (use_gate) {
648
+ tmp_gate[j][i] += tmp_shared_gate[l][j][i][threadIdx.x];
649
+ }
650
+ }
651
+ }
652
+ tmp[j][i] = warp_reduce_sum<warp_size>(tmp[j][i]);
653
+ if constexpr (has_fusion) {
654
+ if (use_gate) {
655
+ tmp_gate[j][i] = warp_reduce_sum<warp_size>(tmp_gate[j][i]);
656
+ }
657
+ }
658
+
659
+ if (threadIdx.x == i && (rows_per_cuda_block == 1 || uint32_t(row0 + i) < stride_col_dst)) {
660
+ float result = tmp[j][i];
661
+ if constexpr (has_fusion) {
662
+ if constexpr (type == GGML_TYPE_NVFP4) {
663
+ result *= x_scales;
664
+ }
665
+ result += x_biases[j];
666
+ if (use_gate) {
667
+ float gate_value = tmp_gate[j][i];
668
+ if constexpr (type == GGML_TYPE_NVFP4) {
669
+ gate_value *= gate_scales;
670
+ }
671
+ gate_value += gate_biases[j];
672
+ switch (active_glu) {
673
+ case GGML_GLU_OP_SWIGLU:
674
+ result *= ggml_cuda_op_silu_single(gate_value);
675
+ break;
676
+ case GGML_GLU_OP_GEGLU:
677
+ result *= ggml_cuda_op_gelu_single(gate_value);
678
+ break;
679
+ case GGML_GLU_OP_SWIGLU_OAI:
680
+ result = ggml_cuda_op_swiglu_oai_single(gate_value, result);
681
+ break;
682
+ default:
683
+ result = result * gate_value;
684
+ break;
685
+ }
686
+ }
687
+ }
688
+ dst[j*stride_col_dst + i] = result;
689
+ }
690
+ }
691
+ }
692
+
693
+ if constexpr (!has_fusion) {
694
+ GGML_UNUSED_VARS(use_gate, use_bias, use_gate_bias, use_scale, use_gate_scale, active_glu, gate_bias, x_bias, x_scale, gate_scale, tmp_gate);
695
+ }
696
+ if constexpr (type != GGML_TYPE_NVFP4) {
697
+ GGML_UNUSED_VARS(use_scale, use_gate_scale, x_scale, gate_scale, x_scales, gate_scales);
698
+ }
699
+ }
700
+
701
+ // Dedicated MoE multi-token kernel.
702
+ // Grid: (ceil(nrows_x / c_rows_per_block), nchannels_dst)
703
+ // Block: (warp_size, ncols_dst) - each warp handles one token independently.
704
+ // No shared memory reduction needed since each warp works alone.
705
+ template <ggml_type type, int c_rows_per_block>
706
+ __launch_bounds__(get_mmvq_mmid_max_batch_for_device<type>()*ggml_cuda_get_physical_warp_size(), 1)
707
+ static __global__ void mul_mat_vec_q_moe(
708
+ const void * vx_ptr, const void * vy_ptr, const int32_t * ids_ptr,
709
+ float * dst_ptr,
710
+ const uint32_t ncols_x, const uint3 nchannels_y, const uint32_t nrows_x,
711
+ const uint32_t stride_row_x, const uint32_t stride_col_y, const uint32_t stride_col_dst,
712
+ const uint32_t stride_channel_x, const uint32_t stride_channel_y, const uint32_t stride_channel_dst,
713
+ const uint32_t ncols_dst, const uint32_t ids_stride) {
714
+ const void * GGML_CUDA_RESTRICT vx = vx_ptr;
715
+ const void * GGML_CUDA_RESTRICT vy = vy_ptr;
716
+ const int32_t * GGML_CUDA_RESTRICT ids = ids_ptr;
717
+ float * GGML_CUDA_RESTRICT dst = dst_ptr;
718
+
719
+ constexpr int qk = ggml_cuda_type_traits<type>::qk;
720
+ constexpr int qi = ggml_cuda_type_traits<type>::qi;
721
+ constexpr int vdr = get_vdr_mmvq(type);
722
+ constexpr int warp_size = ggml_cuda_get_physical_warp_size();
723
+
724
+ constexpr vec_dot_q_cuda_t vec_dot_q_cuda = get_vec_dot_q_cuda(type);
725
+
726
+ const uint32_t token_idx = threadIdx.y;
727
+ const int row0 = c_rows_per_block*blockIdx.x;
728
+ const int blocks_per_row_x = ncols_x / qk;
729
+ constexpr int blocks_per_iter = vdr * warp_size / qi;
730
+
731
+ const uint32_t channel_dst = blockIdx.y;
732
+
733
+ if (token_idx >= ncols_dst) {
734
+ return;
735
+ }
736
+
737
+ ggml_cuda_pdl_sync();
738
+ const uint32_t channel_x = ids[channel_dst + token_idx * ids_stride];
739
+ const uint32_t channel_y = fastmodulo(channel_dst, nchannels_y);
740
+
741
+ const block_q8_1 * y = ((const block_q8_1 *) vy) + channel_y*stride_channel_y + token_idx*stride_col_y;
742
+ const int kbx_offset = channel_x*stride_channel_x + row0*stride_row_x;
743
+
744
+ // partial sum for each thread
745
+ float tmp[c_rows_per_block] = {0.0f};
746
+
747
+ for (int kbx = threadIdx.x / (qi/vdr); kbx < blocks_per_row_x; kbx += blocks_per_iter) {
748
+ const int kby = kbx * (qk/QK8_1);
749
+ const int kqs = vdr * (threadIdx.x % (qi/vdr));
750
+
751
+ #pragma unroll
752
+ for (int i = 0; i < c_rows_per_block; ++i) {
753
+ tmp[i] += vec_dot_q_cuda(vx, &y[kby], kbx_offset + i*stride_row_x + kbx, kqs);
754
+ }
755
+ }
756
+
757
+ ggml_cuda_pdl_lc();
758
+
759
+ // Warp-level reduction only - no shared memory needed
760
+ #pragma unroll
761
+ for (int i = 0; i < c_rows_per_block; ++i) {
762
+ tmp[i] = warp_reduce_sum<warp_size>(tmp[i]);
763
+ }
764
+
765
+ // Write results
766
+ if (threadIdx.x < c_rows_per_block && (c_rows_per_block == 1 || uint32_t(row0 + threadIdx.x) < nrows_x)) {
767
+ dst[channel_dst*stride_channel_dst + token_idx*stride_col_dst + row0 + threadIdx.x] = tmp[threadIdx.x];
768
+ }
769
+ }
770
+
771
+ template<ggml_type type>
772
+ static std::pair<dim3, dim3> calc_launch_params(
773
+ const int ncols_dst, const int nrows_x, const int nchannels_dst, const int nsamples_or_ntokens,
774
+ const int warp_size, const mmvq_parameter_table_id table_id, const bool small_k = false) {
775
+ const int nwarps = calc_nwarps(type, ncols_dst, table_id);
776
+ const int rpb = calc_rows_per_block(ncols_dst, table_id, small_k, nwarps);
777
+ const int64_t nblocks = (nrows_x + rpb - 1) / rpb;
778
+ const dim3 block_nums(nblocks, nchannels_dst, nsamples_or_ntokens);
779
+ const dim3 block_dims(warp_size, nwarps, 1);
780
+ return {block_nums, block_dims};
781
+ }
782
+
783
+ template<ggml_type type, int c_ncols_dst, bool small_k = false>
784
+ static void mul_mat_vec_q_switch_fusion(
785
+ const void * vx, const void * vy, const int32_t * ids, const ggml_cuda_mm_fusion_args_device fusion, float * dst,
786
+ const uint32_t ncols_x, const uint3 nchannels_y, const uint32_t stride_row_x, const uint32_t stride_col_y,
787
+ const uint32_t stride_col_dst, const uint3 channel_ratio, const uint32_t stride_channel_x,
788
+ const uint32_t stride_channel_y, const uint32_t stride_channel_dst, const uint3 sample_ratio,
789
+ const uint32_t stride_sample_x, const uint32_t stride_sample_y, const uint32_t stride_sample_dst,
790
+ const dim3 & block_nums, const dim3 & block_dims, const int nbytes_shared,
791
+ const uint32_t ids_stride, cudaStream_t stream) {
792
+
793
+ const bool has_fusion = fusion.gate != nullptr || fusion.x_bias != nullptr || fusion.gate_bias != nullptr ||
794
+ fusion.x_scale != nullptr || fusion.gate_scale != nullptr;
795
+ if constexpr (c_ncols_dst == 1) {
796
+ if (has_fusion) {
797
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(block_nums, block_dims, nbytes_shared, stream);
798
+ ggml_cuda_kernel_launch(mul_mat_vec_q<type, c_ncols_dst, true, small_k>, launch_params,
799
+ vx, vy, ids, fusion, dst, ncols_x, nchannels_y, stride_row_x, stride_col_y, stride_col_dst,
800
+ channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
801
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride);
802
+ return;
803
+ }
804
+ }
805
+
806
+ GGML_ASSERT(!has_fusion && "fusion only supported for ncols_dst=1");
807
+
808
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(block_nums, block_dims, nbytes_shared, stream);
809
+ ggml_cuda_kernel_launch(mul_mat_vec_q<type, c_ncols_dst, false, small_k>, launch_params,
810
+ vx, vy, ids, fusion, dst, ncols_x, nchannels_y, stride_row_x, stride_col_y, stride_col_dst,
811
+ channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst,
812
+ sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride);
813
+ }
814
+
815
+ template <ggml_type type>
816
+ static void mul_mat_vec_q_moe_launch(
817
+ const void * vx, const void * vy, const int32_t * ids, float * dst,
818
+ const uint32_t ncols_x, const uint3 nchannels_y, const uint32_t nrows_x,
819
+ const uint32_t stride_row_x, const uint32_t stride_col_y, const uint32_t stride_col_dst,
820
+ const uint32_t stride_channel_x, const uint32_t stride_channel_y, const uint32_t stride_channel_dst,
821
+ const uint32_t ncols_dst, const uint32_t ids_stride,
822
+ const int warp_size, const int nchannels_dst, cudaStream_t stream) {
823
+
824
+ constexpr int rows_per_block = 2; // 2 gives best perf based on tuning
825
+ const int64_t nblocks_rows = (nrows_x + rows_per_block - 1) / rows_per_block;
826
+ const dim3 block_nums(nblocks_rows, nchannels_dst);
827
+ const dim3 block_dims(warp_size, ncols_dst);
828
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(block_nums, block_dims, 0, stream);
829
+
830
+ ggml_cuda_kernel_launch(mul_mat_vec_q_moe<type, rows_per_block>, launch_params,
831
+ vx, vy, ids, dst, ncols_x, nchannels_y, nrows_x,
832
+ stride_row_x, stride_col_y, stride_col_dst,
833
+ stride_channel_x, stride_channel_y, stride_channel_dst,
834
+ ncols_dst, ids_stride);
835
+ }
836
+
837
+ template <ggml_type type>
838
+ static void mul_mat_vec_q_switch_ncols_dst(
839
+ const void * vx, const void * vy, const int32_t * ids, const ggml_cuda_mm_fusion_args_device fusion, float * dst,
840
+ const int ncols_x, const int nrows_x, const int ncols_dst,
841
+ const int stride_row_x, const int stride_col_y, const int stride_col_dst,
842
+ const int nchannels_x, const int nchannels_y, const int nchannels_dst,
843
+ const int stride_channel_x, const int stride_channel_y, const int stride_channel_dst,
844
+ const int nsamples_x, const int nsamples_dst, const int stride_sample_x, const int stride_sample_y, const int stride_sample_dst,
845
+ const int ids_stride, cudaStream_t stream) {
846
+
847
+ GGML_ASSERT(ncols_x % ggml_blck_size(type) == 0);
848
+ GGML_ASSERT(ncols_dst <= MMVQ_MAX_BATCH_SIZE);
849
+
850
+ const uint3 nchannels_y_fd = ids ? init_fastdiv_values(nchannels_y) : make_uint3(0, 0, 0);
851
+ const uint3 channel_ratio_fd = ids ? make_uint3(0, 0, 0) : init_fastdiv_values(nchannels_dst / nchannels_x);
852
+ const uint3 sample_ratio_fd = init_fastdiv_values(nsamples_dst / nsamples_x);
853
+
854
+ const int device = ggml_cuda_get_device();
855
+ const int cc = ggml_cuda_info().devices[device].cc;
856
+ const int warp_size = ggml_cuda_info().devices[device].warp_size;
857
+ const mmvq_parameter_table_id table_id = get_device_table_id(cc);
858
+
859
+ const bool has_ids = ids != nullptr;
860
+
861
+ const auto should_use_small_k = [&](int c_ncols_dst) {
862
+ // When K is small, increase rows_per_block to match nwarps so each warp has more work to do
863
+ // Trigger when the full thread block covers all K blocks in a single loop iteration and few threads remain idle.
864
+ constexpr int qk = ggml_cuda_type_traits<type>::qk;
865
+ constexpr int qi = ggml_cuda_type_traits<type>::qi;
866
+ constexpr int vdr = get_vdr_mmvq(type);
867
+ const int blocks_per_row_x = ncols_x / qk;
868
+ const int blocks_per_iter_1warp = vdr * warp_size / qi;
869
+ const int nwarps = calc_nwarps(type, c_ncols_dst, table_id);
870
+ bool use = nwarps > 1 && blocks_per_row_x < nwarps * blocks_per_iter_1warp;
871
+
872
+ constexpr std::array<ggml_type, 2> iq_slow_turing = {
873
+ GGML_TYPE_IQ3_XXS,
874
+ GGML_TYPE_IQ3_S,
875
+ };
876
+ constexpr std::array<ggml_type, 8> iq_slow_other = {
877
+ GGML_TYPE_IQ1_S, GGML_TYPE_IQ1_M, GGML_TYPE_IQ2_XXS, GGML_TYPE_IQ2_XS,
878
+ GGML_TYPE_IQ2_S, GGML_TYPE_IQ3_XXS, GGML_TYPE_IQ3_S, GGML_TYPE_IQ4_XS,
879
+ };
880
+ constexpr std::array<ggml_type, 3> slow_pascal = {
881
+ GGML_TYPE_IQ3_S,
882
+ GGML_TYPE_Q2_K,
883
+ GGML_TYPE_Q3_K,
884
+ };
885
+
886
+ const bool is_nvidia_turing_plus = GGML_CUDA_CC_IS_NVIDIA(cc) && cc >= GGML_CUDA_CC_TURING;
887
+ const bool is_nvidia_pascal_older = GGML_CUDA_CC_IS_NVIDIA(cc) && cc < GGML_CUDA_CC_VOLTA;
888
+
889
+ if (is_nvidia_turing_plus) {
890
+ if (ncols_dst == 1 &&
891
+ std::find(iq_slow_turing.begin(), iq_slow_turing.end(), type) != iq_slow_turing.end()) {
892
+ use = false;
893
+ }
894
+ } else if ((ncols_dst == 1 && std::find(iq_slow_other.begin(), iq_slow_other.end(), type) != iq_slow_other.end()) ||
895
+ (is_nvidia_pascal_older && std::find(slow_pascal.begin(), slow_pascal.end(), type) != slow_pascal.end()) ||
896
+ GGML_CUDA_CC_IS_RDNA(cc)) {
897
+ use = false;
898
+ }
899
+
900
+ return use;
901
+ };
902
+
903
+ if (has_ids && ncols_dst > 1) {
904
+ // Multi-token MUL_MAT_ID path - dedicated MoE kernel
905
+ mul_mat_vec_q_moe_launch<type>(
906
+ vx, vy, ids, dst, ncols_x, nchannels_y_fd, nrows_x,
907
+ stride_row_x, stride_col_y, stride_col_dst,
908
+ stride_channel_x, stride_channel_y, stride_channel_dst,
909
+ ncols_dst, ids_stride, warp_size, nchannels_dst, stream);
910
+ return;
911
+ }
912
+
913
+ switch (ncols_dst) {
914
+ case 1: {
915
+ constexpr int c_ncols_dst = 1;
916
+
917
+ bool use_small_k = should_use_small_k(c_ncols_dst);
918
+
919
+ if (use_small_k) {
920
+ std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst,
921
+ nsamples_dst, warp_size, table_id, true);
922
+ mul_mat_vec_q_switch_fusion<type, c_ncols_dst, true>(
923
+ vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst,
924
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst, sample_ratio_fd,
925
+ stride_sample_x, stride_sample_y, stride_sample_dst, dims.first, dims.second, 0, ids_stride,
926
+ stream);
927
+ } else {
928
+ std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst,
929
+ nsamples_dst, warp_size, table_id);
930
+ mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(
931
+ vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst,
932
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst, sample_ratio_fd,
933
+ stride_sample_x, stride_sample_y, stride_sample_dst, dims.first, dims.second, 0, ids_stride,
934
+ stream);
935
+ }
936
+ } break;
937
+ case 2: {
938
+ constexpr int c_ncols_dst = 2;
939
+ std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id);
940
+ mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst,
941
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
942
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst,
943
+ dims.first, dims.second, 0, ids_stride, stream);
944
+ } break;
945
+ case 3: {
946
+ constexpr int c_ncols_dst = 3;
947
+ std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id);
948
+ mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst,
949
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
950
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst,
951
+ dims.first, dims.second, 0, ids_stride, stream);
952
+ } break;
953
+ case 4: {
954
+ constexpr int c_ncols_dst = 4;
955
+ std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id);
956
+ mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst,
957
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
958
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst,
959
+ dims.first, dims.second, 0, ids_stride, stream);
960
+ } break;
961
+ case 5: {
962
+ constexpr int c_ncols_dst = 5;
963
+ std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id);
964
+ mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst,
965
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
966
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst,
967
+ dims.first, dims.second, 0, ids_stride, stream);
968
+ } break;
969
+ case 6: {
970
+ constexpr int c_ncols_dst = 6;
971
+ std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id);
972
+ mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst,
973
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
974
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst,
975
+ dims.first, dims.second, 0, ids_stride, stream);
976
+ } break;
977
+ case 7: {
978
+ constexpr int c_ncols_dst = 7;
979
+ std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id);
980
+ mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst,
981
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
982
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst,
983
+ dims.first, dims.second, 0, ids_stride, stream);
984
+ } break;
985
+ case 8: {
986
+ constexpr int c_ncols_dst = 8;
987
+ std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id);
988
+ mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst,
989
+ channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst,
990
+ sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst,
991
+ dims.first, dims.second, 0, ids_stride, stream);
992
+ } break;
993
+ default:
994
+ GGML_ABORT("fatal error");
995
+ break;
996
+ }
997
+ }
998
+ static void mul_mat_vec_q_switch_type(
999
+ const void * vx, const ggml_type type_x, const void * vy, const int32_t * ids, const ggml_cuda_mm_fusion_args_device fusion, float * dst,
1000
+ const int ncols_x, const int nrows_x, const int ncols_dst,
1001
+ const int stride_row_x, const int stride_col_y, const int stride_col_dst,
1002
+ const int nchannels_x, const int nchannels_y, const int nchannels_dst,
1003
+ const int stride_channel_x, const int stride_channel_y, const int stride_channel_dst,
1004
+ const int nsamples_x, const int nsamples_dst, const int stride_sample_x, const int stride_sample_y, const int stride_sample_dst,
1005
+ const int ids_stride, cudaStream_t stream) {
1006
+ switch (type_x) {
1007
+ case GGML_TYPE_Q1_0:
1008
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q1_0>
1009
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1010
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1011
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1012
+ break;
1013
+ case GGML_TYPE_Q4_0:
1014
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q4_0>
1015
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1016
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1017
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1018
+ break;
1019
+ case GGML_TYPE_Q4_1:
1020
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q4_1>
1021
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1022
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1023
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1024
+ break;
1025
+ case GGML_TYPE_Q5_0:
1026
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q5_0>
1027
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1028
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1029
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1030
+ break;
1031
+ case GGML_TYPE_Q5_1:
1032
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q5_1>
1033
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1034
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1035
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1036
+ break;
1037
+ case GGML_TYPE_Q8_0:
1038
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q8_0>
1039
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1040
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1041
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1042
+ break;
1043
+ case GGML_TYPE_MXFP4:
1044
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_MXFP4>
1045
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1046
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1047
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1048
+ break;
1049
+ case GGML_TYPE_NVFP4:
1050
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_NVFP4>
1051
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1052
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1053
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1054
+ break;
1055
+ case GGML_TYPE_Q2_K:
1056
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q2_K>
1057
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1058
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1059
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1060
+ break;
1061
+ case GGML_TYPE_Q3_K:
1062
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q3_K>
1063
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1064
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1065
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1066
+ break;
1067
+ case GGML_TYPE_Q4_K:
1068
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q4_K>
1069
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1070
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1071
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1072
+ break;
1073
+ case GGML_TYPE_Q5_K:
1074
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q5_K>
1075
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1076
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1077
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1078
+ break;
1079
+ case GGML_TYPE_Q6_K:
1080
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q6_K>
1081
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1082
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1083
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1084
+ break;
1085
+ case GGML_TYPE_IQ2_XXS:
1086
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ2_XXS>
1087
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1088
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1089
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1090
+ break;
1091
+ case GGML_TYPE_IQ2_XS:
1092
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ2_XS>
1093
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1094
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1095
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1096
+ break;
1097
+ case GGML_TYPE_IQ2_S:
1098
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ2_S>
1099
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1100
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1101
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1102
+ break;
1103
+ case GGML_TYPE_IQ3_XXS:
1104
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ3_XXS>
1105
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1106
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1107
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1108
+ break;
1109
+ case GGML_TYPE_IQ1_S:
1110
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ1_S>
1111
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1112
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1113
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1114
+ break;
1115
+ case GGML_TYPE_IQ1_M:
1116
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ1_M>
1117
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1118
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1119
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1120
+ break;
1121
+ case GGML_TYPE_IQ4_NL:
1122
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ4_NL>
1123
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1124
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1125
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1126
+ break;
1127
+ case GGML_TYPE_IQ4_XS:
1128
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ4_XS>
1129
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1130
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1131
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1132
+ break;
1133
+ case GGML_TYPE_IQ3_S:
1134
+ mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ3_S>
1135
+ (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst,
1136
+ nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst,
1137
+ nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream);
1138
+ break;
1139
+ default:
1140
+ GGML_ABORT("fatal error");
1141
+ break;
1142
+ }
1143
+ }
1144
+
1145
+ void ggml_cuda_mul_mat_vec_q(
1146
+ ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, const ggml_tensor * ids, ggml_tensor * dst,
1147
+ const ggml_cuda_mm_fusion_args_host * fusion) {
1148
+ GGML_ASSERT( src1->type == GGML_TYPE_F32);
1149
+ GGML_ASSERT( dst->type == GGML_TYPE_F32);
1150
+ GGML_ASSERT(!ids || ids->type == GGML_TYPE_I32); // Optional, used for batched GGML_MUL_MAT_ID.
1151
+
1152
+ GGML_TENSOR_BINARY_OP_LOCALS;
1153
+
1154
+ cudaStream_t stream = ctx.stream();
1155
+
1156
+ const size_t ts_src0 = ggml_type_size(src0->type);
1157
+ const size_t ts_src1 = ggml_type_size(src1->type);
1158
+ const size_t ts_dst = ggml_type_size(dst->type);
1159
+
1160
+ GGML_ASSERT( nb00 == ts_src0);
1161
+ GGML_ASSERT( nb10 == ts_src1);
1162
+ GGML_ASSERT( nb0 == ts_dst);
1163
+ GGML_ASSERT(!ids || ids->nb[0] == ggml_type_size(ids->type));
1164
+
1165
+ GGML_ASSERT(!ids || ne12 <= MMVQ_MAX_BATCH_SIZE);
1166
+
1167
+ const float * src1_d = (const float *) src1->data;
1168
+ const int32_t * ids_d = ids ? (const int32_t *) ids->data : nullptr;
1169
+ float * dst_d = (float *) dst->data;
1170
+
1171
+ ggml_cuda_mm_fusion_args_device fusion_local{};
1172
+
1173
+ if (fusion) {
1174
+ GGML_ASSERT( !ids || dst->ne[2] == 1);
1175
+ GGML_ASSERT( ids || dst->ne[1] == 1);
1176
+ // Scale fusion is only allowed for NVFP4 currently as the cost of checking this at run-time in the prologue is
1177
+ // non-negligible for some models such as gpt-oss-20b
1178
+ GGML_ASSERT((fusion->x_scale == nullptr && fusion->gate_scale == nullptr) || src0->type == GGML_TYPE_NVFP4);
1179
+
1180
+ if (fusion->x_bias) {
1181
+ GGML_ASSERT(fusion->x_bias->type == GGML_TYPE_F32);
1182
+ GGML_ASSERT(fusion->x_bias->ne[0] == dst->ne[0]);
1183
+ GGML_ASSERT(!ids || fusion->x_bias->ne[1] == src0->ne[2]);
1184
+ fusion_local.x_bias = fusion->x_bias->data;
1185
+ }
1186
+ if (fusion->gate) {
1187
+ GGML_ASSERT(fusion->gate->type == src0->type && ggml_are_same_stride(fusion->gate, src0));
1188
+ fusion_local.gate = fusion->gate->data;
1189
+ }
1190
+ if (fusion->gate_bias) {
1191
+ GGML_ASSERT(fusion->gate_bias->type == GGML_TYPE_F32);
1192
+ GGML_ASSERT(fusion->gate_bias->ne[0] == dst->ne[0]);
1193
+ GGML_ASSERT(!ids || fusion->gate_bias->ne[1] == src0->ne[2]);
1194
+ fusion_local.gate_bias = fusion->gate_bias->data;
1195
+ }
1196
+ if (fusion->x_scale) {
1197
+ GGML_ASSERT(fusion->x_scale->type == GGML_TYPE_F32);
1198
+ GGML_ASSERT(ggml_is_contiguous(fusion->x_scale));
1199
+ GGML_ASSERT(ggml_nelements(fusion->x_scale) == (ids ? src0->ne[2] : 1));
1200
+ fusion_local.x_scale = fusion->x_scale->data;
1201
+ }
1202
+ if (fusion->gate_scale) {
1203
+ GGML_ASSERT(fusion->gate_scale->type == GGML_TYPE_F32);
1204
+ GGML_ASSERT(ggml_is_contiguous(fusion->gate_scale));
1205
+ GGML_ASSERT(ggml_nelements(fusion->gate_scale) == (ids ? src0->ne[2] : 1));
1206
+ fusion_local.gate_scale = fusion->gate_scale->data;
1207
+ }
1208
+ fusion_local.glu_op = fusion->glu_op;
1209
+ }
1210
+
1211
+ // If src0 is a temporary compute buffer, clear any potential padding.
1212
+ if (ggml_backend_buffer_get_usage(src0->buffer) == GGML_BACKEND_BUFFER_USAGE_COMPUTE) {
1213
+ const size_t size_data = ggml_nbytes(src0);
1214
+ const size_t size_alloc = ggml_backend_buffer_get_alloc_size(src0->buffer, src0);
1215
+ if (size_alloc > size_data) {
1216
+ GGML_ASSERT(ggml_is_contiguously_allocated(src0));
1217
+ GGML_ASSERT(!src0->view_src);
1218
+ CUDA_CHECK(cudaMemsetAsync((char *) src0->data + size_data, 0, size_alloc - size_data, stream));
1219
+ }
1220
+ }
1221
+
1222
+ const int64_t ne10_padded = GGML_PAD(ne10, MATRIX_ROW_PADDING);
1223
+ ggml_cuda_pool_alloc<char> src1_q8_1(ctx.pool(), ne13*ne12 * ne11*ne10_padded * sizeof(block_q8_1)/QK8_1);
1224
+ {
1225
+ const int64_t s11 = src1->nb[1] / ts_src1;
1226
+ const int64_t s12 = src1->nb[2] / ts_src1;
1227
+ const int64_t s13 = src1->nb[3] / ts_src1;
1228
+ quantize_row_q8_1_cuda(src1_d, nullptr, src1_q8_1.get(), src0->type, ne10, s11, s12, s13, ne10_padded, ne11, ne12, ne13, stream);
1229
+ }
1230
+
1231
+ const int64_t s01 = src0->nb[1] / ts_src0;
1232
+ const int64_t s11 = ne10_padded / QK8_1;
1233
+ const int64_t s1 = dst->nb[1] / ts_dst;
1234
+ const int64_t s02 = src0->nb[2] / ts_src0;
1235
+ const int64_t s2 = dst->nb[2] / ts_dst;
1236
+ const int64_t s03 = src0->nb[3] / ts_src0;
1237
+ const int64_t s3 = dst->nb[3] / ts_dst;
1238
+
1239
+ const int64_t s12 = ne11*s11;
1240
+ const int64_t s13 = ne12*s12;
1241
+
1242
+ // For MUL_MAT_ID the memory layout is different than for MUL_MAT:
1243
+ const int64_t ncols_dst = ids ? ne2 : ne1;
1244
+ const int64_t nchannels_y = ids ? ne11 : ne12;
1245
+ const int64_t nchannels_dst = ids ? ne1 : ne2;
1246
+ const int64_t stride_col_dst = ids ? s2 : s1;
1247
+ const int64_t stride_col_y = ids ? s12 : s11;
1248
+ const int64_t stride_channel_dst = ids ? s1 : s2;
1249
+ const int64_t stride_channel_y = ids ? s11 : s12;
1250
+
1251
+ const int64_t ids_stride = ids ? ids->nb[1] / ggml_type_size(ids->type) : 0;
1252
+
1253
+ mul_mat_vec_q_switch_type(
1254
+ src0->data, src0->type, src1_q8_1.get(), ids_d, fusion_local, dst_d, ne00,
1255
+ ne01, ncols_dst, s01, stride_col_y, stride_col_dst,
1256
+ ne02, nchannels_y, nchannels_dst, s02, stride_channel_y, stride_channel_dst,
1257
+ ne03, ne3, s03, s13, s3, ids_stride, stream);
1258
+ }
1259
+
1260
+ void ggml_cuda_op_mul_mat_vec_q(
1261
+ ggml_backend_cuda_context & ctx,
1262
+ const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst, const char * src0_dd_i, const float * src1_ddf_i,
1263
+ const char * src1_ddq_i, float * dst_dd_i, const int64_t row_low, const int64_t row_high, const int64_t src1_ncols,
1264
+ const int64_t src1_padded_row_size, cudaStream_t stream) {
1265
+
1266
+ const int64_t ne00 = src0->ne[0];
1267
+ const int64_t row_diff = row_high - row_low;
1268
+
1269
+ const int64_t ne10 = src1->ne[0];
1270
+ GGML_ASSERT(ne10 % QK8_1 == 0);
1271
+
1272
+ const int64_t ne0 = dst->ne[0];
1273
+
1274
+ int id = ggml_cuda_get_device();
1275
+
1276
+ // the main device has a larger memory buffer to hold the results from all GPUs
1277
+ // nrows_dst == nrows of the matrix that the kernel writes into
1278
+ const int64_t nrows_dst = id == ctx.device ? ne0 : row_diff;
1279
+
1280
+ const int stride_row_x = ne00 / ggml_blck_size(src0->type);
1281
+ const int stride_col_y = src1_padded_row_size / QK8_1;
1282
+
1283
+ ggml_cuda_mm_fusion_args_device fusion_local{};
1284
+ mul_mat_vec_q_switch_type(
1285
+ src0_dd_i, src0->type, src1_ddq_i, nullptr, fusion_local, dst_dd_i, ne00, row_diff, src1_ncols, stride_row_x, stride_col_y, nrows_dst,
1286
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, stream);
1287
+
1288
+ GGML_UNUSED_VARS(src1, dst, src1_ddf_i, src1_ncols, src1_padded_row_size);
1289
+ }
backend/llama.cpp/ggml/src/ggml-cuda/mmvq.cuh ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ #define MMVQ_MAX_BATCH_SIZE 8 // Max. batch size for which to use MMVQ kernels.
4
+
5
+ bool ggml_cuda_should_use_mmvq(enum ggml_type type, int cc, int64_t ne11);
6
+
7
+ // Returns the maximum batch size for which MMVQ should be used for MUL_MAT_ID,
8
+ // based on the quantization type and GPU architecture (compute capability).
9
+ int get_mmvq_mmid_max_batch(ggml_type type, int cc);
10
+
11
+ void ggml_cuda_mul_mat_vec_q(ggml_backend_cuda_context & ctx,
12
+ const ggml_tensor * src0, const ggml_tensor * src1, const ggml_tensor * ids, ggml_tensor * dst, const ggml_cuda_mm_fusion_args_host * fusion = nullptr);
13
+
14
+ void ggml_cuda_op_mul_mat_vec_q(
15
+ ggml_backend_cuda_context & ctx,
16
+ const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst, const char * src0_dd_i, const float * src1_ddf_i,
17
+ const char * src1_ddq_i, float * dst_dd_i, const int64_t row_low, const int64_t row_high, const int64_t src1_ncols,
18
+ const int64_t src1_padded_row_size, cudaStream_t stream);
backend/llama.cpp/ggml/src/ggml-cuda/norm.cu ADDED
@@ -0,0 +1,698 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "norm.cuh"
2
+ #include <cstdint>
3
+
4
+ template <int block_size>
5
+ static __global__ void norm_f32(
6
+ const float * x, float * dst, const int ncols, const int64_t stride_row, const int64_t stride_channel,
7
+ const int64_t stride_sample, const float eps) {
8
+ const int nrows = gridDim.x;
9
+ const int nchannels = gridDim.y;
10
+
11
+ const int row = blockIdx.x;
12
+ const int channel = blockIdx.y;
13
+ const int sample = blockIdx.z;
14
+ const int tid = threadIdx.x;
15
+
16
+ x += sample*stride_sample + channel*stride_channel + row*stride_row;
17
+ dst += ((sample*nchannels + channel)*nrows + row)*ncols;
18
+
19
+ float2 mean_var = make_float2(0.0f, 0.0f);
20
+
21
+ ggml_cuda_pdl_sync();
22
+ for (int col = tid; col < ncols; col += block_size) {
23
+ const float xi = x[col];
24
+ mean_var.x += xi;
25
+ mean_var.y += xi * xi;
26
+ }
27
+
28
+ // sum up partial sums
29
+ extern __shared__ float2 s_sum2[];
30
+ mean_var = block_reduce<block_reduce_method::SUM, block_size>(mean_var, s_sum2);
31
+
32
+ const float mean = mean_var.x / ncols;
33
+ const float var = mean_var.y / ncols - mean * mean;
34
+ const float inv_std = rsqrtf(var + eps);
35
+
36
+ for (int col = tid; col < ncols; col += block_size) {
37
+ dst[col] = (x[col] - mean) * inv_std;
38
+ }
39
+ }
40
+
41
+ template <int block_size>
42
+ static __global__ void group_norm_f32(const float * x, float * dst, const int group_size, const int ne_elements, const float eps) {
43
+ // blockIdx.x: num_groups idx
44
+ // threadIdx.x: block_size idx
45
+ const int start = blockIdx.x*group_size + threadIdx.x;
46
+ const int end = min(blockIdx.x*group_size + group_size, ne_elements);
47
+
48
+ float tmp = 0.0f; // partial sum for thread in warp
49
+
50
+ ggml_cuda_pdl_sync();
51
+ for (int j = start; j < end; j += block_size) {
52
+ tmp += x[j];
53
+ }
54
+
55
+ extern __shared__ float s_sum[];
56
+ tmp = block_reduce<block_reduce_method::SUM, block_size>(tmp, s_sum);
57
+
58
+ const float mean = tmp / group_size;
59
+ tmp = 0.0f;
60
+
61
+ for (int j = start; j < end; j += block_size) {
62
+ const float xi = x[j] - mean;
63
+ dst[j] = xi;
64
+ tmp += xi * xi;
65
+ }
66
+
67
+ tmp = block_reduce<block_reduce_method::SUM, block_size>(tmp, s_sum);
68
+
69
+ const float variance = tmp / group_size;
70
+ const float scale = rsqrtf(variance + eps);
71
+ for (int j = start; j < end; j += block_size) {
72
+ dst[j] *= scale;
73
+ }
74
+ }
75
+
76
+ template <int block_size, bool do_multiply = false, bool do_add = false>
77
+ static __global__ void rms_norm_f32(const float * x,
78
+ float * dst,
79
+ const int ncols,
80
+ const int64_t stride_row,
81
+ const int64_t stride_channel,
82
+ const int64_t stride_sample,
83
+ const float eps,
84
+ const float * mul = nullptr,
85
+ const int64_t mul_stride_row = 0,
86
+ const int64_t mul_stride_channel = 0,
87
+ const int64_t mul_stride_sample = 0,
88
+ const uint3 mul_ncols_packed = make_uint3(0, 0, 0),
89
+ const uint3 mul_nrows_packed = make_uint3(0, 0, 0),
90
+ const uint3 mul_nchannels_packed = make_uint3(0, 0, 0),
91
+ const uint3 mul_nsamples_packed = make_uint3(0, 0, 0),
92
+ const float * add = nullptr,
93
+ const int64_t add_stride_row = 0,
94
+ const int64_t add_stride_channel = 0,
95
+ const int64_t add_stride_sample = 0,
96
+ const uint3 add_ncols_packed = make_uint3(0, 0, 0),
97
+ const uint3 add_nrows_packed = make_uint3(0, 0, 0),
98
+ const uint3 add_nchannels_packed = make_uint3(0, 0, 0),
99
+ const uint3 add_nsamples_packed = make_uint3(0, 0, 0)) {
100
+ ggml_cuda_pdl_lc();
101
+ const int nrows = gridDim.x;
102
+ const int nchannels = gridDim.y;
103
+
104
+ const int row = blockIdx.x;
105
+ const int channel = blockIdx.y;
106
+ const int sample = blockIdx.z;
107
+ const int tid = threadIdx.x;
108
+
109
+ static_assert(!do_add || do_multiply, "fusing add is not supported without multiplying");
110
+
111
+ x += sample*stride_sample + channel*stride_channel + row*stride_row;
112
+ dst += ((sample*nchannels + channel)*nrows + row)*ncols;
113
+
114
+ if constexpr (do_multiply) {
115
+ const uint32_t mul_row = fastmodulo(row, mul_nrows_packed);
116
+ const uint32_t mul_channel = fastmodulo(channel, mul_nchannels_packed);
117
+ const uint32_t mul_sample = fastmodulo(sample, mul_nsamples_packed);
118
+ mul += mul_sample * mul_stride_sample + mul_channel * mul_stride_channel + mul_row * mul_stride_row;
119
+ }
120
+
121
+ if constexpr (do_add) {
122
+ const int add_row = fastmodulo(row, add_nrows_packed);
123
+ const int add_channel = fastmodulo(channel, add_nchannels_packed);
124
+ const int add_sample = fastmodulo(sample, add_nsamples_packed);
125
+ add += add_sample * add_stride_sample + add_channel * add_stride_channel + add_row * add_stride_row;
126
+ }
127
+
128
+ float tmp = 0.0f; // partial sum for thread in warp
129
+
130
+ ggml_cuda_pdl_sync();
131
+ for (int col = tid; col < ncols; col += block_size) {
132
+ const float xi = x[col];
133
+ tmp += xi * xi;
134
+ }
135
+
136
+ // sum up partial sums
137
+ extern __shared__ float s_sum[];
138
+ tmp = block_reduce<block_reduce_method::SUM, block_size>(tmp, s_sum);
139
+
140
+ const float mean = tmp / ncols;
141
+ const float scale = rsqrtf(mean + eps);
142
+
143
+ for (int col = tid; col < ncols; col += block_size) {
144
+ if constexpr (do_multiply && do_add) {
145
+ const int mul_col = fastmodulo(col, mul_ncols_packed);
146
+ const int add_col = fastmodulo(col, add_ncols_packed);
147
+ dst[col] = scale * x[col] * mul[mul_col] + add[add_col];
148
+ } else if constexpr (do_multiply) {
149
+ const int mul_col = fastmodulo(col, mul_ncols_packed);
150
+ dst[col] = scale * x[col] * mul[mul_col];
151
+ } else {
152
+ dst[col] = scale * x[col];
153
+ }
154
+ }
155
+ }
156
+
157
+ template <int block_size>
158
+ static __global__ void rms_norm_back_f32(
159
+ const float * grad, const float * xf, float * dst, const int ncols, const float eps) {
160
+ const int row = blockIdx.x*blockDim.y + threadIdx.y;
161
+ const int tid = threadIdx.x;
162
+
163
+ grad += int64_t(row)*ncols;
164
+ xf += int64_t(row)*ncols;
165
+ dst += int64_t(row)*ncols;
166
+
167
+ float sum_xx = 0.0f; // sum for squares of x, equivalent to forward pass
168
+ float sum_xg = 0.0f; // sum for x * gradient, needed because RMS norm mixes inputs
169
+
170
+ ggml_cuda_pdl_sync();
171
+ for (int col = tid; col < ncols; col += block_size) {
172
+ const float xfi = xf[col];
173
+ sum_xx += xfi * xfi;
174
+ sum_xg += xfi * grad[col];
175
+ }
176
+
177
+ // sum up partial sums
178
+ sum_xx = warp_reduce_sum(sum_xx);
179
+ sum_xg = warp_reduce_sum(sum_xg);
180
+ if constexpr (block_size > WARP_SIZE) {
181
+ static_assert(block_size == 1024, "unexpected block_size");
182
+ __shared__ float s_sum_xx[32];
183
+ __shared__ float s_sum_xg[32];
184
+ const int warp_id = threadIdx.x / WARP_SIZE;
185
+ const int lane_id = threadIdx.x % WARP_SIZE;
186
+ if (lane_id == 0) {
187
+ s_sum_xx[warp_id] = sum_xx;
188
+ s_sum_xg[warp_id] = sum_xg;
189
+ }
190
+ __syncthreads();
191
+
192
+ sum_xx = s_sum_xx[lane_id];
193
+ sum_xx = warp_reduce_sum(sum_xx);
194
+
195
+ sum_xg = s_sum_xg[lane_id];
196
+ sum_xg = warp_reduce_sum(sum_xg);
197
+ }
198
+
199
+ const float mean_eps = sum_xx / ncols + eps;
200
+ const float sum_eps = sum_xx + ncols*eps;
201
+
202
+ const float scale_grad = rsqrtf(mean_eps);
203
+ const float scale_x = -scale_grad * sum_xg/sum_eps;
204
+
205
+ for (int col = tid; col < ncols; col += block_size) {
206
+ dst[col] = scale_grad*grad[col] + scale_x*xf[col];
207
+ }
208
+ }
209
+
210
+ // template <int block_size>
211
+ // static __global__ void l2_norm_f32(const float * x, float * dst, const int ncols, const float eps) {
212
+ // const int row = blockIdx.x*blockDim.y + threadIdx.y;
213
+ // const int tid = threadIdx.x;
214
+
215
+ // float tmp = 0.0f; // partial sum for thread in warp
216
+
217
+ // for (int col = tid; col < ncols; col += block_size) {
218
+ // const float xi = x[row*ncols + col];
219
+ // tmp += xi * xi;
220
+ // }
221
+
222
+ // // sum up partial sums
223
+ // tmp = warp_reduce_sum(tmp);
224
+ // if (block_size > WARP_SIZE) {
225
+ // __shared__ float s_sum[32];
226
+ // int warp_id = threadIdx.x / WARP_SIZE;
227
+ // int lane_id = threadIdx.x % WARP_SIZE;
228
+ // if (lane_id == 0) {
229
+ // s_sum[warp_id] = tmp;
230
+ // }
231
+ // __syncthreads();
232
+ // tmp = s_sum[lane_id];
233
+ // tmp = warp_reduce_sum(tmp);
234
+ // }
235
+
236
+ // // from https://pytorch.org/docs/stable/generated/torch.nn.functional.normalize.html
237
+ // const float scale = rsqrtf(fmaxf(tmp, eps * eps));
238
+
239
+ // for (int col = tid; col < ncols; col += block_size) {
240
+ // dst[row*ncols + col] = scale * x[row*ncols + col];
241
+ // }
242
+ // }
243
+
244
+ template <int block_size>
245
+ static __global__ void l2_norm_f32(
246
+ const float * x, float * dst, const int ncols, const int64_t stride_row, const int64_t stride_channel,
247
+ const int64_t stride_sample, const float eps) {
248
+ const int nrows = gridDim.x;
249
+ const int nchannels = gridDim.y;
250
+
251
+ const int row = blockIdx.x;
252
+ const int channel = blockIdx.y;
253
+ const int sample = blockIdx.z;
254
+ const int tid = threadIdx.x;
255
+
256
+ x += sample*stride_sample + channel*stride_channel + row*stride_row;
257
+ dst += ((sample*nchannels + channel)*nrows + row)*ncols;
258
+
259
+ float tmp = 0.0f; // partial sum for thread in warp
260
+
261
+ ggml_cuda_pdl_sync();
262
+ for (int col = tid; col < ncols; col += block_size) {
263
+ const float xi = x[col];
264
+ tmp += xi * xi;
265
+ }
266
+
267
+ // sum up partial sums
268
+ extern __shared__ float s_sum[];
269
+ tmp = block_reduce<block_reduce_method::SUM, block_size>(tmp, s_sum);
270
+ ggml_cuda_pdl_lc();
271
+
272
+ // from https://pytorch.org/docs/stable/generated/torch.nn.functional.normalize.html
273
+ const float scale = rsqrtf(fmaxf(tmp, eps * eps));
274
+
275
+ for (int col = tid; col < ncols; col += block_size) {
276
+ dst[col] = scale * x[col];
277
+ }
278
+ }
279
+
280
+ static void norm_f32_cuda(
281
+ const float * x, float * dst, const int ncols, const int nrows, const int nchannels, const int nsamples,
282
+ const int64_t stride_row, const int64_t stride_channel, const int64_t stride_sample, const float eps, cudaStream_t stream) {
283
+ const dim3 blocks_num(nrows, nchannels, nsamples);
284
+ if (ncols < 1024) {
285
+ const dim3 block_dims(WARP_SIZE, 1, 1);
286
+ norm_f32<WARP_SIZE><<<blocks_num, block_dims, 0, stream>>>(x, dst, ncols, stride_row, stride_channel, stride_sample, eps);
287
+ } else {
288
+ const dim3 block_dims(1024, 1, 1);
289
+ norm_f32<1024><<<blocks_num, block_dims, block_dims.x > WARP_SIZE ? 32 * sizeof(float2): 0, stream>>>(x, dst, ncols, stride_row, stride_channel, stride_sample, eps);
290
+ }
291
+ }
292
+
293
+ static void group_norm_f32_cuda(
294
+ const float * x, float * dst, const int num_groups, const float eps, const int group_size, const int ne_elements, cudaStream_t stream) {
295
+ if (group_size < 1024) {
296
+ const dim3 block_dims(WARP_SIZE, 1, 1);
297
+ group_norm_f32<WARP_SIZE><<<num_groups, block_dims, 0, stream>>>(x, dst, group_size, ne_elements, eps);
298
+ } else {
299
+ const dim3 block_dims(1024, 1, 1);
300
+ group_norm_f32<1024><<<num_groups, block_dims, block_dims.x > WARP_SIZE ? 32 * sizeof(float): 0, stream>>>(x, dst, group_size, ne_elements, eps);
301
+ }
302
+ }
303
+
304
+ static void rms_norm_f32_cuda(
305
+ const float * x, float * dst, const int ncols, const int nrows, const int nchannels, const int nsamples,
306
+ const int64_t stride_row, const int64_t stride_channel, const int64_t stride_sample, const float eps, cudaStream_t stream) {
307
+ const dim3 blocks_num(nrows, nchannels, nsamples);
308
+ if (ncols < 1024) {
309
+ const dim3 block_dims(256, 1, 1);
310
+ const ggml_cuda_kernel_launch_params launch_params = {blocks_num, block_dims, block_dims.x > WARP_SIZE ? 32 * sizeof(float): 0, stream};
311
+ ggml_cuda_kernel_launch(rms_norm_f32<256, false>, launch_params,
312
+ x, dst, ncols, stride_row, stride_channel, stride_sample, eps,
313
+ // underlying cudaLaunchKernelEx does not support default params
314
+ nullptr, 0, 0, 0, make_uint3(0, 0, 0), make_uint3(0, 0, 0), make_uint3(0, 0, 0), make_uint3(0, 0, 0),
315
+ nullptr, 0, 0, 0, make_uint3(0, 0, 0), make_uint3(0, 0, 0), make_uint3(0, 0, 0), make_uint3(0, 0, 0));
316
+ } else {
317
+ const dim3 block_dims(1024, 1, 1);
318
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params{blocks_num, block_dims, block_dims.x > WARP_SIZE ? 32 * sizeof(float): 0, stream};
319
+ ggml_cuda_kernel_launch(rms_norm_f32<1024, false>, launch_params, x, dst, ncols, stride_row, stride_channel, stride_sample, eps,
320
+ // underlying cudaLaunchKernelEx does not support default params
321
+ nullptr, 0, 0, 0, make_uint3(0, 0, 0), make_uint3(0, 0, 0), make_uint3(0, 0, 0), make_uint3(0, 0, 0),
322
+ nullptr, 0, 0, 0, make_uint3(0, 0, 0), make_uint3(0, 0, 0), make_uint3(0, 0, 0), make_uint3(0, 0, 0));
323
+ }
324
+ }
325
+
326
+ static void rms_norm_mul_f32_cuda(const float * x,
327
+ const float * mul,
328
+ const float * add,
329
+ float * dst,
330
+ const int ncols,
331
+ const int nrows,
332
+ const int nchannels,
333
+ const int nsamples,
334
+ const int64_t stride_row,
335
+ const int64_t stride_channel,
336
+ const int64_t stride_sample,
337
+ const int64_t mul_stride_row,
338
+ const int64_t mul_stride_channel,
339
+ const int64_t mul_stride_sample,
340
+ const uint32_t mul_ncols,
341
+ const uint32_t mul_nrows,
342
+ const uint32_t mul_nchannels,
343
+ const uint32_t mul_nsamples,
344
+ const int64_t add_stride_row,
345
+ const int64_t add_stride_channel,
346
+ const int64_t add_stride_sample,
347
+ const uint32_t add_ncols,
348
+ const uint32_t add_nrows,
349
+ const uint32_t add_nchannels,
350
+ const uint32_t add_nsamples,
351
+ const float eps,
352
+ cudaStream_t stream) {
353
+ const dim3 blocks_num(nrows, nchannels, nsamples);
354
+ if (mul == nullptr) {
355
+ rms_norm_f32_cuda(x, dst, ncols, nrows, nchannels, nsamples, stride_row, stride_channel, stride_sample, eps, stream);
356
+ return;
357
+ }
358
+ if (add == nullptr) {
359
+ const uint3 mul_ncols_packed = init_fastdiv_values(mul_ncols);
360
+ const uint3 mul_nrows_packed = init_fastdiv_values(mul_nrows);
361
+ const uint3 mul_nchannels_packed = init_fastdiv_values(mul_nchannels);
362
+ const uint3 mul_nsamples_packed = init_fastdiv_values(mul_nsamples);
363
+ if (ncols < 1024) {
364
+ const dim3 block_dims(256, 1, 1);
365
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params{blocks_num, block_dims, block_dims.x > WARP_SIZE ? 32 * sizeof(float): 0, stream};
366
+ ggml_cuda_kernel_launch(rms_norm_f32<256, true>, launch_params,
367
+ x, dst, ncols, stride_row, stride_channel, stride_sample, eps, mul, mul_stride_row, mul_stride_channel,
368
+ mul_stride_sample, mul_ncols_packed, mul_nrows_packed, mul_nchannels_packed, mul_nsamples_packed,
369
+ // underlying cudaLaunchKernelEx does not support default params
370
+ nullptr, 0, 0, 0, make_uint3(0, 0, 0), make_uint3(0, 0, 0), make_uint3(0, 0, 0), make_uint3(0, 0, 0));
371
+ } else {
372
+ const dim3 block_dims(1024, 1, 1);
373
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params{blocks_num, block_dims, block_dims.x > WARP_SIZE ? 32 * sizeof(float): 0, stream};
374
+ ggml_cuda_kernel_launch(rms_norm_f32<1024, true>, launch_params,
375
+ x, dst, ncols, stride_row, stride_channel, stride_sample, eps, mul, mul_stride_row, mul_stride_channel,
376
+ mul_stride_sample, mul_ncols_packed, mul_nrows_packed, mul_nchannels_packed, mul_nsamples_packed,
377
+ // underlying cudaLaunchKernelEx does not support default params
378
+ nullptr, 0, 0, 0, make_uint3(0, 0, 0), make_uint3(0, 0, 0), make_uint3(0, 0, 0), make_uint3(0, 0, 0));
379
+ }
380
+ } else {
381
+ const uint3 mul_ncols_packed = init_fastdiv_values(mul_ncols);
382
+ const uint3 mul_nrows_packed = init_fastdiv_values(mul_nrows);
383
+ const uint3 mul_nchannels_packed = init_fastdiv_values(mul_nchannels);
384
+ const uint3 mul_nsamples_packed = init_fastdiv_values(mul_nsamples);
385
+
386
+ const uint3 add_ncols_packed = init_fastdiv_values(add_ncols);
387
+ const uint3 add_nrows_packed = init_fastdiv_values(add_nrows);
388
+ const uint3 add_nchannels_packed = init_fastdiv_values(add_nchannels);
389
+ const uint3 add_nsamples_packed = init_fastdiv_values(add_nsamples);
390
+ if (ncols < 1024) {
391
+ const dim3 block_dims(256, 1, 1);
392
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params{blocks_num, block_dims,block_dims.x > WARP_SIZE ? 32 * sizeof(float): 0, stream};
393
+ ggml_cuda_kernel_launch(rms_norm_f32<256, true, true>, launch_params,
394
+ x, dst, ncols, stride_row, stride_channel, stride_sample, eps, mul, mul_stride_row, mul_stride_channel,
395
+ mul_stride_sample, mul_ncols_packed, mul_nrows_packed, mul_nchannels_packed, mul_nsamples_packed, add,
396
+ add_stride_row, add_stride_channel, add_stride_sample, add_ncols_packed, add_nrows_packed,
397
+ add_nchannels_packed, add_nsamples_packed);
398
+ } else {
399
+ const dim3 block_dims(1024, 1, 1);
400
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params{blocks_num, block_dims, block_dims.x > WARP_SIZE ? 32 * sizeof(float): 0, stream};
401
+ ggml_cuda_kernel_launch(rms_norm_f32<1024, true, true>, launch_params,
402
+ x, dst, ncols, stride_row, stride_channel, stride_sample, eps, mul, mul_stride_row, mul_stride_channel,
403
+ mul_stride_sample, mul_ncols_packed, mul_nrows_packed, mul_nchannels_packed, mul_nsamples_packed, add,
404
+ add_stride_row, add_stride_channel, add_stride_sample, add_ncols_packed, add_nrows_packed,
405
+ add_nchannels_packed, add_nsamples_packed);
406
+ }
407
+ }
408
+ }
409
+
410
+ static void rms_norm_back_f32_cuda(const float * grad, const float * xf, float * dst, const int ncols, const int nrows, const float eps, cudaStream_t stream) {
411
+ if (ncols < 1024) {
412
+ const dim3 block_dims(WARP_SIZE, 1, 1);
413
+ rms_norm_back_f32<WARP_SIZE><<<nrows, block_dims, 0, stream>>>(grad, xf, dst, ncols, eps);
414
+ } else {
415
+ const dim3 block_dims(1024, 1, 1);
416
+ rms_norm_back_f32<1024><<<nrows, block_dims, 0, stream>>>(grad, xf, dst, ncols, eps);
417
+ }
418
+ }
419
+
420
+ static void l2_norm_f32_cuda(
421
+ const float * x, float * dst, const int ncols, const int nrows, const int nchannels, const int nsamples,
422
+ const int64_t stride_row, const int64_t stride_channel, const int64_t stride_sample, const float eps, cudaStream_t stream) {
423
+ const dim3 blocks_num(nrows, nchannels, nsamples);
424
+ if (ncols < 1024) {
425
+ const dim3 block_dims(WARP_SIZE, 1, 1);
426
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params{blocks_num, block_dims, 0, stream};
427
+ ggml_cuda_kernel_launch(l2_norm_f32<WARP_SIZE>, launch_params, x, dst, ncols, stride_row, stride_channel, stride_sample, eps);
428
+ } else {
429
+ const dim3 block_dims(1024, 1, 1);
430
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params{blocks_num, block_dims, block_dims.x > WARP_SIZE ? 32 * sizeof(float): 0, stream};
431
+ ggml_cuda_kernel_launch(l2_norm_f32<1024>, launch_params, x, dst, ncols, stride_row, stride_channel, stride_sample, eps);
432
+ }
433
+ }
434
+
435
+ void ggml_cuda_op_norm(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
436
+ const ggml_tensor * src0 = dst->src[0];
437
+ const float * src0_d = (const float *) src0->data;
438
+ float * dst_d = (float *) dst->data;
439
+ cudaStream_t stream = ctx.stream();
440
+
441
+ GGML_ASSERT(src0->type == GGML_TYPE_F32);
442
+ GGML_ASSERT( dst->type == GGML_TYPE_F32);
443
+
444
+ GGML_TENSOR_UNARY_OP_LOCALS;
445
+
446
+ float eps;
447
+ memcpy(&eps, dst->op_params, sizeof(float));
448
+ GGML_ASSERT(eps >= 0.0f);
449
+
450
+ const size_t ts0 = ggml_type_size(src0->type);
451
+ GGML_ASSERT(nb00 == ts0);
452
+ const int64_t s01 = nb01 / ts0;
453
+ const int64_t s02 = nb02 / ts0;
454
+ const int64_t s03 = nb03 / ts0;
455
+
456
+ norm_f32_cuda(src0_d, dst_d, ne00, ne01, ne02, ne03, s01, s02, s03, eps, stream);
457
+ }
458
+
459
+ void ggml_cuda_op_group_norm(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
460
+ const ggml_tensor * src0 = dst->src[0];
461
+ const float * src0_d = (const float *)src0->data;
462
+ float * dst_d = (float *)dst->data;
463
+ cudaStream_t stream = ctx.stream();
464
+
465
+ GGML_ASSERT(src0->type == GGML_TYPE_F32);
466
+ GGML_ASSERT( dst->type == GGML_TYPE_F32);
467
+
468
+ int num_groups = dst->op_params[0];
469
+
470
+ float eps;
471
+ memcpy(&eps, dst->op_params + 1, sizeof(float));
472
+ GGML_ASSERT(eps >= 0.0f);
473
+
474
+ int group_size = src0->ne[0] * src0->ne[1] * ((src0->ne[2] + num_groups - 1) / num_groups);
475
+ group_norm_f32_cuda(src0_d, dst_d, num_groups * src0->ne[3], eps, group_size, ggml_nelements(src0), stream);
476
+ }
477
+
478
+ void ggml_cuda_op_rms_norm(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
479
+ const ggml_tensor * src0 = dst->src[0];
480
+ const float * src0_d = (const float *) src0->data;
481
+ float * dst_d = (float *) dst->data;
482
+ cudaStream_t stream = ctx.stream();
483
+
484
+ GGML_ASSERT(src0->type == GGML_TYPE_F32);
485
+ GGML_ASSERT( dst->type == GGML_TYPE_F32);
486
+
487
+ GGML_TENSOR_UNARY_OP_LOCALS;
488
+
489
+ float eps;
490
+ memcpy(&eps, dst->op_params, sizeof(float));
491
+ GGML_ASSERT(eps >= 0.0f);
492
+
493
+ const size_t ts0 = ggml_type_size(src0->type);
494
+ GGML_ASSERT(nb00 == ts0);
495
+ const int64_t s01 = nb01 / ts0;
496
+ const int64_t s02 = nb02 / ts0;
497
+ const int64_t s03 = nb03 / ts0;
498
+
499
+ rms_norm_f32_cuda(src0_d, dst_d, ne00, ne01, ne02, ne03, s01, s02, s03, eps, stream);
500
+ }
501
+
502
+ void ggml_cuda_op_rms_norm_fused(ggml_backend_cuda_context & ctx, ggml_tensor * dst, ggml_tensor * mul_tensor) {
503
+ const ggml_tensor * rms_norm_src = (ggml_tensor *) dst->src[0];
504
+ float eps = 0.0f;
505
+
506
+ memcpy(&eps, dst->op_params, sizeof(float));
507
+
508
+ const float * src0_d = (const float *) rms_norm_src->data;
509
+ const float * mul_d = nullptr;
510
+ const ggml_tensor * mul_src = nullptr;
511
+
512
+ if (mul_tensor->src[0] == dst) {
513
+ mul_d = (float *) mul_tensor->src[1]->data;
514
+ mul_src = mul_tensor->src[1];
515
+ } else if(mul_tensor->src[1] == dst) {
516
+ mul_d = (float *) mul_tensor->src[0]->data;
517
+ mul_src = mul_tensor->src[0];
518
+ } else {
519
+ GGML_ASSERT(false);
520
+ }
521
+
522
+ float * dst_d = (float *) mul_tensor->data;
523
+ cudaStream_t stream = ctx.stream();
524
+
525
+ GGML_ASSERT(rms_norm_src->type == GGML_TYPE_F32);
526
+ GGML_ASSERT(dst->type == GGML_TYPE_F32);
527
+ GGML_ASSERT(mul_tensor->type == GGML_TYPE_F32);
528
+ GGML_ASSERT(eps >= 0.0f);
529
+
530
+ const int64_t ne00 = rms_norm_src->ne[0];
531
+ const int64_t ne01 = rms_norm_src->ne[1];
532
+ const int64_t ne02 = rms_norm_src->ne[2];
533
+ const int64_t ne03 = rms_norm_src->ne[3];
534
+
535
+ const size_t ts0 = ggml_type_size(rms_norm_src->type);
536
+ GGML_ASSERT(rms_norm_src->nb[0] == ts0);
537
+ const int64_t s01 = rms_norm_src->nb[1] / ts0;
538
+ const int64_t s02 = rms_norm_src->nb[2] / ts0;
539
+ const int64_t s03 = rms_norm_src->nb[3] / ts0;
540
+
541
+ const size_t ts_mul = ggml_type_size(mul_src->type);
542
+ GGML_ASSERT(mul_src->nb[0] == ts_mul);
543
+ const int64_t mul_s01 = mul_src->nb[1] / ts_mul;
544
+ const int64_t mul_s02 = mul_src->nb[2] / ts_mul;
545
+ const int64_t mul_s03 = mul_src->nb[3] / ts_mul;
546
+
547
+ const int mul_ncols = mul_src->ne[0];
548
+ const int mul_nrows = mul_src->ne[1];
549
+ const int mul_nchannels = mul_src->ne[2];
550
+ const int mul_nsamples = mul_src->ne[3];
551
+
552
+ rms_norm_mul_f32_cuda(src0_d, mul_d, nullptr, dst_d,
553
+ ne00, ne01, ne02, ne03,
554
+ /*s00*/ s01, s02, s03,
555
+ /*mul_s00*/ mul_s01, mul_s02, mul_s03,
556
+ mul_ncols, mul_nrows, mul_nchannels, mul_nsamples,
557
+ /*add_s00*/ 0, 0, 0,
558
+ 0, 0, 0, 0,
559
+ eps, stream);
560
+ }
561
+
562
+ void ggml_cuda_op_rms_norm_fused_add(ggml_backend_cuda_context & ctx,
563
+ ggml_tensor * dst,
564
+ ggml_tensor * mul_tensor,
565
+ ggml_tensor * add_tensor) {
566
+ const ggml_tensor * rms_norm_src = (ggml_tensor *) dst->src[0];
567
+ float eps = 0.0f;
568
+
569
+ memcpy(&eps, dst->op_params, sizeof(float));
570
+
571
+ const float * src0_d = (const float *) rms_norm_src->data;
572
+ const float * mul_d = nullptr;
573
+ const ggml_tensor * mul_src = nullptr;
574
+
575
+ if (mul_tensor->src[0] == dst) {
576
+ mul_d = (float *) mul_tensor->src[1]->data;
577
+ mul_src = mul_tensor->src[1];
578
+ } else if (mul_tensor->src[1] == dst) {
579
+ mul_d = (float *) mul_tensor->src[0]->data;
580
+ mul_src = mul_tensor->src[0];
581
+ } else {
582
+ GGML_ASSERT(false);
583
+ }
584
+
585
+ const float * add_d = nullptr;
586
+ const ggml_tensor * add_src = nullptr;
587
+
588
+ if (add_tensor->src[0] == mul_tensor) {
589
+ add_d = (float *) add_tensor->src[1]->data;
590
+ add_src = add_tensor->src[1];
591
+ } else if (add_tensor->src[1] == mul_tensor) {
592
+ add_d = (float *) add_tensor->src[0]->data;
593
+ add_src = add_tensor->src[0];
594
+ } else {
595
+ GGML_ASSERT(false);
596
+ }
597
+
598
+ float * dst_d = (float *) add_tensor->data;
599
+ cudaStream_t stream = ctx.stream();
600
+
601
+ GGML_ASSERT(rms_norm_src->type == GGML_TYPE_F32);
602
+ GGML_ASSERT(dst->type == GGML_TYPE_F32);
603
+ GGML_ASSERT(mul_tensor->type == GGML_TYPE_F32);
604
+ GGML_ASSERT(add_tensor->type == GGML_TYPE_F32);
605
+ GGML_ASSERT(eps >= 0.0f);
606
+
607
+ const int64_t ne00 = rms_norm_src->ne[0];
608
+ const int64_t ne01 = rms_norm_src->ne[1];
609
+ const int64_t ne02 = rms_norm_src->ne[2];
610
+ const int64_t ne03 = rms_norm_src->ne[3];
611
+
612
+ const size_t ts0 = ggml_type_size(rms_norm_src->type);
613
+ GGML_ASSERT(rms_norm_src->nb[0] == ts0);
614
+ const int64_t s01 = rms_norm_src->nb[1] / ts0;
615
+ const int64_t s02 = rms_norm_src->nb[2] / ts0;
616
+ const int64_t s03 = rms_norm_src->nb[3] / ts0;
617
+
618
+ const size_t ts_mul = ggml_type_size(mul_src->type);
619
+ GGML_ASSERT(mul_src->nb[0] == ts_mul);
620
+ const int64_t mul_s01 = mul_src->nb[1] / ts_mul;
621
+ const int64_t mul_s02 = mul_src->nb[2] / ts_mul;
622
+ const int64_t mul_s03 = mul_src->nb[3] / ts_mul;
623
+
624
+ const int mul_ncols = mul_src->ne[0];
625
+ const int mul_nrows = mul_src->ne[1];
626
+ const int mul_nchannels = mul_src->ne[2];
627
+ const int mul_nsamples = mul_src->ne[3];
628
+
629
+ const size_t ts_add = ggml_type_size(add_src->type);
630
+ GGML_ASSERT(add_src->nb[0] == ts_add);
631
+ const int64_t add_s01 = add_src->nb[1] / ts_add;
632
+ const int64_t add_s02 = add_src->nb[2] / ts_add;
633
+ const int64_t add_s03 = add_src->nb[3] / ts_add;
634
+
635
+ const int add_ncols = add_src->ne[0];
636
+ const int add_nrows = add_src->ne[1];
637
+ const int add_nchannels = add_src->ne[2];
638
+ const int add_nsamples = add_src->ne[3];
639
+
640
+ rms_norm_mul_f32_cuda(src0_d, mul_d,add_d,dst_d,
641
+ ne00,ne01, ne02, ne03,
642
+ /*s00*/ s01, s02, s03,
643
+ /*mul_s00*/ mul_s01, mul_s02, mul_s03,
644
+ mul_ncols, mul_nrows, mul_nchannels, mul_nsamples,
645
+ /*add_s00*/ add_s01, add_s02, add_s03,
646
+ add_ncols, add_nrows, add_nchannels, add_nsamples,
647
+ eps, stream);
648
+ }
649
+
650
+ void ggml_cuda_op_rms_norm_back(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
651
+ const ggml_tensor * grad = dst->src[0]; // gradients
652
+ const ggml_tensor * src0f = dst->src[1]; // src0 from forward pass
653
+
654
+ const float * grad_d = (const float *) grad->data;
655
+ const float * src0f_d = (const float *) src0f->data;
656
+ float * dst_d = (float *) dst->data;
657
+
658
+ cudaStream_t stream = ctx.stream();
659
+
660
+ GGML_ASSERT(ggml_is_contiguous(grad));
661
+
662
+ GGML_ASSERT( grad->type == GGML_TYPE_F32);
663
+ GGML_ASSERT(src0f->type == GGML_TYPE_F32);
664
+ GGML_ASSERT( dst->type == GGML_TYPE_F32);
665
+
666
+ const int64_t ne00 = src0f->ne[0];
667
+ const int64_t nrows = ggml_nrows(src0f);
668
+
669
+ float eps;
670
+ memcpy(&eps, dst->op_params, sizeof(float));
671
+ GGML_ASSERT(eps >= 0.0f);
672
+
673
+ rms_norm_back_f32_cuda(grad_d, src0f_d, dst_d, ne00, nrows, eps, stream);
674
+ }
675
+
676
+ void ggml_cuda_op_l2_norm(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
677
+ const ggml_tensor * src0 = dst->src[0];
678
+ const float * src0_d = (const float *) src0->data;
679
+ float * dst_d = (float *) dst->data;
680
+ cudaStream_t stream = ctx.stream();
681
+
682
+ GGML_ASSERT(src0->type == GGML_TYPE_F32);
683
+ GGML_ASSERT( dst->type == GGML_TYPE_F32);
684
+
685
+ GGML_TENSOR_UNARY_OP_LOCALS;
686
+
687
+ float eps;
688
+ memcpy(&eps, dst->op_params, sizeof(float));
689
+ GGML_ASSERT(eps >= 0.0f);
690
+
691
+ const size_t ts0 = ggml_type_size(src0->type);
692
+ GGML_ASSERT(nb00 == ts0);
693
+ const int64_t s01 = nb01 / ts0;
694
+ const int64_t s02 = nb02 / ts0;
695
+ const int64_t s03 = nb03 / ts0;
696
+
697
+ l2_norm_f32_cuda(src0_d, dst_d, ne00, ne01, ne02, ne03, s01, s02, s03, eps, stream);
698
+ }
backend/llama.cpp/ggml/src/ggml-cuda/norm.cuh ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ void ggml_cuda_op_norm(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
4
+
5
+ void ggml_cuda_op_group_norm(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
6
+
7
+ void ggml_cuda_op_rms_norm(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
8
+
9
+ void ggml_cuda_op_rms_norm_fused(ggml_backend_cuda_context & ctx, ggml_tensor * dst, ggml_tensor * mul_tensor);
10
+
11
+ void ggml_cuda_op_rms_norm_fused_add(ggml_backend_cuda_context & ctx,
12
+ ggml_tensor * dst,
13
+ ggml_tensor * mul_tensor,
14
+ ggml_tensor * add_tensor);
15
+
16
+ void ggml_cuda_op_rms_norm_back(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
17
+
18
+ void ggml_cuda_op_l2_norm(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/opt-step-adamw.cu ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "ggml-impl.h"
2
+ #include "opt-step-adamw.cuh"
3
+
4
+ #include <cstdint>
5
+
6
+ static __global__ void opt_step_adamw_f32(
7
+ float * __restrict__ x, const float * __restrict__ g, float * __restrict__ g_m, float * __restrict__ g_v,
8
+ const float * __restrict__ pars, const int64_t k) {
9
+
10
+ const int64_t i = (int64_t) blockIdx.x*blockDim.x + threadIdx.x;
11
+
12
+ if (i >= k) {
13
+ return;
14
+ }
15
+
16
+ const float alpha = pars[0];
17
+ const float beta1 = pars[1];
18
+ const float beta2 = pars[2];
19
+ const float eps = pars[3];
20
+ const float wd = pars[4];
21
+ const float beta1h = pars[5];
22
+ const float beta2h = pars[6];
23
+
24
+ const float gi = g[i];
25
+ const float gmi = g_m[i]*beta1 + gi*(1.0f - beta1);
26
+ const float gvi = g_v[i]*beta2 + gi*gi*(1.0f - beta2);
27
+
28
+ g_m[i] = gmi;
29
+ g_v[i] = gvi;
30
+
31
+ const float mh = gmi*beta1h;
32
+ const float vh = sqrtf(gvi*beta2h) + eps;
33
+
34
+ x[i] = x[i]*(1.0f - alpha*wd) - alpha*mh/vh;
35
+ }
36
+
37
+ static void opt_step_adamw_f32_cuda(
38
+ float * x, const float * g, float * g_m, float * g_v, const float * pars, const int64_t k, cudaStream_t stream) {
39
+
40
+ const dim3 block_dims(CUDA_OPT_STEP_ADAMW_BLOCK_SIZE, 1, 1);
41
+ const dim3 block_nums((k + CUDA_OPT_STEP_ADAMW_BLOCK_SIZE - 1) / CUDA_OPT_STEP_ADAMW_BLOCK_SIZE, 1, 1);
42
+ opt_step_adamw_f32<<<block_nums, block_dims, 0, stream>>>(x, g, g_m, g_v, pars, k);
43
+ }
44
+
45
+ void ggml_cuda_opt_step_adamw(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
46
+ const ggml_tensor * src0 = dst->src[0];
47
+ const ggml_tensor * src0_grad = dst->src[1];
48
+ const ggml_tensor * src0_grad_m = dst->src[2];
49
+ const ggml_tensor * src0_grad_v = dst->src[3];
50
+ const ggml_tensor * adamw_params = dst->src[4];
51
+
52
+ GGML_ASSERT(src0->type == GGML_TYPE_F32);
53
+ GGML_ASSERT(src0_grad->type == GGML_TYPE_F32);
54
+ GGML_ASSERT(src0_grad_m->type == GGML_TYPE_F32);
55
+ GGML_ASSERT(src0_grad_v->type == GGML_TYPE_F32);
56
+ GGML_ASSERT(adamw_params->type == GGML_TYPE_F32);
57
+ GGML_ASSERT(ggml_is_contiguous(src0));
58
+ GGML_ASSERT(ggml_is_contiguous(src0_grad));
59
+ GGML_ASSERT(ggml_is_contiguous(src0_grad_m));
60
+ GGML_ASSERT(ggml_is_contiguous(src0_grad_v));
61
+ GGML_ASSERT(ggml_is_contiguous(adamw_params));
62
+ GGML_ASSERT(ggml_are_same_shape(src0, src0_grad));
63
+ GGML_ASSERT(ggml_are_same_shape(src0, src0_grad_m));
64
+ GGML_ASSERT(ggml_are_same_shape(src0, src0_grad_v));
65
+ GGML_ASSERT(ggml_nelements(adamw_params) == 7);
66
+
67
+ float * src0_d = (float *) src0->data;
68
+ const float * src0_grad_d = (const float *) src0_grad->data;
69
+ float * src0_grad_m_d = (float *) src0_grad_m->data;
70
+ float * src0_grad_v_d = (float *) src0_grad_v->data;
71
+ const float * adamw_params_d = (const float *) adamw_params->data;
72
+
73
+ cudaStream_t stream = ctx.stream();
74
+
75
+ const int64_t ne = ggml_nelements(src0);
76
+
77
+ opt_step_adamw_f32_cuda(src0_d, src0_grad_d, src0_grad_m_d, src0_grad_v_d, adamw_params_d, ne, stream);
78
+ }
backend/llama.cpp/ggml/src/ggml-cuda/opt-step-adamw.cuh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ #define CUDA_OPT_STEP_ADAMW_BLOCK_SIZE 256
4
+
5
+ void ggml_cuda_opt_step_adamw(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/opt-step-sgd.cu ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "ggml-impl.h"
2
+ #include "opt-step-sgd.cuh"
3
+
4
+ #include <cstdint>
5
+
6
+ static __global__ void opt_step_sgd_f32(
7
+ float * __restrict__ x, const float * __restrict__ g,
8
+ const float * __restrict__ pars, const int64_t k) {
9
+
10
+ const int64_t i = (int64_t) blockIdx.x*blockDim.x + threadIdx.x;
11
+
12
+ if (i >= k) {
13
+ return;
14
+ }
15
+ x[i] = x[i] * (1.0f - pars[0] * pars[1]) - pars[0] * g[i];
16
+ }
17
+
18
+ static void opt_step_sgd_f32_cuda(
19
+ float * x, const float * g, const float * __restrict__ pars, const int64_t k, cudaStream_t stream) {
20
+
21
+ const dim3 block_dims(CUDA_OPT_STEP_SGD_BLOCK_SIZE, 1, 1);
22
+ const dim3 block_nums((k + CUDA_OPT_STEP_SGD_BLOCK_SIZE - 1) / CUDA_OPT_STEP_SGD_BLOCK_SIZE, 1, 1);
23
+ opt_step_sgd_f32<<<block_nums, block_dims, 0, stream>>>(x, g, pars, k);
24
+ }
25
+
26
+ void ggml_cuda_opt_step_sgd(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
27
+ const ggml_tensor * src0 = dst->src[0];
28
+ const ggml_tensor * src0_grad = dst->src[1];
29
+ const ggml_tensor * params = dst->src[2];
30
+
31
+ GGML_ASSERT(src0->type == GGML_TYPE_F32);
32
+ GGML_ASSERT(src0_grad->type == GGML_TYPE_F32);
33
+ GGML_ASSERT(params->type == GGML_TYPE_F32);
34
+ GGML_ASSERT(ggml_is_contiguous(src0));
35
+ GGML_ASSERT(ggml_is_contiguous(src0_grad));
36
+ GGML_ASSERT(ggml_is_contiguous(params));
37
+ GGML_ASSERT(ggml_are_same_shape(src0, src0_grad));
38
+ GGML_ASSERT(ggml_nelements(params) == 2);
39
+
40
+ float * src0_d = (float *) src0->data;
41
+ const float * src0_grad_d = (const float *) src0_grad->data;
42
+ const float * params_d = (const float *) params->data;
43
+
44
+ cudaStream_t stream = ctx.stream();
45
+
46
+ const int64_t ne = ggml_nelements(src0);
47
+
48
+ opt_step_sgd_f32_cuda(src0_d, src0_grad_d, params_d, ne, stream);
49
+ }
backend/llama.cpp/ggml/src/ggml-cuda/opt-step-sgd.cuh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ #define CUDA_OPT_STEP_SGD_BLOCK_SIZE 256
4
+
5
+ void ggml_cuda_opt_step_sgd(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/out-prod.cu ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "out-prod.cuh"
2
+
3
+ #include <cstdint>
4
+
5
+ static __global__ void k_compute_out_prod_ptrs(
6
+ const float * src0_d, const float * src1_d, float * dst_d,
7
+ const float ** ptrs_a, const float ** ptrs_b, float ** ptrs_c,
8
+ const int64_t ne2, const int64_t ne3,
9
+ const int64_t dps2, const int64_t dps3,
10
+ const size_t s02, const size_t s03,
11
+ const size_t s12, const size_t s13,
12
+ const size_t s2, const size_t s3) {
13
+ const int64_t i2 = blockIdx.x*blockDim.x + threadIdx.x;
14
+ const int64_t i3 = blockIdx.y*blockDim.y + threadIdx.y;
15
+
16
+ if (i2 >= ne2 || i3 >= ne3) {
17
+ return;
18
+ }
19
+
20
+ const int64_t idx = i3*ne2 + i2;
21
+
22
+ ptrs_a[idx] = src0_d + (i3/dps3)*s03 + (i2/dps2)*s02;
23
+ ptrs_b[idx] = src1_d + i3 *s13 + i2 *s12;
24
+ ptrs_c[idx] = dst_d + i3 *s3 + i2 *s2;
25
+ }
26
+
27
+ void ggml_cuda_out_prod(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
28
+ const ggml_tensor * src0 = dst->src[0];
29
+ const ggml_tensor * src1 = dst->src[1];
30
+
31
+ GGML_TENSOR_BINARY_OP_LOCALS
32
+
33
+ GGML_ASSERT(src0->type == GGML_TYPE_F32);
34
+ GGML_ASSERT(src1->type == GGML_TYPE_F32);
35
+ GGML_ASSERT(dst->type == GGML_TYPE_F32);
36
+
37
+ GGML_ASSERT(ne01 == ne11);
38
+ GGML_ASSERT(ne0 == ne00);
39
+ GGML_ASSERT(ne1 == ne10);
40
+
41
+ GGML_ASSERT(ne2 % src0->ne[2] == 0);
42
+ GGML_ASSERT(ne3 % src0->ne[3] == 0);
43
+
44
+ GGML_ASSERT(ne2 == src1->ne[2]);
45
+ GGML_ASSERT(ne3 == src1->ne[3]);
46
+
47
+ const float * src0_d = (const float *) src0->data;
48
+ const float * src1_d = (const float *) src1->data;
49
+ float * dst_d = (float *) dst->data;
50
+
51
+ cudaStream_t stream = ctx.stream();
52
+ cublasHandle_t handle = ctx.cublas_handle();
53
+
54
+ const float alpha = 1.0f;
55
+ const float beta = 0.0f;
56
+
57
+ CUBLAS_CHECK(cublasSetStream(handle, stream));
58
+
59
+ const int64_t lda = nb01 / sizeof(float);
60
+ const int64_t ldc = nb1 / sizeof(float);
61
+
62
+ const bool src1_T = ggml_is_transposed(src1);
63
+ const cublasOperation_t src1_cublas_op = src1_T ? CUBLAS_OP_N : CUBLAS_OP_T;
64
+ const int64_t ldb = (src1_T ? nb10 : nb11) / sizeof(float);
65
+ GGML_ASSERT( (src1_T ? nb11 : nb10) == sizeof(float));
66
+
67
+ // data strides in dimensions 2/3
68
+ const size_t s02 = nb02 / sizeof(float);
69
+ const size_t s03 = nb03 / sizeof(float);
70
+ const size_t s12 = nb12 / sizeof(float);
71
+ const size_t s13 = nb13 / sizeof(float);
72
+ const size_t s2 = nb2 / sizeof(float);
73
+ const size_t s3 = nb3 / sizeof(float);
74
+
75
+ // dps == dst per src0, used for group query attention
76
+ const int64_t dps2 = ne2 / ne02;
77
+ const int64_t dps3 = ne3 / ne03;
78
+
79
+ if (dps2 == 1 && ne2 > 1) {
80
+ // src0 has uniform stride s02 along dim 2; batch the inner loop with a strided GEMM
81
+ GGML_ASSERT(ne2 <= std::numeric_limits<int>::max());
82
+ const int batch_count = (int) ne2;
83
+ for (int64_t i3 = 0; i3 < ne3; ++i3) {
84
+ CUBLAS_CHECK(
85
+ cublasSgemmStridedBatched(handle, CUBLAS_OP_N, src1_cublas_op,
86
+ ne0, ne1, ne01,
87
+ &alpha, src0_d + (i3/dps3)*s03, lda, s02,
88
+ src1_d + i3 *s13, ldb, s12,
89
+ &beta, dst_d + i3 *s3, ldc, s2,
90
+ batch_count));
91
+ }
92
+ } else if (ne2 > 1 || ne3 > 1) {
93
+ // dps2 > 1 (src0 broadcast along dim 2 with non-uniform stride) or multiple GEMMs
94
+ // along dim 3: compute per-GEMM pointers on the device and use a single batched GEMM.
95
+ GGML_ASSERT(ne3 > 0);
96
+ GGML_ASSERT(ne2 <= (int64_t) std::numeric_limits<int>::max() / ne3);
97
+ const int batch_count = (int) (ne2 * ne3);
98
+
99
+ ggml_cuda_pool_alloc<const float *> ptrs_a(ctx.pool(), batch_count);
100
+ ggml_cuda_pool_alloc<const float *> ptrs_b(ctx.pool(), batch_count);
101
+ ggml_cuda_pool_alloc< float *> ptrs_c(ctx.pool(), batch_count);
102
+
103
+ const dim3 block_dims(16, 16);
104
+ const dim3 grid_dims((ne2 + block_dims.x - 1)/block_dims.x, (ne3 + block_dims.y - 1)/block_dims.y);
105
+ k_compute_out_prod_ptrs<<<grid_dims, block_dims, 0, stream>>>(
106
+ src0_d, src1_d, dst_d,
107
+ ptrs_a.get(), ptrs_b.get(), ptrs_c.get(),
108
+ ne2, ne3, dps2, dps3, s02, s03, s12, s13, s2, s3);
109
+ CUDA_CHECK(cudaGetLastError());
110
+
111
+ CUBLAS_CHECK(
112
+ cublasSgemmBatched(handle, CUBLAS_OP_N, src1_cublas_op,
113
+ ne0, ne1, ne01,
114
+ &alpha, ptrs_a.get(), lda,
115
+ ptrs_b.get(), ldb,
116
+ &beta, ptrs_c.get(), ldc,
117
+ batch_count));
118
+ } else {
119
+ // ne2 == 1 && ne3 == 1: single GEMM
120
+ CUBLAS_CHECK(
121
+ cublasSgemm(handle, CUBLAS_OP_N, src1_cublas_op,
122
+ ne0, ne1, ne01,
123
+ &alpha, src0_d, lda,
124
+ src1_d, ldb,
125
+ &beta, dst_d, ldc));
126
+ }
127
+ }
backend/llama.cpp/ggml/src/ggml-cuda/out-prod.cuh ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ void ggml_cuda_out_prod(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/pad.cu ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "pad.cuh"
2
+
3
+ #include <stdint.h>
4
+
5
+ __device__ __forceinline__ int64_t wrap_around(int64_t coord, int64_t size) {
6
+ // + size ensures negatives are handled properly
7
+ return (coord + size) % size;
8
+ }
9
+
10
+ static __global__ void pad_f32(const float * src, size_t s00, size_t s01, size_t s02, size_t s03, float * dst,
11
+ const int lp0, const int rp0, const int lp1, const int rp1,
12
+ const int lp2, const int rp2, const int lp3, const int rp3,
13
+ const int ne0, const int ne1, const int ne2, const int ne3,
14
+ const bool circular) {
15
+ // blockIdx.z: i3*ne2+i2
16
+ // blockIdx.y: i1
17
+ // blockIDx.x: i0 / CUDA_PAD_BLOCK_SIZE
18
+ // gridDim.y: ne1
19
+ int i0 = threadIdx.x + blockIdx.x * blockDim.x;
20
+ int i1 = blockIdx.y;
21
+ int i2 = blockIdx.z % ne2;
22
+ int i3 = blockIdx.z / ne2;
23
+
24
+ if (i0 >= ne0 || i1 >= ne1 || i2 >= ne2 || i3 >= ne3) {
25
+ return;
26
+ }
27
+
28
+ const int64_t dst_idx = i3 * (ne0 * ne1 * ne2) + i2 * (ne0 * ne1) + i1 * ne0 + i0;
29
+
30
+ if (!circular) {
31
+ if ((i0 >= lp0 && i0 < ne0 - rp0) && (i1 >= lp1 && i1 < ne1 - rp1) && (i2 >= lp2 && i2 < ne2 - rp2) &&
32
+ (i3 >= lp3 && i3 < ne3 - rp3)) {
33
+ const int64_t i00 = i0 - lp0;
34
+ const int64_t i01 = i1 - lp1;
35
+ const int64_t i02 = i2 - lp2;
36
+ const int64_t i03 = i3 - lp3;
37
+
38
+ const int64_t src_idx = i03 * s03 + i02 * s02 + i01 * s01 + i00 * s00;
39
+
40
+ dst[dst_idx] = src[src_idx];
41
+ } else {
42
+ dst[dst_idx] = 0.0f;
43
+ }
44
+ }
45
+ // circular means on a torus, so x and y wrap around
46
+ else {
47
+ const int64_t ne00 = ne0 - lp0 - rp0;
48
+ const int64_t ne01 = ne1 - lp1 - rp1;
49
+ const int64_t ne02 = ne2 - lp2 - rp2;
50
+ const int64_t ne03 = ne3 - lp3 - rp3;
51
+
52
+ const int64_t i00 = wrap_around(i0 - lp0, ne00);
53
+ const int64_t i01 = wrap_around(i1 - lp1, ne01);
54
+ const int64_t i02 = wrap_around(i2 - lp2, ne02);
55
+ const int64_t i03 = wrap_around(i3 - lp3, ne03);
56
+
57
+ const int64_t src_idx = i03 * s03 + i02 * s02 + i01 * s01 + i00 * s00;
58
+
59
+ dst[dst_idx] = src[src_idx];
60
+ }
61
+ }
62
+
63
+
64
+ static void pad_f32_cuda(const float * src, size_t s00, size_t s01, size_t s02, size_t s03, float * dst,
65
+ const int lp0, const int rp0, const int lp1, const int rp1,
66
+ const int lp2, const int rp2, const int lp3, const int rp3,
67
+ const int ne0, const int ne1, const int ne2, const int ne3,
68
+ const bool circular, cudaStream_t stream) {
69
+ int num_blocks = (ne0 + CUDA_PAD_BLOCK_SIZE - 1) / CUDA_PAD_BLOCK_SIZE;
70
+ dim3 gridDim(num_blocks, ne1, ne2 * ne3);
71
+ pad_f32<<<gridDim, CUDA_PAD_BLOCK_SIZE, 0, stream>>>(src, s00, s01, s02, s03, dst,
72
+ lp0, rp0, lp1, rp1, lp2, rp2, lp3, rp3,
73
+ ne0, ne1, ne2, ne3, circular);
74
+ }
75
+
76
+ void ggml_cuda_op_pad(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
77
+ const ggml_tensor * src0 = dst->src[0];
78
+ const float * src0_d = (const float *) src0->data;
79
+ float * dst_d = (float *) dst->data;
80
+ cudaStream_t stream = ctx.stream();
81
+
82
+ GGML_TENSOR_UNARY_OP_LOCALS;
83
+
84
+ GGML_ASSERT(src0->type == GGML_TYPE_F32);
85
+ GGML_ASSERT(dst->type == GGML_TYPE_F32);
86
+
87
+ const int32_t lp0 = ((const int32_t *) (dst->op_params))[0];
88
+ const int32_t rp0 = ((const int32_t *) (dst->op_params))[1];
89
+ const int32_t lp1 = ((const int32_t *) (dst->op_params))[2];
90
+ const int32_t rp1 = ((const int32_t *) (dst->op_params))[3];
91
+ const int32_t lp2 = ((const int32_t *) (dst->op_params))[4];
92
+ const int32_t rp2 = ((const int32_t *) (dst->op_params))[5];
93
+ const int32_t lp3 = ((const int32_t *) (dst->op_params))[6];
94
+ const int32_t rp3 = ((const int32_t *) (dst->op_params))[7];
95
+ const int32_t circular = ((const int32_t *) (dst->op_params))[8];
96
+
97
+ const size_t s00 = nb00 / ggml_type_size(src0->type);
98
+ const size_t s01 = nb01 / ggml_type_size(src0->type);
99
+ const size_t s02 = nb02 / ggml_type_size(src0->type);
100
+ const size_t s03 = nb03 / ggml_type_size(src0->type);
101
+
102
+ pad_f32_cuda(src0_d, s00, s01, s02, s03, dst_d,
103
+ lp0, rp0, lp1, rp1, lp2, rp2, lp3, rp3,
104
+ dst->ne[0], dst->ne[1], dst->ne[2], dst->ne[3],
105
+ (bool) circular, stream);
106
+ }
backend/llama.cpp/ggml/src/ggml-cuda/pad.cuh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ #define CUDA_PAD_BLOCK_SIZE 256
4
+
5
+ void ggml_cuda_op_pad(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/pad_reflect_1d.cu ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "pad_reflect_1d.cuh"
2
+
3
+ static __global__ __launch_bounds__(CUDA_PAD_REFLECT_1D_BLOCK_SIZE, 1) void
4
+ pad_reflect_1d_kernel_f32(
5
+ const void * __restrict__ src0,
6
+ void * __restrict__ dst,
7
+ const int64_t ne0,
8
+ const int64_t ne00,
9
+ const uint3 ne01,
10
+ const int64_t ne02,
11
+ const int64_t ne03,
12
+ const int64_t nb00,
13
+ const int64_t nb01,
14
+ const int64_t nb02,
15
+ const int64_t nb03,
16
+ const int64_t nb0,
17
+ const int64_t nb1,
18
+ const int64_t nb2,
19
+ const int64_t nb3,
20
+ const int p0,
21
+ const int p1) {
22
+ const int64_t i3 = blockIdx.z;
23
+ const int64_t i2 = blockIdx.y;
24
+
25
+ const uint2 div_mod_packed = fast_div_modulo(blockIdx.x, ne01);
26
+ const int64_t tile1 = div_mod_packed.y; // i1
27
+ const int64_t tile0 = div_mod_packed.x; // nth i0 tile
28
+ const int64_t i1 = tile1;
29
+ const int64_t i0 = threadIdx.x + tile0 * blockDim.x;
30
+
31
+ // ne01.z is original value of unpacked ne01 (see init_fastdiv_values in common.cuh)
32
+ if (i0 >= ne0 || i1 >= ne01.z || i2 >= ne02 || i3 >= ne03) {
33
+ return;
34
+ }
35
+
36
+ const char * src0_ptr = (const char *) src0 + i3 * nb03 + i2 * nb02 + i1 * nb01;
37
+ char * dst_ptr = (char *) dst + i3 * nb3 + i2 * nb2 + i1 * nb1;
38
+
39
+ const int64_t rel_i0 = i0 - p0; // relative i0 in src0
40
+ int64_t src_idx;
41
+
42
+ if (rel_i0 < 0) {
43
+ // Left padding - reflect
44
+ src_idx = -rel_i0;
45
+ } else if (rel_i0 < ne00) {
46
+ // Middle - copy
47
+ src_idx = rel_i0;
48
+ } else {
49
+ // Right padding - reflect
50
+ src_idx = 2 * ne00 - 2 - rel_i0;
51
+ }
52
+ const float value = *(const float *) (src0_ptr + src_idx * nb00);
53
+ *(float *) (dst_ptr + i0 * nb0) = value;
54
+
55
+ GGML_UNUSED(p1);
56
+ }
57
+
58
+ void ggml_cuda_op_pad_reflect_1d(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
59
+ const ggml_tensor * src0 = dst->src[0];
60
+ cudaStream_t stream = ctx.stream();
61
+
62
+ GGML_ASSERT(src0->type == GGML_TYPE_F32);
63
+ GGML_ASSERT(dst->type == GGML_TYPE_F32);
64
+
65
+ const int32_t * opts = (const int32_t *) dst->op_params;
66
+ const int p0 = opts[0];
67
+ const int p1 = opts[1];
68
+
69
+ const int64_t ne00 = src0->ne[0];
70
+ const int64_t ne01 = src0->ne[1];
71
+ const uint3 ne01_packed = init_fastdiv_values(ne01);
72
+ const int64_t ne02 = src0->ne[2];
73
+ const int64_t ne03 = src0->ne[3];
74
+
75
+ const int64_t ne0 = dst->ne[0];
76
+
77
+ // sanity: padded length matches
78
+ GGML_ASSERT(ne0 == ne00 + p0 + p1);
79
+
80
+ constexpr int64_t bx = CUDA_PAD_REFLECT_1D_BLOCK_SIZE; // threads per block (x)
81
+ const int64_t tiles0 = (ne0 + bx - 1) / bx; // number of tiles along i0
82
+ // grid.x covers i1 and all tiles of i0: [ne01 * tiles0]
83
+ // grid.y covers i2: [ne02]
84
+ // grid.z covers i3: [ne03]
85
+ const dim3 grid_dims((unsigned) (ne01 * tiles0), (unsigned) ne02, (unsigned) ne03);
86
+ const dim3 block_dims((unsigned) bx, 1, 1);
87
+
88
+ pad_reflect_1d_kernel_f32<<<grid_dims, block_dims, 0, stream>>>(
89
+ src0->data, dst->data, ne0, ne00, ne01_packed, ne02, ne03, src0->nb[0], src0->nb[1], src0->nb[2], src0->nb[3],
90
+ dst->nb[0], dst->nb[1], dst->nb[2], dst->nb[3], p0, p1);
91
+ }
backend/llama.cpp/ggml/src/ggml-cuda/pad_reflect_1d.cuh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ #define CUDA_PAD_REFLECT_1D_BLOCK_SIZE 256
4
+
5
+ void ggml_cuda_op_pad_reflect_1d(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/pool2d.cu ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "pool2d.cuh"
2
+
3
+ template <typename Ti, typename To>
4
+ static __global__ void pool2d_nchw_kernel(
5
+ const int ih, const int iw, const int oh, const int ow,
6
+ const int kh, const int kw, const int sh, const int sw,
7
+ const int ph, const int pw, const int parallel_elements,
8
+ const Ti* src, To* dst, const enum ggml_op_pool op) {
9
+ int idx = threadIdx.x + blockIdx.x * blockDim.x;
10
+ if (idx >= parallel_elements) {
11
+ return;
12
+ }
13
+
14
+ const int I_HW = ih * iw;
15
+ const int O_HW = oh * ow;
16
+ const int nc = idx / O_HW;
17
+ const int cur_oh = idx % O_HW / ow;
18
+ const int cur_ow = idx % O_HW % ow;
19
+ const Ti* i_ptr = src + nc * I_HW;
20
+ To* o_ptr = dst + nc * O_HW;
21
+ const int start_h = cur_oh * sh - ph;
22
+ const int bh = max(0, start_h);
23
+ const int eh = min(ih, start_h + kh);
24
+ const int start_w = cur_ow * sw - pw;
25
+ const int bw = max(0, start_w);
26
+ const int ew = min(iw, start_w + kw);
27
+ const To scale = 1. / (kh * kw);
28
+ To res = 0;
29
+
30
+ switch (op) {
31
+ case GGML_OP_POOL_AVG: res = 0; break;
32
+ case GGML_OP_POOL_MAX: res = -FLT_MAX; break;
33
+ default: assert(false);
34
+ }
35
+
36
+ for (int i = bh; i < eh; i += 1) {
37
+ for (int j = bw; j < ew; j += 1) {
38
+ #if __CUDA_ARCH__ >= 350
39
+ Ti cur = __ldg(i_ptr + i * iw + j);
40
+ #else
41
+ Ti cur = i_ptr[i * iw + j];
42
+ #endif
43
+ switch (op) {
44
+ case GGML_OP_POOL_AVG: res += cur * scale; break;
45
+ case GGML_OP_POOL_MAX: res = max(res, (To)cur); break;
46
+ default: assert(false);
47
+ }
48
+ }
49
+ }
50
+ o_ptr[cur_oh * ow + cur_ow] = res;
51
+ }
52
+
53
+ static void pool2d_nchw_kernel_f32_f32_cuda(
54
+ const int ih, const int iw, const int oh, const int ow,
55
+ const int kh, const int kw, const int sh, const int sw,
56
+ const int ph, const int pw, const int parallel_elements,
57
+ const float * src, float * dst, const enum ggml_op_pool op,
58
+ cudaStream_t stream) {
59
+
60
+ const int num_blocks = (parallel_elements + CUDA_POOL2D_BLOCK_SIZE - 1) / CUDA_POOL2D_BLOCK_SIZE;
61
+ dim3 block_nums(num_blocks);
62
+ pool2d_nchw_kernel<<<block_nums, CUDA_POOL2D_BLOCK_SIZE, 0, stream>>>(ih, iw, oh, ow, kh, kw, sh, sw, ph, pw, parallel_elements, src, dst, op);
63
+ }
64
+
65
+ void ggml_cuda_op_pool2d(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
66
+ const ggml_tensor * src0 = dst->src[0];
67
+ const float * src0_d = (const float *)src0->data;
68
+ float * dst_d = (float *)dst->data;
69
+ cudaStream_t stream = ctx.stream();
70
+
71
+ GGML_ASSERT(src0->type == GGML_TYPE_F32);
72
+ GGML_ASSERT( dst->type == GGML_TYPE_F32);
73
+
74
+ const int32_t * opts = (const int32_t *)dst->op_params;
75
+ enum ggml_op_pool op = static_cast<ggml_op_pool>(opts[0]);
76
+ const int k0 = opts[1];
77
+ const int k1 = opts[2];
78
+ const int s0 = opts[3];
79
+ const int s1 = opts[4];
80
+ const int p0 = opts[5];
81
+ const int p1 = opts[6];
82
+
83
+ const int64_t IH = src0->ne[1];
84
+ const int64_t IW = src0->ne[0];
85
+
86
+ const int64_t N = dst->ne[3];
87
+ const int64_t OC = dst->ne[2];
88
+ const int64_t OH = dst->ne[1];
89
+ const int64_t OW = dst->ne[0];
90
+
91
+ const int parallel_elements = N * OC * OH * OW;
92
+
93
+ pool2d_nchw_kernel_f32_f32_cuda(IH, IW, OH, OW, k1, k0, s1, s0, p1, p0, parallel_elements, src0_d, dst_d, op, stream);
94
+ }
backend/llama.cpp/ggml/src/ggml-cuda/pool2d.cuh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ #define CUDA_POOL2D_BLOCK_SIZE 256
4
+
5
+ void ggml_cuda_op_pool2d(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/quantize.cu ADDED
@@ -0,0 +1,450 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "quantize.cuh"
2
+ #include <cstdint>
3
+
4
+ __launch_bounds__(CUDA_QUANTIZE_BLOCK_SIZE, 1)
5
+ static __global__ void quantize_q8_1(
6
+ const float * x_ptr, void * vy_ptr,
7
+ const int64_t ne00, const int64_t s01, const int64_t s02, const int64_t s03,
8
+ const int64_t ne0, const uint32_t ne1, const uint3 ne2) {
9
+ ggml_cuda_pdl_lc();
10
+ const float * GGML_CUDA_RESTRICT x = x_ptr;
11
+ void * GGML_CUDA_RESTRICT vy = vy_ptr;
12
+ const int64_t i0 = (int64_t)blockDim.x*blockIdx.x + threadIdx.x;
13
+
14
+ if (i0 >= ne0) {
15
+ return;
16
+ }
17
+
18
+ const int64_t i3 = fastdiv(blockIdx.z, ne2);
19
+ const int64_t i2 = blockIdx.z - i3*ne2.z;
20
+ const int64_t i1 = blockIdx.y;
21
+
22
+ const int64_t & i00 = i0;
23
+ const int64_t & i01 = i1;
24
+ const int64_t & i02 = i2;
25
+ const int64_t & i03 = i3;
26
+
27
+ const int64_t i_cont = ((i3*ne2.z + i2) * ne1 + i1) * ne0 + i0;
28
+
29
+ block_q8_1 * y = (block_q8_1 *) vy;
30
+
31
+ const int64_t ib = i_cont / QK8_1; // block index
32
+ const int64_t iqs = i_cont % QK8_1; // quant index
33
+
34
+ ggml_cuda_pdl_sync();
35
+ const float xi = i0 < ne00 ? x[i03*s03 + i02*s02 + i01*s01 + i00] : 0.0f;
36
+ float amax = fabsf(xi);
37
+ float sum = xi;
38
+
39
+ amax = warp_reduce_max<QK8_1>(amax);
40
+ sum = warp_reduce_sum<QK8_1>(sum);
41
+
42
+ const float d = amax / 127.0f;
43
+ const int8_t q = amax == 0.0f ? 0 : roundf(xi / d);
44
+
45
+ y[ib].qs[iqs] = q;
46
+
47
+ if (iqs > 0) {
48
+ return;
49
+ }
50
+
51
+ y[ib].ds = make_half2(d, sum);
52
+ }
53
+
54
+ __device__ __forceinline__ uint8_t compute_e8m0_scale(float amax) {
55
+ if (!(amax > 0.0f)) {
56
+ return 0;
57
+ }
58
+
59
+ // FP4 E2M1: max exponent (unbiased) is 2.
60
+ constexpr int FP4_E2M1_EMAX = 2;
61
+
62
+ const float e = log2f(amax);
63
+
64
+ // "even" -> round-to-nearest integer, ties-to-even
65
+ const int e_int = __float2int_rn(e);
66
+
67
+ const int shared_exp = e_int - FP4_E2M1_EMAX;
68
+
69
+ int biased = shared_exp + 127;
70
+
71
+ biased = max(biased, 0);
72
+ biased = min(biased, 254);
73
+
74
+ return static_cast<uint8_t>(biased);
75
+ }
76
+
77
+
78
+ static __global__ void quantize_mmq_nvfp4(
79
+ const float * __restrict__ x, const int32_t * __restrict__ ids, void * __restrict__ vy,
80
+ const int64_t ne00, const int64_t s01, const int64_t s02, const int64_t s03,
81
+ const int64_t ne0, const int64_t ne1, const int64_t ne2) {
82
+ #if defined(BLACKWELL_MMA_AVAILABLE)
83
+
84
+ const int64_t i0_base = ((int64_t) blockDim.x * blockIdx.y + threadIdx.x) * QK_NVFP4_SUB;
85
+ if (i0_base >= ne0) {
86
+ return;
87
+ }
88
+
89
+ const int64_t i1 = blockIdx.x;
90
+ const int64_t i2 = blockIdx.z % ne2;
91
+ const int64_t i3 = blockIdx.z / ne2;
92
+ const int64_t i01 = ids ? ids[i1] : i1;
93
+ const int64_t k_block = i0_base / QK_K;
94
+ const int64_t blocks_per_col = (ne0 + QK_K - 1) / QK_K;
95
+ if (k_block >= blocks_per_col) {
96
+ return;
97
+ }
98
+
99
+ const int64_t ib = blockIdx.z * ((int64_t) blocks_per_col * ne1) + k_block * ne1 + blockIdx.x;
100
+ block_fp4_mmq * y = (block_fp4_mmq *) vy;
101
+ block_fp4_mmq * yb = y + ib;
102
+
103
+ const int sub = (i0_base % QK_K) / QK_NVFP4_SUB;
104
+
105
+ float vals_raw[QK_NVFP4_SUB];
106
+ float amax_raw = 0.0f;
107
+ const int64_t base_idx = i3 * s03 + i2 * s02 + i01 * s01;
108
+ #pragma unroll
109
+ for (int k = 0; k < QK_NVFP4_SUB; k++) {
110
+ const int64_t i00 = i0_base + k;
111
+ if (i00 < ne00) {
112
+ const float v = x[base_idx + i00];
113
+ vals_raw[k] = v;
114
+ amax_raw = fmaxf(amax_raw, fabsf(v));
115
+ } else {
116
+ vals_raw[k] = 0.0f;
117
+ }
118
+ }
119
+
120
+ static constexpr int test_offsets[5] = { 0, -1, 1, -2, 2};
121
+ const int first_fp8_code = (int) ggml_cuda_fp32_to_ue4m3(amax_raw / 6.0f);
122
+
123
+ float best_err = FLT_MAX;
124
+ uint8_t fp8_code = 0;
125
+ float subblock_scale = 0.0f;
126
+
127
+ #pragma unroll // Check +/- 2 to find best code to reduce NVFP4 activation loss. Negligible overhead on Blackwell.
128
+ for (int i = 0; i < 5; i++) {
129
+ const int test_code = first_fp8_code + test_offsets[i];
130
+ if (test_code < 0 || test_code > 0x7e) {
131
+ continue;
132
+ }
133
+ const uint8_t code = (uint8_t) test_code;
134
+ const float test_scale = ggml_cuda_ue4m3_to_fp32(code);
135
+ const float test_inv_scale = test_scale > 0.0f ? 0.5f / test_scale : 0.0f;
136
+ float cur_err = 0.0f;
137
+ #pragma unroll
138
+ for (int k = 0; k < QK_NVFP4_SUB; ++k) {
139
+ const float v = vals_raw[k];
140
+ const uint8_t q = ggml_cuda_float_to_fp4_e2m1(v, test_inv_scale);
141
+ const float err_diff = fabsf(v) - fabsf(kvalues_mxfp4[q & 0x7]) * test_scale;
142
+ cur_err = fmaf(err_diff, err_diff, cur_err);
143
+ }
144
+
145
+ if (cur_err < best_err) {
146
+ best_err = cur_err;
147
+ fp8_code = test_code;
148
+ subblock_scale = test_scale;
149
+ }
150
+ }
151
+
152
+ const float inv_scale = subblock_scale > 0.0f ? 0.5f / subblock_scale : 0.0f;
153
+ uint32_t q0 = 0;
154
+ uint32_t q1 = 0;
155
+ #pragma unroll // this is faster than the previous __nv_fp4x4_e2m1
156
+ for (int k = 0; k < QK_NVFP4_SUB / 4; ++k) {
157
+ q0 |= (uint32_t) ggml_cuda_float_to_fp4_e2m1(vals_raw[k + 0], inv_scale) << (8 * k);
158
+ q0 |= (uint32_t) ggml_cuda_float_to_fp4_e2m1(vals_raw[k + 8], inv_scale) << (8 * k + 4);
159
+ q1 |= (uint32_t) ggml_cuda_float_to_fp4_e2m1(vals_raw[k + 4], inv_scale) << (8 * k);
160
+ q1 |= (uint32_t) ggml_cuda_float_to_fp4_e2m1(vals_raw[k + 12], inv_scale) << (8 * k + 4);
161
+ }
162
+
163
+ uint32_t * yqs = reinterpret_cast<uint32_t *>(yb->qs);
164
+ yqs[2 * sub + 0] = q0;
165
+ yqs[2 * sub + 1] = q1;
166
+ reinterpret_cast<uint8_t *>(yb->d4)[sub] = fp8_code;
167
+ #else
168
+ NO_DEVICE_CODE; // This is for Blackwell NVFP4 activations only.
169
+ #endif // defined(BLACKWELL_MMA_AVAILABLE)
170
+
171
+ }
172
+
173
+ // quantize values in the format mxfp4 is stored which is interleaved nibbles
174
+ // i.e. a block a0-a31 is represented as a0a16,a1a17 ...a15a31
175
+ static __global__ void quantize_mmq_mxfp4(const float * __restrict__ x,
176
+ const int32_t * __restrict__ ids,
177
+ void * __restrict__ vy,
178
+ const int64_t ne00,
179
+ const int64_t s01,
180
+ const int64_t s02,
181
+ const int64_t s03,
182
+ const int64_t ne0,
183
+ const int ne1,
184
+ const int ne2) {
185
+ constexpr int vals_per_scale = 32;
186
+ constexpr int vals_per_warp = 2 * vals_per_scale; // Each warp processes 2 blocks of 32 = 64 values
187
+
188
+ const int warp_id = threadIdx.y;
189
+ const int lane_id_32 = threadIdx.x;
190
+
191
+ const int nwarps = blockDim.y;
192
+
193
+ const int64_t warp_start_offset = (blockIdx.y * nwarps + warp_id) * vals_per_warp;
194
+
195
+ if (warp_start_offset >= ne0) {
196
+ return;
197
+ }
198
+
199
+ const int64_t i1 = blockIdx.x;
200
+ const int64_t i2 = blockIdx.z % ne2;
201
+ const int64_t i3 = blockIdx.z / ne2;
202
+
203
+ ggml_cuda_pdl_sync();
204
+ const int64_t i01 = ids ? ids[i1] : i1;
205
+ const int64_t i02 = i2;
206
+ const int64_t i03 = i3;
207
+
208
+ block_fp4_mmq * y = (block_fp4_mmq *) vy;
209
+
210
+ const int64_t block_fp4_mmq_size = 8 * QK_MXFP4; // 256 values
211
+ const int64_t ib0 = blockIdx.z * ((int64_t) ne1 * (ne0 / block_fp4_mmq_size));
212
+ const int64_t ib = ib0 + (warp_start_offset / block_fp4_mmq_size) * ne1 + blockIdx.x;
213
+ const int64_t quad_idx_in_block = (warp_start_offset % block_fp4_mmq_size) / vals_per_warp;
214
+
215
+ const int group_id = lane_id_32 / 4;
216
+ const int lane_in_group = lane_id_32 % 4;
217
+ const int base = group_id * 2;
218
+ char2 * yqs2 = (char2 *) y[ib].qs;
219
+
220
+ const int64_t base_pos = i03 * s03 + i02 * s02 + i01 * s01;
221
+
222
+ uint8_t scales[2];
223
+
224
+ #pragma unroll
225
+ for (int b = 0; b < 2; ++b) {
226
+ const int64_t i0 = warp_start_offset + b * vals_per_scale + lane_id_32;
227
+ const float xi = (i0 < ne00) ? x[base_pos + i0] : 0.0f;
228
+
229
+ float amax = fabsf(xi);
230
+ #pragma unroll
231
+ for (int mask = 16; mask > 0; mask >>= 1) {
232
+ amax = fmaxf(amax, __shfl_xor_sync(0xFFFFFFFF, amax, mask, WARP_SIZE));
233
+ }
234
+
235
+ const uint8_t e = compute_e8m0_scale(amax);
236
+ scales[b] = e;
237
+ const float inv_s = (amax == 0.0f) ? 0.0f : __frcp_rn(ggml_cuda_e8m0_to_fp32(e));
238
+
239
+ #if CUDART_VERSION >= 12080
240
+ const float scaled_val = xi * inv_s;
241
+
242
+ const float val0 = __shfl_sync(0xFFFFFFFF, scaled_val, base, WARP_SIZE);
243
+ const float val1 = __shfl_sync(0xFFFFFFFF, scaled_val, base + 16, WARP_SIZE);
244
+ const float val2 = __shfl_sync(0xFFFFFFFF, scaled_val, base + 1, WARP_SIZE);
245
+ const float val3 = __shfl_sync(0xFFFFFFFF, scaled_val, base + 17, WARP_SIZE);
246
+
247
+ if (lane_in_group == 0) {
248
+ __nv_fp4x4_e2m1 fp4_packed(make_float4(val0, val1, val2, val3));
249
+
250
+ yqs2[quad_idx_in_block * 16 + b * 8 + group_id] = *(char2 *) &fp4_packed;
251
+ }
252
+ #else
253
+ // Fallback: manual FP4 conversion using LUT
254
+ const uint8_t q_val = ggml_cuda_float_to_fp4_e2m1(xi, inv_s);
255
+
256
+ const uint8_t q_lo_0 = __shfl_sync(0xFFFFFFFF, q_val, base, WARP_SIZE);
257
+ const uint8_t q_lo_1 = __shfl_sync(0xFFFFFFFF, q_val, base + 1, WARP_SIZE);
258
+ const uint8_t q_hi_0 = __shfl_sync(0xFFFFFFFF, q_val, base + 16, WARP_SIZE);
259
+ const uint8_t q_hi_1 = __shfl_sync(0xFFFFFFFF, q_val, base + 17, WARP_SIZE);
260
+
261
+ if (lane_in_group == 0) {
262
+ char2 q;
263
+ q.x = (q_hi_0 << 4) | q_lo_0;
264
+ q.y = (q_hi_1 << 4) | q_lo_1;
265
+ yqs2[quad_idx_in_block * 16 + b * 8 + group_id] = q;
266
+ }
267
+ #endif // CUDART_VERSION >= 12080
268
+ }
269
+
270
+ if (lane_id_32 == 0) {
271
+ // Store 2 scales packed into 1 uint32
272
+ y[ib].d4[quad_idx_in_block] = (scales[1] << 8) | scales[0];
273
+ }
274
+ }
275
+
276
+ template <mmq_q8_1_ds_layout ds_layout>
277
+ static __global__ void quantize_mmq_q8_1(
278
+ const float * __restrict__ x, const int32_t * __restrict__ ids, void * __restrict__ vy,
279
+ const int64_t ne00, const int64_t s01, const int64_t s02, const int64_t s03,
280
+ const int64_t ne0, const int ne1, const int ne2) {
281
+
282
+ constexpr int vals_per_scale = ds_layout == MMQ_Q8_1_DS_LAYOUT_D2S6 ? 64 : 32;
283
+ constexpr int vals_per_sum = ds_layout == MMQ_Q8_1_DS_LAYOUT_D2S6 ? 16 : 32;
284
+
285
+ const int64_t i0 = ((int64_t)blockDim.x*blockIdx.y + threadIdx.x)*4;
286
+
287
+ if (i0 >= ne0) {
288
+ return;
289
+ }
290
+
291
+ const int64_t i1 = blockIdx.x;
292
+ const int64_t i2 = blockIdx.z % ne2;
293
+ const int64_t i3 = blockIdx.z / ne2;
294
+
295
+ const int64_t i00 = i0;
296
+ ggml_cuda_pdl_sync();
297
+ const int64_t i01 = ids ? ids[i1] : i1;
298
+ const int64_t i02 = i2;
299
+ const int64_t i03 = i3;
300
+
301
+ const float4 * x4 = (const float4 *) x;
302
+
303
+ block_q8_1_mmq * y = (block_q8_1_mmq *) vy;
304
+
305
+ const int64_t ib0 = blockIdx.z*((int64_t)gridDim.x*gridDim.y*blockDim.x/QK8_1); // first block of channel
306
+ const int64_t ib = ib0 + (i0 / (4*QK8_1))*ne1 + blockIdx.x; // block index in channel
307
+ const int64_t iqs = i0 % (4*QK8_1); // quant index in block
308
+
309
+ // Load 4 floats per thread and calculate max. abs. value between them:
310
+ const float4 xi = i0 < ne00 ? x4[(i03*s03 + i02*s02 + i01*s01 + i00)/4] : make_float4(0.0f, 0.0f, 0.0f, 0.0f);
311
+ float amax = fabsf(xi.x);
312
+ amax = fmaxf(amax, fabsf(xi.y));
313
+ amax = fmaxf(amax, fabsf(xi.z));
314
+ amax = fmaxf(amax, fabsf(xi.w));
315
+
316
+ // Exchange max. abs. value between vals_per_scale/4 threads.
317
+ #pragma unroll
318
+ for (int offset = vals_per_scale/8; offset > 0; offset >>= 1) {
319
+ amax = fmaxf(amax, __shfl_xor_sync(0xFFFFFFFF, amax, offset, WARP_SIZE));
320
+ }
321
+
322
+ float sum;
323
+ if (ds_layout != MMQ_Q8_1_DS_LAYOUT_D4) {
324
+ sum = xi.x + xi.y + xi.z + xi.w;
325
+
326
+ // Calculate sums across vals_per_sum/4 threads.
327
+ #pragma unroll
328
+ for (int offset = vals_per_sum/8; offset > 0; offset >>= 1) {
329
+ sum += __shfl_xor_sync(0xFFFFFFFF, sum, offset, WARP_SIZE);
330
+ }
331
+ }
332
+
333
+ const float d_inv = 127.0f / amax;
334
+ char4 q;
335
+ q.x = roundf(xi.x*d_inv);
336
+ q.y = roundf(xi.y*d_inv);
337
+ q.z = roundf(xi.z*d_inv);
338
+ q.w = roundf(xi.w*d_inv);
339
+
340
+ // Write back 4 int8 values as a single 32 bit value for better memory bandwidth:
341
+ char4 * yqs4 = (char4 *) y[ib].qs;
342
+ yqs4[iqs/4] = q;
343
+
344
+ if (ds_layout == MMQ_Q8_1_DS_LAYOUT_D2S6) {
345
+ if (iqs % 16 != 0 || iqs >= 96) {
346
+ return;
347
+ }
348
+
349
+ y[ib].d2s6[2 + iqs/16] = sum;
350
+
351
+ if (iqs % 64 != 0) {
352
+ return;
353
+ }
354
+
355
+ const float d = 1.0f / d_inv;
356
+
357
+ y[ib].d2s6[iqs/64] = d;
358
+
359
+ return;
360
+ }
361
+
362
+ if (iqs % 32 != 0) {
363
+ return;
364
+ }
365
+
366
+ const float d = 1.0f / d_inv;
367
+
368
+ if (ds_layout == MMQ_Q8_1_DS_LAYOUT_DS4) {
369
+ y[ib].ds4[iqs/32] = make_half2(d, sum);
370
+ } else {
371
+ y[ib].d4[iqs/32] = d;
372
+ }
373
+ }
374
+
375
+ void quantize_row_q8_1_cuda(
376
+ const float * x, const int32_t * ids, void * vy, const ggml_type type_src0,
377
+ const int64_t ne00, const int64_t s01, const int64_t s02, const int64_t s03,
378
+ const int64_t ne0, const int64_t ne1, const int64_t ne2, const int64_t ne3, cudaStream_t stream) {
379
+ GGML_ASSERT(!ids);
380
+ GGML_ASSERT(ne0 % QK8_1 == 0);
381
+
382
+ const uint3 ne2_fastdiv = init_fastdiv_values(ne2);
383
+
384
+ const int64_t block_num_x = (ne0 + CUDA_QUANTIZE_BLOCK_SIZE - 1) / CUDA_QUANTIZE_BLOCK_SIZE;
385
+ const dim3 num_blocks(block_num_x, ne1, ne2*ne3);
386
+ const dim3 block_size(CUDA_QUANTIZE_BLOCK_SIZE, 1, 1);
387
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(num_blocks, block_size, 0, stream);
388
+ ggml_cuda_kernel_launch(quantize_q8_1, launch_params, x, vy, ne00, s01, s02, s03, ne0, ne1, ne2_fastdiv);
389
+ GGML_UNUSED(type_src0);
390
+ }
391
+
392
+ void quantize_mmq_q8_1_cuda(
393
+ const float * x, const int32_t * ids, void * vy, const ggml_type type_src0,
394
+ const int64_t ne00, const int64_t s01, const int64_t s02, const int64_t s03,
395
+ const int64_t ne0, const int64_t ne1, const int64_t ne2, const int64_t ne3, cudaStream_t stream) {
396
+ GGML_ASSERT(ne00 % 4 == 0);
397
+ GGML_ASSERT(ne0 % (4*QK8_1) == 0);
398
+
399
+ // ne1 tends to assume the highest values, therefore use it as the "x" dimension of the CUDA grid:
400
+ const int64_t block_num_y = (ne0 + 4*CUDA_QUANTIZE_BLOCK_SIZE_MMQ - 1) / (4*CUDA_QUANTIZE_BLOCK_SIZE_MMQ);
401
+ const dim3 num_blocks(ne1, block_num_y, ne2*ne3);
402
+ const dim3 block_size(CUDA_QUANTIZE_BLOCK_SIZE_MMQ, 1, 1);
403
+ switch (mmq_get_q8_1_ds_layout(type_src0)) {
404
+ case MMQ_Q8_1_DS_LAYOUT_D4:
405
+ quantize_mmq_q8_1<MMQ_Q8_1_DS_LAYOUT_D4>
406
+ <<<num_blocks, block_size, 0, stream>>>(x, ids, vy, ne00, s01, s02, s03, ne0, ne1, ne2);
407
+ break;
408
+ case MMQ_Q8_1_DS_LAYOUT_DS4:
409
+ quantize_mmq_q8_1<MMQ_Q8_1_DS_LAYOUT_DS4>
410
+ <<<num_blocks, block_size, 0, stream>>>(x, ids, vy, ne00, s01, s02, s03, ne0, ne1, ne2);
411
+ break;
412
+ case MMQ_Q8_1_DS_LAYOUT_D2S6:
413
+ quantize_mmq_q8_1<MMQ_Q8_1_DS_LAYOUT_D2S6>
414
+ <<<num_blocks, block_size, 0, stream>>>(x, ids, vy, ne00, s01, s02, s03, ne0, ne1, ne2);
415
+ break;
416
+ default:
417
+ GGML_ABORT("fatal error");
418
+ break;
419
+ }
420
+ }
421
+
422
+ void quantize_mmq_fp4_cuda(
423
+ const float * x, const int32_t * ids, void * vy, const ggml_type type_src0,
424
+ const int64_t ne00, const int64_t s01, const int64_t s02, const int64_t s03,
425
+ const int64_t ne0, const int64_t ne1, const int64_t ne2, const int64_t ne3, cudaStream_t stream) {
426
+ GGML_ASSERT(type_src0 == GGML_TYPE_MXFP4 || type_src0 == GGML_TYPE_NVFP4);
427
+ GGML_ASSERT(ne0 > 0);
428
+
429
+ if (type_src0 == GGML_TYPE_NVFP4) {
430
+ GGML_ASSERT(ne00 % QK_NVFP4 == 0);
431
+ constexpr int nvfp4_block_size = 128;
432
+ const int64_t block_num_y = (ne0 + QK_NVFP4_SUB * nvfp4_block_size - 1) / (QK_NVFP4_SUB * nvfp4_block_size);
433
+ const dim3 block_size(nvfp4_block_size, 1, 1);
434
+ const dim3 num_blocks(ne1, block_num_y, ne2 * ne3);
435
+ quantize_mmq_nvfp4<<<num_blocks, block_size, 0, stream>>>(
436
+ x, ids, vy, ne00, s01, s02, s03, ne0, ne1, ne2);
437
+ } else {
438
+ GGML_ASSERT(ne0 % (2 * QK_MXFP4) == 0);
439
+
440
+ constexpr int nwarps = 8;
441
+ constexpr int vals_per_warp = 2 * QK_MXFP4;
442
+ constexpr int vals_per_block = nwarps * vals_per_warp;
443
+
444
+ const int64_t block_num_y = (ne0 + vals_per_block - 1) / vals_per_block;
445
+ const dim3 num_blocks(ne1, block_num_y, ne2 * ne3);
446
+ const dim3 block_size(WARP_SIZE, nwarps, 1);
447
+
448
+ quantize_mmq_mxfp4<<<num_blocks, block_size, 0, stream>>>(x, ids, vy, ne00, s01, s02, s03, ne0, ne1, ne2);
449
+ }
450
+ }
backend/llama.cpp/ggml/src/ggml-cuda/quantize.cuh ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #pragma once
2
+
3
+ #include "common.cuh"
4
+ #include "mmq.cuh"
5
+
6
+ #include <cstdint>
7
+
8
+ #define CUDA_QUANTIZE_BLOCK_SIZE 256
9
+ #define CUDA_QUANTIZE_BLOCK_SIZE_MMQ 128
10
+
11
+ static_assert(MATRIX_ROW_PADDING % CUDA_QUANTIZE_BLOCK_SIZE == 0, "Risk of out-of-bounds access.");
12
+ static_assert(MATRIX_ROW_PADDING % (4*CUDA_QUANTIZE_BLOCK_SIZE_MMQ) == 0, "Risk of out-of-bounds access.");
13
+
14
+ typedef void (*quantize_cuda_t)(
15
+ const float * x, const int32_t * ids, void * vy,
16
+ ggml_type type_src0, int64_t ne00, int64_t s01, int64_t s02, int64_t s03,
17
+ int64_t ne0, int64_t ne1, int64_t ne2, int64_t ne3, cudaStream_t stream);
18
+
19
+ void quantize_row_q8_1_cuda(
20
+ const float * x, const int32_t * ids, void * vy,
21
+ ggml_type type_src0, int64_t ne00, int64_t s01, int64_t s02, int64_t s03,
22
+ int64_t ne0, int64_t ne1, int64_t ne2, int64_t ne3, cudaStream_t stream);
23
+
24
+ void quantize_mmq_q8_1_cuda(
25
+ const float * x, const int32_t * ids, void * vy,
26
+ ggml_type type_src0, int64_t ne00, int64_t s01, int64_t s02, int64_t s03,
27
+ int64_t ne0, int64_t ne1, int64_t ne2, int64_t ne3, cudaStream_t stream);
28
+
29
+ void quantize_mmq_fp4_cuda(const float * x,
30
+ const int32_t * ids,
31
+ void * vy,
32
+ ggml_type type_src0,
33
+ int64_t ne00,
34
+ int64_t s01,
35
+ int64_t s02,
36
+ int64_t s03,
37
+ int64_t ne0,
38
+ int64_t ne1,
39
+ int64_t ne2,
40
+ int64_t ne3,
41
+ cudaStream_t stream);
backend/llama.cpp/ggml/src/ggml-cuda/reduce_rows.cuh ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ // Row reduction kernel template - compute sum (norm=false) or mean (norm=true)
4
+ template <bool norm>
5
+ static __global__ void reduce_rows_f32(const float * x_ptr, float * dst_ptr, const int ncols) {
6
+ const float * GGML_CUDA_RESTRICT x = x_ptr;
7
+ float * GGML_CUDA_RESTRICT dst = dst_ptr;
8
+ const int row = blockIdx.x;
9
+ const int col = threadIdx.x;
10
+
11
+ float sum = 0.0f;
12
+ const int num_unroll = 8;
13
+ float temp[num_unroll];
14
+ float sum_temp[num_unroll] = { 0.0f };
15
+
16
+ ggml_cuda_pdl_sync();
17
+ for (int i = col; i < ncols;) {
18
+ for (int j = 0; j < num_unroll; ++j) {
19
+ if (i < ncols) {
20
+ temp[j] = x[row * ncols + i];
21
+ } else {
22
+ temp[j] = 0;
23
+ }
24
+ i += blockDim.x;
25
+ }
26
+ for (int j = 0; j < num_unroll; ++j) {
27
+ sum_temp[j] += temp[j];
28
+ }
29
+ }
30
+ for (int j = 0; j < num_unroll; ++j) {
31
+ sum += sum_temp[j];
32
+ }
33
+
34
+ // sum up partial sums
35
+ __shared__ float shared_vals[32];
36
+ sum = block_reduce<block_reduce_method::SUM>(sum, shared_vals);
37
+
38
+ if (col != 0) {
39
+ return;
40
+ }
41
+
42
+ dst[row] = norm ? sum / ncols : sum;
43
+ }
backend/llama.cpp/ggml/src/ggml-cuda/roll.cu ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "ggml-cuda/common.cuh"
2
+ #include "roll.cuh"
3
+
4
+ static __forceinline__ __device__ int64_t wrap_index(const int64_t idx, const int64_t ne) {
5
+ if (idx < 0) {
6
+ return idx + ne;
7
+ }
8
+ if (idx >= ne) {
9
+ return idx - ne;
10
+ }
11
+ return idx;
12
+ }
13
+
14
+ static __global__ void roll_f32_cuda(const float * __restrict__ src,
15
+ float * __restrict__ dst,
16
+ const int64_t ne00,
17
+ const int64_t ne01,
18
+ const int64_t ne02,
19
+ const int64_t ne03,
20
+ const int s0,
21
+ const int s1,
22
+ const int s2,
23
+ const int s3) {
24
+ const int64_t idx = int64_t(blockDim.x) * blockIdx.x + threadIdx.x;
25
+ const int64_t n_elements = ne00 * ne01 * ne02 * ne03;
26
+
27
+ if (idx >= n_elements) {
28
+ return;
29
+ }
30
+
31
+ const int64_t i0 = idx % ne00;
32
+ const int64_t i1 = (idx / ne00) % ne01;
33
+ const int64_t i2 = (idx / (ne00 * ne01)) % ne02;
34
+ const int64_t i3 = (idx / (ne00 * ne01 * ne02)) % ne03;
35
+
36
+ const int64_t d0 = wrap_index(i0 - s0, ne00);
37
+ const int64_t d1 = wrap_index(i1 - s1, ne01);
38
+ const int64_t d2 = wrap_index(i2 - s2, ne02);
39
+ const int64_t d3 = wrap_index(i3 - s3, ne03);
40
+
41
+ dst[i3 * (ne00 * ne01 * ne02) + i2 * (ne01 * ne00) + i1 * ne00 + i0] =
42
+ src[d3 * (ne00 * ne01 * ne02) + d2 * (ne01 * ne00) + d1 * ne00 + d0];
43
+ }
44
+
45
+ void ggml_cuda_op_roll(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
46
+ int s0 = dst->op_params[0];
47
+ int s1 = dst->op_params[1];
48
+ int s2 = dst->op_params[2];
49
+ int s3 = dst->op_params[3];
50
+
51
+ const ggml_tensor * src0 = dst->src[0];
52
+ const float * src0_d = (const float *) dst->src[0]->data;
53
+ float * dst_d = (float *) dst->data;
54
+
55
+ GGML_TENSOR_UNARY_OP_LOCALS;
56
+
57
+ GGML_ASSERT(dst->src[0]->type == GGML_TYPE_F32);
58
+ GGML_ASSERT(ggml_are_same_shape(dst->src[0], dst));
59
+
60
+ cudaStream_t stream = ctx.stream();
61
+
62
+ int64_t sz = (ne00 * ne01 * ne02 * ne03);
63
+ int64_t num_blocks = (sz + CUDA_ROLL_BLOCK_SIZE - 1) / CUDA_ROLL_BLOCK_SIZE;
64
+
65
+ roll_f32_cuda<<<num_blocks, CUDA_ROLL_BLOCK_SIZE, 0, stream>>>(
66
+ src0_d, dst_d, ne00, ne01, ne02, ne03, s0, s1, s2, s3);
67
+ }
backend/llama.cpp/ggml/src/ggml-cuda/roll.cuh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ #define CUDA_ROLL_BLOCK_SIZE 256
4
+
5
+ void ggml_cuda_op_roll(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/rope.cu ADDED
@@ -0,0 +1,672 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "convert.cuh"
2
+ #include "ggml-cuda/common.cuh"
3
+ #include "ggml.h"
4
+ #include "rope.cuh"
5
+
6
+ struct rope_corr_dims {
7
+ float v[2];
8
+ };
9
+
10
+
11
+ struct mrope_sections {
12
+ int v[4];
13
+ };
14
+
15
+ static __device__ float rope_yarn_ramp(const float low, const float high, const int i0) {
16
+ const float y = (i0 / 2 - low) / max(0.001f, high - low);
17
+ return 1.0f - min(1.0f, max(0.0f, y));
18
+ }
19
+
20
+ // YaRN algorithm based on LlamaYaRNScaledRotaryEmbedding.py from https://github.com/jquesnelle/yarn
21
+ // MIT licensed. Copyright (c) 2023 Jeffrey Quesnelle and Bowen Peng.
22
+ template<bool forward>
23
+ static __device__ void rope_yarn(
24
+ const float theta_extrap, const float freq_scale, const rope_corr_dims corr_dims, const int64_t i0, const float ext_factor,
25
+ float mscale, float & cos_theta, float & sin_theta) {
26
+ // Get n-d rotational scaling corrected for extrapolation
27
+ float theta_interp = freq_scale * theta_extrap;
28
+ float theta = theta_interp;
29
+ if (ext_factor != 0.0f) {
30
+ float ramp_mix = rope_yarn_ramp(corr_dims.v[0], corr_dims.v[1], i0) * ext_factor;
31
+ theta = theta_interp * (1 - ramp_mix) + theta_extrap * ramp_mix;
32
+
33
+ // Get n-d magnitude scaling corrected for interpolation
34
+ mscale *= 1.0f + 0.1f * logf(1.0f / freq_scale);
35
+ }
36
+ cos_theta = cosf(theta) * mscale;
37
+ sin_theta = sinf(theta) * mscale;
38
+ if (!forward) {
39
+ sin_theta *= -1.0f;
40
+ }
41
+ }
42
+
43
+ template <bool forward, bool has_ff, typename T, typename D>
44
+ static __global__ void rope_norm(const T * x,
45
+ D * dst,
46
+ const int ne00,
47
+ const int ne01,
48
+ const int ne02,
49
+ const int s01,
50
+ const int s02,
51
+ const int s03,
52
+ const int s1,
53
+ const int s2,
54
+ const int s3,
55
+ const int n_dims,
56
+ const int32_t * pos,
57
+ const float freq_scale,
58
+ const float ext_factor,
59
+ const float attn_factor,
60
+ const rope_corr_dims corr_dims,
61
+ const float theta_scale,
62
+ const float * freq_factors,
63
+ const int64_t * row_indices,
64
+ const int set_rows_stride) {
65
+ const int i0 = 2*(blockDim.y*blockIdx.y + threadIdx.y);
66
+
67
+ if (i0 >= ne00) {
68
+ return;
69
+ }
70
+
71
+ const int row_dst = blockDim.x*blockIdx.x + threadIdx.x;
72
+
73
+ const uint32_t i3 = row_dst / (ne01 * ne02);
74
+ const uint32_t i2 = (row_dst - i3 * ne01 * ne02) / ne01;
75
+ const uint32_t i1 = row_dst - i3 * ne01 * ne02 - i2 * ne01;
76
+
77
+ int idst = i0 + i1 * s1 + i2 * s2 + i3 * s3;
78
+ const int ix = i0 + i1 * s01 + i2 * s02 + i3 * s03;
79
+ // Fusion optimization: ROPE + VIEW + SET_ROWS.
80
+ // The rope output is viewed as a 1D tensor and offset based on a row index in row_indices.
81
+ if (set_rows_stride != 0) {
82
+ idst = i1 * s1 + i0;
83
+ idst += row_indices[i2] * set_rows_stride;
84
+ }
85
+
86
+ const auto & store_coaelsced = [&](float x0, float x1) {
87
+ if constexpr (std::is_same_v<float, D>) {
88
+ float2 v = make_float2(x0, x1);
89
+ ggml_cuda_memcpy_1<8>(dst + idst, &v);
90
+ } else if constexpr (std::is_same_v<half, D>) {
91
+ half2 v = make_half2(x0, x1);
92
+ ggml_cuda_memcpy_1<4>(dst + idst, &v);
93
+ }
94
+ };
95
+ if (i0 >= n_dims) {
96
+ store_coaelsced(x[ix + 0], x[ix + 1]);
97
+ return;
98
+ }
99
+
100
+ const float theta_base = pos[i2]*powf(theta_scale, i0/2.0f);
101
+
102
+ const float freq_factor = has_ff ? freq_factors[i0/2] : 1.0f;
103
+
104
+ float cos_theta;
105
+ float sin_theta;
106
+
107
+ rope_yarn<forward>(theta_base/freq_factor, freq_scale, corr_dims, i0, ext_factor, attn_factor, cos_theta, sin_theta);
108
+
109
+ const float x0 = x[ix + 0];
110
+ const float x1 = x[ix + 1];
111
+
112
+ store_coaelsced(x0 * cos_theta - x1 * sin_theta, x0 * sin_theta + x1 * cos_theta);
113
+ }
114
+
115
+ template <bool forward, bool has_ff, typename T, typename D>
116
+ static __global__ void rope_neox(const T * x,
117
+ D * dst,
118
+ const int ne00,
119
+ const int ne01,
120
+ const int ne02,
121
+ const int s01,
122
+ const int s02,
123
+ const int s03,
124
+ const int s1,
125
+ const int s2,
126
+ const int s3,
127
+ const int n_dims,
128
+ const int32_t * pos,
129
+ const float freq_scale,
130
+ const float ext_factor,
131
+ const float attn_factor,
132
+ const rope_corr_dims corr_dims,
133
+ const float theta_scale,
134
+ const float * freq_factors,
135
+ const int64_t * row_indices,
136
+ const int set_rows_stride) {
137
+ ggml_cuda_pdl_lc();
138
+ const int i0 = 2*(blockDim.y*blockIdx.y + threadIdx.y);
139
+
140
+ if (i0 >= ne00) {
141
+ return;
142
+ }
143
+
144
+ const int row_dst = blockDim.x*blockIdx.x + threadIdx.x;
145
+
146
+ const uint32_t i3 = row_dst / (ne01 * ne02);
147
+ const uint32_t i2 = (row_dst - i3 * ne01 * ne02) / ne01;
148
+ const uint32_t i1 = row_dst - i3 * ne01 * ne02 - i2 * ne01;
149
+
150
+ int idst = i0 / 2 + i1 * s1 + i2 * s2 + i3 * s3;
151
+ const int ix = i0 / 2 + i1 * s01 + i2 * s02 + i3 * s03;
152
+ ggml_cuda_pdl_sync();
153
+
154
+ // Fusion optimization: ROPE + VIEW + SET_ROWS.
155
+ // The rope output is viewed as a 1D tensor and offset based on a row index in row_indices.
156
+ if (set_rows_stride != 0) {
157
+ idst = i1 * s1 + i0 / 2;
158
+ idst += row_indices[i2] * set_rows_stride;
159
+ }
160
+
161
+ if (i0 >= n_dims) {
162
+ dst[idst + i0 / 2 + 0] = ggml_cuda_cast<D>(x[ix + i0 / 2 + 0]);
163
+ dst[idst + i0 / 2 + 1] = ggml_cuda_cast<D>(x[ix + i0 / 2 + 1]);
164
+
165
+ return;
166
+ }
167
+
168
+ const float theta_base = pos[i2]*powf(theta_scale, i0/2.0f);
169
+
170
+ const float freq_factor = has_ff ? freq_factors[i0/2] : 1.0f;
171
+
172
+ float cos_theta;
173
+ float sin_theta;
174
+
175
+ rope_yarn<forward>(theta_base/freq_factor, freq_scale, corr_dims, i0, ext_factor, attn_factor, cos_theta, sin_theta);
176
+
177
+ const float x0 = x[ix + 0];
178
+ const float x1 = x[ix + n_dims/2];
179
+
180
+ dst[idst + 0] = ggml_cuda_cast<D>(x0 * cos_theta - x1 * sin_theta);
181
+ dst[idst + n_dims / 2] = ggml_cuda_cast<D>(x0 * sin_theta + x1 * cos_theta);
182
+ }
183
+
184
+ template <bool forward, bool has_ff, typename T>
185
+ static __global__ void rope_multi(const T * x,
186
+ T * dst,
187
+ const int ne00,
188
+ const int ne01,
189
+ const int ne02,
190
+ const int s01,
191
+ const int s02,
192
+ const int s03,
193
+ const int s1,
194
+ const int s2,
195
+ const int s3,
196
+ const int n_dims,
197
+ const int32_t * pos,
198
+ const float freq_scale,
199
+ const float ext_factor,
200
+ const float attn_factor,
201
+ const rope_corr_dims corr_dims,
202
+ const float theta_scale,
203
+ const float * freq_factors,
204
+ const mrope_sections sections,
205
+ const bool is_imrope) {
206
+ const int i0 = 2 * (blockDim.y * blockIdx.y + threadIdx.y);
207
+
208
+ if (i0 >= ne00) {
209
+ return;
210
+ }
211
+
212
+ const int row_dst = blockDim.x*blockIdx.x + threadIdx.x;
213
+
214
+ const uint32_t i3 = row_dst / (ne01 * ne02);
215
+ const uint32_t i2 = (row_dst - i3 * ne01 * ne02) / ne01;
216
+ const uint32_t i1 = row_dst - i3 * ne01 * ne02 - i2 * ne01;
217
+
218
+ int idst = i0 / 2 + i1 * s1 + i2 * s2 + i3 * s3;
219
+ const int ix = i0 / 2 + i1 * s01 + i2 * s02 + i3 * s03;
220
+
221
+ ggml_cuda_pdl_sync();
222
+ if (i0 >= n_dims) {
223
+ dst[idst + i0/2 + 0] = x[ix + i0/2 + 0];
224
+ dst[idst + i0/2 + 1] = x[ix + i0/2 + 1];
225
+
226
+ return;
227
+ }
228
+
229
+ const int sect_dims = sections.v[0] + sections.v[1] + sections.v[2] + sections.v[3];
230
+ const int sec_w = sections.v[1] + sections.v[0];
231
+ const int sector = (i0 / 2) % sect_dims;
232
+
233
+ float theta_base = 0.0;
234
+ if (is_imrope) {
235
+ if (sector % 3 == 1 && sector < 3 * sections.v[1]) { // h
236
+ theta_base = pos[i2 + ne02 * 1] * powf(theta_scale, i0 / 2.0f);
237
+ } else if (sector % 3 == 2 && sector < 3 * sections.v[2]) { // w
238
+ theta_base = pos[i2 + ne02 * 2] * powf(theta_scale, i0 / 2.0f);
239
+ } else if (sector % 3 == 0 && sector < 3 * sections.v[0]) { // t
240
+ theta_base = pos[i2] * powf(theta_scale, i0 / 2.0f);
241
+ } else {
242
+ theta_base = pos[i2 + ne02 * 3] * powf(theta_scale, i0 / 2.0f);
243
+ }
244
+ } else {
245
+ if (sector < sections.v[0]) {
246
+ theta_base = pos[i2] * powf(theta_scale, i0 / 2.0f);
247
+ } else if (sector >= sections.v[0] && sector < sec_w) {
248
+ theta_base = pos[i2 + ne02 * 1] * powf(theta_scale, i0 / 2.0f);
249
+ } else if (sector >= sec_w && sector < sec_w + sections.v[2]) {
250
+ theta_base = pos[i2 + ne02 * 2] * powf(theta_scale, i0 / 2.0f);
251
+ } else if (sector >= sec_w + sections.v[2]) {
252
+ theta_base = pos[i2 + ne02 * 3] * powf(theta_scale, i0 / 2.0f);
253
+ }
254
+ }
255
+
256
+ const float freq_factor = has_ff ? freq_factors[i0/2] : 1.0f;
257
+
258
+ float cos_theta;
259
+ float sin_theta;
260
+
261
+ rope_yarn<forward>(theta_base/freq_factor, freq_scale, corr_dims, i0, ext_factor, attn_factor, cos_theta, sin_theta);
262
+
263
+ const float x0 = x[ix + 0];
264
+ const float x1 = x[ix + n_dims/2];
265
+
266
+ dst[idst + 0] = x0*cos_theta - x1*sin_theta;
267
+ dst[idst + n_dims/2] = x0*sin_theta + x1*cos_theta;
268
+ }
269
+
270
+ template <bool forward, bool has_ff, typename T>
271
+ static __global__ void rope_vision(const T * x,
272
+ T * dst,
273
+ const int ne00,
274
+ const int ne01,
275
+ const int ne02,
276
+ const int s01,
277
+ const int s02,
278
+ const int s03,
279
+ const int s1,
280
+ const int s2,
281
+ const int s3,
282
+ const int n_dims,
283
+ const int32_t * pos,
284
+ const float freq_scale,
285
+ const float ext_factor,
286
+ const float attn_factor,
287
+ const rope_corr_dims corr_dims,
288
+ const float theta_scale,
289
+ const float * freq_factors,
290
+ const mrope_sections sections) {
291
+ const int i0 = 2*(blockDim.y*blockIdx.y + threadIdx.y);
292
+
293
+ if (i0 >= ne00) {
294
+ return;
295
+ }
296
+
297
+ const int row_dst = blockDim.x*blockIdx.x + threadIdx.x;
298
+
299
+ const uint32_t i3 = row_dst / (ne01 * ne02);
300
+ const uint32_t i2 = (row_dst - i3 * ne01 * ne02) / ne01;
301
+ const uint32_t i1 = row_dst - i3 * ne01 * ne02 - i2 * ne01;
302
+
303
+ int idst = i0 / 2 + i1 * s1 + i2 * s2 + i3 * s3;
304
+ const int ix = i0 / 2 + i1 * s01 + i2 * s02 + i3 * s03;
305
+
306
+ ggml_cuda_pdl_sync();
307
+ const int sect_dims = sections.v[0] + sections.v[1];
308
+ const int sec_w = sections.v[1] + sections.v[0];
309
+ const int sector = (i0 / 2) % sect_dims;
310
+
311
+ float theta_base = 0.0;
312
+ if (sector < sections.v[0]) {
313
+ const int p = sector;
314
+ theta_base = pos[i2] * powf(theta_scale, p);
315
+ } else if (sector >= sections.v[0] && sector < sec_w) {
316
+ const int p = sector - sections.v[0];
317
+ theta_base = pos[i2 + ne02] * powf(theta_scale, p);
318
+ }
319
+
320
+ const float freq_factor = has_ff ? freq_factors[i0/2] : 1.0f;
321
+
322
+ float cos_theta;
323
+ float sin_theta;
324
+
325
+ rope_yarn<forward>(theta_base/freq_factor, freq_scale, corr_dims, i0, ext_factor, attn_factor, cos_theta, sin_theta);
326
+
327
+ const float x0 = x[ix + 0];
328
+ const float x1 = x[ix + n_dims];
329
+
330
+ dst[idst + 0] = x0*cos_theta - x1*sin_theta;
331
+ dst[idst + n_dims] = x0*sin_theta + x1*cos_theta;
332
+ }
333
+
334
+ template <bool forward, typename T, typename D>
335
+ static void rope_norm_cuda(const T * x,
336
+ D * dst,
337
+ const int ne00,
338
+ const int ne01,
339
+ const int ne02,
340
+ const int s01,
341
+ const int s02,
342
+ const int s03,
343
+ const int s1,
344
+ const int s2,
345
+ const int s3,
346
+ const int n_dims,
347
+ const int nr,
348
+ const int32_t * pos,
349
+ const float freq_scale,
350
+ const float freq_base,
351
+ const float ext_factor,
352
+ const float attn_factor,
353
+ const rope_corr_dims corr_dims,
354
+ const float * freq_factors,
355
+ const int64_t * row_indices,
356
+ const int set_rows_stride,
357
+ cudaStream_t stream) {
358
+ GGML_ASSERT(ne00 % 2 == 0);
359
+ const dim3 block_dims(1, CUDA_ROPE_BLOCK_SIZE, 1);
360
+ const int n_blocks_x = (ne00 + 2 * CUDA_ROPE_BLOCK_SIZE - 1) / (2 * CUDA_ROPE_BLOCK_SIZE);
361
+ const dim3 block_nums(nr, n_blocks_x, 1);
362
+
363
+ const float theta_scale = powf(freq_base, -2.0f / n_dims);
364
+
365
+ if (freq_factors == nullptr) {
366
+ rope_norm<forward, false><<<block_nums, block_dims, 0, stream>>>(
367
+ x, dst, ne00, ne01, ne02, s01, s02, s03, s1, s2, s3, n_dims, pos, freq_scale, ext_factor,
368
+ attn_factor, corr_dims, theta_scale, freq_factors, row_indices, set_rows_stride);
369
+ } else {
370
+ rope_norm<forward, true><<<block_nums, block_dims, 0, stream>>>(
371
+ x, dst, ne00, ne01, ne02, s01, s02, s03, s1, s2, s3, n_dims, pos, freq_scale, ext_factor,
372
+ attn_factor, corr_dims, theta_scale, freq_factors, row_indices, set_rows_stride);
373
+ }
374
+ }
375
+
376
+ template <bool forward, typename T, typename D>
377
+ static void rope_neox_cuda(const T * x,
378
+ D * dst,
379
+ const int ne00,
380
+ const int ne01,
381
+ const int ne02,
382
+ const int s01,
383
+ const int s02,
384
+ const int s03,
385
+ const int s1,
386
+ const int s2,
387
+ const int s3,
388
+ const int n_dims,
389
+ const int nr,
390
+ const int32_t * pos,
391
+ const float freq_scale,
392
+ const float freq_base,
393
+ const float ext_factor,
394
+ const float attn_factor,
395
+ const rope_corr_dims corr_dims,
396
+ const float * freq_factors,
397
+ const int64_t * row_indices,
398
+ const int set_rows_stride,
399
+ cudaStream_t stream) {
400
+ GGML_ASSERT(ne00 % 2 == 0);
401
+ const dim3 block_dims(1, CUDA_ROPE_BLOCK_SIZE, 1);
402
+ const int n_blocks_x = (ne00 + 2 * CUDA_ROPE_BLOCK_SIZE - 1) / (2 * CUDA_ROPE_BLOCK_SIZE);
403
+ const dim3 block_nums(nr, n_blocks_x, 1);
404
+
405
+ const float theta_scale = powf(freq_base, -2.0f / n_dims);
406
+ const ggml_cuda_kernel_launch_params launch_params = {block_nums, block_dims, 0, stream};
407
+
408
+ if (freq_factors == nullptr) {
409
+ ggml_cuda_kernel_launch(rope_neox<forward, false, T, D>, launch_params,
410
+ x, dst, ne00, ne01, ne02, s01, s02, s03, s1, s2, s3, n_dims, pos, freq_scale, ext_factor,
411
+ attn_factor, corr_dims, theta_scale, freq_factors, row_indices, set_rows_stride);
412
+ } else {
413
+ ggml_cuda_kernel_launch(rope_neox<forward, true, T, D>, launch_params,
414
+ x, dst, ne00, ne01, ne02, s01, s02, s03, s1, s2, s3, n_dims, pos, freq_scale, ext_factor,
415
+ attn_factor, corr_dims, theta_scale, freq_factors, row_indices, set_rows_stride);
416
+ }
417
+ }
418
+
419
+ template <bool forward, typename T>
420
+ static void rope_multi_cuda(const T * x,
421
+ T * dst,
422
+ const int ne00,
423
+ const int ne01,
424
+ const int ne02,
425
+ const int s01,
426
+ const int s02,
427
+ const int s03,
428
+ const int s1,
429
+ const int s2,
430
+ const int s3,
431
+ const int n_dims,
432
+ const int nr,
433
+ const int32_t * pos,
434
+ const float freq_scale,
435
+ const float freq_base,
436
+ const float ext_factor,
437
+ const float attn_factor,
438
+ const rope_corr_dims corr_dims,
439
+ const float * freq_factors,
440
+ const mrope_sections sections,
441
+ const bool is_imrope,
442
+ cudaStream_t stream) {
443
+ GGML_ASSERT(ne00 % 2 == 0);
444
+ const dim3 block_dims(1, CUDA_ROPE_BLOCK_SIZE, 1);
445
+ const int n_blocks_x = (ne00 + 2 * CUDA_ROPE_BLOCK_SIZE - 1) / (2 * CUDA_ROPE_BLOCK_SIZE);
446
+ const dim3 block_nums(nr, n_blocks_x, 1);
447
+
448
+ const float theta_scale = powf(freq_base, -2.0f / n_dims);
449
+
450
+ if (freq_factors == nullptr) {
451
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(block_nums, block_dims, 0, stream);
452
+ ggml_cuda_kernel_launch(rope_multi<forward, false, T>, launch_params,
453
+ x, dst, ne00, ne01, ne02, s01, s02, s03, s1, s2, s3, n_dims, pos, freq_scale, ext_factor,
454
+ attn_factor, corr_dims, theta_scale, freq_factors, sections, is_imrope);
455
+ } else {
456
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(block_nums, block_dims, 0, stream);
457
+ ggml_cuda_kernel_launch(rope_multi<forward, true, T>, launch_params,
458
+ x, dst, ne00, ne01, ne02, s01, s02, s03, s1, s2, s3, n_dims, pos, freq_scale, ext_factor,
459
+ attn_factor, corr_dims, theta_scale, freq_factors, sections, is_imrope);
460
+ }
461
+ }
462
+
463
+ template <bool forward, typename T>
464
+ static void rope_vision_cuda(const T * x,
465
+ T * dst,
466
+ const int ne00,
467
+ const int ne01,
468
+ const int ne02,
469
+ const int s01,
470
+ const int s02,
471
+ const int s03,
472
+ const int s1,
473
+ const int s2,
474
+ const int s3,
475
+ const int n_dims,
476
+ const int nr,
477
+ const int32_t * pos,
478
+ const float freq_scale,
479
+ const float freq_base,
480
+ const float ext_factor,
481
+ const float attn_factor,
482
+ const rope_corr_dims corr_dims,
483
+ const float * freq_factors,
484
+ const mrope_sections sections,
485
+ cudaStream_t stream) {
486
+ GGML_ASSERT(ne00 % 2 == 0);
487
+ const dim3 block_dims(1, CUDA_ROPE_BLOCK_SIZE, 1);
488
+ const int n_blocks_x = (ne00 + 2 * CUDA_ROPE_BLOCK_SIZE - 1) / (2 * CUDA_ROPE_BLOCK_SIZE);
489
+ const dim3 block_nums(nr, n_blocks_x, 1);
490
+ // break down (head_dim, heads, seq) into (CUDA_ROPE_BLOCK_SIZE, x, heads * seq)
491
+ // where x ~= ceil(head_dim / CUDA_ROPE_BLOCK_SIZE);
492
+
493
+ const float theta_scale = powf(freq_base, -2.0f/n_dims);
494
+
495
+ if (freq_factors == nullptr) {
496
+ rope_vision<forward, false, T><<<block_nums, block_dims, 0, stream>>>(
497
+ x, dst, ne00, ne01, ne02, s01, s02, s03, s1, s2, s3, n_dims, pos, freq_scale, ext_factor,
498
+ attn_factor, corr_dims, theta_scale, freq_factors, sections);
499
+ } else {
500
+ rope_vision<forward, true, T><<<block_nums, block_dims, 0, stream>>>(
501
+ x, dst, ne00, ne01, ne02, s01, s02, s03, s1, s2, s3, n_dims, pos, freq_scale, ext_factor,
502
+ attn_factor, corr_dims, theta_scale, freq_factors, sections);
503
+ }
504
+ }
505
+
506
+ template <bool forward>
507
+ void ggml_cuda_op_rope_impl(ggml_backend_cuda_context & ctx,
508
+ ggml_tensor * dst,
509
+ const ggml_tensor * set_rows = nullptr) {
510
+ const ggml_tensor * src0 = dst->src[0];
511
+ const ggml_tensor * src1 = dst->src[1];
512
+ const ggml_tensor * src2 = dst->src[2];
513
+
514
+ const float * src0_d = (const float *)src0->data;
515
+ const float * src1_d = (const float *)src1->data;
516
+
517
+ void * dst_d = dst->data;
518
+ const int64_t * row_indices = nullptr;
519
+ ggml_type dst_type = dst->type;
520
+ int set_rows_stride = 0;
521
+
522
+ if (set_rows != nullptr) {
523
+ GGML_ASSERT(forward);
524
+ dst_d = set_rows->data;
525
+ row_indices = (const int64_t *) set_rows->src[1]->data;
526
+ dst_type = set_rows->type;
527
+ set_rows_stride = set_rows->nb[1] / ggml_type_size(set_rows->type);
528
+ }
529
+ cudaStream_t stream = ctx.stream();
530
+
531
+ GGML_ASSERT(src0->type == GGML_TYPE_F32 || src0->type == GGML_TYPE_F16);
532
+ GGML_ASSERT( dst->type == GGML_TYPE_F32 || dst->type == GGML_TYPE_F16);
533
+ // When not fused, src0 and dst types must match
534
+ // When fused (ROPE+VIEW+SET_ROWS), src0 may be F32 and dst may be F16
535
+ GGML_ASSERT(src0->type == dst->type || (src0->type == GGML_TYPE_F32 && dst->type == GGML_TYPE_F16));
536
+
537
+ const int64_t ne00 = src0->ne[0]; // head dims
538
+ const int64_t ne01 = src0->ne[1]; // num heads
539
+ const int64_t ne02 = src0->ne[2]; // num heads
540
+ const int64_t nr = ggml_nrows(src0);
541
+
542
+ const size_t s01 = src0->nb[1] / ggml_type_size(src0->type);
543
+ const size_t s02 = src0->nb[2] / ggml_type_size(src0->type);
544
+ const size_t s03 = src0->nb[3] / ggml_type_size(src0->type);
545
+
546
+ const size_t s1 = dst->nb[1] / ggml_type_size(dst->type);
547
+ const size_t s2 = dst->nb[2] / ggml_type_size(dst->type);
548
+ const size_t s3 = dst->nb[3] / ggml_type_size(dst->type);
549
+
550
+ //const int n_past = ((int32_t *) dst->op_params)[0];
551
+ const int n_dims = ((int32_t *) dst->op_params)[1];
552
+ const int mode = ((int32_t *) dst->op_params)[2];
553
+ //const int n_ctx = ((int32_t *) dst->op_params)[3];
554
+ const int n_ctx_orig = ((int32_t *) dst->op_params)[4];
555
+ mrope_sections sections;
556
+
557
+ // RoPE alteration for extended context
558
+ float freq_base;
559
+ float freq_scale;
560
+ float ext_factor;
561
+ float attn_factor;
562
+ float beta_fast;
563
+ float beta_slow;
564
+
565
+ memcpy(&freq_base, (int32_t *) dst->op_params + 5, sizeof(float));
566
+ memcpy(&freq_scale, (int32_t *) dst->op_params + 6, sizeof(float));
567
+ memcpy(&ext_factor, (int32_t *) dst->op_params + 7, sizeof(float));
568
+ memcpy(&attn_factor, (int32_t *) dst->op_params + 8, sizeof(float));
569
+ memcpy(&beta_fast, (int32_t *) dst->op_params + 9, sizeof(float));
570
+ memcpy(&beta_slow, (int32_t *) dst->op_params + 10, sizeof(float));
571
+ memcpy(&sections.v, (int32_t *) dst->op_params + 11, sizeof(int)*4);
572
+
573
+ const bool is_neox = mode & GGML_ROPE_TYPE_NEOX;
574
+ const bool is_mrope = mode & GGML_ROPE_TYPE_MROPE;
575
+ const bool is_imrope = mode == GGML_ROPE_TYPE_IMROPE;
576
+ const bool is_vision = mode == GGML_ROPE_TYPE_VISION;
577
+
578
+ if (is_mrope) {
579
+ GGML_ASSERT(sections.v[0] > 0 || sections.v[1] > 0 || sections.v[2] > 0);
580
+ }
581
+
582
+ if (is_vision) {
583
+ GGML_ASSERT(n_dims == ne00/2);
584
+ }
585
+
586
+ const int32_t * pos = (const int32_t *) src1_d;
587
+
588
+ const float * freq_factors = nullptr;
589
+ if (src2 != nullptr) {
590
+ freq_factors = (const float *) src2->data;
591
+ }
592
+
593
+ rope_corr_dims corr_dims;
594
+ ggml_rope_yarn_corr_dims(n_dims, n_ctx_orig, freq_base, beta_fast, beta_slow, corr_dims.v);
595
+
596
+ // compute
597
+ if (is_neox) {
598
+ if (src0->type == GGML_TYPE_F32 && dst_type == GGML_TYPE_F32) {
599
+ rope_neox_cuda<forward, float, float>((const float *) src0_d, (float *) dst_d, ne00, ne01, ne02, s01, s02,
600
+ s03, s1, s2, s3, n_dims, nr, pos, freq_scale, freq_base,
601
+ ext_factor, attn_factor, corr_dims, freq_factors, row_indices,
602
+ set_rows_stride, stream);
603
+ } else if (src0->type == GGML_TYPE_F32 && dst_type == GGML_TYPE_F16) {
604
+ rope_neox_cuda<forward, float, half>((const float *) src0_d, (half *) dst_d, ne00, ne01, ne02, s01, s02,
605
+ s03, s1, s2, s3, n_dims, nr, pos, freq_scale, freq_base,
606
+ ext_factor, attn_factor, corr_dims, freq_factors, row_indices,
607
+ set_rows_stride, stream);
608
+ } else if (src0->type == GGML_TYPE_F16 && dst_type == GGML_TYPE_F16) {
609
+ rope_neox_cuda<forward, half, half>((const half *) src0_d, (half *) dst_d, ne00, ne01, ne02, s01, s02,
610
+ s03, s1, s2, s3, n_dims, nr, pos, freq_scale, freq_base,
611
+ ext_factor, attn_factor, corr_dims, freq_factors, row_indices,
612
+ set_rows_stride, stream);
613
+ } else {
614
+ GGML_ABORT("fatal error");
615
+ }
616
+ } else if (is_mrope && !is_vision) {
617
+ if (src0->type == GGML_TYPE_F32) {
618
+ rope_multi_cuda<forward>((const float *) src0_d, (float *) dst_d, ne00, ne01, ne02, s01, s02, s03, s1,
619
+ s2, s3, n_dims, nr, pos, freq_scale, freq_base, ext_factor, attn_factor,
620
+ corr_dims, freq_factors, sections, is_imrope, stream);
621
+ } else if (src0->type == GGML_TYPE_F16) {
622
+ rope_multi_cuda<forward>((const half *) src0_d, (half *) dst_d, ne00, ne01, ne02, s01, s02, s03, s1,
623
+ s2, s3, n_dims, nr, pos, freq_scale, freq_base, ext_factor, attn_factor,
624
+ corr_dims, freq_factors, sections, is_imrope, stream);
625
+ } else {
626
+ GGML_ABORT("fatal error");
627
+ }
628
+ } else if (is_vision) {
629
+ if (src0->type == GGML_TYPE_F32) {
630
+ rope_vision_cuda<forward>((const float *) src0_d, (float *) dst_d, ne00, ne01, ne02, s01, s02, s03, s1,
631
+ s2, s3, n_dims, nr, pos, freq_scale, freq_base, ext_factor, attn_factor,
632
+ corr_dims, freq_factors, sections, stream);
633
+ } else if (src0->type == GGML_TYPE_F16) {
634
+ rope_vision_cuda<forward>((const half *) src0_d, (half *) dst_d, ne00, ne01, ne02, s01, s02, s03, s1,
635
+ s2, s3, n_dims, nr, pos, freq_scale, freq_base, ext_factor, attn_factor,
636
+ corr_dims, freq_factors, sections, stream);
637
+ } else {
638
+ GGML_ABORT("fatal error");
639
+ }
640
+ } else {
641
+ if (src0->type == GGML_TYPE_F32 && dst_type == GGML_TYPE_F32) {
642
+ rope_norm_cuda<forward, float, float>((const float *) src0_d, (float *) dst_d, ne00, ne01, ne02, s01, s02,
643
+ s03, s1, s2, s3, n_dims, nr, pos, freq_scale, freq_base,
644
+ ext_factor, attn_factor, corr_dims, freq_factors, row_indices,
645
+ set_rows_stride, stream);
646
+ } else if (src0->type == GGML_TYPE_F32 && dst_type == GGML_TYPE_F16) {
647
+ rope_norm_cuda<forward, float, half>((const float *) src0_d, (half *) dst_d, ne00, ne01, ne02, s01, s02,
648
+ s03, s1, s2, s3, n_dims, nr, pos, freq_scale, freq_base,
649
+ ext_factor, attn_factor, corr_dims, freq_factors, row_indices,
650
+ set_rows_stride, stream);
651
+ } else if (src0->type == GGML_TYPE_F16 && dst_type == GGML_TYPE_F16) {
652
+ rope_norm_cuda<forward, half, half>((const half *) src0_d, (half *) dst_d, ne00, ne01, ne02, s01, s02,
653
+ s03, s1, s2, s3, n_dims, nr, pos, freq_scale, freq_base,
654
+ ext_factor, attn_factor, corr_dims, freq_factors, row_indices,
655
+ set_rows_stride, stream);
656
+ } else {
657
+ GGML_ABORT("fatal error");
658
+ }
659
+ }
660
+ }
661
+
662
+ void ggml_cuda_op_rope(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
663
+ ggml_cuda_op_rope_impl<true>(ctx, dst);
664
+ }
665
+
666
+ void ggml_cuda_op_rope_back(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
667
+ ggml_cuda_op_rope_impl<false>(ctx, dst);
668
+ }
669
+
670
+ void ggml_cuda_op_rope_fused(ggml_backend_cuda_context & ctx, ggml_tensor * rope, ggml_tensor * set_rows) {
671
+ ggml_cuda_op_rope_impl<true>(ctx, rope, set_rows);
672
+ }
backend/llama.cpp/ggml/src/ggml-cuda/rope.cuh ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ #define CUDA_ROPE_BLOCK_SIZE 256
4
+
5
+ void ggml_cuda_op_rope(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
6
+
7
+ void ggml_cuda_op_rope_back(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
8
+
9
+ void ggml_cuda_op_rope_fused(ggml_backend_cuda_context & ctx, ggml_tensor * dst, ggml_tensor * set_rows);
backend/llama.cpp/ggml/src/ggml-cuda/scale.cu ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "scale.cuh"
2
+
3
+ #define MAX_GRIDDIM_X 0x7FFFFFFF
4
+
5
+ static __global__ void scale_f32(const float * x, float * dst, const float scale, const float bias, const int64_t nelements) {
6
+ ggml_cuda_pdl_lc();
7
+ int64_t tid = (int64_t)blockIdx.x * (int64_t)blockDim.x + (int64_t)threadIdx.x;
8
+ int64_t stride = (int64_t)blockDim.x * (int64_t)gridDim.x;
9
+
10
+ ggml_cuda_pdl_sync();
11
+ for (int64_t i = tid; i < nelements; i += stride) {
12
+ dst[i] = scale * x[i] + bias;
13
+ }
14
+ }
15
+
16
+ static void scale_f32_cuda(const float * x, float * dst, const float scale, const float bias, const int64_t nelements, cudaStream_t stream) {
17
+ const int64_t num_blocks = (nelements + CUDA_SCALE_BLOCK_SIZE - 1) / CUDA_SCALE_BLOCK_SIZE;
18
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(MIN(MAX_GRIDDIM_X, num_blocks), CUDA_SCALE_BLOCK_SIZE, 0, stream);
19
+ ggml_cuda_kernel_launch(scale_f32, launch_params, x, dst, scale, bias, nelements);
20
+ }
21
+
22
+ void ggml_cuda_op_scale(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
23
+ const ggml_tensor * src0 = dst->src[0];
24
+ const float * src0_d = (const float *)src0->data;
25
+ float * dst_d = (float *)dst->data;
26
+ cudaStream_t stream = ctx.stream();
27
+
28
+ GGML_ASSERT(src0->type == GGML_TYPE_F32);
29
+ GGML_ASSERT( dst->type == GGML_TYPE_F32);
30
+
31
+ float scale;
32
+ float bias;
33
+ memcpy(&scale, (float *) dst->op_params + 0, sizeof(float));
34
+ memcpy(&bias, (float *) dst->op_params + 1, sizeof(float));
35
+
36
+ scale_f32_cuda(src0_d, dst_d, scale, bias, ggml_nelements(src0), stream);
37
+ }
backend/llama.cpp/ggml/src/ggml-cuda/scale.cuh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #include "common.cuh"
2
+
3
+ #define CUDA_SCALE_BLOCK_SIZE 256
4
+
5
+ void ggml_cuda_op_scale(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/set-rows.cu ADDED
@@ -0,0 +1,398 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "set-rows.cuh"
2
+ #include "cpy-utils.cuh"
3
+
4
+ typedef void (*set_rows_kernel_t)(const char * src, char * dst);
5
+
6
+ // Generic quantized set_rows kernel template
7
+ template <typename idx_t, typename block_type, int qk, void (*quantize_func)(const float *, block_type *)>
8
+ static __global__ void k_set_rows_quant(const float * __restrict__ src0,
9
+ const idx_t * __restrict__ src1,
10
+ block_type * __restrict__ dst,
11
+ const int64_t ne_total,
12
+ const int64_t ne10,
13
+ const int64_t ne11,
14
+ const int64_t ne12,
15
+ const int64_t ne13,
16
+ const int64_t s01,
17
+ const int64_t s02,
18
+ const int64_t s03,
19
+ const int64_t s10,
20
+ const int64_t s11,
21
+ const int64_t s12,
22
+ const int64_t s1,
23
+ const int64_t s2,
24
+ const int64_t s3,
25
+ const uint3 ne00,
26
+ const uint3 ne01,
27
+ const uint3 ne02,
28
+ const uint3 ne11_fd,
29
+ const uint3 ne12_fd) {
30
+ const int64_t i = int64_t(blockDim.x) * blockIdx.x + threadIdx.x;
31
+
32
+ if (i >= ne_total) {
33
+ return;
34
+ }
35
+
36
+ const int64_t i_base = i * qk;
37
+ uint32_t tmp = (uint32_t) i_base;
38
+ uint2 div_mod;
39
+
40
+ div_mod = fast_div_modulo(tmp, ne00);
41
+ const int64_t i00 = div_mod.y;
42
+ tmp = div_mod.x;
43
+
44
+ div_mod = fast_div_modulo(tmp, ne01);
45
+ const int64_t i01 = div_mod.y;
46
+ tmp = div_mod.x;
47
+
48
+ div_mod = fast_div_modulo(tmp, ne02);
49
+ const int64_t i02 = div_mod.y;
50
+ const int64_t i03 = div_mod.x;
51
+
52
+ const int64_t i12 = fastmodulo((uint32_t) i03, ne12_fd);
53
+ const int64_t i11 = fastmodulo((uint32_t) i02, ne11_fd);
54
+ const int64_t i10 = i01;
55
+
56
+ ggml_cuda_pdl_sync();
57
+ const int64_t dst_row = *(src1 + i10*s10 + i11*s11 + i12*s12);
58
+
59
+ const float * src0_row = src0 + i01*s01 + i02*s02 + i03*s03;
60
+ block_type * dst_row_ptr = dst + (dst_row*s1 + i02*s2 + i03*s3) / sizeof(block_type);
61
+
62
+ const float * src_block = src0_row + i00;
63
+ block_type * dst_block = dst_row_ptr + i00 / qk;
64
+
65
+ quantize_func(src_block, dst_block);
66
+
67
+ GGML_UNUSED(ne10);
68
+ GGML_UNUSED(ne11);
69
+ GGML_UNUSED(ne12);
70
+ GGML_UNUSED(ne13);
71
+ }
72
+
73
+ // Template dispatch function for quantized set_rows
74
+ template<typename idx_t, typename block_type, int qk, void (*quantize_func)(const float*, block_type*)>
75
+ static void set_rows_cuda_quant(
76
+ const float * src0_d, const idx_t * src1_d, block_type * dst_d,
77
+ const int64_t ne00, const int64_t ne01, const int64_t ne02, const int64_t ne03,
78
+ const int64_t ne10, const int64_t ne11, const int64_t ne12, const int64_t ne13,
79
+ const size_t nb01, const size_t nb02, const size_t nb03,
80
+ const size_t nb10, const size_t nb11, const size_t nb12,
81
+ const size_t nb1, const size_t nb2, const size_t nb3,
82
+ cudaStream_t stream) {
83
+
84
+ GGML_ASSERT(ne00 % qk == 0);
85
+ const int64_t ne_total = (ne00 * ne01 * ne02 * ne03) / qk;
86
+ const int num_blocks = (ne_total + CUDA_SET_ROWS_BLOCK_SIZE - 1) / CUDA_SET_ROWS_BLOCK_SIZE;
87
+ const dim3 block_size(CUDA_SET_ROWS_BLOCK_SIZE);
88
+ const dim3 grid_size(num_blocks);
89
+
90
+ const int64_t s01 = nb01/sizeof(float);
91
+ const int64_t s02 = nb02/sizeof(float);
92
+ const int64_t s03 = nb03/sizeof(float);
93
+ const int64_t s10 = nb10/sizeof(idx_t);
94
+ const int64_t s11 = nb11/sizeof(idx_t);
95
+ const int64_t s12 = nb12/sizeof(idx_t);
96
+ const int64_t s1 = nb1;
97
+ const int64_t s2 = nb2;
98
+ const int64_t s3 = nb3;
99
+
100
+ if (ne_total > 0 && ne00 > 0 && ne01 > 0 && ne02 > 0 && ne11 > 0 && ne12 > 0) {
101
+ const uint3 ne00_fd = init_fastdiv_values((uint32_t) ne00);
102
+ const uint3 ne01_fd = init_fastdiv_values((uint32_t) ne01);
103
+ const uint3 ne02_fd = init_fastdiv_values((uint32_t) ne02);
104
+ const uint3 ne11_fd = init_fastdiv_values((uint32_t) ne11);
105
+ const uint3 ne12_fd = init_fastdiv_values((uint32_t) ne12);
106
+
107
+ k_set_rows_quant<idx_t, block_type, qk, quantize_func><<<grid_size, block_size, 0, stream>>>(
108
+ src0_d, src1_d, dst_d, ne_total, ne10, ne11, ne12, ne13, s01, s02, s03, s10, s11, s12, s1, s2, s3, ne00_fd,
109
+ ne01_fd, ne02_fd, ne11_fd, ne12_fd);
110
+ }
111
+ }
112
+
113
+ template <typename src_t, typename idx_t, typename dst_t>
114
+ static __global__ void k_set_rows(const src_t * src0_ptr,
115
+ const idx_t * src1_ptr,
116
+ dst_t * dst_ptr,
117
+ const int64_t ne_total,
118
+ const int64_t ne10,
119
+ const int64_t ne11,
120
+ const int64_t ne12,
121
+ const int64_t ne13,
122
+ const int64_t s01,
123
+ const int64_t s02,
124
+ const int64_t s03,
125
+ const int64_t s10,
126
+ const int64_t s11,
127
+ const int64_t s12,
128
+ const int64_t s1,
129
+ const int64_t s2,
130
+ const int64_t s3,
131
+ const uint3 ne00,
132
+ const uint3 ne01,
133
+ const uint3 ne02,
134
+ const uint3 ne11_fd,
135
+ const uint3 ne12_fd) {
136
+ const src_t * GGML_CUDA_RESTRICT src0 = src0_ptr;
137
+ const idx_t * GGML_CUDA_RESTRICT src1 = src1_ptr;
138
+ dst_t * GGML_CUDA_RESTRICT dst = dst_ptr;
139
+ const int64_t i = int64_t(blockDim.x) * blockIdx.x + threadIdx.x;
140
+
141
+ if (i >= ne_total) {
142
+ return;
143
+ }
144
+
145
+ uint32_t tmp = (uint32_t) i;
146
+ uint2 div_mod;
147
+
148
+ div_mod = fast_div_modulo(tmp, ne00);
149
+ const int64_t i00 = div_mod.y;
150
+ tmp = div_mod.x;
151
+
152
+ div_mod = fast_div_modulo(tmp, ne01);
153
+ const int64_t i01 = div_mod.y;
154
+ tmp = div_mod.x;
155
+
156
+ div_mod = fast_div_modulo(tmp, ne02);
157
+ const int64_t i02 = div_mod.y;
158
+ const int64_t i03 = div_mod.x;
159
+
160
+ const int64_t i12 = fastmodulo((uint32_t) i03, ne12_fd);
161
+ const int64_t i11 = fastmodulo((uint32_t) i02, ne11_fd);
162
+ const int64_t i10 = i01;
163
+
164
+ ggml_cuda_pdl_sync();
165
+ const int64_t dst_row = *(src1 + i10*s10 + i11*s11 + i12*s12);
166
+ ggml_cuda_pdl_lc();
167
+
168
+ const src_t * src0_row = src0 + i01*s01 + i02*s02 + i03*s03;
169
+ dst_t * dst_row_ptr = dst + dst_row*s1 + i02*s2 + i03*s3;
170
+
171
+ dst_row_ptr[i00] = ggml_cuda_cast<dst_t>(src0_row[i00]);
172
+
173
+ GGML_UNUSED(ne10);
174
+ GGML_UNUSED(ne11);
175
+ GGML_UNUSED(ne12);
176
+ GGML_UNUSED(ne13);
177
+ }
178
+
179
+ template<typename src_t, typename idx_t, typename dst_t>
180
+ static void set_rows_cuda(
181
+ const src_t * src0_d, const idx_t * src1_d, dst_t * dst_d,
182
+ const int64_t ne00, const int64_t ne01, const int64_t ne02, const int64_t ne03,
183
+ const int64_t ne10, const int64_t ne11, const int64_t ne12, const int64_t ne13,
184
+ const size_t nb01, const size_t nb02, const size_t nb03,
185
+ const size_t nb10, const size_t nb11, const size_t nb12,
186
+ const size_t nb1, const size_t nb2, const size_t nb3,
187
+ cudaStream_t stream) {
188
+
189
+ const int64_t ne_total = ne00 * ne01 * ne02 * ne03;
190
+ const int num_blocks = (ne_total + CUDA_SET_ROWS_BLOCK_SIZE - 1) / CUDA_SET_ROWS_BLOCK_SIZE;
191
+ const dim3 block_size(CUDA_SET_ROWS_BLOCK_SIZE);
192
+ const dim3 grid_size(num_blocks);
193
+
194
+
195
+ const int64_t s01 = nb01/sizeof(src_t);
196
+ const int64_t s02 = nb02/sizeof(src_t);
197
+ const int64_t s03 = nb03/sizeof(src_t);
198
+ const int64_t s10 = nb10/sizeof(idx_t);
199
+ const int64_t s11 = nb11/sizeof(idx_t);
200
+ const int64_t s12 = nb12/sizeof(idx_t);
201
+ const int64_t s1 = nb1/sizeof(dst_t);
202
+ const int64_t s2 = nb2/sizeof(dst_t);
203
+ const int64_t s3 = nb3/sizeof(dst_t);
204
+
205
+ if (ne_total > 0 && ne00 > 0 && ne01 > 0 && ne02 > 0 && ne11 > 0 && ne12 > 0) {
206
+ const uint3 ne00_fd = init_fastdiv_values((uint32_t) ne00);
207
+ const uint3 ne01_fd = init_fastdiv_values((uint32_t) ne01);
208
+ const uint3 ne02_fd = init_fastdiv_values((uint32_t) ne02);
209
+ const uint3 ne11_fd = init_fastdiv_values((uint32_t) ne11);
210
+ const uint3 ne12_fd = init_fastdiv_values((uint32_t) ne12);
211
+
212
+ const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(grid_size, block_size, 0, stream);
213
+ ggml_cuda_kernel_launch(k_set_rows<src_t, idx_t, dst_t>, launch_params,
214
+ src0_d, src1_d, dst_d, ne_total, ne10, ne11, ne12, ne13, s01,
215
+ s02, s03, s10, s11, s12, s1, s2, s3, ne00_fd, ne01_fd, ne02_fd,
216
+ ne11_fd, ne12_fd);
217
+ }
218
+ }
219
+
220
+ template<typename src_t, typename idx_t>
221
+ static void set_rows_cuda(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) {
222
+ const src_t * src0_d = (const src_t *)src0->data;
223
+ const idx_t * src1_d = (const idx_t *)src1->data;
224
+
225
+ GGML_TENSOR_BINARY_OP_LOCALS
226
+
227
+ cudaStream_t stream = ctx.stream();
228
+
229
+
230
+ if (dst->type == GGML_TYPE_F32) {
231
+ set_rows_cuda(
232
+ src0_d, src1_d, (float*)dst->data,
233
+ ne00, ne01, ne02, ne03,
234
+ ne10, ne11, ne12, ne13,
235
+ nb01, nb02, nb03,
236
+ nb10, nb11, nb12,
237
+ nb1, nb2, nb3,
238
+ stream
239
+ );
240
+ } else if (dst->type == GGML_TYPE_F16) {
241
+ set_rows_cuda(
242
+ src0_d, src1_d, (half*)dst->data,
243
+ ne00, ne01, ne02, ne03,
244
+ ne10, ne11, ne12, ne13,
245
+ nb01, nb02, nb03,
246
+ nb10, nb11, nb12,
247
+ nb1, nb2, nb3,
248
+ stream
249
+ );
250
+ } else if (dst->type == GGML_TYPE_BF16) {
251
+ set_rows_cuda(
252
+ src0_d, src1_d, (nv_bfloat16*)dst->data,
253
+ ne00, ne01, ne02, ne03,
254
+ ne10, ne11, ne12, ne13,
255
+ nb01, nb02, nb03,
256
+ nb10, nb11, nb12,
257
+ nb1, nb2, nb3,
258
+ stream
259
+ );
260
+ } else if (dst->type == GGML_TYPE_Q4_0) {
261
+ set_rows_cuda_quant<idx_t, block_q4_0, QK4_0, quantize_f32_q4_0_block>(
262
+ src0_d, src1_d, (block_q4_0*)dst->data,
263
+ ne00, ne01, ne02, ne03,
264
+ ne10, ne11, ne12, ne13,
265
+ nb01, nb02, nb03,
266
+ nb10, nb11, nb12,
267
+ nb1, nb2, nb3,
268
+ stream
269
+ );
270
+ } else if (dst->type == GGML_TYPE_Q4_1) {
271
+ set_rows_cuda_quant<idx_t, block_q4_1, QK4_1, quantize_f32_q4_1_block>(
272
+ src0_d, src1_d, (block_q4_1*)dst->data,
273
+ ne00, ne01, ne02, ne03,
274
+ ne10, ne11, ne12, ne13,
275
+ nb01, nb02, nb03,
276
+ nb10, nb11, nb12,
277
+ nb1, nb2, nb3,
278
+ stream
279
+ );
280
+ } else if (dst->type == GGML_TYPE_Q5_0) {
281
+ set_rows_cuda_quant<idx_t, block_q5_0, QK5_0, quantize_f32_q5_0_block>(
282
+ src0_d, src1_d, (block_q5_0*)dst->data,
283
+ ne00, ne01, ne02, ne03,
284
+ ne10, ne11, ne12, ne13,
285
+ nb01, nb02, nb03,
286
+ nb10, nb11, nb12,
287
+ nb1, nb2, nb3,
288
+ stream
289
+ );
290
+ } else if (dst->type == GGML_TYPE_Q5_1) {
291
+ set_rows_cuda_quant<idx_t, block_q5_1, QK5_1, quantize_f32_q5_1_block>(
292
+ src0_d, src1_d, (block_q5_1*)dst->data,
293
+ ne00, ne01, ne02, ne03,
294
+ ne10, ne11, ne12, ne13,
295
+ nb01, nb02, nb03,
296
+ nb10, nb11, nb12,
297
+ nb1, nb2, nb3,
298
+ stream
299
+ );
300
+ } else if (dst->type == GGML_TYPE_Q8_0) {
301
+ set_rows_cuda_quant<idx_t, block_q8_0, QK8_0, quantize_f32_q8_0_block>(
302
+ src0_d, src1_d, (block_q8_0*)dst->data,
303
+ ne00, ne01, ne02, ne03,
304
+ ne10, ne11, ne12, ne13,
305
+ nb01, nb02, nb03,
306
+ nb10, nb11, nb12,
307
+ nb1, nb2, nb3,
308
+ stream
309
+ );
310
+ } else if (dst->type == GGML_TYPE_IQ4_NL) {
311
+ set_rows_cuda_quant<idx_t, block_iq4_nl, QK4_NL, quantize_f32_iq4_nl_block>(
312
+ src0_d, src1_d, (block_iq4_nl*)dst->data,
313
+ ne00, ne01, ne02, ne03,
314
+ ne10, ne11, ne12, ne13,
315
+ nb01, nb02, nb03,
316
+ nb10, nb11, nb12,
317
+ nb1, nb2, nb3,
318
+ stream
319
+ );
320
+ } else {
321
+ GGML_ABORT("unsupported type %s", ggml_type_name(dst->type));
322
+ }
323
+ }
324
+
325
+ template<>
326
+ void set_rows_cuda<half, int32_t>(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) {
327
+ const half * src0_d = (const half *)src0->data;
328
+ const int32_t * src1_d = (const int32_t *)src1->data;
329
+
330
+ GGML_TENSOR_BINARY_OP_LOCALS
331
+
332
+ cudaStream_t stream = ctx.stream();
333
+
334
+
335
+ if (dst->type == GGML_TYPE_F16) {
336
+ set_rows_cuda(
337
+ src0_d, src1_d, (half*)dst->data,
338
+ ne00, ne01, ne02, ne03,
339
+ ne10, ne11, ne12, ne13,
340
+ nb01, nb02, nb03,
341
+ nb10, nb11, nb12,
342
+ nb1, nb2, nb3,
343
+ stream
344
+ );
345
+ } else {
346
+ GGML_ABORT("unsupported type %s", ggml_type_name(dst->type));
347
+ }
348
+ }
349
+
350
+ template<>
351
+ void set_rows_cuda<half, int64_t>(ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) {
352
+ const half * src0_d = (const half *)src0->data;
353
+ const int64_t * src1_d = (const int64_t *)src1->data;
354
+
355
+ GGML_TENSOR_BINARY_OP_LOCALS
356
+
357
+ cudaStream_t stream = ctx.stream();
358
+
359
+
360
+ if (dst->type == GGML_TYPE_F16) {
361
+ set_rows_cuda(
362
+ src0_d, src1_d, (half*)dst->data,
363
+ ne00, ne01, ne02, ne03,
364
+ ne10, ne11, ne12, ne13,
365
+ nb01, nb02, nb03,
366
+ nb10, nb11, nb12,
367
+ nb1, nb2, nb3,
368
+ stream
369
+ );
370
+ } else {
371
+ GGML_ABORT("unsupported type %s", ggml_type_name(dst->type));
372
+ }
373
+ }
374
+
375
+
376
+ void ggml_cuda_op_set_rows(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
377
+ const ggml_tensor * src0 = dst->src[0];
378
+ const ggml_tensor * src1 = dst->src[1];
379
+
380
+ GGML_ASSERT(src0->type == GGML_TYPE_F32 || (src0->type == GGML_TYPE_F16 && dst->type == GGML_TYPE_F16));
381
+ GGML_ASSERT(src1->type == GGML_TYPE_I64 || src1->type == GGML_TYPE_I32);
382
+
383
+ if (src0->type == GGML_TYPE_F32) {
384
+ if (src1->type == GGML_TYPE_I64) {
385
+ set_rows_cuda<float, int64_t>(ctx, src0, src1, dst);
386
+ } else {
387
+ set_rows_cuda<float, int32_t>(ctx, src0, src1, dst);
388
+ }
389
+ } else if (src0->type == GGML_TYPE_F16) {
390
+ if (src1->type == GGML_TYPE_I64) {
391
+ set_rows_cuda<half, int64_t>(ctx, src0, src1, dst);
392
+ } else {
393
+ set_rows_cuda<half, int32_t>(ctx, src0, src1, dst);
394
+ }
395
+ } else {
396
+ GGML_ABORT("unsupported type %s", ggml_type_name(src0->type));
397
+ }
398
+ }
backend/llama.cpp/ggml/src/ggml-cuda/set-rows.cuh ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ #pragma once
2
+
3
+ #include "common.cuh"
4
+
5
+ #define CUDA_SET_ROWS_BLOCK_SIZE 256
6
+
7
+ void ggml_cuda_op_set_rows(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
backend/llama.cpp/ggml/src/ggml-cuda/set.cu ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "set.cuh"
2
+ #include "cpy.cuh"
3
+
4
+ void ggml_cuda_op_set(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
5
+ const ggml_tensor * src0 = dst->src[0];
6
+ const ggml_tensor * src1 = dst->src[1];
7
+
8
+ GGML_ASSERT((src0->type == GGML_TYPE_F32 || src0->type == GGML_TYPE_I32));
9
+ GGML_ASSERT(src1->type == src0->type);
10
+ GGML_ASSERT(dst ->type == src0->type);
11
+
12
+ GGML_ASSERT(ggml_is_contiguous(dst));
13
+ GGML_ASSERT(ggml_is_contiguous(src0));
14
+ GGML_ASSERT(ggml_is_contiguous(src1));
15
+
16
+ const size_t nb1 = ((int32_t *) dst->op_params)[0];
17
+ const size_t nb2 = ((int32_t *) dst->op_params)[1];
18
+ const size_t nb3 = ((int32_t *) dst->op_params)[2];
19
+ const size_t offset = ((int32_t *) dst->op_params)[3];
20
+ const bool inplace= (bool) ((int32_t *) dst->op_params)[4];
21
+
22
+ if (!inplace) {
23
+ ggml_cuda_cpy(ctx, src0, dst);
24
+ }
25
+
26
+ ggml_tensor dst_view = *dst;
27
+ dst_view.data = (void *)((char *)dst->data + offset);
28
+ dst_view.ne[0] = src1->ne[0];
29
+ dst_view.ne[1] = src1->ne[1];
30
+ dst_view.ne[2] = src1->ne[2];
31
+ dst_view.ne[3] = src1->ne[3];
32
+
33
+ dst_view.nb[0] = ggml_element_size(dst);
34
+ dst_view.nb[1] = nb1;
35
+ dst_view.nb[2] = nb2;
36
+ dst_view.nb[3] = nb3;
37
+
38
+ ggml_cuda_cpy(ctx, src1, &dst_view);
39
+ }