1#![allow(unused_imports)]
6
7use anyhow::Result;
8use spark_runtime::gpu::{DevicePtr, GpuBackend, KernelHandle};
9use spark_runtime::kernel_args::{KernelLaunch, div_ceil};
10
11use crate::layers::moe;
12use crate::weight_map::{DenseWeight, Fp8DenseWeight, Fp8Weight, QuantizedWeight};
13
14use super::*;
15
16#[allow(clippy::too_many_arguments)]
21pub fn quant_gemv(
22 gpu: &dyn GpuBackend,
23 gemv_nvfp4: KernelHandle,
24 gemv_fp8: KernelHandle,
25 gemv_dense: KernelHandle,
26 input: DevicePtr,
27 weight: &crate::weight_map::QuantWeight,
28 output: DevicePtr,
29 n: u32,
30 k: u32,
31 stream: u64,
32) -> Result<()> {
33 use crate::weight_map::QuantWeight;
34 match weight {
35 QuantWeight::Nvfp4(w) => w4a16_gemv(gpu, gemv_nvfp4, input, w, output, n, k, stream),
36 QuantWeight::Fp8(w) => w8a16_gemv(
37 gpu,
38 gemv_fp8,
39 input,
40 w.weight,
41 w.row_scale,
42 output,
43 n,
44 k,
45 stream,
46 ),
47 QuantWeight::Dense(w) => dense_gemv(gpu, gemv_dense, input, w, output, n, k, stream),
48 QuantWeight::PackedQ2(_) => anyhow::bail!(
52 "quant_gemv: PackedQ2 not routed through the generic dispatcher; use q2_0_gemv_vec"
53 ),
54 }
55}
56
57#[allow(clippy::too_many_arguments)]
61pub fn quant_gemm(
62 gpu: &dyn GpuBackend,
63 gemm_nvfp4: KernelHandle,
64 gemm_fp8: KernelHandle,
65 gemm_dense: KernelHandle,
66 input: DevicePtr,
67 weight: &crate::weight_map::QuantWeight,
68 output: DevicePtr,
69 m: u32,
70 n: u32,
71 k: u32,
72 stream: u64,
73) -> Result<()> {
74 use crate::weight_map::QuantWeight;
75 match weight {
76 QuantWeight::Nvfp4(w) => w4a16_gemm(gpu, gemm_nvfp4, input, w, output, m, n, k, stream),
77 QuantWeight::Fp8(w) => w8a16_gemm(
78 gpu,
79 gemm_fp8,
80 input,
81 w.weight,
82 w.row_scale,
83 output,
84 m,
85 n,
86 k,
87 stream,
88 ),
89 QuantWeight::Dense(w) => dense_gemm(gpu, gemm_dense, input, w, output, m, n, k, stream),
90 QuantWeight::PackedQ2(_) => anyhow::bail!(
91 "quant_gemm: PackedQ2 not routed through the generic dispatcher; \
92 use the layer's transient-dequant prefill path"
93 ),
94 }
95}
96
97pub fn w4a16_gemv(
105 gpu: &dyn GpuBackend,
106 kernel: KernelHandle,
107 input: DevicePtr,
108 weight: &QuantizedWeight,
109 output: DevicePtr,
110 n: u32,
111 k: u32,
112 stream: u64,
113) -> Result<()> {
114 KernelLaunch::new(gpu, kernel)
115 .grid([w4a16_gemv_grid_x(n), 1, 1])
116 .block([256, 1, 1])
117 .arg_ptr(input)
118 .arg_ptr(weight.weight)
119 .arg_ptr(weight.weight_scale)
120 .arg_f32(weight.weight_scale_2)
121 .arg_ptr(output)
122 .arg_u32(n)
123 .arg_u32(k)
124 .launch(stream)
125}
126
127pub fn w4a16_gemv_batch2(
135 gpu: &dyn GpuBackend,
136 kernel: KernelHandle,
137 input: DevicePtr,
138 weight: &QuantizedWeight,
139 output: DevicePtr,
140 n: u32,
141 k: u32,
142 stream: u64,
143) -> Result<()> {
144 KernelLaunch::new(gpu, kernel)
145 .grid([div_ceil(n, 4), 1, 1])
146 .block([256, 1, 1])
147 .arg_ptr(input)
148 .arg_ptr(weight.weight)
149 .arg_ptr(weight.weight_scale)
150 .arg_f32(weight.weight_scale_2)
151 .arg_ptr(output)
152 .arg_u32(n)
153 .arg_u32(k)
154 .launch(stream)
155}
156
157pub fn w4a16_gemv_batch3(
165 gpu: &dyn GpuBackend,
166 kernel: KernelHandle,
167 input: DevicePtr,
168 weight: &QuantizedWeight,
169 output: DevicePtr,
170 n: u32,
171 k: u32,
172 stream: u64,
173) -> Result<()> {
174 KernelLaunch::new(gpu, kernel)
175 .grid([div_ceil(n, 4), 1, 1])
176 .block([256, 1, 1])
177 .arg_ptr(input)
178 .arg_ptr(weight.weight)
179 .arg_ptr(weight.weight_scale)
180 .arg_f32(weight.weight_scale_2)
181 .arg_ptr(output)
182 .arg_u32(n)
183 .arg_u32(k)
184 .launch(stream)
185}
186
187pub fn w4a16_gemv_batchm(
197 gpu: &dyn GpuBackend,
198 kernel: KernelHandle,
199 input: DevicePtr,
200 weight: &QuantizedWeight,
201 output: DevicePtr,
202 m: u32,
203 n: u32,
204 k: u32,
205 stream: u64,
206) -> Result<()> {
207 debug_assert!(m <= 16, "w4a16_gemv_batchm caps at M=16 (m={m})");
211 KernelLaunch::new(gpu, kernel)
212 .grid([div_ceil(n, 4), 1, 1])
213 .block([256, 1, 1])
214 .arg_ptr(input)
215 .arg_ptr(weight.weight)
216 .arg_ptr(weight.weight_scale)
217 .arg_f32(weight.weight_scale_2)
218 .arg_ptr(output)
219 .arg_u32(m)
220 .arg_u32(n)
221 .arg_u32(k)
222 .launch(stream)
223}
224
225#[allow(clippy::too_many_arguments)]
233pub fn w4a16_gemv_qg(
234 gpu: &dyn GpuBackend,
235 kernel: KernelHandle,
236 input: DevicePtr,
237 weight: &QuantizedWeight,
238 output: DevicePtr,
239 n: u32,
240 k: u32,
241 num_heads: u32,
242 head_dim: u32,
243 stream: u64,
244) -> Result<()> {
245 KernelLaunch::new(gpu, kernel)
246 .grid([div_ceil(n, 4), 1, 1])
247 .block([256, 1, 1])
248 .arg_ptr(input)
249 .arg_ptr(weight.weight)
250 .arg_ptr(weight.weight_scale)
251 .arg_f32(weight.weight_scale_2)
252 .arg_ptr(output)
253 .arg_u32(n)
254 .arg_u32(k)
255 .arg_u32(num_heads)
256 .arg_u32(head_dim)
257 .launch(stream)
258}
259
260#[allow(clippy::too_many_arguments)]
268pub fn w4a16_gemv_qkvz(
269 gpu: &dyn GpuBackend,
270 kernel: KernelHandle,
271 input: DevicePtr,
272 weight: &QuantizedWeight,
273 output: DevicePtr,
274 n: u32,
275 k: u32,
276 num_groups: u32,
277 head_k_dim: u32,
278 vheads_per_group: u32,
279 head_v_dim: u32,
280 stream: u64,
281) -> Result<()> {
282 KernelLaunch::new(gpu, kernel)
283 .grid([div_ceil(n, 4), 1, 1])
284 .block([256, 1, 1])
285 .arg_ptr(input)
286 .arg_ptr(weight.weight)
287 .arg_ptr(weight.weight_scale)
288 .arg_f32(weight.weight_scale_2)
289 .arg_ptr(output)
290 .arg_u32(n)
291 .arg_u32(k)
292 .arg_u32(num_groups)
293 .arg_u32(head_k_dim)
294 .arg_u32(vheads_per_group)
295 .arg_u32(head_v_dim)
296 .launch(stream)
297}
298
299#[allow(clippy::too_many_arguments)]
308pub fn w4a16_gemv_qg_batch2(
309 gpu: &dyn GpuBackend,
310 kernel: KernelHandle,
311 input: DevicePtr,
312 weight: &QuantizedWeight,
313 output: DevicePtr,
314 n: u32,
315 k: u32,
316 num_heads: u32,
317 head_dim: u32,
318 stream: u64,
319) -> Result<()> {
320 KernelLaunch::new(gpu, kernel)
321 .grid([div_ceil(n, 4), 1, 1])
322 .block([256, 1, 1])
323 .arg_ptr(input)
324 .arg_ptr(weight.weight)
325 .arg_ptr(weight.weight_scale)
326 .arg_f32(weight.weight_scale_2)
327 .arg_ptr(output)
328 .arg_u32(n)
329 .arg_u32(k)
330 .arg_u32(num_heads)
331 .arg_u32(head_dim)
332 .launch(stream)
333}
334
335#[allow(clippy::too_many_arguments)]
344pub fn w4a16_gemv_qg_batch3(
345 gpu: &dyn GpuBackend,
346 kernel: KernelHandle,
347 input: DevicePtr,
348 weight: &QuantizedWeight,
349 output: DevicePtr,
350 n: u32,
351 k: u32,
352 num_heads: u32,
353 head_dim: u32,
354 stream: u64,
355) -> Result<()> {
356 KernelLaunch::new(gpu, kernel)
357 .grid([div_ceil(n, 4), 1, 1])
358 .block([256, 1, 1])
359 .arg_ptr(input)
360 .arg_ptr(weight.weight)
361 .arg_ptr(weight.weight_scale)
362 .arg_f32(weight.weight_scale_2)
363 .arg_ptr(output)
364 .arg_u32(n)
365 .arg_u32(k)
366 .arg_u32(num_heads)
367 .arg_u32(head_dim)
368 .launch(stream)
369}
370
371#[allow(clippy::too_many_arguments)]
380pub fn w4a16_gemv_dual_batch3(
381 gpu: &dyn GpuBackend,
382 kernel: KernelHandle,
383 input: DevicePtr,
384 weight0: &QuantizedWeight,
385 output0: DevicePtr,
386 weight1: &QuantizedWeight,
387 output1: DevicePtr,
388 n: u32,
389 k: u32,
390 stream: u64,
391) -> Result<()> {
392 KernelLaunch::new(gpu, kernel)
393 .grid([div_ceil(n, 4), 1, 2])
394 .block([256, 1, 1])
395 .arg_ptr(input)
396 .arg_ptr(weight0.weight)
397 .arg_ptr(weight0.weight_scale)
398 .arg_f32(weight0.weight_scale_2)
399 .arg_ptr(output0)
400 .arg_ptr(weight1.weight)
401 .arg_ptr(weight1.weight_scale)
402 .arg_f32(weight1.weight_scale_2)
403 .arg_ptr(output1)
404 .arg_u32(n)
405 .arg_u32(k)
406 .launch(stream)
407}
408
409#[allow(clippy::too_many_arguments)]
418pub fn w4a16_gemv_dual_batch2(
419 gpu: &dyn GpuBackend,
420 kernel: KernelHandle,
421 input: DevicePtr,
422 weight0: &QuantizedWeight,
423 output0: DevicePtr,
424 weight1: &QuantizedWeight,
425 output1: DevicePtr,
426 n: u32,
427 k: u32,
428 stream: u64,
429) -> Result<()> {
430 KernelLaunch::new(gpu, kernel)
431 .grid([div_ceil(n, 4), 1, 2])
432 .block([256, 1, 1])
433 .arg_ptr(input)
434 .arg_ptr(weight0.weight)
435 .arg_ptr(weight0.weight_scale)
436 .arg_f32(weight0.weight_scale_2)
437 .arg_ptr(output0)
438 .arg_ptr(weight1.weight)
439 .arg_ptr(weight1.weight_scale)
440 .arg_f32(weight1.weight_scale_2)
441 .arg_ptr(output1)
442 .arg_u32(n)
443 .arg_u32(k)
444 .launch(stream)
445}
446
447