//! MTPLX model operations using its pinned custom and runtime 0.32.2 shaders. //! Rust owns selection and dispatch. No runtime C/C++ library is linked. use super::*; use std::cell::RefCell; #[cfg(test)] use std::cell::{Cell, Ref}; use std::ffi::CString; use std::rc::Rc; pub(super) mod allocator; mod ar; mod array; mod attention; mod binary; mod binding; mod cache; mod compile_graph; mod compiled; mod context_copy; mod decoder; mod dense; mod encoder; mod eval; mod execution; mod fused; mod gdn; mod graph_sync; mod hyper; mod indexing; #[cfg(test)] mod issue103_analysis; #[cfg(test)] mod issue104; #[cfg(test)] mod issue105; #[cfg(test)] mod issue106; #[cfg(test)] mod issue108; #[cfg(test)] mod issue109; mod linear; mod load; mod mlp; mod model; mod moe; mod mtp; mod ngram; mod ngram_sidecar; mod ngram_stage; mod normalization; mod ops; mod owner; mod ple; mod policy; mod prefill; mod qsa_attention; mod qsa_compile; mod qsa_core; #[cfg(test)] mod qsa_graph; mod qsa_indexer; mod qsa_prefill; mod qsa_prepare; mod qsa_select; mod random; mod reduce; mod request; mod residency; mod rope; mod sampling; mod scheduler; mod sdpa; mod session_cache; mod session_checkpoint; mod session_codec; mod sort; mod sparse_attention; mod speculative; mod stream; #[cfg(test)] mod submission; mod unary; mod views; mod vision; mod vision_kernels; mod weights; #[cfg(test)] pub(super) use encoder::Scope; pub(super) use encoder::active_allocator; pub(in crate::engine) use owner::QwenExecutor; #[cfg(test)] pub(super) use qsa_graph::{QsaCacheInput, QsaGraphBank}; pub(in crate::engine) use request::LiveSession as QwenResidentState; #[cfg(test)] pub(super) use stream::{Device as StreamDevice, Streams}; struct Binding<'a> { raw: MetalBinding, allocation: Option, access: Option, _borrow: std::marker::PhantomData<&'a ()>, } fn tensor(index: u32, buffer: &Buffer) -> Binding<'_> { Binding { raw: MetalBinding { tensor: buffer.raw(), bytes: std::ptr::null(), size: 0, index, offset: 0, }, allocation: Some(buffer.hold_allocation()), access: None, _borrow: std::marker::PhantomData, } } fn bytes(index: u32, value: &T) -> Binding<'_> { Binding { raw: MetalBinding { tensor: std::ptr::null(), bytes: std::ptr::from_ref(value).cast(), size: u32::try_from(std::mem::size_of_val(value)).expect("Metal inline bytes size"), index, offset: 0, }, allocation: None, access: None, _borrow: std::marker::PhantomData, } } fn scalar_buffer(value: &[u8]) -> Result { let buffer = Buffer::mtplx_bytes(value.len() as u64)?; buffer.write(0, value)?; Ok(buffer) } fn compile_custom( name: &str, source: impl FnOnce() -> Result, ) -> Result<(), String> { let name = CString::new(name).map_err(|e| e.to_string())?; if unsafe { ds4_gpu_mtplx_compile(name.as_ptr(), std::ptr::null()) } == 0 { let source = CString::new(source()?).map_err(|e| e.to_string())?; check( unsafe { ds4_gpu_mtplx_compile(name.as_ptr(), source.as_ptr()) }, "compiling original MTPLX custom kernel", )?; } Ok(()) } fn qsa_output_args(section: &serde_json::Value) -> Result, String> { section["outputs"] .as_array() .ok_or("invalid QSA output names")? .iter() .map(|name| { let name = name.as_str().ok_or("invalid QSA output name")?; let ty = if name.ends_with("ids") { "int" } else if name == "adjusted_scores" { "float" } else { "bool" }; Ok(format!("device {ty}* {name}")) }) .collect() } fn qsa_shader_source(header: &str, name: &str, args: &[String], body: &str) -> String { let args = args .iter() .enumerate() .map(|(i, a)| format!("{a} [[buffer({i})]]")) .collect::>() .join(",\n"); format!( "{header}kernel void {name}(\n{args},\nuint3 threadgroup_position_in_grid [[threadgroup_position_in_grid]],\nuint3 thread_position_in_threadgroup [[thread_position_in_threadgroup]]) {{{body}}}\n" ) } fn dispatch( name: &str, bindings: &[Binding<'_>], groups: [u32; 3], threads: [u32; 3], ) -> Result<(), String> { dispatch_specialized(name, bindings, &[], groups, threads) } fn dispatch_specialized( name: &str, bindings: &[Binding<'_>], constants: &[MetalConstant], groups: [u32; 3], threads: [u32; 3], ) -> Result<(), String> { dispatch_geometry(name, bindings, constants, groups, threads, false) } fn dispatch_geometry( name: &str, bindings: &[Binding<'_>], constants: &[MetalConstant], grid: [u32; 3], threads: [u32; 3], individual_threads: bool, ) -> Result<(), String> { if let Some(result) = encoder::with_active(|encoder| { encoder.dispatch(name, bindings, constants, grid, threads, individual_threads) }) { return result; } dispatch_geometry_on( name, bindings, constants, grid, threads, individual_threads, None, ) } fn dispatch_geometry_on( name: &str, bindings: &[Binding<'_>], constants: &[MetalConstant], grid: [u32; 3], threads: [u32; 3], individual_threads: bool, target: Option<(*mut c_void, *mut c_void, bool)>, ) -> Result<(), String> { let name = CString::new(name).map_err(|e| e.to_string())?; let raw = bindings.iter().map(|b| b.raw).collect::>(); let mut seen = std::collections::HashSet::new(); let allocations = bindings .iter() .filter_map(|b| b.allocation.as_ref()) .filter(|a| seen.insert(a.identity())) .cloned() .collect::>(); unsafe extern "C" fn release(context: *mut c_void) { // The bridge takes this Box exactly once at callback registration, // including when a submitted standalone command subsequently fails. drop(unsafe { Box::from_raw(context.cast::>()) }); } let mut owner = Box::into_raw(Box::new(allocations)).cast::(); let (command, encoder, barrier) = target.unwrap_or((std::ptr::null_mut(), std::ptr::null_mut(), false)); let result = unsafe { ds4_gpu_mtplx_encode( name.as_ptr(), raw.as_ptr(), raw.len() as u32, constants.as_ptr(), constants.len() as u32, grid.as_ptr(), threads.as_ptr(), u32::from(individual_threads), &mut owner, Some(release), command, encoder, u32::from(barrier), ) }; if !owner.is_null() { // Validation/pipeline/encoder failure: no ownership was transferred. unsafe { release(owner) }; } let result = check(result, &format!("dispatching MTPLX {name:?}")); #[cfg(test)] if result.is_ok() { super::qwen_mtplx_tests::record_dispatch( name.to_str().unwrap(), grid, threads, individual_threads, ); } result } #[derive(Clone, Copy)] #[cfg(test)] pub(super) enum SortDtype { U32, Bf16, F32, } #[cfg(test)] pub(super) struct RouterOutput { pub(super) probabilities: Buffer, /// Last ten columns of argsort, not a contiguous [rows,10] allocation. pub(super) indices: Buffer, pub(super) index_row_stride: u32, pub(super) scores: Buffer, _temporaries: Vec, } /// SparseMoeBlock's precise softmax -> argpartition -> take_along_axis -> /// optional normalization. Consumes donatable logits; retains GPU scratch. #[cfg(test)] pub(super) fn router( logits: Buffer, [rows, experts]: [u32; 2], normalize: bool, ) -> Result { let count = u64::from(rows) * u64::from(experts); if rows == 0 || experts < 10 || count > i32::MAX as u64 || unsafe { ds4_gpu_tensor_bytes(logits.raw()) } < count * 2 { return Err("invalid MTPLX top-10 router shape or buffer".into()); } let group = if experts <= 4096 { experts.div_ceil(4).div_ceil(32) * 32 } else { 1024 // Pinned looped-softmax pipeline maximum on M5 Max. }; let threads = rows .checked_mul(group) .ok_or("MTPLX softmax grid overflow")?; dispatch_geometry( if experts <= 4096 { "block_softmax_precise_bfloat16" } else { "looped_softmax_precise_bfloat16" }, &[ tensor(0, &logits).input(count as usize), tensor(1, &logits).output(count as usize), bytes(2, &experts), ], &[], [threads, 1, 1], [group, 1, 1], true, )?; let order = Buffer::mtplx_bytes(count * 4)?; let mut temporary = argsort(&logits, &order, [rows, experts], SortDtype::Bf16)?; let offset = u64::from(experts - 10) * 4; let indices = order.view(offset, count * 4 - offset)?; let scores = Buffer::mtplx_bytes(u64::from(rows) * 10 * 2)?; let grid = [1, 10, rows]; dispatch_geometry( if rows == 1 || experts == 10 { "kernel_qwen_mtplx_gather_axis_bf16_int_11" } else { "kernel_qwen_mtplx_gather_axis_bf16_int_10" }, &[ tensor(0, &logits).input(count as usize), tensor(1, &indices).input(((u64::from(rows) - 1) * u64::from(experts) + 10) as usize), tensor(2, &scores).output((u64::from(rows) * 10) as usize), bytes(3, &rows), bytes(4, &u64::from(experts)), bytes(5, &u64::from(experts)), bytes(6, &1_u64), bytes(7, &1_u32), bytes(8, &experts), bytes(9, &1_u64), bytes(10, &1_u64), ], &[], grid, block_dims(grid), true, )?; if normalize { let sums = Buffer::mtplx_bytes(u64::from(rows) * 2)?; dispatch_geometry( "row_reduce_small_1_reduce_sumbfloat16", &[ tensor(0, &scores).input((u64::from(rows) * 10) as usize), tensor(1, &sums).output(rows as usize), bytes(2, &10_u64), bytes(3, &1_u64), bytes(4, &rows), bytes(5, &10_u64), bytes(6, &1_u32), bytes(7, &0_u32), bytes(8, &0_u64), bytes(9, &0_u32), ], &[], [rows, 1, 1], [rows.min(1024), 1, 1], true, )?; if rows == 1 { dispatch_geometry( "vs_Dividebfloat16", &[ tensor(0, &scores).input((u64::from(rows) * 10) as usize), tensor(1, &sums).input(rows as usize), tensor(2, &scores).output((u64::from(rows) * 10) as usize), bytes(3, &10_u32), ], &[], [10, 1, 1], [10, 1, 1], true, )?; } else { let grid = [10, rows, 1]; dispatch_geometry( "g2_Dividebfloat16", &[ tensor(0, &scores).input((u64::from(rows) * 10) as usize), tensor(1, &sums).input(rows as usize), tensor(2, &scores).output((u64::from(rows) * 10) as usize), bytes(3, &[10_u64, 1]), bytes(4, &[1_u64, 0]), ], &[], grid, block_dims(grid), true, )?; } temporary.push(sums); } temporary.push(order); Ok(RouterOutput { probabilities: logits, indices, index_row_stride: experts, scores, _temporaries: temporary, }) } /// Contiguous last-axis argsort used by routing and _gather_sort. The reference /// also implements argpartition by this complete sort, not a local top-k kernel. #[cfg(test)] pub(super) fn argsort( input: &Buffer, output: &Buffer, [rows, width]: [u32; 2], dtype: SortDtype, ) -> Result, String> { use array::{Array, Dtype}; let dtype = match dtype { SortDtype::U32 => Dtype::U32, SortDtype::Bf16 => Dtype::BF16, SortDtype::F32 => Dtype::F32, }; let count = u64::from(rows) * u64::from(width); let item_bytes = dtype.itemsize() as u64; if rows == 0 || width == 0 || count > i32::MAX as u64 || unsafe { ds4_gpu_tensor_bytes(input.raw()) } < count * item_bytes || unsafe { ds4_gpu_tensor_bytes(output.raw()) } < count * 4 { return Err("invalid MTPLX contiguous argsort shape or buffer".into()); } let shape = if rows == 1 { vec![width as i32] } else { vec![rows as i32, width as i32] }; let input = Array::new(&shape, dtype, input.view(0, count * item_bytes)?)?; let output = Array::new(&shape, Dtype::U32, output.view(0, count * 4)?)?; sort::sort_into(&input, &output, shape.len() - 1, true) } fn block_dims(grid: [u32; 3]) -> [u32; 3] { block_dims_pow2(grid, 10) } fn block_dims_pow2(grid: [u32; 3], pow2: u32) -> [u32; 3] { let mut group = [1, 1, 1]; let mut used = 0; loop { let before = used; for axis in 0..3 { if grid[axis] >= group[axis] * 2 { group[axis] *= 2; used += 1; } if used == pow2 { break; } } if used == pow2 || used == before { break; } } group } /// Actual compiled nn.silu(gate) followed by the reference's separate * up. /// Input is the fused [rows,2*intermediate] BF16 pack, with strided half views. /// Keep returned SiLU storage alive until the enclosing GPU batch completes. #[cfg(test)] pub(super) fn gate_up_bf16( input: &Buffer, output: &Buffer, [rows, intermediate]: [u32; 2], ) -> Result { let count = u64::from(rows) * u64::from(intermediate); if rows == 0 || intermediate == 0 || !intermediate.is_multiple_of(2) || count > i32::MAX as u64 || unsafe { ds4_gpu_tensor_bytes(input.raw()) } < count * 4 || unsafe { ds4_gpu_tensor_bytes(output.raw()) } < count * 2 { return Err("invalid MTPLX fused gate/up buffer or shape".into()); } let activated = Buffer::mtplx_bytes(count * 2)?; let up = input.view( u64::from(intermediate) * 2, count * 4 - u64::from(intermediate) * 2, )?; let count = count as u32; if rows == 1 { let work = if count < 65536 { 1 } else { 4 }; let threads = count.div_ceil(work); dispatch_geometry( if work == 1 { "kernel_qwen_mtplx_silu_bf16_contiguous" } else { "kernel_qwen_mtplx_silu_bf16_contiguous_n" }, &[ tensor(0, input).input((u64::from(count) * 2 - u64::from(intermediate)) as usize), tensor(1, &activated).output(count as usize), bytes(2, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; dispatch_geometry( if work == 1 { "vv_Multiplybfloat16" } else { "vvn_Multiplybfloat16" }, &[ tensor(0, &activated).input(count as usize), tensor(1, &up).input((u64::from(count) * 2 - u64::from(intermediate)) as usize), tensor(2, output).output(count as usize), bytes(3, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; } else { let shape = [rows, intermediate]; let in_strides = [u64::from(intermediate) * 2, 1]; let out_strides = [u64::from(intermediate), 1]; let grid = [intermediate, rows, 1]; let group = block_dims(grid); dispatch_geometry( "kernel_qwen_mtplx_silu_bf16_strided_2", &[ tensor(0, input).input((u64::from(count) * 2 - u64::from(intermediate)) as usize), bytes(1, &in_strides), tensor(2, &activated).output(count as usize), bytes(3, &shape), ], &[], grid, group, true, )?; dispatch_geometry( "g2_Multiplybfloat16", &[ tensor(0, &activated).input(count as usize), tensor(1, &up).input((u64::from(count) * 2 - u64::from(intermediate)) as usize), tensor(2, output).output(count as usize), bytes(3, &out_strides), bytes(4, &in_strides), ], &[], grid, group, true, )?; } Ok(activated) } #[cfg(test)] fn rms_norm_bf16( input: &Buffer, weight: Option<&Buffer>, output: &Buffer, [rows, width]: [u32; 2], eps: f32, ) -> Result<(), String> { let count = u64::from(rows) * u64::from(width); if rows == 0 || width == 0 || count > i32::MAX as u64 || !eps.is_finite() || eps < 0.0 || [input, output] .iter() .any(|b| unsafe { ds4_gpu_tensor_bytes(b.raw()) } < count * 2) || weight.is_some_and(|w| unsafe { ds4_gpu_tensor_bytes(w.raw()) } < u64::from(width) * 2) { return Err("invalid MTPLX BF16 RMS norm".into()); } let default_weight = weight .is_none() .then(|| scalar_buffer(&0x3f80_u16.to_le_bytes())) .transpose()?; let bound_weight = weight.or(default_weight.as_ref()).unwrap(); normalization::dispatch( [ (input, 0, count as usize), ( bound_weight, 0, if weight.is_some() { width as usize } else { 1 }, ), (output, 0, count as usize), ], array::Dtype::BF16, width, u32::from(weight.is_some()), eps, ) } /// The shared HC/PLE GroupedRMSNorm: unweighted per-group RMS followed by /// separate full-feature weighting. Folding the weight into RMS changes rounding. #[cfg(test)] pub(super) fn grouped_rms_norm( input: &Buffer, weight: &Buffer, [rows, width, group_width]: [u32; 3], eps: f32, ) -> Result { if group_width == 0 || !width.is_multiple_of(group_width) || unsafe { ds4_gpu_tensor_bytes(weight.raw()) } < u64::from(width) * 2 { return Err("invalid MTPLX grouped RMS shape or weight".into()); } let count = u64::from(rows) * u64::from(width); if count == 0 || count > i32::MAX as u64 { return Err("invalid MTPLX grouped RMS size".into()); } let output = Buffer::mtplx_bytes(count * 2)?; rms_norm_bf16( input, None, &output, [count as u32 / group_width, group_width], eps, )?; if rows == 1 { let work = if width < 65536 { 1 } else { 4 }; let threads = width.div_ceil(work); dispatch_geometry( if work == 1 { "vv_Multiplybfloat16" } else { "vvn_Multiplybfloat16" }, &[ tensor(0, &output).input(count as usize), tensor(1, weight).input(width as usize), tensor(2, &output).output(count as usize), bytes(3, &width), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; } else { let grid = [width, rows, 1]; dispatch_geometry( "g2_Multiplybfloat16", &[ tensor(0, &output).input(count as usize), tensor(1, weight).input(width as usize), tensor(2, &output).output(count as usize), bytes(3, &[u64::from(width), 1]), bytes(4, &[0_u64, 1]), ], &[], grid, block_dims(grid), true, )?; } Ok(output) } #[cfg(test)] fn cast_bf16_f32(input: &Buffer, output: &Buffer, count: u32, to_f32: bool) -> Result<(), String> { let (in_bytes, out_bytes) = if to_f32 { (2, 4) } else { (4, 2) }; if count == 0 || count > i32::MAX as u32 || unsafe { ds4_gpu_tensor_bytes(input.raw()) } < u64::from(count) * in_bytes || unsafe { ds4_gpu_tensor_bytes(output.raw()) } < u64::from(count) * out_bytes { return Err("invalid MTPLX BF16/FP32 cast".into()); } let work = if count < 65536 { 1 } else if to_f32 { 2 } else { 4 }; let threads = count.div_ceil(work); let dtype = if to_f32 { "bfloat16float32" } else { "float32bfloat16" }; dispatch_geometry( &format!("v{}_copy{dtype}", if work == 1 { "" } else { "n" }), &[ tensor(0, input).input(count as usize), tensor(1, output).output(count as usize), bytes(2, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, ) } #[cfg(test)] pub(super) struct GatedNormOutput { pub(super) hidden: Buffer, _temporaries: Vec, } /// SigmoidRMSNormGated, including the projected Z view's token stride. /// RMS output rounds to BF16 before its FP32 sigmoid/multiply epilogue. #[cfg(test)] pub(super) fn sigmoid_rms_norm( input: &Buffer, weight: &Buffer, gate: Option<&Buffer>, [tokens, heads, width, gate_stride]: [u32; 4], eps: f32, ) -> Result { let row_width = heads .checked_mul(width) .ok_or("MTPLX gated RMS width overflow")?; let count = tokens .checked_mul(row_width) .filter(|n| *n > 0 && *n <= i32::MAX as u32) .ok_or("invalid MTPLX gated RMS count")?; let rows = tokens .checked_mul(heads) .ok_or("MTPLX gated RMS row overflow")?; let hidden = Buffer::mtplx_bytes(u64::from(count) * 2)?; rms_norm_bf16(input, Some(weight), &hidden, [rows, width], eps)?; let Some(gate) = gate else { return Ok(GatedNormOutput { hidden, _temporaries: Vec::new(), }); }; if gate_stride < row_width || unsafe { ds4_gpu_tensor_bytes(gate.raw()) } < (u64::from(tokens - 1) * u64::from(gate_stride) + u64::from(row_width)) * 2 { return Err("invalid MTPLX gated RMS Z view".into()); } let g = Buffer::mtplx_bytes(u64::from(count) * 4)?; if tokens == 1 || gate_stride == row_width { cast_bf16_f32(gate, &g, count, true)?; } else { let grid = [row_width, tokens, 1]; dispatch_geometry( "g2_copybfloat16float32", &[ tensor(0, gate).input( (u64::from(tokens - 1) * u64::from(gate_stride) + u64::from(row_width)) as usize, ), tensor(1, &g).output(count as usize), bytes(3, &[u64::from(gate_stride), 1]), ], &[], grid, block_dims(grid), true, )?; } let work = if count < 65536 { 1 } else { 2 }; let threads = count.div_ceil(work); dispatch_geometry( if work == 1 { "v_Sigmoidfloat32float32" } else { "vn_Sigmoidfloat32float32" }, &[ tensor(0, &g).input(count as usize), tensor(1, &g).output(count as usize), bytes(2, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; let x = Buffer::mtplx_bytes(u64::from(count) * 4)?; cast_bf16_f32(&hidden, &x, count, true)?; dispatch_geometry( if work == 1 { "vv_Multiplyfloat32" } else { "vvn_Multiplyfloat32" }, &[ tensor(0, &g).input(count as usize), tensor(1, &x).input(count as usize), tensor(2, &x).output(count as usize), bytes(3, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; cast_bf16_f32(&x, &hidden, count, false)?; Ok(GatedNormOutput { hidden, _temporaries: vec![g, x], }) } /// Row gather used by MTPLX's _gather_sort and _scatter_unsort. Indices must /// originate from the checked routing/sort path, not unchecked external data. #[cfg(test)] pub(super) fn gather_front( input: &Buffer, indices: &Buffer, output: &Buffer, [rows, width, routes]: [u32; 3], dtype: SortDtype, ) -> Result<(), String> { let (tag, item_bytes) = match dtype { SortDtype::U32 => ("u32", 4), SortDtype::Bf16 => ("bf16", 2), SortDtype::F32 => ("f32", 4), }; let src_count = u64::from(rows) * u64::from(width); let out_count = u64::from(routes) * u64::from(width); if [rows, width, routes] .iter() .any(|v| *v == 0 || *v > i32::MAX as u32) || unsafe { ds4_gpu_tensor_bytes(input.raw()) } < src_count * item_bytes || unsafe { ds4_gpu_tensor_bytes(indices.raw()) } < u64::from(routes) * 4 || unsafe { ds4_gpu_tensor_bytes(output.raw()) } < out_count * item_bytes { return Err("invalid MTPLX gather-front shape or buffer".into()); } let work = if width > 8 && item_bytes < 4 { 2 } else { 1 }; let grid = [width.div_ceil(work), routes, 1]; let group = block_dims(grid); let loc = if src_count > i32::MAX as u64 || out_count > i32::MAX as u64 { "int64_t" } else { "int" }; dispatch_geometry( &format!("kernel_qwen_mtplx_gather_front_{tag}_{loc}_{work}"), &[ tensor(0, input).input(src_count as usize), tensor(1, indices).input(routes as usize), tensor(2, output).output(out_count as usize), bytes(3, &u64::from(width)), bytes(4, &rows), ], &[], grid, group, true, ) } #[cfg(test)] pub(super) struct GatherSorted { pub(super) x: Buffer, pub(super) indices: Buffer, pub(super) inverse: Buffer, _temporaries: Vec, } /// The connected reference _gather_sort path. Retain the result through GPU /// completion; the caller applies the reference's >=64-route sort condition. #[cfg(test)] pub(super) fn gather_sort( input: &Buffer, indices: &Buffer, [tokens, top_k, width]: [u32; 3], ) -> Result { let routes = tokens .checked_mul(top_k) .filter(|v| *v > 0 && *v <= i32::MAX as u32) .ok_or("invalid MTPLX route count")?; if width == 0 || width > i32::MAX as u32 || unsafe { ds4_gpu_tensor_bytes(input.raw()) } < u64::from(tokens) * u64::from(width) * 2 { return Err("invalid MTPLX gather-sort input".into()); } let order = Buffer::mtplx_bytes(u64::from(routes) * 4)?; let inverse = Buffer::mtplx_bytes(u64::from(routes) * 4)?; let token_rows = Buffer::mtplx_bytes(u64::from(routes) * 4)?; let sorted_indices = Buffer::mtplx_bytes(u64::from(routes) * 4)?; let x = Buffer::mtplx_bytes(u64::from(routes) * u64::from(width) * 2)?; let mut temporary = argsort(indices, &order, [1, routes], SortDtype::U32)?; temporary.extend(argsort(&order, &inverse, [1, routes], SortDtype::U32)?); let divisor = scalar_buffer(&top_k.to_le_bytes())?; let work = if routes < 65536 { 1 } else { 2 }; let threads = routes.div_ceil(work); dispatch_geometry( if work == 1 { "vs_Divideuint32" } else { "vsn_Divideuint32" }, &[ tensor(0, &order).input(routes as usize), tensor(1, &divisor).input(1), tensor(2, &token_rows).output(routes as usize), bytes(3, &routes), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; gather_front( input, &token_rows, &x, [tokens, width, routes], SortDtype::Bf16, )?; gather_front( indices, &order, &sorted_indices, [routes, 1, routes], SortDtype::U32, )?; temporary.extend([order, token_rows]); Ok(GatherSorted { x, indices: sorted_indices, inverse, _temporaries: temporary, }) } fn qmv_limit(k: u32, n: u32) -> u32 { if k <= 2048 && n <= 2048 { 33 } else if k <= 4096 && n <= 4096 { 25 } else { 13 } } #[derive(Debug, PartialEq)] pub(super) struct AffinePlan { pub(super) name: String, pub(super) groups: [u32; 3], pub(super) threads: [u32; 3], pub(super) splits: u32, pub(super) parameters: Vec, } /// Contiguous, non-batched affine x @ W.T on the requested M5 Max. /// Selection follows quantized.cpp at 1f8e74e, not a local speed heuristic. pub(super) fn affine_plan( shape: [u32; 3], bits: u32, group: u32, nax: bool, ) -> Result { affine_plan_batched(shape, bits, group, nax, 1) } /// QuantizedMatmul uses M=x.shape(-2) and the original batch strides when /// x is not row-contiguous. Only the B=1 matrix route may use Split-K. fn affine_plan_batched( [m, n, k]: [u32; 3], bits: u32, group: u32, nax: bool, batches: u32, ) -> Result { if [m, n, k].iter().any(|d| *d == 0 || *d > i32::MAX as u32) || !matches!(bits, 4 | 8) || !matches!(group, 32 | 64) || !k.is_multiple_of(group) || batches == 0 || u64::from(m) .checked_mul(u64::from(n)) .and_then(|v| v.checked_mul(u64::from(batches))) .is_none_or(|v| v > i32::MAX as u64) { return Err("invalid MTPLX BF16 affine shape or installed-pack quantization".into()); } let suffix = format!("bfloat16_t_gs_{group}_b_{bits}"); let batch = u8::from(batches > 1); let limit = qmv_limit(k, n); let mut plan = AffinePlan { name: String::new(), groups: [1, 1, 1], threads: [32, 2, 1], splits: 1, parameters: vec![k, n], }; if m < limit { if matches!(k, 64 | 128) { plan.name = format!("affine_qmv_quad_{suffix}_d_{k}_batch_{batch}"); plan.groups = [m, n.div_ceil(64), batches]; plan.threads = [32, 1, 1]; } else if m >= 2 { let vectors = m.div_ceil(m.div_ceil(5)); plan.name = format!("affine_qmv_wide_{suffix}_nv_{vectors}_kl_8_batch_{batch}"); plan.groups = [m.div_ceil(vectors), n.div_ceil(8), batches]; plan.parameters.push(m); } else { let fast = n.is_multiple_of(8) && k.is_multiple_of((32 / bits) * 2 * 32); plan.name = format!( "affine_qmv{}_{suffix}_batch_{batch}", if fast { "_fast" } else { "" } ); plan.groups = [m, n.div_ceil(8), batches]; } return Ok(plan); } let tiles = u64::from(n.div_ceil(32)) * u64::from(m.div_ceil(32)); let alignment = group.max(32); let mut splits = if batches == 1 { ((512 / tiles) as u32).max(1).min(k / alignment) } else { 1 }; while splits > 1 && !k.is_multiple_of(splits * alignment) { splits -= 1; } plan.splits = splits; plan.parameters.push(m); plan.threads = [32, 2, 2]; if splits > 1 { plan.name = format!("affine_qmm_t_splitk_{suffix}_alN_{}", n.is_multiple_of(32)); plan.groups = [n.div_ceil(32), m.div_ceil(32), splits]; plan.parameters.extend([k / splits, m * n]); } else if nax && k.is_multiple_of(64) { let bm = if m <= 32 { 32 } else { 64 }; plan.name = format!( "affine_qmm_t_nax_{suffix}_bm{bm}_bn64_bk64_wm2_wn2_alN_{}_batch_{batch}", n.is_multiple_of(64) ); plan.groups = [n.div_ceil(64), m.div_ceil(bm), batches]; } else { plan.name = format!( "affine_qmm_t_{suffix}_alN_{}_batch_{batch}", n.is_multiple_of(32) ); plan.groups = [n.div_ceil(32), m.div_ceil(32), batches]; } Ok(plan) } /// Normalized x[X,M,K], affine weights[E,N,K], index vectors[R], y[R,M,N]. /// For sorted=true x is already gathered in rhs order and lhs is identity, /// matching _gather_sort and the reference's implicit-lhs sorted dispatch. /// Indices originate from the checked router/sort path, not unchecked user data. #[cfg(test)] pub(super) fn gather_bf16( buffers: [&Buffer; 7], shape: [u32; 6], quant: [u32; 2], sorted: bool, nax: bool, ) -> Result<(), String> { gather_bf16_broadcast(buffers, shape, quant, sorted, nax, 1, [shape[5]; 2]) } #[cfg(test)] fn gather_bf16_broadcast( buffers: [&Buffer; 7], [x_batches, m, n, k, experts, routes]: [u32; 6], [bits, group]: [u32; 2], sorted: bool, nax: bool, lhs_repeat: u32, [rhs_width, rhs_stride]: [u32; 2], ) -> Result<(), String> { affine_plan([m, n, k], bits, group, nax)?; if [x_batches, experts, routes] .iter() .any(|d| *d == 0 || *d > i32::MAX as u32) || u64::from(m) * u64::from(routes) * u64::from(n) > i32::MAX as u64 || (sorted && x_batches != routes) || lhs_repeat == 0 || !routes.is_multiple_of(lhs_repeat) || (sorted && lhs_repeat != 1) || rhs_width == 0 || rhs_stride < rhs_width || !routes.is_multiple_of(rhs_width) || (rhs_stride != rhs_width && lhs_repeat != 1 && lhs_repeat != rhs_width) || (sorted && rhs_stride != rhs_width) { return Err("invalid normalized MTPLX gather shape".into()); } let [w, s, b, x, lhs, rhs, y] = buffers; let packed_cols = k / (32 / bits); let param_cols = k / group; let w_bytes = (u64::from(experts) * u64::from(n)).checked_mul(u64::from(packed_cols) * 4); let p_bytes = (u64::from(experts) * u64::from(n)).checked_mul(u64::from(param_cols) * 2); let expected = [ w_bytes, p_bytes, p_bytes, (u64::from(x_batches) * u64::from(m)).checked_mul(u64::from(k) * 2), Some(u64::from(routes / lhs_repeat) * 4), Some( (u64::from(routes / rhs_width - 1) * u64::from(rhs_stride) + u64::from(rhs_width)) * 4, ), Some(u64::from(routes) * u64::from(m) * u64::from(n) * 2), ]; for (buffer, size) in buffers.iter().zip(expected) { if size.is_none_or(|size| unsafe { ds4_gpu_tensor_bytes(buffer.raw()) } < size) { return Err("MTPLX gather buffer is smaller than its shape".into()); } } let elements: [usize; 7] = std::array::from_fn(|i| (expected[i].unwrap() / [4, 2, 2, 2, 4, 4, 2][i]) as usize); let strided_rhs = rhs_stride != rhs_width && rhs_width < routes; let batch_dim = if strided_rhs || (lhs_repeat > 1 && lhs_repeat < routes) { 2_u32 } else { 1 }; let batch_shape = if batch_dim == 2 { let width = if strided_rhs { rhs_width } else { lhs_repeat }; [routes / width, width] } else { [routes, 1] }; let lhs_strides = if strided_rhs && lhs_repeat == 1 { [u64::from(rhs_width), 1] } else if lhs_repeat > 1 && batch_dim == 1 { [0, 0] } else { [1_u64, 0] }; let rhs_strides = if strided_rhs { [u64::from(rhs_stride), 1] } else if batch_dim == 1 { [1_u64, 0] } else { [u64::from(lhs_repeat), 1] }; let x_shape = [x_batches, m, k]; let x_strides = [u64::from(m) * u64::from(k), u64::from(k), 1]; let w_shape = [experts, n, packed_cols]; let w_strides = [ u64::from(n) * u64::from(packed_cols), u64::from(packed_cols), 1, ]; let p_strides = [ u64::from(n) * u64::from(param_cols), u64::from(param_cols), 1, ]; let batch_shape = batch_shape.map(|d| d as i32); let lhs_strides = lhs_strides.map(|d| d as i64); let rhs_strides = rhs_strides.map(|d| d as i64); gather_bf16_layout( [ tensor(0, w).input(elements[0]), tensor(1, s).input(elements[1]), tensor(2, b).input(elements[2]), tensor(3, x).input(elements[3]), tensor(4, lhs).input(elements[4]), tensor(5, rhs).input(elements[5]), tensor(6, y).output(elements[6]), ], [m, n, k, experts, routes, routes], [bits, group], sorted, nax, [ &x_shape.map(|d| d as i32), &w_shape.map(|d| d as i32), &batch_shape[..batch_dim as usize], ], [ &x_strides.map(|d| d as i64), &w_strides.map(|d| d as i64), &p_strides.map(|d| d as i64), &p_strides.map(|d| d as i64), &lhs_strides[..batch_dim as usize], &rhs_strides[..batch_dim as usize], ], ) } /// Shared original GatherQMM dispatch; array batch strides are passed verbatim, /// while the two broadcast index layouts have jointly collapsed dimensions. fn gather_bf16_layout( bindings: [Binding<'_>; 7], [m, n, k, experts, routes, sorted_rows]: [u32; 6], [bits, group]: [u32; 2], sorted: bool, nax: bool, [x_shape, w_shape, batch_shape]: [&[i32]; 3], [ x_strides, w_strides, s_strides, b_strides, lhs_strides, rhs_strides, ]: [&[i64]; 6], ) -> Result<(), String> { let suffix = format!("bfloat16_t_gs_{group}_b_{bits}"); if m == 1 && routes >= 16 && sorted && routes / experts >= 4 { let (bm, bn, bk, wm, wn) = if nax { ( if sorted_rows / experts < 64 { 32 } else { 64 }, 64, 64, 2, 2, ) } else { (16, 32, 32, 1, 2) }; let name = format!( "affine_gather_qmm_rhs{}_nt_{suffix}_bm_{bm}_bn_{bn}_bk_{bk}_wm_{wm}_wn_{wn}", if nax { "_nax" } else { "" } ); let constants = [ (200, sorted_rows.is_multiple_of(bm)), (201, n.is_multiple_of(bn)), (202, k.is_multiple_of(bk)), ] .map(|(index, value)| MetalConstant { index, value: u32::from(value), kind: 0, }); let [w, s, b, x, _lhs, rhs, y] = bindings; let mut sorted_bindings = [x, w, s, b, rhs, y]; for (index, binding) in sorted_bindings.iter_mut().enumerate() { binding.raw.index = index as u32; } let mut bindings = Vec::from(sorted_bindings); bindings.extend([bytes(6, &sorted_rows), bytes(7, &n), bytes(8, &k)]); return dispatch_specialized( &name, &bindings, &constants, [n.div_ceil(bn), sorted_rows.div_ceil(bm), 1], [32, wn, wm], ); } let matrix = m >= qmv_limit(k, n); let (name, groups, threads) = if matrix { if nax && k.is_multiple_of(64) { ( format!( "affine_gather_qmm_t_nax_{suffix}_bm64_bn64_bk64_wm2_wn2_alN_{}", n.is_multiple_of(64) ), [n.div_ceil(64), m.div_ceil(64), routes], [32, 2, 2], ) } else { ( format!("affine_gather_qmm_t_{suffix}_alN_{}", n.is_multiple_of(32)), [n.div_ceil(32), m.div_ceil(32), routes], [32, 2, 2], ) } } else { let fast = n.is_multiple_of(8) && k.is_multiple_of((32 / bits) * 2 * 32); ( format!( "affine_gather_qmv{}_{suffix}", if fast { "_fast" } else { "" } ), [m, n.div_ceil(8), routes], [32, 2, 1], ) }; let x_dim = (x_shape.len() - 2) as u32; let w_dim = (w_shape.len() - 2) as u32; let batch_dim = batch_shape.len() as u32; let mut bindings = Vec::from(bindings); bindings.extend([bytes(7, &k), bytes(8, &n)]); if matrix { bindings.push(bytes(9, &m)); } let base = bindings.len() as u32; bindings.extend([ bytes(base, &x_dim), bytes(base + 1, x_shape), bytes(base + 2, x_strides), bytes(base + 3, &w_dim), bytes(base + 4, w_shape), bytes(base + 5, w_strides), bytes(base + 6, s_strides), bytes(base + 7, b_strides), bytes(base + 8, &batch_dim), bytes(base + 9, batch_shape), bytes(base + 10, lhs_strides), bytes(base + 11, rhs_strides), ]); dispatch(&name, &bindings, groups, threads) } #[derive(Clone, Copy)] #[cfg(test)] pub(super) enum GateUpWeights<'a> { Fused { pack: [&'a Buffer; 3], quant: [u32; 2], }, Separate { gate: [&'a Buffer; 3], up: [&'a Buffer; 3], gate_quant: [u32; 2], up_quant: [u32; 2], }, } #[cfg(test)] pub(super) struct SwitchWeights<'a> { pub(super) input: GateUpWeights<'a>, pub(super) down: [&'a Buffer; 3], pub(super) down_quant: [u32; 2], } /// Actual shapeless compiled swiglu for two contiguous projection outputs. #[cfg(test)] fn swiglu_bf16(gate: &Buffer, up: &Buffer, output: &Buffer, count: u32) -> Result<(), String> { if count == 0 || count > i32::MAX as u32 || [gate, up, output] .iter() .any(|buffer| unsafe { ds4_gpu_tensor_bytes(buffer.raw()) } < u64::from(count) * 2) { return Err("invalid MTPLX contiguous SwiGLU input".into()); } let work = if count < 65536 { 1 } else { 4 }; let threads = count.div_ceil(work); dispatch_geometry( if work == 1 { "kernel_qwen_mtplx_swiglu_bf16_contiguous" } else { "kernel_qwen_mtplx_swiglu_bf16_contiguous_n" }, &[ tensor(0, gate).input(count as usize), tensor(1, up).input(count as usize), tensor(2, output).output(count as usize), bytes(3, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, ) } #[cfg(test)] pub(super) struct SwitchOutput { pub(super) hidden: Buffer, _temporaries: Vec, _sorted: Option, } #[cfg(test)] fn flatten_indices(input: &Buffer, [rows, width, stride]: [u32; 3]) -> Result { let count = u64::from(rows) * u64::from(width); if rows == 0 || width == 0 || stride < width || count > i32::MAX as u64 || unsafe { ds4_gpu_tensor_bytes(input.raw()) } < (u64::from(rows - 1) * u64::from(stride) + u64::from(width)) * 4 { return Err("invalid MTPLX index flatten view".into()); } if rows == 1 || stride == width { return input.view(0, count * 4); } let flat = Buffer::mtplx_bytes(count * 4)?; let grid = [width, rows, 1]; dispatch_geometry( "g2_copyuint32uint32", &[ tensor(0, input) .input((u64::from(rows - 1) * u64::from(stride) + u64::from(width)) as usize), tensor(1, &flat).output(count as usize), bytes(3, &[u64::from(stride), 1]), ], &[], grid, block_dims(grid), true, )?; Ok(flat) } /// Complete SwitchGLU or _FusedGateUpSwitchGLU with already-routed expert indices. /// Own the result until GPU completion; router/shared-expert combination belongs /// to SparseMoeBlock, not this reference submodule. #[cfg(test)] pub(super) fn switch_glu( weights: SwitchWeights<'_>, input: &Buffer, indices: &Buffer, [tokens, top_k, k, intermediate, experts]: [u32; 5], ) -> Result { switch_glu_strided( weights, input, indices, [tokens, top_k, k, intermediate, experts], top_k, ) } #[cfg(test)] fn switch_glu_strided( weights: SwitchWeights<'_>, input: &Buffer, indices: &Buffer, [tokens, top_k, k, intermediate, experts]: [u32; 5], index_stride: u32, ) -> Result { let routes = tokens .checked_mul(top_k) .filter(|v| *v > 0 && *v <= i32::MAX as u32) .ok_or("invalid MTPLX switch route count")?; if [k, intermediate, experts] .iter() .any(|v| *v == 0 || *v > i32::MAX as u32) || u64::from(routes) * u64::from(intermediate) * 2 > i32::MAX as u64 || u64::from(routes) * u64::from(k) > i32::MAX as u64 || index_stride < top_k || unsafe { ds4_gpu_tensor_bytes(indices.raw()) } < (u64::from(tokens - 1) * u64::from(index_stride) + u64::from(top_k)) * 4 { return Err("invalid MTPLX switch dimensions".into()); } let arange = |size: u32| -> Result { let result = Buffer::mtplx_bytes(u64::from(size) * 4)?; dispatch_geometry( "arangeuint32", &[ bytes(0, &0_u32), bytes(1, &1_u32), tensor(2, &result).output(size as usize), ], &[], [size, 1, 1], [size.min(1024), 1, 1], true, )?; Ok(result) }; // _gather_sort flattens the strided top-k view. Only that flatten needs // materialization; the unsorted GatherQMM path accepts original strides. let flat_indices = if routes >= 64 { Some(flatten_indices(indices, [tokens, top_k, index_stride])?) } else { None }; let sorted = if routes >= 64 { Some(gather_sort( input, flat_indices.as_ref().unwrap_or(indices), [tokens, top_k, k], )?) } else { None }; let route_range = arange(routes)?; let token_range = if sorted.is_none() { Some(arange(tokens)?) } else { None }; let (x, rhs, lhs, batches, repeat) = if let Some(sorted) = &sorted { (&sorted.x, &sorted.indices, &route_range, routes, 1) } else { (input, indices, token_range.as_ref().unwrap(), tokens, top_k) }; let rhs_layout = if sorted.is_some() { [routes; 2] } else { [top_k, index_stride] }; let h = Buffer::mtplx_bytes(u64::from(routes) * u64::from(intermediate) * 2)?; let y = Buffer::mtplx_bytes(u64::from(routes) * u64::from(k) * 2)?; let activation_temporary = match weights.input { GateUpWeights::Fused { pack: [w, s, b], quant, } => { let gu = Buffer::mtplx_bytes(u64::from(routes) * u64::from(intermediate) * 4)?; gather_bf16_broadcast( [w, s, b, x, lhs, rhs, &gu], [batches, 1, intermediate * 2, k, experts, routes], quant, sorted.is_some(), true, repeat, rhs_layout, )?; let activated = gate_up_bf16(&gu, &h, [routes, intermediate])?; vec![gu, activated] } GateUpWeights::Separate { gate, up, gate_quant, up_quant, } => { let gate_out = Buffer::mtplx_bytes(u64::from(routes) * u64::from(intermediate) * 2)?; let up_out = Buffer::mtplx_bytes(u64::from(routes) * u64::from(intermediate) * 2)?; // SwitchGLU constructs Up before Gate; Qwen3NextMLP uses the reverse. for ([w, s, b], quant, output) in [(up, up_quant, &up_out), (gate, gate_quant, &gate_out)] { gather_bf16_broadcast( [w, s, b, x, lhs, rhs, output], [batches, 1, intermediate, k, experts, routes], quant, sorted.is_some(), true, repeat, rhs_layout, )?; } swiglu_bf16(&gate_out, &up_out, &h, routes * intermediate)?; vec![gate_out, up_out] } }; let [w, s, b] = weights.down; gather_bf16_broadcast( [w, s, b, &h, &route_range, rhs, &y], [routes, 1, k, intermediate, experts, routes], weights.down_quant, sorted.is_some(), true, 1, rhs_layout, )?; let hidden = if let Some(sorted) = &sorted { let unsorted = Buffer::mtplx_bytes(u64::from(routes) * u64::from(k) * 2)?; gather_front( &y, &sorted.inverse, &unsorted, [routes, k, routes], SortDtype::Bf16, )?; unsorted } else { y.view(0, u64::from(routes) * u64::from(k) * 2)? }; let mut temporary = vec![route_range, h, y]; temporary.extend(activation_temporary); temporary.extend(token_range); temporary.extend(flat_indices); Ok(SwitchOutput { hidden, _temporaries: temporary, _sorted: sorted, }) } #[cfg(test)] pub(super) struct MoeWeights<'a> { pub(super) experts: SwitchWeights<'a>, pub(super) shared: SwitchWeights<'a>, pub(super) router: [&'a Buffer; 3], pub(super) router_quant: [u32; 2], pub(super) shared_gate: [&'a Buffer; 3], pub(super) shared_gate_quant: [u32; 2], } #[cfg(test)] pub(super) struct MoeOutput { pub(super) hidden: Buffer, pub(super) used_fused: bool, _router: RouterOutput, _switch: Option, _temporaries: Vec, } /// Connected SparseMoeBlock with separate or sanitize-fused expert/shared MLPs. The two flags /// are MTPLX_FUSED_MOE_DECODE / VERIFY; both default off in the reference. #[cfg(test)] pub(super) fn sparse_moe( weights: MoeWeights<'_>, input: &Buffer, [tokens, experts, k, intermediate, shared_intermediate]: [u32; 5], normalize: bool, [fused_decode, fused_verify]: [bool; 2], ) -> Result { let count = u64::from(tokens) * u64::from(k); if tokens == 0 || experts < 10 || k == 0 || count * 10 > i32::MAX as u64 || u64::from(tokens) * u64::from(experts) > i32::MAX as u64 || [intermediate, shared_intermediate] .iter() .any(|d| *d == 0 || u64::from(tokens) * u64::from(*d) * 20 > i32::MAX as u64) { return Err("invalid MTPLX sparse MoE shape".into()); } let logits = Buffer::mtplx_bytes(u64::from(tokens) * u64::from(experts) * 2)?; let [w, s, b] = weights.router; let [bits, group] = weights.router_quant; let mut temporary = affine_bf16( [w, s, b, input, &logits], [tokens, experts, k], bits, group, true, )?; let routing = router(logits, [tokens, experts], normalize)?; let used_fused = ((tokens == 1 && fused_decode) || ((2..=4).contains(&tokens) && fused_verify)) && matches!( weights.experts.input, GateUpWeights::Fused { quant: [4, 32 | 64], .. } ) && weights.experts.down_quant[0] == 4 && matches!(weights.experts.down_quant[1], 32 | 64); let hidden = Buffer::mtplx_bytes(count * 2)?; let switched = if used_fused { if k != 2560 || intermediate != 640 { return Err("MTPLX fused MoE requires the installed 2560/640 model shape".into()); } temporary.extend(fused_experts( &weights.experts, input, &routing, &hidden, [tokens, experts], )?); None } else { let switched = switch_glu_strided( weights.experts, input, &routing.indices, [tokens, 10, k, intermediate, experts], routing.index_row_stride, )?; let grid = [k, tokens * 10, 1]; dispatch_geometry( "g2_Multiplybfloat16", &[ tensor(0, &switched.hidden).input((count * 10) as usize), tensor(1, &routing.scores).input((u64::from(tokens) * 10) as usize), tensor(2, &switched.hidden).output((count * 10) as usize), bytes(3, &[u64::from(k), 1]), bytes(4, &[1_u64, 0]), ], &[], grid, block_dims(grid), true, )?; let gx = k.div_ceil(4).min(32); dispatch( "col_reduce_small_1_reduce_sumbfloat16", &[ tensor(0, &switched.hidden).input((count * 10) as usize), tensor(1, &hidden).output(count as usize), bytes(2, &10_u64), bytes(3, &u64::from(k)), bytes(4, &tokens), bytes(5, &(u64::from(k) * 10)), bytes(6, &1_u32), bytes(7, &10_u32), bytes(8, &u64::from(k)), bytes(9, &1_u32), bytes(10, &1_u64), ], [k.div_ceil(4).div_ceil(gx), tokens, 1], [gx, 8, 1], )?; Some(switched) }; // The fused branch evaluates sigmoid(shared_gate(x)) before shared_expert(x); // the parent stock branch evaluates the MLP first. Keep both source orders. let gate = || { shared_gate_sigmoid( weights.shared_gate, weights.shared_gate_quant, input, [tokens, k], ) }; let early_gate = if used_fused { Some(gate()?) } else { None }; let shared_h = Buffer::mtplx_bytes(u64::from(tokens) * u64::from(shared_intermediate) * 2)?; let shared = Buffer::mtplx_bytes(count * 2)?; match weights.shared.input { GateUpWeights::Fused { pack: [w, s, b], quant: [bits, group], } => { let gu = Buffer::mtplx_bytes(u64::from(tokens) * u64::from(shared_intermediate) * 4)?; temporary.extend(affine_bf16( [w, s, b, input, &gu], [tokens, shared_intermediate * 2, k], bits, group, true, )?); temporary.push(gate_up_bf16(&gu, &shared_h, [tokens, shared_intermediate])?); temporary.push(gu); } GateUpWeights::Separate { gate, up, gate_quant, up_quant, } => { let gate_out = Buffer::mtplx_bytes(u64::from(tokens) * u64::from(shared_intermediate) * 2)?; let up_out = Buffer::mtplx_bytes(u64::from(tokens) * u64::from(shared_intermediate) * 2)?; for ([w, s, b], [bits, group], output) in [(gate, gate_quant, &gate_out), (up, up_quant, &up_out)] { temporary.extend(affine_bf16( [w, s, b, input, output], [tokens, shared_intermediate, k], bits, group, true, )?); } swiglu_bf16(&gate_out, &up_out, &shared_h, tokens * shared_intermediate)?; temporary.extend([gate_out, up_out]); } } let [w, s, b] = weights.shared.down; let [bits, group] = weights.shared.down_quant; temporary.extend(affine_bf16( [w, s, b, &shared_h, &shared], [tokens, k, shared_intermediate], bits, group, true, )?); let (shared_gate, gate_temporary) = match early_gate { Some(result) => result, None => gate()?, }; temporary.extend(gate_temporary); if tokens == 1 { let work = if k < 65536 { 1 } else { 4 }; let threads = k.div_ceil(work); dispatch_geometry( if work == 1 { "sv_Multiplybfloat16" } else { "svn_Multiplybfloat16" }, &[ tensor(0, &shared_gate).input(tokens as usize), tensor(1, &shared).input(count as usize), tensor(2, &shared).output(count as usize), bytes(3, &k), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; } else { let grid = [k, tokens, 1]; dispatch_geometry( "g2_Multiplybfloat16", &[ tensor(0, &shared_gate).input(tokens as usize), tensor(1, &shared).input(count as usize), tensor(2, &shared).output(count as usize), bytes(3, &[1_u64, 0]), bytes(4, &[u64::from(k), 1]), ], &[], grid, block_dims(grid), true, )?; } let count = count as u32; let work = if count < 65536 { 1 } else { 4 }; let threads = count.div_ceil(work); dispatch_geometry( if work == 1 { "vv_Addbfloat16" } else { "vvn_Addbfloat16" }, &[ tensor(0, &hidden).input(count as usize), tensor(1, &shared).input(count as usize), tensor(2, &hidden).output(count as usize), bytes(3, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; temporary.extend([shared_h, shared, shared_gate]); Ok(MoeOutput { hidden, used_fused, _router: routing, _switch: switched, _temporaries: temporary, }) } #[cfg(test)] fn shared_gate_sigmoid( [w, s, b]: [&Buffer; 3], [bits, group]: [u32; 2], input: &Buffer, [tokens, k]: [u32; 2], ) -> Result<(Buffer, Vec), String> { let gate = Buffer::mtplx_bytes(u64::from(tokens) * 2)?; let temporary = affine_bf16([w, s, b, input, &gate], [tokens, 1, k], bits, group, true)?; let work = if tokens < 65536 { 1 } else { 4 }; let threads = tokens.div_ceil(work); dispatch_geometry( if work == 1 { "v_Sigmoidbfloat16bfloat16" } else { "vn_Sigmoidbfloat16bfloat16" }, &[ tensor(0, &gate).input(tokens as usize), tensor(1, &gate).output(tokens as usize), bytes(2, &tokens), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; Ok((gate, temporary)) } #[cfg(test)] fn fused_experts( weights: &SwitchWeights<'_>, input: &Buffer, routing: &RouterOutput, output: &Buffer, [tokens, experts]: [u32; 2], ) -> Result, String> { let GateUpWeights::Fused { pack: gu_pack, quant: [4, gu_group], } = weights.input else { return Err("MTPLX fused MoE requires a fused Q4 gate/up pack".into()); }; // Entry conditions are checked by SparseMoeBlock, including the installed // dimensions for these template instantiations. Validate all six packs. for (pack, n, k, group) in [ (gu_pack, 1280_u64, 2560_u64, gu_group), (weights.down, 2560, 640, weights.down_quant[1]), ] { let count = u64::from(experts) * n * k; for (buffer, size) in pack.into_iter().zip([ count / 2, count / u64::from(group) * 2, count / u64::from(group) * 2, ]) { if unsafe { ds4_gpu_tensor_bytes(buffer.raw()) } < size { return Err("MTPLX fused MoE pack smaller than shape".into()); } } } let indices = flatten_indices(&routing.indices, [tokens, 10, routing.index_row_stride])?; let routes = tokens * 10; let scores = Buffer::mtplx_bytes(u64::from(routes) * 4)?; dispatch_geometry( "v_copybfloat16float32", &[ tensor(0, &routing.scores).input(routes as usize), tensor(1, &scores).output(routes as usize), bytes(2, &routes), ], &[], [routes, 1, 1], [routes, 1, 1], true, )?; let h = Buffer::mtplx_bytes(u64::from(routes) * 640 * 2)?; let suffix = |group| { if tokens == 1 { format!("g{group}_bf16") } else { format!("m_m{tokens}_g{group}_bf16") } }; let [w, s, b] = gu_pack; dispatch( &format!("kernel_qwen_mtplx_moe_glu_h_{}", suffix(gu_group)), &[ tensor(0, input).input(tokens as usize * 2560), tensor(1, w).input(experts as usize * 1280 * 2560 / 8), tensor(2, s).input(experts as usize * 1280 * 2560 / gu_group as usize), tensor(3, b).input(experts as usize * 1280 * 2560 / gu_group as usize), tensor(4, &indices).input(routes as usize), tensor(5, &h).output(routes as usize * 640), ], [(routes * 640).div_ceil(32), 1, 1], [1024, 1, 1], )?; let [w, s, b] = weights.down; dispatch( &format!( "kernel_qwen_mtplx_moe_down_y_{}", suffix(weights.down_quant[1]) ), &[ tensor(0, &h).input(routes as usize * 640), tensor(1, w).input(experts as usize * 2560 * 640 / 8), tensor(2, s).input(experts as usize * 2560 * 640 / weights.down_quant[1] as usize), tensor(3, b).input(experts as usize * 2560 * 640 / weights.down_quant[1] as usize), tensor(4, &indices).input(routes as usize), tensor(5, &scores).input(routes as usize), tensor(6, output).output(tokens as usize * 2560), ], [(tokens * 2560).div_ceil(32), 1, 1], [1024, 1, 1], )?; Ok(vec![indices, scores, h]) } /// Keep returned intermediate buffers alive until the enclosing command batch completes. #[cfg(test)] pub(super) fn affine_bf16( buffers: [&Buffer; 5], shape: [u32; 3], bits: u32, group: u32, nax: bool, ) -> Result, String> { affine_bf16_layout(buffers, shape, bits, group, nax, None) } fn affine_bf16_layout( buffers: [&Buffer; 5], shape: [u32; 3], bits: u32, group: u32, nax: bool, input_layout: Option<[(u64, usize); 4]>, ) -> Result, String> { let [m, n, k] = shape; let plan = affine_plan(shape, bits, group, nax)?; let expected = [ u64::from(n) * u64::from(k) / (8 / u64::from(bits)), u64::from(n) * u64::from(k / group) * 2, u64::from(n) * u64::from(k / group) * 2, u64::from(m) * u64::from(k) * 2, u64::from(m) * u64::from(n) * 2, ]; let elements: [usize; 5] = std::array::from_fn(|i| (expected[i] / [4, 2, 2, 2, 2][i]) as usize); let input_layout = input_layout.unwrap_or_else(|| std::array::from_fn(|i| (0, elements[i]))); for (i, (buffer, size)) in buffers.iter().zip(expected).enumerate() { let offset = input_layout.get(i).map_or(0, |layout| layout.0); if offset .checked_add(size) .is_none_or(|end| unsafe { ds4_gpu_tensor_bytes(buffer.raw()) } < end) { return Err("MTPLX affine binding is smaller than its shape".into()); } } let mut temporary = Vec::new(); if plan.splits > 1 { temporary.push(Buffer::mtplx_bytes(expected[4] * u64::from(plan.splits))?); encoder::add_temporaries(&temporary); } let output = temporary.first().unwrap_or(buffers[4]); let mut bindings = buffers[..4] .iter() .enumerate() .map(|(i, b)| { tensor(i as u32, b) .at_byte_offset(input_layout[i].0) .input(input_layout[i].1) }) .collect::>(); bindings.push(tensor(4, output).output(elements[4] * plan.splits as usize)); bindings.extend( plan.parameters .iter() .enumerate() .map(|(i, p)| bytes(i as u32 + 5, p)), ); dispatch(&plan.name, &bindings, plan.groups, plan.threads)?; if plan.splits > 1 && let Some(extra) = reduce_split_bf16(output, buffers[4], plan.splits, m * n)? { temporary.push(extra); } Ok(temporary) } fn reduce_split_bf16( input: &Buffer, output: &Buffer, splits: u32, width: u32, ) -> Result, String> { // ColReduceArgs for contiguous [split, M, N], reducing axis 0. let size = u64::from(splits); let stride = u64::from(width); let zero = 0_u32; let zero_stride = 0_u64; let ndim = 1_u32; let non_col = 1_u64; let two_pass = splits > 256 && width / 32 < 1024; let intermediate = if two_pass { Some(Buffer::mtplx_bytes(stride * 32 * 2)?) } else { None }; if let Some(buffer) = &intermediate { encoder::add_temporaries(std::slice::from_ref(buffer)); } let mut bindings = vec![ tensor(0, input).input((size * stride) as usize), tensor(1, intermediate.as_ref().unwrap_or(output)) .output((stride * if two_pass { 32 } else { 1 }) as usize), bytes(2, &size), bytes(3, &stride), bytes(4, &zero), bytes(5, &zero_stride), bytes(6, &zero), bytes(7, &splits), bytes(8, &stride), bytes(9, &ndim), bytes(10, &non_col), ]; let large = if size * stride > i32::MAX as u64 { "_large" } else { "" }; if splits < 32 { let x = width.div_ceil(4).min(32); dispatch( &format!("col_reduce_small{large}_1_reduce_sumbfloat16"), &bindings, [width.div_ceil(4).div_ceil(x), 1, 1], [x, splits.min(8), 1], )?; } else if two_pass { bindings.push(bytes(11, &non_col)); dispatch( &format!("col_reduce_2pass{large}_1_32_32_reduce_sumbfloat16"), &bindings, [width.div_ceil(32), 32, 1], [256, 1, 1], )?; reduce_split_bf16(intermediate.as_ref().unwrap(), output, 32, width)?; } else { dispatch( &format!("col_reduce_looped{large}_1_32_32_reduce_sumbfloat16"), &bindings, [width.div_ceil(32), 1, 1], [256, 1, 1], )?; } Ok(intermediate) } #[cfg(test)] pub(super) struct ConvNormOutput { pub(super) q: Buffer, pub(super) k: Buffer, pub(super) v: Buffer, pub(super) conv: Buffer, /// Pre-convolution rows retained by the reference's verify capture. pub(super) qkv: Buffer, pub(super) used_fused: bool, _temporaries: Vec, } /// Stock GatedDeltaNet._l2norm, including its BF16 boundary before Q scaling. #[cfg(test)] fn gdn_l2_norm(input: &Buffer, output: &Buffer, rows: u32, q: bool) -> Result, String> { let count = rows * 2048; let heads = rows * 16; let xf = Buffer::mtplx_bytes(u64::from(count) * 4)?; let sq = Buffer::mtplx_bytes(u64::from(count) * 4)?; let sum = Buffer::mtplx_bytes(u64::from(heads) * 4)?; if rows == 1 { cast_bf16_f32(input, &xf, count, true)?; } else { let grid = [2048, rows, 1]; dispatch_geometry( "g2_copybfloat16float32", &[ tensor(0, input).input(((rows - 1) * 10240 + 2048) as usize), tensor(1, &xf).output(count as usize), bytes(3, &[10240_u64, 1]), ], &[], grid, block_dims(grid), true, )?; } let work = if count < 65536 { 1 } else { 2 }; let threads = count.div_ceil(work); dispatch_geometry( if work == 1 { "vv_Multiplyfloat32" } else { "vvn_Multiplyfloat32" }, &[ tensor(0, &xf).input(count as usize), tensor(1, &xf).input(count as usize), tensor(2, &sq).output(count as usize), bytes(3, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; if heads >= 32 { dispatch_geometry( "row_reduce_simple_sumfloat32", &[ tensor(0, &sq).input(count as usize), tensor(1, &sum).output(heads as usize), bytes(2, &128_u64), bytes(3, &u64::from(heads)), ], &[], [32, heads.div_ceil(4), 1], [32, 1, 1], true, )?; } else { dispatch_geometry( "row_reduce_looped_1_reduce_sumfloat32", &[ tensor(0, &sq).input(count as usize), tensor(1, &sum).output(heads as usize), bytes(2, &128_u64), bytes(3, &1_u64), bytes(4, &heads), bytes(5, &128_u64), bytes(6, &1_u32), bytes(7, &0_u32), bytes(8, &0_u64), bytes(9, &0_u32), ], &[], [32, heads, 1], [32, 1, 1], true, )?; } let epsilon = scalar_buffer(&1e-6_f32.to_le_bytes())?; let work = if heads < 65536 { 1 } else { 2 }; let threads = heads.div_ceil(work); dispatch_geometry( if work == 1 { "vs_Addfloat32" } else { "vsn_Addfloat32" }, &[ tensor(0, &sum).input(heads as usize), tensor(1, &epsilon).input(1), tensor(2, &sum).output(heads as usize), bytes(3, &heads), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; dispatch_geometry( if work == 1 { "v_Rsqrtfloat32float32" } else { "vn_Rsqrtfloat32float32" }, &[ tensor(0, &sum).input(heads as usize), tensor(1, &sum).output(heads as usize), bytes(2, &heads), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; let grid = [128, heads, 1]; dispatch_geometry( "g2_Multiplyfloat32", &[ tensor(0, &xf).input(count as usize), tensor(1, &sum).input(heads as usize), tensor(2, &xf).output(count as usize), bytes(3, &[128_u64, 1]), bytes(4, &[1_u64, 0]), ], &[], grid, block_dims(grid), true, )?; cast_bf16_f32(&xf, output, count, false)?; if q { // Weak Python scalar converts to BF16 BEFORE Multiplybfloat16. let bits = 128_f32.powf(-0.5).to_bits(); let scale = ((bits + 0x7fff + ((bits >> 16) & 1)) >> 16) as u16; let scale = scalar_buffer(&scale.to_le_bytes())?; let work = if count < 65536 { 1 } else { 4 }; let threads = count.div_ceil(work); dispatch_geometry( if work == 1 { "sv_Multiplybfloat16" } else { "svn_Multiplybfloat16" }, &[ tensor(0, &scale).input(1), tensor(1, output).input(count as usize), tensor(2, output).output(count as usize), bytes(3, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; } Ok(vec![xf, sq, sum]) } /// GDN conv/state and Q/K/V preparation for B=1. `fused` contains the /// model's two conv-norm flags; cache absence/lengths/mask suppress fusion. /// `length` is the cache's optional one-element INT32 valid-length tensor. #[cfg(test)] pub(super) fn gdn_conv_norm( input: &Buffer, weight: &Buffer, [rows, stride]: [u32; 2], [state, length]: [Option<&Buffer>; 2], mask: Option<&Buffer>, fused: [bool; 2], has_cache: bool, ) -> Result { let count = u64::from(rows) * 10240; if rows == 0 || stride < 10240 || (u64::from(rows) + 3) * 10240 > i32::MAX as u64 || unsafe { ds4_gpu_tensor_bytes(input.raw()) } < (u64::from(rows - 1) * u64::from(stride) + 10240) * 2 || unsafe { ds4_gpu_tensor_bytes(weight.raw()) } < 10240 * 4 * 2 || state.is_some_and(|x| unsafe { ds4_gpu_tensor_bytes(x.raw()) } < 3 * 10240 * 2) || mask.is_some_and(|x| unsafe { ds4_gpu_tensor_bytes(x.raw()) } < u64::from(rows)) || length.is_some_and(|x| unsafe { ds4_gpu_tensor_bytes(x.raw()) } < 4) { return Err("invalid MTPLX GDN conv inputs".into()); } let mut temporary = Vec::new(); let input_span = ((rows - 1) as usize * stride as usize) + 10240; let qkv = if let Some(mask) = mask { let qkv = Buffer::mtplx_bytes(count * 2)?; let zero = scalar_buffer(&0_u16.to_le_bytes())?; let grid = [10240, rows, 1]; dispatch_geometry( if rows == 1 { "g1_Selectbfloat16" } else { "g2_Selectbfloat16" }, &[ tensor(0, mask).input(rows as usize), tensor(1, input).input(input_span), tensor(2, &zero).input(1), tensor(3, &qkv).output(count as usize), bytes(4, &if rows == 1 { [0_u64, 0] } else { [1_u64, 0] }), bytes( 5, &if rows == 1 { [1_u64, 0] } else { [u64::from(stride), 1] }, ), bytes(6, &[0_u64, 0]), ], &[], grid, block_dims(grid), true, )?; qkv } else { input.view(0, (u64::from(rows - 1) * u64::from(stride) + 10240) * 2)? }; let stride = if mask.is_some() { 10240 } else { stride }; let qkv_span = (rows - 1) as usize * stride as usize + 10240; let q = Buffer::mtplx_bytes(u64::from(rows) * 2048 * 2)?; let k = Buffer::mtplx_bytes(u64::from(rows) * 2048 * 2)?; let v; let conv; let used_fused = has_cache && mask.is_none() && length.is_none() && ((rows == 1 && fused[0]) || ((2..=6).contains(&rows) && fused[1])); if used_fused { v = Buffer::mtplx_bytes(u64::from(rows) * 6144 * 2)?; conv = Buffer::mtplx_bytes(3 * 10240 * 2)?; let packed; let source = if rows == 1 || stride == 10240 { &qkv } else { packed = Buffer::mtplx_bytes(count * 2)?; let grid = [10240, rows, 1]; dispatch_geometry( "g2_copybfloat16bfloat16", &[ tensor(0, &qkv).input(qkv_span), tensor(1, &packed).output(count as usize), bytes(3, &[u64::from(stride), 1]), ], &[], grid, block_dims(grid), true, )?; temporary.push(packed); temporary.last().unwrap() }; let source = source.view(0, count * 2)?; let zero; let state = if let Some(state) = state { state } else { zero = Buffer::mtplx_bytes(3 * 10240 * 2)?; let scalar = scalar_buffer(&0_u16.to_le_bytes())?; // CustomKernel materializes the broadcast scalar with General copy. dispatch_geometry( "g1_copybfloat16bfloat16", &[ tensor(0, &scalar).input(1), tensor(1, &zero).output(3 * 10240), bytes(3, &0_u64), ], &[], [3 * 10240, 1, 1], [1024, 1, 1], true, )?; temporary.push(zero); temporary.last().unwrap() }; let state = state.view(0, 3 * 10240 * 2)?; dispatch( &if rows == 1 { "kernel_qwen_mtplx_gdn_conv_norm_bf16".into() } else { format!("kernel_qwen_mtplx_gdn_conv_norm_rows_s{rows}_bf16") }, &[ tensor(0, &source).input(count as usize), tensor(1, &state).input(3 * 10240), tensor(2, weight).input(4 * 10240), tensor(3, &q).output(rows as usize * 2048), tensor(4, &k).output(rows as usize * 2048), tensor(5, &v).output(rows as usize * 6144), tensor(6, &conv).output(3 * 10240), ], [10, 1, 1], [1024, 1, 1], )?; encoder::add_temporaries(&temporary); } else { conv = Buffer::mtplx_bytes(3 * 10240 * 2)?; let window = Buffer::mtplx_bytes((count + 3 * 10240) * 2)?; let tail = window.view(3 * 10240 * 2, count * 2)?; // Original concatenate_gpu uses concurrent disjoint out_slice writers. let concurrent = encoder::concurrent_scope(); let zero = state .is_none() .then(|| scalar_buffer(&0_u16.to_le_bytes())) .transpose()?; // Concatenate uses GeneralGeneral copies, even for contiguous slices. dispatch_geometry( "gg1_copybfloat16bfloat16", &[ tensor(0, state.or(zero.as_ref()).unwrap()).input(if state.is_some() { 3 * 10240 } else { 1 }), tensor(1, &window).output(3 * 10240), bytes(3, &u64::from(state.is_some())), bytes(4, &1_u64), ], &[], [3 * 10240, 1, 1], [1024, 1, 1], true, )?; let contiguous = rows == 1 || stride == 10240; let grid = if contiguous { [count as u32, 1, 1] } else { [10240, rows, 1] }; dispatch_geometry( if contiguous { "gg1_copybfloat16bfloat16" } else { "gg2_copybfloat16bfloat16" }, &[ tensor(0, &qkv).input(qkv_span), tensor(1, &tail).output(count as usize), bytes( 3, &if contiguous { [1_u64, 0] } else { [u64::from(stride), 1] }, ), bytes( 4, &if contiguous { [1_u64, 0] } else { [10240_u64, 1] }, ), ], &[], grid, block_dims(grid), true, )?; drop(concurrent); if let Some(length) = length { let zero = scalar_buffer(&0_i32.to_le_bytes())?; let upper = scalar_buffer(&(rows as i32).to_le_bytes())?; let end = Buffer::mtplx_bytes(4)?; let positions = Buffer::mtplx_bytes(12)?; let range = Buffer::mtplx_bytes(12)?; dispatch_geometry( "vs_Maximumint32", &[ tensor(0, length).input(1), tensor(1, &zero).input(1), tensor(2, &end).output(1), bytes(3, &1_u32), ], &[], [1, 1, 1], [1, 1, 1], true, )?; dispatch_geometry( "vs_Minimumint32", &[ tensor(0, &end).input(1), tensor(1, &upper).input(1), tensor(2, &end).output(1), bytes(3, &1_u32), ], &[], [1, 1, 1], [1, 1, 1], true, )?; dispatch_geometry( "arangeint32", &[ bytes(0, &0_i32), bytes(1, &1_i32), tensor(2, &range).output(3), ], &[], [3, 1, 1], [3, 1, 1], true, )?; dispatch_geometry( "sv_Addint32", &[ tensor(0, &end).input(1), tensor(1, &range).input(3), tensor(2, &positions).output(3), bytes(3, &3_u32), ], &[], [3, 1, 1], [3, 1, 1], true, )?; let grid = [10240, 3, 1]; dispatch_geometry( "kernel_qwen_mtplx_gather_axis_bf16_idxi32_int_10", &[ tensor(0, &window).input(count as usize + 3 * 10240), tensor(1, &positions).input(3), tensor(2, &conv).output(3 * 10240), bytes(3, &10240_u32), bytes(4, &1_u64), bytes(5, &0_u64), bytes(6, &1_u64), bytes(7, &0_u32), bytes(8, &(rows + 3)), bytes(9, &10240_u64), bytes(10, &1_u64), ], &[], grid, block_dims(grid), true, )?; temporary.extend([end, positions, range]); } else { let view = window.view(u64::from(rows) * 10240 * 2, 3 * 10240 * 2)?; dispatch_geometry( "g1_copybfloat16bfloat16", &[ tensor(0, &view).input(3 * 10240), tensor(1, &conv).output(3 * 10240), bytes(3, &1_u64), ], &[], [3 * 10240, 1, 1], [1024, 1, 1], true, )?; } let convolved = Buffer::mtplx_bytes(count * 2)?; let grid = [10240, rows, 1]; dispatch_geometry( "depthwise_conv_1d_bfloat16", &[ tensor(0, &window).input(count as usize + 3 * 10240), tensor(1, weight).input(4 * 10240), tensor(2, &convolved).output(count as usize), bytes(3, &[(rows + 3) * 10240, 10240, 1]), bytes(4, &4_u32), ], &[], grid, block_dims(grid), true, )?; let count = count as u32; let work = if count < 65536 { 1 } else { 4 }; let threads = count.div_ceil(work); dispatch_geometry( if work == 1 { "kernel_qwen_mtplx_silu_bf16_contiguous" } else { "kernel_qwen_mtplx_silu_bf16_contiguous_n" }, &[ tensor(0, &convolved).input(count as usize), tensor(1, &convolved).output(count as usize), bytes(2, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; temporary.extend(gdn_l2_norm(&convolved, &q, rows, true)?); let key = convolved.view(2048 * 2, u64::from(count - 2048) * 2)?; temporary.extend(gdn_l2_norm(&key, &k, rows, false)?); let value = convolved.view(4096 * 2, u64::from(count - 4096) * 2)?; if rows == 1 { v = value; } else { v = Buffer::mtplx_bytes(u64::from(rows) * 6144 * 2)?; let grid = [6144, rows, 1]; dispatch_geometry( "g2_copybfloat16bfloat16", &[ tensor(0, &value).input((rows - 1) as usize * 10240 + 6144), tensor(1, &v).output(rows as usize * 6144), bytes(3, &[10240_u64, 1]), ], &[], grid, block_dims(grid), true, )?; } temporary.extend([window, convolved]); } Ok(ConvNormOutput { q, k, v, conv, qkv, used_fused, _temporaries: temporary, }) } #[cfg(test)] pub(super) struct DeltaUpdateOutput { pub(super) hidden: Buffer, pub(super) delta: Buffer, pub(super) g: Buffer, pub(super) beta: Buffer, _initial_state: Option, } /// Actual gated_delta_update inference branch, including compute_g, sigmoid, /// optional zero initial state and mask. Q/K/V are contiguous as required by /// the reference custom-kernel dispatcher; A/B retain projection row strides. #[cfg(test)] pub(super) fn gated_delta_update( [q, k, v]: [&Buffer; 3], [a, b, a_log, dt_bias]: [&Buffer; 4], [rows, gate_stride]: [u32; 2], state: Option<&Buffer>, mask: Option<&Buffer>, ) -> Result { let count = u64::from(rows) * 48; let state_count = 48 * 128 * 128_u32; if rows == 0 || gate_stride < 48 || u64::from(rows) * 6144 > i32::MAX as u64 || [q, k].iter().any(|x| unsafe { ds4_gpu_tensor_bytes(x.raw()) } < u64::from(rows) * 2048 * 2) || unsafe { ds4_gpu_tensor_bytes(v.raw()) } < u64::from(rows) * 6144 * 2 || [a, b].iter().any(|x| unsafe { ds4_gpu_tensor_bytes(x.raw()) } < (u64::from(rows - 1) * u64::from(gate_stride) + 48) * 2) || [a_log, dt_bias].iter().any(|x| unsafe { ds4_gpu_tensor_bytes(x.raw()) } < 48 * 2) || state.is_some_and(|x| unsafe { ds4_gpu_tensor_bytes(x.raw()) } < u64::from(state_count) * 4) || mask.is_some_and(|x| unsafe { ds4_gpu_tensor_bytes(x.raw()) } < u64::from(rows)) { return Err("invalid MTPLX gated delta inputs".into()); } let gate_span = (rows - 1) as usize * gate_stride as usize + 48; let beta = Buffer::mtplx_bytes(count * 2)?; let g = Buffer::mtplx_bytes(count * 4)?; if rows == 1 || gate_stride == 48 { let count = count as u32; let work = if count < 65536 { 1 } else { 4 }; let threads = count.div_ceil(work); dispatch_geometry( if work == 1 { "v_Sigmoidbfloat16bfloat16" } else { "vn_Sigmoidbfloat16bfloat16" }, &[ tensor(0, b).input(gate_span), tensor(1, &beta).output(count as usize), bytes(2, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; } else { let grid = [48, rows, 1]; dispatch_geometry( "gn1_Sigmoidbfloat16bfloat16", &[ tensor(0, b).input(gate_span), tensor(1, &beta).output(count as usize), bytes(2, &[rows, 48]), bytes(3, &[u64::from(gate_stride), 1]), bytes(4, &2_u32), ], &[], grid, block_dims(grid), true, )?; } if rows == 1 { dispatch_geometry( "kernel_qwen_mtplx_compute_g_bf16_contiguous", &[ tensor(0, a_log).input(48), tensor(1, a).input(gate_span), tensor(2, dt_bias).input(48), tensor(3, &g).output(count as usize), bytes(4, &48_u32), ], &[], [48, 1, 1], [48, 1, 1], true, )?; } else { let grid = [48, rows, 1]; dispatch_geometry( "kernel_qwen_mtplx_compute_g_bf16_strided_2", &[ tensor(0, a_log).input(48), tensor(1, a).input(gate_span), tensor(2, dt_bias).input(48), bytes(3, &[0_u64, 1, u64::from(gate_stride), 1, 0, 1]), tensor(4, &g).output(count as usize), bytes(5, &[rows, 48]), ], &[], grid, block_dims(grid), true, )?; } let hidden = Buffer::mtplx_bytes(u64::from(rows) * 6144 * 2)?; let delta = Buffer::mtplx_bytes(u64::from(state_count) * 4)?; let initial_state = if state.is_none() { let zero = Buffer::mtplx_bytes(u64::from(state_count) * 4)?; let scalar = scalar_buffer(&0_f32.to_le_bytes())?; dispatch_geometry( "g1_copyfloat32float32", &[ tensor(0, &scalar).input(1), tensor(1, &zero).output(state_count as usize), bytes(3, &0_u64), ], &[], [state_count, 1, 1], [1024, 1, 1], true, )?; Some(zero) } else { None }; let state = state.or(initial_state.as_ref()).unwrap(); let length = scalar_buffer(&(rows as i32).to_le_bytes())?; let mut bindings = vec![ tensor(0, q).input(rows as usize * 2048), tensor(1, k).input(rows as usize * 2048), tensor(2, v).input(rows as usize * 6144), tensor(3, &g).input(count as usize), tensor(4, &beta).input(count as usize), tensor(5, state).input(state_count as usize), tensor(6, &length).input(1), ]; if let Some(mask) = mask { bindings.push(tensor(7, mask).input(rows as usize)); } let index = bindings.len() as u32; bindings.extend([ tensor(index, &hidden).output(rows as usize * 6144), tensor(index + 1, &delta).output(state_count as usize), ]); dispatch( if mask.is_some() { "kernel_qwen_mtplx_gated_delta_masked_bf16" } else { "kernel_qwen_mtplx_gated_delta_bf16" }, &bindings, [1, 32, 48], [32, 4, 1], )?; if let Some(initial_state) = &initial_state { encoder::add_temporaries(std::slice::from_ref(initial_state)); } Ok(DeltaUpdateOutput { hidden, delta, g, beta, _initial_state: initial_state, }) } #[cfg(test)] fn qsa_copy_span(shape: [u32; 3], strides: [u64; 3]) -> Result { if shape.contains(&0) { return Ok(0); } shape .into_iter() .zip(strides) .try_fold(1_usize, |span, (dim, stride)| { usize::try_from(stride) .ok() .and_then(|stride| (dim as usize - 1).checked_mul(stride)) .and_then(|n| span.checked_add(n)) .ok_or_else(|| "QSA copy element span overflow".into()) }) } /// GeneralGeneral copy used by the reference's slice updates/concatenations. /// Collapse only dimensions contiguous in BOTH source and destination. #[cfg(test)] fn qsa_copy( source: Option<&Buffer>, target: &Buffer, shape: [u32; 3], source_strides: [u64; 3], target_strides: [u64; 3], width: u32, output_elements: usize, ) -> Result<(), String> { qsa_copy_typed( source, target, shape, source_strides, target_strides, if width == 2 { "bfloat16" } else { "float32" }, output_elements, ) } #[cfg(test)] fn qsa_copy_typed( source: Option<&Buffer>, target: &Buffer, shape: [u32; 3], source_strides: [u64; 3], target_strides: [u64; 3], dtype: &str, output_elements: usize, ) -> Result<(), String> { if shape.contains(&0) { return Ok(()); } let itemsize = match dtype { "bool_" => 1, "bfloat16" => 2, "float32" | "int32" | "uint32" => 4, _ => return Err("unsupported QSA copy dtype".into()), }; let zero = source .is_none() .then(|| scalar_buffer(&[0; 4][..itemsize])) .transpose()?; qsa_copy_offsets( [ tensor(0, source.or(zero.as_ref()).unwrap()).input(if source.is_some() { qsa_copy_span(shape, source_strides)? } else { 1 }), tensor(1, target).output(output_elements), ], shape, source_strides, target_strides, dtype, [None; 2], ) } #[cfg(test)] fn qsa_copy_offsets( buffers: [Binding<'_>; 2], shape: [u32; 3], source_strides: [u64; 3], target_strides: [u64; 3], dtype: &str, offsets: [Option<&Buffer>; 2], ) -> Result<(), String> { if shape.contains(&0) { return Ok(()); } let mut dims: Vec<(u32, u64, u64)> = Vec::new(); for ((n, s), d) in shape.into_iter().zip(source_strides).zip(target_strides) { if n == 1 { continue; } if let Some(last) = dims.last_mut() && last.1 == u64::from(n) * s && last.2 == u64::from(n) * d { last.0 = last.0.checked_mul(n).ok_or("QSA copy shape overflow")?; last.1 = s; last.2 = d; } else { dims.push((n, s, d)); } } if dims.is_empty() { dims.push((1, 0, 0)); } let mut ss = [0_u64; 3]; let mut ds = [0_u64; 3]; let mut grid = [1_u32; 3]; for (i, (n, s, d)) in dims.iter().enumerate() { ss[i] = *s; ds[i] = *d; grid[dims.len() - 1 - i] = *n; } let dynamic = offsets.iter().any(Option::is_some); let zero = 0_i64; let [source, target] = buffers; let bindings = [ source, target, bytes(3, &ss), bytes(4, &ds), offsets[0].map_or_else(|| bytes(6, &zero), |b| tensor(6, b).input(1)), offsets[1].map_or_else(|| bytes(7, &zero), |b| tensor(7, b).input(1)), ]; dispatch_geometry( &format!( "gg{}{}_copy{dtype}{dtype}", dims.len(), if dynamic { "_dynamic" } else { "" } ), &bindings[..if dynamic { 6 } else { 4 }], &[], grid, block_dims(grid), true, ) } /// Original DynamicSlice/Update row-copy stage for B1 BF16 indexer leaves. /// Start leaves are int32[1] graph values with validated in-bounds semantics; /// they stay on-device, just as in the reference's private GPU primitives. /// Returns offset temporaries so callers retain the entire asynchronous chain. #[cfg(test)] pub(super) fn qsa_dynamic_copy_rows( [source, target]: [&Buffer; 2], [source_stride, target_stride]: [u64; 2], [rows, width]: [u32; 2], starts: [Option<&Buffer>; 2], data_sizes: [usize; 2], ) -> Result, String> { if rows == 0 || width == 0 || rows.checked_mul(width).is_none_or(|n| n > i32::MAX as u32) || source_stride < u64::from(width) || target_stride < u64::from(width) || starts .iter() .flatten() .any(|b| unsafe { ds4_gpu_tensor_bytes(b.raw()) } < 4) || [source, target] .into_iter() .zip([source_stride, target_stride]) .any(|(b, stride)| { u64::from(rows - 1) .checked_mul(stride) .and_then(|n| n.checked_add(u64::from(width))) .and_then(|n| n.checked_mul(2)) .is_none_or(|n| unsafe { ds4_gpu_tensor_bytes(b.raw()) } < n) }) { return Err("invalid QSA dynamic copy buffers or geometry".into()); } for ((buffer, size), stride) in [source, target] .into_iter() .zip(data_sizes) .zip([source_stride, target_stride]) { if size < qsa_copy_span([1, rows, width], [0, stride, 1])? || size .checked_mul(2) .is_none_or(|n| n as u64 > unsafe { ds4_gpu_tensor_bytes(buffer.raw()) }) { return Err("invalid QSA dynamic copy array data_size".into()); } } let mut offsets = [None, None]; for (i, (start, stride)) in starts .into_iter() .zip([source_stride, target_stride]) .enumerate() { if let Some(start) = start { let indices = array::Array::new(&[1], array::Dtype::I32, start.view(0, 4)?)?; let stride = i64::try_from(stride).map_err(|_| "QSA dynamic copy stride overflow")?; let offset = views::dynamic_offset(&indices, &[0, stride, 1], &[1])?; offsets[i] = Some(offset.buffer().view(0, 8)?); } } qsa_copy_offsets( [ tensor(0, source).input(data_sizes[0]), tensor(1, target).output(data_sizes[1]), ], [1, rows, width], [0, source_stride, 1], [0, target_stride, 1], "bfloat16", [offsets[0].as_ref(), offsets[1].as_ref()], )?; Ok(offsets.into_iter().flatten().collect()) } #[cfg(test)] fn qsa_zero(count: u32, width: u32) -> Result { let output = Buffer::mtplx_bytes(u64::from(count) * u64::from(width))?; let zero = scalar_buffer(&[0; 4][..width as usize])?; let work = if count < 65536 { 1 } else { 8 / width }; let threads = count.div_ceil(work); let dtype = if width == 2 { "bfloat16" } else { "float32" }; dispatch_geometry( &format!("s{}_copy{dtype}{dtype}", if work == 1 { "" } else { "n" }), &[ tensor(0, &zero).input(1), tensor(1, &output).output(count as usize), bytes(2, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; Ok(output) } #[cfg(test)] fn qsa_grown_capacity(end: u32, current: u32) -> Result { end.checked_add(255) .map(|n| n / 256 * 256) .zip(current.checked_mul(2)) .map(|(a, b)| a.max(b)) .filter(|cap| *cap <= i32::MAX as u32 / 512) .ok_or_else(|| "QSA capacity overflow".into()) } /// Four logical state leaves, sharing immutable backing until a later write. /// Python array identity and its separately shared storage are different things: /// __setitem__ overwrites the array descriptor, whereas slicing creates an array. #[cfg(test)] pub(super) struct QsaArray { storage: array::Array, pub(super) head_stride: Cell, } #[cfg(test)] impl QsaArray { pub(super) fn new(buffer: Buffer, head_stride: u64) -> Result, String> { let elements = i32::try_from(unsafe { ds4_gpu_tensor_bytes(buffer.raw()) } / 2) .map_err(|_| "QSA backing dimension overflow")?; Ok(Rc::new(Self { storage: array::Array::new(&[elements], array::Dtype::BF16, buffer)?, head_stride: Cell::new(head_stride), })) } pub(super) fn buffer(&self) -> Ref<'_, Buffer> { self.storage.buffer() } fn slice(&self) -> Rc { Rc::new(Self { storage: self.storage.share_data(), head_stride: Cell::new(self.head_stride.get()), }) } fn shared_storage(&self) -> bool { self.storage.shared_storage() } // Installed BF16 vector-copy contract: descriptor and Data must both be // exclusive, and at most 16 KiB of the root allocation may be unused. fn can_donate_bf16(array: &Rc, input: &Buffer, output_bytes: u64) -> bool { let storage = array.buffer(); Rc::strong_count(array) == 1 && array.storage.is_donatable() && storage.identity() == input.identity() && input.unique_data() && unsafe { ds4_gpu_tensor_bytes(input.raw()) } >= output_bytes && input.allocation_bytes().saturating_sub(output_bytes) <= 16384 } } #[derive(Clone)] #[cfg(test)] pub(super) struct QsaSnapshot { pub(super) leaves: [Option>; 4], // keys, values, raw, pooled pub(super) offset: u32, pub(super) pooled_len: u32, } /// Installed single-sequence QSACache + KVCache geometry (KV2x256, index128). /// Array aliases follow MTPLX's state setter; distinct views use storage COW. #[derive(Default)] #[cfg(test)] pub(super) struct QsaCache { pub(super) keys: Option>, pub(super) values: Option>, pub(super) raw: Option>, pub(super) pooled: Option>, pub(super) mirror: Option>, pub(super) offset: u32, pub(super) kv_cap: u32, pub(super) kv_head_stride: u64, pub(super) raw_cap: u32, pub(super) pooled_cap: u32, pub(super) pooled_len: u32, pub(super) mirror_cap: u32, pub(super) mirror_strides: [u64; 2], // D, blocks; initial transpose is a VIEW reserved_raw: u32, reserved_pooled: u32, } /// Original precompute_qsa_replay_capacity for the installed ratio4/step256. /// The fixed ceil(window/4) staging window can exceed the logical frontier. #[cfg(test)] pub(super) fn qsa_replay_capacity( start: u32, window: u32, existing: [u32; 2], ) -> Result<[u32; 2], String> { let end = start .checked_add(window) .ok_or("QSA replay frontier overflow")?; let staging = window.div_ceil(4); let staging_tokens = staging.checked_mul(4).ok_or("QSA replay window overflow")?; let [raw, pooled] = [ existing[0].max(end).max(staging_tokens), existing[1].max(end / 4).max(staging), ] .map(|required| { if required == 0 { return Ok(0); } required .max(256) .checked_next_power_of_two() .filter(|n| *n <= i32::MAX as u32 / 512) .ok_or_else(|| "QSA replay capacity overflow".to_owned()) }); Ok([raw?, pooled?]) } #[cfg(test)] impl QsaCache { fn grow_index( buffer: &mut Option>, cap: &mut u32, target: u32, ) -> Result<(), String> { if target == 0 || target > i32::MAX as u32 / 512 { return Err("invalid QSA capacity".into()); } let grown = qsa_zero(target * 128, 2)?; if let Some(old) = buffer.as_ref() { qsa_copy( Some(&old.buffer()), &grown, [1, *cap, 128], [0, 128, 1], [0, 128, 1], 2, target as usize * 128, )?; } *buffer = Some(QsaArray::new(grown, 0)?); *cap = target; Ok(()) } fn index_cow(buffer: &Option>, cap: u32) -> Result<(), String> { if let Some(old) = buffer.as_ref() && old.shared_storage() { let copy = Buffer::mtplx_bytes(u64::from(cap) * 128 * 2)?; let count = cap * 128; let work = if count < 65536 { 1 } else { 4 }; let threads = count.div_ceil(work); dispatch_geometry( if work == 1 { "v_copybfloat16bfloat16" } else { "vn_copybfloat16bfloat16" }, &[ tensor(0, &old.buffer()).input(count as usize), tensor(1, ©).output(count as usize), bytes(2, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; old.storage.replace(copy); } Ok(()) } pub(super) fn reserve(&mut self, raw: u32, pooled: u32) -> Result<(), String> { let raw = raw.max(self.raw_cap).max(self.reserved_raw); let pooled = pooled.max(self.pooled_cap).max(self.reserved_pooled); if raw < self.offset || pooled < self.pooled_len || raw > i32::MAX as u32 / 512 || pooled > i32::MAX as u32 / 512 { return Err("invalid QSA reservation".into()); } self.reserved_raw = raw; self.reserved_pooled = pooled; if self.raw.is_some() && raw > self.raw_cap { Self::grow_index(&mut self.raw, &mut self.raw_cap, raw)?; } if self.pooled.is_some() && pooled > self.pooled_cap { Self::grow_index(&mut self.pooled, &mut self.pooled_cap, pooled)?; } Ok(()) } /// _ensure_compiled_backings includes pending reservations and materializes /// pristine leaves. It neither advances KV.offset nor the pooled frontier. pub(super) fn ensure_compiled_backings(&mut self, rows: u32) -> Result<(), String> { if rows == 0 { return Err("compiled QSA requires positive rows".into()); } let [raw, pooled] = qsa_replay_capacity( self.offset, rows, [ self.raw_cap.max(self.reserved_raw), self.pooled_cap.max(self.reserved_pooled), ], )?; self.reserve(raw, pooled.max(256))?; if self.raw.is_none() { Self::grow_index(&mut self.raw, &mut self.raw_cap, self.reserved_raw)?; } if self.pooled.is_none() { Self::grow_index(&mut self.pooled, &mut self.pooled_cap, self.reserved_pooled)?; } Ok(()) } pub(super) fn write_raw( &mut self, keys: &Buffer, rows: u32, stride: u64, ) -> Result<(), String> { let end = self .offset .checked_add(rows) .filter(|n| *n <= i32::MAX as u32 / 512) .ok_or("QSA raw range overflow")?; let bytes_needed = u64::from(rows.saturating_sub(1)) .checked_mul(stride) .and_then(|n| n.checked_add(128)) .and_then(|n| n.checked_mul(2)); if rows == 0 || stride < 128 || bytes_needed.is_none_or(|n| unsafe { ds4_gpu_tensor_bytes(keys.raw()) } < n) { return Err("invalid QSA raw input".into()); } if self.raw.is_none() || end > self.raw_cap { let target = qsa_grown_capacity(end, self.raw_cap)?.max(self.reserved_raw); Self::grow_index(&mut self.raw, &mut self.raw_cap, target)?; } else { Self::index_cow(&self.raw, self.raw_cap)?; } let target = self .raw .as_ref() .unwrap() .buffer() .view(u64::from(self.offset) * 128 * 2, u64::from(rows) * 128 * 2)?; qsa_copy( Some(keys), &target, [1, rows, 128], [0, stride, 1], [0, 128, 1], 2, self.raw_cap as usize * 128, ) } pub(super) fn write_pooled( &mut self, blocks: &Buffer, start: u32, total: u32, ) -> Result<(), String> { if total <= start || total > i32::MAX as u32 / 512 || unsafe { ds4_gpu_tensor_bytes(blocks.raw()) } < u64::from(total - start) * 128 * 2 { return Err("invalid QSA pooled input".into()); } if self.pooled.is_none() || total > self.pooled_cap { let target = qsa_grown_capacity(total, self.pooled_cap)?.max(self.reserved_pooled); Self::grow_index(&mut self.pooled, &mut self.pooled_cap, target)?; } else { Self::index_cow(&self.pooled, self.pooled_cap)?; } let target = self.pooled.as_ref().unwrap().buffer().view( u64::from(start) * 128 * 2, u64::from(total - start) * 128 * 2, )?; qsa_copy( Some(blocks), &target, [1, total - start, 128], [0, 128, 1], [0, 128, 1], 2, self.pooled_cap as usize * 128, )?; if self.mirror.is_none() { self.rebuild_mirror()?; } else { if self.mirror_cap < self.pooled_cap { let grown = qsa_zero(self.pooled_cap * 128, 4)?; qsa_copy( self.mirror.as_deref(), &grown, [1, 128, self.mirror_cap], [0, self.mirror_strides[0], self.mirror_strides[1]], [0, u64::from(self.pooled_cap), 1], 4, self.pooled_cap as usize * 128, )?; self.mirror = Some(Rc::new(grown)); self.mirror_cap = self.pooled_cap; self.mirror_strides = [u64::from(self.pooled_cap), 1]; } let f32blocks = Buffer::mtplx_bytes(u64::from(total - start) * 128 * 4)?; cast_bf16_f32(blocks, &f32blocks, (total - start) * 128, true)?; let at = u64::from(start) * self.mirror_strides[1] * 4; let span = (127 * self.mirror_strides[0] + u64::from(total - start - 1) * self.mirror_strides[1] + 1) * 4; let target = self.mirror.as_ref().unwrap().view(at, span)?; qsa_copy( Some(&f32blocks), &target, [1, 128, total - start], [0, 1, 128], [0, self.mirror_strides[0], self.mirror_strides[1]], 4, self.mirror_cap as usize * 128, )?; } self.pooled_len = total; Ok(()) } fn rebuild_mirror(&mut self) -> Result<(), String> { let pooled = self .pooled .as_ref() .ok_or("QSA mirror needs pooled state")?; let mirror = Buffer::mtplx_bytes(u64::from(self.pooled_cap) * 128 * 4)?; cast_bf16_f32(&pooled.buffer(), &mirror, self.pooled_cap * 128, true)?; self.mirror = Some(Rc::new(mirror)); self.mirror_cap = self.pooled_cap; self.mirror_strides = [1, 128]; Ok(()) } pub(super) fn pooled_f32_view(&mut self, nb: u32) -> Result<(&Buffer, [u64; 2]), String> { if nb == 0 || nb > self.pooled_cap { return Err("invalid QSA mirror frontier".into()); } if self.mirror.is_none() || self.mirror_cap < nb { self.rebuild_mirror()?; } Ok((self.mirror.as_deref().unwrap(), self.mirror_strides)) } pub(super) fn extend_pooled( &mut self, total: u32, norm: &Buffer, freq: &Buffer, eager: bool, ) -> Result, String> { let nb = total / 4; let old = self.pooled_len.min(nb); if total > self.raw_cap { return Err("QSA pool exceeds raw backing".into()); } if nb > old { let fresh = self .raw .as_ref() .ok_or("QSA pool needs raw keys")? .buffer() .view( u64::from(old) * 4 * 128 * 2, u64::from(nb - old) * 4 * 128 * 2, )?; let (blocks, mut temporary) = if eager { qsa_pool_keys_eager([&fresh, norm, freq], nb - old, [128, 1], old as i32)? } else { ( qsa_pool_keys([&fresh, norm, freq], nb - old, [128, 1], old as i32)?, Vec::new(), ) }; self.write_pooled(&blocks, old, nb)?; temporary.push(blocks); return Ok(temporary); } Ok(Vec::new()) } pub(super) fn update_kv( &mut self, keys: &Buffer, values: &Buffer, rows: u32, strides: [u64; 2], ) -> Result<(), String> { let end = self .offset .checked_add(rows) .filter(|n| *n <= i32::MAX as u32 / 512) .ok_or("QSA KV range overflow")?; let bytes_needed = u64::from(rows.saturating_sub(1)) .checked_mul(strides[1]) .and_then(|n| n.checked_add(strides[0])) .and_then(|n| n.checked_add(256)) .and_then(|n| n.checked_mul(2)); if rows == 0 || bytes_needed.is_none_or(|n| { [keys, values] .iter() .any(|b| unsafe { ds4_gpu_tensor_bytes(b.raw()) } < n) }) { return Err("invalid QSA KV input".into()); } if self.keys.is_none() || end > self.kv_cap { let keep = if !self.offset.is_multiple_of(256) { self.offset } else { self.kv_cap }; let extra = rows.div_ceil(256) * 256; let cap = keep .checked_add(extra) .filter(|n| *n <= i32::MAX as u32 / 512) .ok_or("QSA KV allocation overflow")?; for buffer in [&mut self.keys, &mut self.values] { let grown = if buffer.is_none() { qsa_zero(cap * 512, 2)? } else { Buffer::mtplx_bytes(u64::from(cap) * 512 * 2)? }; let concurrent = encoder::concurrent_scope(); if let Some(old) = buffer.as_ref() { qsa_copy( Some(&old.buffer()), &grown, [2, keep, 256], [self.kv_head_stride, 256, 1], [u64::from(cap) * 256, 256, 1], 2, keep as usize * 512, )?; } if buffer.is_some() { let tail = grown.view( u64::from(keep) * 256 * 2, (u64::from(cap) * 256 + u64::from(extra) * 256) * 2, )?; qsa_copy( None, &tail, [2, extra, 256], [0; 3], [u64::from(cap) * 256, 256, 1], 2, extra as usize * 512, )?; } drop(concurrent); *buffer = Some(QsaArray::new(grown, u64::from(cap) * 256)?); } self.kv_cap = cap; self.kv_head_stride = u64::from(cap) * 256; } else { // Distinct slices can prevent donation; aliases of the same array // object observe its descriptor replacement instead. let need_copy = [&self.keys, &self.values] .iter() .any(|b| b.as_ref().unwrap().shared_storage()) || self.kv_head_stride != u64::from(self.kv_cap) * 256; if need_copy { for buffer in [&mut self.keys, &mut self.values] { let copy = Buffer::mtplx_bytes(u64::from(self.kv_cap) * 512 * 2)?; if self.kv_head_stride == u64::from(self.kv_cap) * 256 { let count = self.kv_cap * 512; let work = if count < 65536 { 1 } else { 4 }; let threads = count.div_ceil(work); dispatch_geometry( if work == 1 { "v_copybfloat16bfloat16" } else { "vn_copybfloat16bfloat16" }, &[ tensor(0, &buffer.as_ref().unwrap().buffer()).input( (self.kv_head_stride + u64::from(self.kv_cap) * 256) as usize, ), tensor(1, ©).output(self.kv_cap as usize * 512), bytes(2, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; } else { let grid = [self.kv_cap * 256, 2, 1]; dispatch_geometry( "g2_copybfloat16bfloat16", &[ tensor(0, &buffer.as_ref().unwrap().buffer()).input( (self.kv_head_stride + u64::from(self.kv_cap) * 256) as usize, ), tensor(1, ©).output(self.kv_cap as usize * 512), bytes(3, &[self.kv_head_stride, 1]), ], &[], grid, block_dims(grid), true, )?; } let array = buffer.as_ref().unwrap(); array.storage.replace(copy); array.head_stride.set(u64::from(self.kv_cap) * 256); } self.kv_head_stride = u64::from(self.kv_cap) * 256; } } for (source, target) in [keys, values].into_iter().zip([&self.keys, &self.values]) { let span = (self.kv_head_stride + u64::from(rows) * 256) * 2; let target = target .as_ref() .unwrap() .buffer() .view(u64::from(self.offset) * 256 * 2, span)?; qsa_copy( Some(source), &target, [2, rows, 256], [strides[0], strides[1], 1], [self.kv_head_stride, 256, 1], 2, self.kv_cap as usize * 512, )?; } self.offset = end; Ok(()) } pub(super) fn trim(&mut self, n: u32) -> u32 { let trimmed = n.min(self.offset); self.offset -= trimmed; self.pooled_len = self.pooled_len.min(self.offset / 4); trimmed } pub(super) fn nbytes(&self) -> u64 { // QSACache reports logical backing capacities, excluding its FP32 mirror. u64::from(if self.keys.is_some() { self.kv_cap } else { 0 }) * 2048 + u64::from(self.raw_cap) * 256 + u64::from(self.pooled_cap) * 256 } pub(super) fn snapshot(&self) -> QsaSnapshot { let nb = self.pooled_len.min(self.offset / 4); let kv = |array: &Option>| { array.as_ref().map(|a| { if self.offset == self.kv_cap { a.clone() } else { a.slice() } }) }; QsaSnapshot { leaves: [ kv(&self.keys), kv(&self.values), self.raw.as_ref().map(|a| a.slice()), if nb == 0 { None } else { self.pooled.as_ref().map(|a| a.slice()) }, ], offset: self.offset, pooled_len: nb, } } pub(super) fn restore(&mut self, state: &QsaSnapshot) -> Result<(), String> { let head_stride = state.leaves[0].as_ref().map_or(0, |a| a.head_stride.get()); let kv_span = head_stride .checked_add(u64::from(state.offset) * 256) .and_then(|n| n.checked_mul(2)); if state.offset>i32::MAX as u32/512 || state.pooled_len>state.offset/4 || state.leaves[0].is_some()!=state.leaves[1].is_some() || (state.offset>0 && state.leaves[0].is_none()) || (state.pooled_len>0 && state.leaves[3].is_none()) || state.leaves[..2].iter().flatten().any(|b|kv_span.is_none_or(|n|unsafe{ds4_gpu_tensor_bytes(b.buffer().raw())} &'static str { match self { Self::Blocks => "blocks", Self::DenseMask => "dense_mask", Self::RowTokens => "row_tokens", } } } /// Original selector specialization for the installed H4/D128/ratio4 model. /// Logical frontiers remain device scalars, not shader specializations. #[derive(Clone, Copy)] #[cfg(test)] pub(super) struct QsaSelectPlan { pub(super) rows: u32, pub(super) blocks: u32, pub(super) topk: u32, pub(super) pos: u32, pub(super) total: u32, pub(super) logical: u32, pub(super) dense_width: u32, pub(super) mode: QsaSelectMode, pub(super) tf32: bool, pub(super) input_f32: [bool; 2], } #[cfg(test)] impl QsaSelectPlan { fn widths(self) -> Vec<(u32, u32)> { match self.mode { QsaSelectMode::Blocks => vec![(self.topk, 4), (self.topk, 1), (self.topk, 4)], QsaSelectMode::DenseMask => vec![(self.dense_width, 1)], QsaSelectMode::RowTokens => vec![(self.topk * 4 + 4, 4), (self.topk * 4 + 4, 1)], } } fn canonical(self) -> qsa_select::Kernel { use array::Dtype; qsa_select::Kernel { heads: 4, dim: 128, blocks: self.blocks as i32, topk: self.topk as i32, ratio: 4, dense_width: if self.mode == QsaSelectMode::DenseMask { self.dense_width as i32 } else { 0 }, mode: self.mode, tf32: self.tf32, dtypes: self .input_f32 .map(|f32| if f32 { Dtype::F32 } else { Dtype::BF16 }), } } pub(super) fn source(self) -> Result { self.canonical().source() } } /// One original fused selector dispatch, including its otherwise private scratch. #[cfg(test)] pub(super) struct QsaSelection { pub(super) outputs: Vec, pub(super) row_widths: Vec<(u32, u32)>, // elements, storage bytes pub(super) row_strides: Vec, _temporaries: Vec, } /// One original fused selector dispatch, including its otherwise private scratch. #[cfg(test)] pub(super) fn qsa_select( [q, pooled]: [&Buffer; 2], q_strides: [u64; 3], pooled_strides: [u64; 2], plan: QsaSelectPlan, ) -> Result { if plan.rows == 0 || plan.rows > i32::MAX as u32 / 512 || !(1..=512).contains(&plan.topk) || plan.total > i32::MAX as u32 || plan .pos .checked_add(plan.rows) .is_none_or(|n| n > plan.total) || plan.logical > plan.blocks || plan.logical != plan.total / 4 || (plan.mode == QsaSelectMode::DenseMask && plan.dense_width < plan.total) { return Err("invalid QSA selector geometry or frontier".into()); } let positions = [plan.pos, plan.total, plan.logical].map(|value| scalar_buffer(&value.to_le_bytes())); let [pos, total, logical] = positions; let positions = [pos?, total?, logical?]; let mut out = qsa_select_device( [q, pooled], q_strides, pooled_strides, plan, [&positions[0], &positions[1], &positions[2]], )?; out._temporaries.extend(positions); Ok(out) } /// Fixed selector geometry with explicit int32[1] graph frontier leaves. /// plan.pos/total/logical are unused here; only the device leaves are consumed. #[cfg(test)] pub(super) fn qsa_select_device( [q, pooled]: [&Buffer; 2], q_strides: [u64; 3], pooled_strides: [u64; 2], plan: QsaSelectPlan, [pos, total, logical]: [&Buffer; 3], ) -> Result { if plan.rows == 0 || plan.rows > i32::MAX as u32 / 512 || plan.blocks > i32::MAX as u32 || !(1..=512).contains(&plan.topk) || [pos, total, logical] .into_iter() .any(|b| unsafe { ds4_gpu_tensor_bytes(b.raw()) } < 4) { return Err("invalid QSA device selector geometry or leaves".into()); } for (buffer, shape, strides, f32) in [ (q, [plan.rows, 4, 128], q_strides, plan.input_f32[0]), ( pooled, [1, plan.blocks, 128], [0, pooled_strides[0], pooled_strides[1]], plan.input_f32[1], ), ] { let span = shape .into_iter() .zip(strides) .try_fold(0_u64, |n, (dim, stride)| { u64::from(dim.saturating_sub(1)) .checked_mul(stride) .and_then(|v| n.checked_add(v)) }) .and_then(|n| n.checked_add(1)) .and_then(|n| n.checked_mul(if f32 { 4 } else { 2 })); if !shape.contains(&0) && span.is_none_or(|n| unsafe { ds4_gpu_tensor_bytes(buffer.raw()) } < n) { return Err("QSA selector input exceeds backing buffer".into()); } } use array::{Array, Dtype}; let kernel = plan.canonical(); let q = buffer_array( q, &[1, plan.rows as i32, 4, 128], &[0, q_strides[0], q_strides[1], q_strides[2]], kernel.dtypes[0], )?; let pooled = buffer_array( pooled, &[1, plan.blocks as i32, 128], &[0, pooled_strides[0], pooled_strides[1]], kernel.dtypes[1], )?; let inputs = vec![ q, pooled, Array::new(&[1], Dtype::I32, pos.view(0, 4)?)?, Array::new(&[1], Dtype::I32, total.view(0, 4)?)?, Array::new(&[1], Dtype::I32, logical.view(0, 4)?)?, ]; let arrays = kernel .layouts(plan.rows as i32)? .into_iter() .map(|layout| { Array::new( layout.shape(), layout.dtype(), Buffer::mtplx_bytes((layout.nbytes() as u64).max(4))?, ) }) .collect::, String>>()?; qsa_select::encode(&inputs, &arrays, kernel)?; let mut buffers = arrays .iter() .map(|a| a.buffer().view(0, (a.layout().nbytes() as u64).max(4))) .collect::, _>>()?; let scratch = buffers.pop().ok_or("QSA scratch sibling missing")?; let widths = plan.widths(); Ok(QsaSelection { outputs: buffers, row_strides: widths.iter().map(|(w, _)| *w).collect(), row_widths: widths, _temporaries: vec![scratch], }) } /// Preserve an existing Buffer view when delegating to the canonical backend. #[cfg(test)] fn buffer_array( buffer: &Buffer, shape: &[i32], strides: &[u64], dtype: array::Dtype, ) -> Result { use array::{Array, Flags}; let strides = strides .iter() .map(|&s| i64::try_from(s).map_err(|_| "QSA stride overflow")) .collect::, _>>()?; let size = if shape.contains(&0) { 0 } else { shape.iter().zip(&strides).try_fold(1_i64, |n, (&d, &s)| { n.checked_add( i64::from(d.saturating_sub(1)) .checked_mul(s) .ok_or("QSA span overflow")?, ) .ok_or("QSA span overflow") })? as usize }; let a = Array::unallocated(shape, dtype)?; let (_, row, col) = a.layout().contiguity(&strides)?; a.set_strided_data( buffer.view(0, (size * dtype.itemsize()) as u64)?, size, &strides, Flags { contiguous: row || col, row_contiguous: row, col_contiguous: col, }, 0, )?; Ok(a) } /// QSAIndexer._select_fused: bound score scratch per dispatch, concatenate /// original typed outputs, then return a zero-copy logical dense-mask slice. #[cfg(test)] pub(super) fn qsa_select_chunked( input: [&Buffer; 2], q_strides: [u64; 3], pooled_strides: [u64; 2], mut plan: QsaSelectPlan, ) -> Result { if plan.rows == 0 || plan.rows > i32::MAX as u32 / 512 || !(1..=512).contains(&plan.topk) || plan.total > i32::MAX as u32 || plan .pos .checked_add(plan.rows) .is_none_or(|n| n > plan.total) || plan.logical > plan.blocks || plan.logical != plan.total / 4 { return Err("invalid chunked QSA geometry".into()); } if plan.mode == QsaSelectMode::DenseMask { plan.dense_width = plan .blocks .checked_add(1) .and_then(|n| n.checked_mul(4)) .ok_or("QSA dense capacity overflow")?; } let chunk_rows = u64::from(plan.rows) .min(((32 * 1024 * 1024) / (u64::from(plan.blocks.max(1)) * 4)).max(1)) as u32; let mut chunks = Vec::new(); for start in (0..plan.rows).step_by(chunk_rows as usize) { let rows = chunk_rows.min(plan.rows - start); let at = u64::from(start) .checked_mul(q_strides[0]) .and_then(|n| n.checked_mul(if plan.input_f32[0] { 4 } else { 2 })) .ok_or("QSA query slice overflow")?; let bytes = unsafe { ds4_gpu_tensor_bytes(input[0].raw()) } .checked_sub(at) .ok_or("QSA query slice outside backing")?; let query = input[0].view(at, bytes)?; let pos = plan .pos .checked_add(start) .ok_or("QSA query position overflow")?; chunks.push(qsa_select( [&query, input[1]], q_strides, pooled_strides, QsaSelectPlan { rows, pos, ..plan }, )?); } let mut result = qsa_concat_selection(chunks, plan, chunk_rows)?; if plan.mode == QsaSelectMode::DenseMask { result.row_widths[0].0 = plan.total; } Ok(result) } #[cfg(test)] fn qsa_concat_selection( mut chunks: Vec, plan: QsaSelectPlan, chunk_rows: u32, ) -> Result { Ok(if chunks.len() == 1 { chunks.pop().unwrap() } else { let widths = plan.widths(); let outputs = widths .iter() .map(|(width, bytes)| { Buffer::mtplx_bytes(u64::from(plan.rows) * u64::from(*width) * u64::from(*bytes)) }) .collect::, _>>()?; for (i, (target, (width, bytes))) in outputs.iter().zip(&widths).enumerate() { let dtype = if *bytes == 1 { "bool_" } else if i == 0 { "int32" } else { "float32" }; let concurrent = encoder::concurrent_scope(); for (chunk_index, chunk) in chunks.iter().enumerate() { let start = chunk_index as u32 * chunk_rows; let rows = chunk_rows.min(plan.rows - start); let view = target.view( u64::from(start) * u64::from(*width) * u64::from(*bytes), u64::from(rows) * u64::from(*width) * u64::from(*bytes), )?; qsa_copy_typed( Some(&chunk.outputs[i]), &view, [1, rows, *width], [0, u64::from(*width), 1], [0, u64::from(*width), 1], dtype, (rows) as usize * (*width) as usize, )?; } drop(concurrent); } let mut temporaries = Vec::new(); for chunk in chunks { temporaries.extend(chunk.outputs); temporaries.extend(chunk._temporaries); } QsaSelection { outputs, row_strides: widths.iter().map(|(w, _)| *w).collect(), row_widths: widths, _temporaries: temporaries, } }) } /// The producer-aware 128MiB score-plane budget, including the original /// alignment-down rule. The general FP32 producer needs H4+1 planes. #[cfg(test)] pub(super) fn qsa_prefill_chunk_rows( rows: u32, blocks: u32, budget: u64, alignment: u32, mpp: bool, ) -> Result { if rows == 0 || blocks == 0 || budget == 0 || alignment == 0 { return Err("invalid QSA prefill budget".into()); } let per_row = u64::from(blocks) * 4 * if mpp { 1 } else { 5 }; let mut chunk = u64::from(rows).min((budget / per_row).max(1)) as u32; if chunk >= alignment && chunk < rows { chunk = alignment.max(chunk / alignment * alignment); } Ok(chunk) } /// Original General copy (including cast), after runtime dimension collapse. #[cfg(test)] fn qsa_copy_f32( input: &Buffer, shape: [u32; 3], strides: [u64; 3], bf16: bool, ) -> Result { qsa_copy_general( input, shape, strides, if bf16 { "bfloat16" } else { "float32" }, "float32", 4, ) } #[cfg(test)] fn qsa_copy_general( input: &Buffer, shape: [u32; 3], strides: [u64; 3], source_type: &str, output_type: &str, output_bytes: u32, ) -> Result { let count = shape .into_iter() .try_fold(1_u32, |n, d| n.checked_mul(d)) .filter(|n| *n > 0 && *n <= i32::MAX as u32) .ok_or("QSA General copy exceeds its index range")?; let output = Buffer::mtplx_bytes(u64::from(count) * u64::from(output_bytes))?; let mut dims: Vec<(u32, u64)> = Vec::new(); for (d, s) in shape.into_iter().zip(strides).filter(|(d, _)| *d > 1) { if let Some(last) = dims.last_mut() && last.1 == u64::from(d) * s { last.0 *= d; last.1 = s; } else { dims.push((d, s)); } } let mut grid = [1; 3]; let mut ss = [0_u64; 3]; for (i, &(d, s)) in dims.iter().enumerate() { grid[dims.len() - 1 - i] = d; ss[i] = s; } dispatch_geometry( &format!("g{}_copy{source_type}{output_type}", dims.len()), &[ tensor(0, input).input(qsa_copy_span(shape, strides)?), tensor(1, &output).output(count as usize), bytes(3, &ss), ], &[], grid, block_dims(grid), true, )?; Ok(output) } // AsType Vector preserves physically contiguous layouts, including transposes // and broadcasts; General materializes all logical entries. #[cfg(test)] fn qsa_cast_f32(input: &Buffer, shape: [u32; 3], strides: &mut [u64; 3]) -> Result { let count = shape.into_iter().try_fold(1_u32, |n, d| n.checked_mul(d)); let span = shape .into_iter() .zip(*strides) .try_fold(1_u64, |n, (d, s)| { u64::from(d.saturating_sub(1)) .checked_mul(s) .and_then(|v| n.checked_add(v)) }) .and_then(|n| n.checked_mul(2)); if shape.contains(&0) || count.is_none_or(|n| n > i32::MAX as u32) || span.is_none_or(|n| unsafe { ds4_gpu_tensor_bytes(input.raw()) } < n) { return Err("invalid QSA cast input".into()); } let mut dims = shape .into_iter() .zip(*strides) .filter(|(d, s)| *d > 1 && *s != 0) .collect::>(); dims.sort_unstable_by_key(|(_, s)| *s); let mut size = 1_u64; let contiguous = dims.into_iter().all(|(d, s)| { let fits = s == size; size *= u64::from(d); fits }); if contiguous { let cast = Buffer::mtplx_bytes(size * 4)?; cast_bf16_f32(input, &cast, size as u32, true)?; Ok(cast) } else { let cast = qsa_copy_f32(input, shape, *strides, true)?; *strides = [ u64::from(shape[1]) * u64::from(shape[2]), u64::from(shape[2]), 1, ]; Ok(cast) } } #[repr(C)] struct QsaGemmParams { matrix: [i32; 8], batch_strides: [i64; 3], swizzle: i32, k_iterations: i32, batch_ndim: i32, padding: i32, } /// qsa_indexer_prefill_scores / _select_eager, installed H4/D128 geometry. /// Preserve the pinned runtime's casts, layout checks, batch collapse and /// M5 Max GEMV/Steel/NAX/Split-K selection, followed by per-head ReLU and sum. /// The caller retains the returned temporaries through GPU completion. #[cfg(test)] pub(super) fn qsa_prefill_f32_scores( [q, pooled_t]: [&Buffer; 2], [rows, blocks]: [u32; 2], mut q_strides: [u64; 3], pooled_strides: [u64; 2], q_bf16: bool, tf32: bool, ) -> Result<(Buffer, Vec), String> { if rows == 0 || blocks == 0 || rows.checked_mul(512).is_none_or(|n| n > i32::MAX as u32) || rows .checked_mul(4) .and_then(|n| n.checked_mul(blocks)) .is_none_or(|n| n > i32::MAX as u32) || blocks.checked_mul(128).is_none_or(|n| n > i32::MAX as u32) { return Err("invalid QSA FP32 score geometry".into()); } for (b, shape, strides, width) in [ (q, [rows, 4, 128], q_strides, if q_bf16 { 2 } else { 4 }), ( pooled_t, [1, 128, blocks], [0, pooled_strides[0], pooled_strides[1]], 4, ), ] { let span = shape .into_iter() .zip(strides) .try_fold(1_u64, |n, (d, s)| { u64::from(d - 1) .checked_mul(s) .and_then(|v| n.checked_add(v)) }) .and_then(|n| n.checked_mul(width)); if strides.iter().any(|s| *s > i32::MAX as u64) || span.is_none_or(|n| unsafe { ds4_gpu_tensor_bytes(b.raw()) } < n) { return Err("QSA FP32 input outside backing or index range".into()); } } let mut temporary = Vec::new(); let cast = if q_bf16 { Some(qsa_cast_f32(q, [rows, 4, 128], &mut q_strides)?) } else { None }; let a = cast.as_ref().unwrap_or(q); let per_head_size = rows as usize * 4 * blocks as usize; // Matmul allocates its output before check_transpose's input copies. let per_head = Buffer::mtplx_bytes(per_head_size as u64 * 4)?; let copied_a = if q_strides[2] != 1 && q_strides[1] != 1 { let copied = qsa_copy_f32(a, [rows, 4, 128], q_strides, false)?; q_strides = [512, 128, 1]; Some(copied) } else { None }; let a = copied_a.as_ref().unwrap_or(a); let ta = q_strides[2] != 1; let lda = q_strides[if ta { 2 } else { 1 }] as i32; let [bd, bn_stride] = pooled_strides; let b_normal = bn_stride == 1 && (blocks != 1 || bd == u64::from(blocks)); let b_transposed = bd == 1 && (blocks != 1 || bn_stride == 128); // check_transpose sees the already broadcast B. A General copy therefore // duplicates B across rows and prevents collapsing the rows into M. let copied_b = if b_normal || b_transposed { None } else { Some(qsa_copy_f32( pooled_t, [rows, 128, blocks], [0, bd, bn_stride], false, )?) }; let b = copied_b.as_ref().unwrap_or(pooled_t); let tb = copied_b.is_none() && !b_normal; let ldb = if copied_b.is_some() { blocks } else if tb { bn_stride as u32 } else { bd as u32 } as i32; let mut batch = rows; let mut m = 4_u32; let mut a_batch = q_strides[0] as i64; let mut b_batch = if copied_b.is_some() { i64::from(blocks) * 128 } else { 0 }; if rows > 1 && !ta && q_strides[1] == 128 && a_batch == 512 && b_batch == 0 { m *= rows; batch = 1; a_batch = 0; b_batch = 0; } let a_size = qsa_copy_span([rows, 4, 128], q_strides)?; let b_size = if copied_b.is_some() { rows as usize * 128 * blocks as usize } else { qsa_copy_span([1, 128, blocks], [0, bd, bn_stride])? }; let trans = format!( "{}{}", if ta { 't' } else { 'n' }, if tb { 't' } else { 'n' } ); if blocks == 1 { let (bm, bn, sm, sn) = if ta { ( 1, if m >= 2048 { 16 } else if m >= 512 { 4 } else { 2 }, 8, 4, ) } else if 128 >= 16 * m { (1, 8, 1, 32) } else { (if m >= 4096 { 8 } else { 4 }, 1, 1, 32) }; let out_per_group = if ta { bn * sn * 4 } else { bm * sm * 4 }; dispatch( &format!( "gemv{}float32_bm{bm}_bn{bn}_sm{sm}_sn{sn}_tm4_tn4_nc0_axpby0", if ta { "_t_" } else { "_" } ), &[ tensor(0, a).input(a_size), tensor(1, b).input(b_size), tensor(3, &per_head).output(per_head_size), bytes(4, &128_i32), bytes(5, &m), bytes(6, &lda), bytes(9, &1_i32), bytes(10, &batch), bytes(11, &b_batch), bytes(12, &a_batch), ], [m.div_ceil(out_per_group), 1, batch], [32, bn, bm], )?; } else if batch == 1 && ((!tf32 && m.max(blocks) <= 128) || (tf32 && m.max(blocks) < 64)) { let (bm, bn, bk, partitions, partition_size) = if tf32 { (64, 64, 256, 2, 64) } else { let parts = (8 / (m.div_ceil(32) * blocks.div_ceil(32))) .next_power_of_two() .clamp(2, 32); ( if m < 40 { 16 } else { 32 }, if blocks < 40 { 16 } else { 32 }, 16, parts, 128 / parts, ) }; let scratch_size = partitions as usize * m as usize * blocks as usize; let scratch = Buffer::mtplx_bytes(scratch_size as u64 * 4)?; let tn = blocks.div_ceil(bn); let tm = m.div_ceil(bm); let params = [ m as i32, blocks as i32, 128, lda, ldb, blocks as i32, tn as i32, tm as i32, partitions as i32, (m * blocks) as i32, partition_size as i32, 0, (partition_size / bk) as i32, ]; let constants = [ (200, m.is_multiple_of(bm)), (201, blocks.is_multiple_of(bn)), ] .map(|(index, value)| MetalConstant { index, value: u32::from(value), kind: 0, }); let name = if tf32 { format!("steel_gemm_splitk_nax_{trans}_float32_float32_bm64_bn64_bk256_wm2_wn2") } else { format!( "steel_gemm_splitk_{trans}_float32_float32_bm{bm}_bn{bn}_bk16_wm2_wn2_MN_{}aligned_K_taligned", if m.is_multiple_of(bm) && blocks.is_multiple_of(bn) { 't' } else { 'n' } ) }; dispatch_specialized( &name, &[ tensor(0, a).input(a_size), tensor(1, b).input(b_size), tensor(2, &scratch).output(scratch_size), bytes(3, ¶ms), ], if tf32 { &constants } else { &[] }, if tf32 { [tn * tm * partitions, 1, 1] } else { [tn, tm, partitions] }, [32, 2, 2], )?; let grid = [blocks, m, 1]; dispatch_geometry( "steel_gemm_splitk_accum_float32_float32", &[ tensor(0, &scratch).input(scratch_size), tensor(1, &per_head).output(per_head_size), bytes(2, &partitions), bytes(3, &(m * blocks)), bytes(4, &blocks), ], &[], grid, block_dims(grid), true, )?; encoder::add_temporaries(std::slice::from_ref(&scratch)); temporary.push(scratch); } else { let (bn, bk, wn, swizzle) = if tf32 { (128, 256, 4, 2) } else { (64, 16, 2, 0) }; let tn = blocks.div_ceil(bn); let tm = m.div_ceil(64); let params = QsaGemmParams { matrix: [ m as i32, blocks as i32, 128, lda, ldb, blocks as i32, tn as i32, tm as i32, ], batch_strides: [a_batch, b_batch, i64::from(m) * i64::from(blocks)], swizzle, k_iterations: 128 / bk, batch_ndim: 1, padding: 0, }; let constants = [ (10, false), (100, false), (110, false), (200, m.is_multiple_of(64)), (201, blocks.is_multiple_of(bn)), (202, !tf32), ] .map(|(index, value)| MetalConstant { index, value: u32::from(value), kind: 0, }); dispatch_specialized( &format!( "steel_gemm_fused_{}{trans}_float32_float32_bm64_bn{bn}_bk{bk}_wm2_wn{wn}", if tf32 { "nax_" } else { "" } ), &[ tensor(0, a).input(a_size), tensor(1, b).input(b_size), tensor(3, &per_head).output(per_head_size), bytes(4, ¶ms), ], &constants, [tn * (1 << swizzle), tm.div_ceil(1 << swizzle), batch], [32, wn, 2], )?; } encoder::add_temporaries(copied_a.as_slice()); encoder::add_temporaries(copied_b.as_slice()); temporary.extend(cast); temporary.extend(copied_a); temporary.extend(copied_b); let zero = scalar_buffer(&0_f32.to_le_bytes())?; let count = rows * 4 * blocks; let work = if count < 65536 { 1 } else { 2 }; dispatch_geometry( &format!("vs{}_Maximumfloat32", if work == 1 { "" } else { "n" }), &[ tensor(0, &per_head).input(per_head_size), tensor(1, &zero).input(1), tensor(2, &per_head).output(per_head_size), bytes(3, &count), ], &[], [count.div_ceil(work), 1, 1], [count.div_ceil(work).min(1024), 1, 1], true, )?; let scores_size = rows as usize * blocks as usize; let scores = Buffer::mtplx_bytes(scores_size as u64 * 4)?; let ndim = u32::from(rows > 1); let outer_shape = if rows > 1 { rows } else { 0 }; let outer_stride = if rows > 1 { u64::from(blocks) * 4 } else { 0 }; if blocks == 1 { dispatch_geometry( "row_reduce_small_1_reduce_sumfloat32", &[ tensor(0, &per_head).input(per_head_size), tensor(1, &scores).output(scores_size), bytes(2, &4_u64), bytes(3, &1_u64), bytes(4, &outer_shape), bytes(5, &outer_stride), bytes(6, &ndim), bytes(7, &0_i32), bytes(8, &0_u64), bytes(9, &0_i32), ], &[], [rows, 1, 1], [rows.min(1024), 1, 1], true, )?; } else { let gx = blocks.div_ceil(4).min(32); dispatch( "col_reduce_small_1_reduce_sumfloat32", &[ tensor(0, &per_head).input(per_head_size), tensor(1, &scores).output(scores_size), bytes(2, &4_u64), bytes(3, &u64::from(blocks)), bytes(4, &outer_shape), bytes(5, &outer_stride), bytes(6, &ndim), bytes(7, &4_u32), bytes(8, &u64::from(blocks)), bytes(9, &1_i32), bytes(10, &1_u64), ], [blocks.div_ceil(4).div_ceil(gx), rows, 1], [gx, 4, 1], )?; } let divisor = scalar_buffer(&(128_f64.sqrt() as f32).to_le_bytes())?; let count = rows * blocks; let work = if count < 65536 { 1 } else { 2 }; dispatch_geometry( &format!("vs{}_Dividefloat32", if work == 1 { "" } else { "n" }), &[ tensor(0, &scores).input(scores_size), tensor(1, &divisor).input(1), tensor(2, &scores).output(scores_size), bytes(3, &count), ], &[], [count.div_ceil(work), 1, 1], [count.div_ceil(work).min(1024), 1, 1], true, )?; temporary.push(per_head); Ok((scores, temporary)) } #[cfg(test)] fn qsa_vector( prefix: &str, op: &str, bindings: &[Binding<'_>], count: u32, width: u32, ) -> Result<(), String> { let work = if count < 65536 { 1 } else { 8 / width }; let suffix = if work == 1 || prefix == "ss" { "" } else { "n" }; dispatch_geometry( &format!("{prefix}{suffix}_{op}"), bindings, &[], [count.div_ceil(work), 1, 1], [count.div_ceil(work).min(1024), 1, 1], true, ) } #[cfg(test)] pub(super) struct QsaEagerTopk { rows: u32, pos_start: u32, tiled: bool, /// Untiled: last K columns of ArgPartition, stride N. Tiled: concat, stride K. pub(super) indices: Buffer, pub(super) valid: Buffer, pub(super) masked_scores: Option, pub(super) positions: Buffer, pub(super) complete_blocks: Buffer, pub(super) width: u32, pub(super) row_stride: u32, pub(super) index_row_stride: u32, _temporaries: Vec, } /// _select_eager, including _tiled_topk's synchronous per-tile eval and concat. /// ArgPartition in the pinned runtime is a complete argsort, not a replacement /// custom selector. The pooled FP32 mirror and tie vector are shared by tiles. #[cfg(test)] pub(super) fn qsa_eager_topk( input: [&Buffer; 2], q_strides: [u64; 3], pooled_t_strides: [u64; 2], plan: QsaSelectPlan, tile_rows: u32, mut commands: Option<&mut Commands>, ) -> Result { if plan .pos .checked_add(plan.rows) .is_none_or(|n| n > plan.total) || plan.total > i32::MAX as u32 || plan.blocks != plan.total / 4 || !plan.input_f32[1] || !(1..=512).contains(&plan.topk) || plan.rows == 0 || plan.blocks == 0 || plan .rows .checked_mul(plan.blocks) .is_none_or(|n| n > i32::MAX as u32) { return Err("invalid QSA eager frontier".into()); } let rows = plan.rows; let blocks = plan.blocks; let positions = Buffer::mtplx_bytes(u64::from(rows) * 4)?; let complete = Buffer::mtplx_bytes(u64::from(rows) * 4)?; let blk = Buffer::mtplx_bytes(u64::from(blocks) * 4)?; let tie = Buffer::mtplx_bytes(u64::from(blocks) * 4)?; let one = scalar_buffer(&1_i32.to_le_bytes())?; let ratio = scalar_buffer(&4_i32.to_le_bytes())?; let tie_scale = scalar_buffer(&1e-12_f32.to_le_bytes())?; let neg = scalar_buffer(&f32::NEG_INFINITY.to_le_bytes())?; // Original vector dispatch threshold for int32/float32; SS entries have // no size argument, which the shared Metal binder may harmlessly leave set. let vector = |prefix: &str, op: &str, bindings: &[Binding<'_>], count: u32| { qsa_vector(prefix, op, bindings, count, 4) }; for (out, count, start) in [(&positions, rows, plan.pos), (&blk, blocks, 0)] { dispatch_geometry( "arangeint32", &[ bytes(0, &start), bytes(1, &1_i32), tensor(2, out).output(count as usize), ], &[], [count, 1, 1], [count.min(1024), 1, 1], true, )?; } let prefix = if rows == 1 { "ss" } else { "vs" }; vector( prefix, "Addint32", &[ tensor(0, &positions).input(rows as usize), tensor(1, &one).input(1), tensor(2, &complete).output(rows as usize), bytes(3, &rows), ], rows, )?; vector( prefix, "Divideint32", &[ tensor(0, &complete).input(rows as usize), tensor(1, &ratio).input(1), tensor(2, &complete).output(rows as usize), bytes(3, &rows), ], rows, )?; let work = if blocks < 65536 { 1 } else { 2 }; dispatch_geometry( &format!("v{}_copyint32float32", if work == 1 { "" } else { "n" }), &[ tensor(0, &blk).input(blocks as usize), tensor(1, &tie).output(blocks as usize), bytes(2, &blocks), ], &[], [blocks.div_ceil(work), 1, 1], [blocks.div_ceil(work).min(1024), 1, 1], true, )?; vector( if blocks == 1 { "ss" } else { "vs" }, "Multiplyfloat32", &[ tensor(0, &tie).input(blocks as usize), tensor(1, &tie_scale).input(1), tensor(2, &tie).output(blocks as usize), bytes(3, &blocks), ], blocks, )?; let width = plan.topk.min(blocks); let tiled = rows > 1 && tile_rows > 0 && tile_rows < rows; let (indices, valid, masked_scores, mut temporary) = if tiled { let mut parts = Vec::new(); for start in (0..rows).step_by(tile_rows as usize) { let len = tile_rows.min(rows - start); let complete_view = complete.view(u64::from(start) * 4, u64::from(len) * 4)?; let valid = qsa_eager_valid(&blk, &complete_view, len, blocks)?; let item_bytes = if plan.input_f32[0] { 4 } else { 2 }; let q_len = u64::from(len - 1) .checked_mul(q_strides[0]) .and_then(|n| n.checked_add(3_u64.checked_mul(q_strides[1])?)) .and_then(|n| n.checked_add(127_u64.checked_mul(q_strides[2])?)) .and_then(|n| n.checked_add(1)) .and_then(|n| n.checked_mul(item_bytes)) .ok_or("QSA eager tile query span overflow")?; let offset = u64::from(start) .checked_mul(q_strides[0]) .and_then(|n| n.checked_mul(item_bytes)) .ok_or("QSA eager tile query offset overflow")?; let q = input[0].view(offset, q_len)?; let (part, _scores, _scratch) = qsa_eager_rank( [&q, input[1]], q_strides, pooled_t_strides, QsaSelectPlan { rows: len, pos: plan.pos + start, ..plan }, &valid, &tie, &neg, )?; // mx.eval(top_t) completes before constructing the next tile. // Keep only the evaluated ArgPartition view/backing in parts; // score intermediates are not retained for the entire query chunk. if let Some(result) = encoder::with_active(|encoder| encoder.synchronize()) { result?; } else { commands .as_deref_mut() .ok_or("QSA eager eval requires an active command owner")? .eval_boundary()?; } parts.push((part, len)); } let indices = Buffer::mtplx_bytes(u64::from(rows) * u64::from(width) * 4)?; let mut start = 0; let mut temporary = Vec::new(); let concurrent = encoder::concurrent_scope(); for (part, len) in parts { let dst = indices.view( u64::from(start) * u64::from(width) * 4, u64::from(len) * u64::from(width) * 4, )?; qsa_copy_typed( Some(&part), &dst, [1, len, width], [0, u64::from(blocks), 1], [0, u64::from(width), 1], "uint32", (len) as usize * (width) as usize, )?; temporary.push(part); start += len; } drop(concurrent); // Global valid is a different lazy expression from valid_t; evaluate // it for the epilogue after the per-tile evals, as in the reference. let valid = qsa_eager_valid(&blk, &complete, rows, blocks)?; (indices, valid, None, temporary) } else { let valid = qsa_eager_valid(&blk, &complete, rows, blocks)?; let (indices, scores, temporary) = qsa_eager_rank(input, q_strides, pooled_t_strides, plan, &valid, &tie, &neg)?; (indices, valid, Some(scores), temporary) }; temporary.extend([blk, tie, one, ratio, tie_scale, neg]); Ok(QsaEagerTopk { rows, pos_start: plan.pos, tiled, indices, valid, masked_scores, positions, complete_blocks: complete, width, row_stride: blocks, index_row_stride: if tiled { width } else { blocks }, _temporaries: temporary, }) } #[cfg(test)] fn qsa_eager_valid( blk: &Buffer, complete: &Buffer, rows: u32, blocks: u32, ) -> Result { let count = rows * blocks; let valid = Buffer::mtplx_bytes(u64::from(count))?; if rows == 1 || blocks == 1 { qsa_vector( if count == 1 { "ss" } else if rows == 1 { "vs" } else { "sv" }, "Lessint32", &[ tensor(0, blk).input(blocks as usize), tensor(1, complete).input(rows as usize), tensor(2, &valid).output(count as usize), bytes(3, &count), ], count, 4, )?; } else { let grid = [blocks, rows, 1]; dispatch_geometry( "g2_Lessint32", &[ tensor(0, blk).input(blocks as usize), tensor(1, complete).input(rows as usize), tensor(2, &valid).output(count as usize), bytes(3, &[0_u64, 1]), bytes(4, &[1_u64, 0]), ], &[], grid, block_dims(grid), true, )?; } Ok(valid) } #[cfg(test)] fn qsa_eager_rank( input: [&Buffer; 2], q_strides: [u64; 3], pooled_t_strides: [u64; 2], plan: QsaSelectPlan, valid: &Buffer, tie: &Buffer, neg: &Buffer, ) -> Result<(Buffer, Buffer, Vec), String> { let rows = plan.rows; let blocks = plan.blocks; let count = rows * blocks; let (scores, mut temporary) = qsa_prefill_f32_scores( input, [rows, blocks], q_strides, pooled_t_strides, !plan.input_f32[0], plan.tf32, )?; qsa_vector( if count == 1 { "v" } else { "vs" }, "Selectfloat32", &[ tensor(0, valid).input(count as usize), tensor(1, &scores).input(count as usize), tensor(2, neg).input(1), tensor(3, &scores).output(count as usize), bytes(4, &count), ], count, 4, )?; if rows == 1 || blocks == 1 { qsa_vector( if count == 1 { "ss" } else if blocks == 1 { "vs" } else { "vv" }, "Subtractfloat32", &[ tensor(0, &scores).input(count as usize), tensor(1, tie).input(blocks as usize), tensor(2, &scores).output(count as usize), bytes(3, &count), ], count, 4, )?; } else { let grid = [blocks, rows, 1]; dispatch_geometry( "g2_Subtractfloat32", &[ tensor(0, &scores).input(count as usize), tensor(1, tie).input(blocks as usize), tensor(2, &scores).output(count as usize), bytes(3, &[u64::from(blocks), 1]), bytes(4, &[0_u64, 1]), ], &[], grid, block_dims(grid), true, )?; } let sorted = Buffer::mtplx_bytes(u64::from(count) * 4)?; temporary.extend(argsort(&scores, &sorted, [rows, blocks], SortDtype::F32)?); let width = plan.topk.min(blocks); let offset = u64::from(blocks - width) * 4; let indices = sorted.view(offset, u64::from(count) * 4 - offset)?; temporary.push(sorted); Ok((indices, scores, temporary)) } /// The eager selector's output switches. `large_prefill` is the common /// phase/rows/earliest-position eligibility decision, also used by the fused /// and compiled selectors; it must not be inferred from rows > 1 alone. pub(super) struct QsaEagerOptions { pub(super) large_prefill: bool, pub(super) flash: bool, pub(super) gather_decode: bool, pub(super) gather: bool, pub(super) gather_max_rows: u32, pub(super) gather_min_context: u32, } #[cfg(test)] pub(super) enum QsaIndexerSelection { Dense(QsaSelection), PrefillBlocks(QsaSelection), FlashBlocks(QsaSelection, u32), DecodeTokens(QsaSelection), RowTokens(QsaSelection), } /// Complete _select_eager return-branch order. Inactive lazy expressions /// (especially the dense scatter mask in flash/gather modes) are not encoded. #[cfg(test)] pub(super) fn qsa_eager_output( top: QsaEagerTopk, total: u32, options: QsaEagerOptions, ) -> Result { if top.pos_start.checked_add(top.rows) != Some(total) || top.row_stride != total / 4 || top.row_stride <= 512 { return Err("invalid active eager selector output frontier".into()); } if top.rows > 1 && options.large_prefill { return qsa_eager_blocks(top).map(QsaIndexerSelection::PrefillBlocks); } if top.rows == 1 && options.flash { let (blocks, tail) = qsa_eager_decode(top, total, false)?; return Ok(QsaIndexerSelection::FlashBlocks(blocks, tail)); } if top.rows == 1 && options.gather_decode { return qsa_eager_decode(top, total, true) .map(|(tokens, _)| QsaIndexerSelection::DecodeTokens(tokens)); } if top.rows > 1 && !top.tiled && options.gather && top.rows <= options.gather_max_rows && total >= options.gather_min_context { return qsa_eager_gather_rows(top).map(QsaIndexerSelection::RowTokens); } qsa_eager_dense(top, total).map(QsaIndexerSelection::Dense) } /// Eager flash_prefill epilogue: chronological int32 blocks, gathered validity, /// then invalid slots replaced by zero. No custom selector substitution. #[cfg(test)] pub(super) fn qsa_eager_blocks(top: QsaEagerTopk) -> Result { let rows = top.rows; let width = top.width; let count = rows .checked_mul(width) .filter(|n| *n > 0 && *n <= i32::MAX as u32) .ok_or("invalid eager QSA block output shape")?; let (sorted, ids) = qsa_eager_sorted_ids(&top)?; let indices64 = Buffer::mtplx_bytes(u64::from(count) * 8)?; let valid = Buffer::mtplx_bytes(u64::from(count))?; let work = if count < 65536 { 1 } else { 2 }; // int64 output has one element per thread even above the vector threshold. dispatch_geometry( "v_copyint32int64", &[ tensor(0, &sorted).input(count as usize), tensor(1, &indices64).output(count as usize), bytes(2, &count), ], &[], [count, 1, 1], [count.min(1024), 1, 1], true, )?; let grid = [1, width, rows]; dispatch_geometry( "kernel_qwen_mtplx_gather_axis_bool_idxi64_int_11", &[ tensor(0, &top.valid).input(rows as usize * top.row_stride as usize), tensor(1, &indices64).input(count as usize), tensor(2, &valid).output(count as usize), bytes(3, &rows), bytes(4, &u64::from(top.row_stride)), bytes(5, &u64::from(width)), bytes(6, &1_u64), bytes(7, &1_u32), bytes(8, &top.row_stride), bytes(9, &1_u64), bytes(10, &1_u64), ], &[], grid, block_dims(grid), true, )?; let zero = scalar_buffer(&0_i32.to_le_bytes())?; dispatch_geometry( &format!( "{}{}_Selectint32", if count == 1 { "v" } else { "vs" }, if work == 1 { "" } else { "n" } ), &[ tensor(0, &valid).input(count as usize), tensor(1, &sorted).input(count as usize), tensor(2, &zero).input(1), tensor(3, &sorted).output(count as usize), bytes(4, &count), ], &[], [count.div_ceil(work), 1, 1], [count.div_ceil(work).min(1024), 1, 1], true, )?; let mut temporary = top._temporaries; temporary.extend(top.masked_scores); temporary.extend([ ids, indices64, top.indices, top.valid, top.positions, top.complete_blocks, ]); Ok(QsaSelection { outputs: vec![sorted, valid], row_widths: vec![(width, 4), (width, 1)], row_strides: vec![width; 2], _temporaries: temporary, }) } #[cfg(test)] fn qsa_eager_sorted_ids(top: &QsaEagerTopk) -> Result<(Buffer, Buffer), String> { let width = top.width; let rows = top.rows; let ids = qsa_eager_cast_indices(top, "int32", 4)?; let sorted = Buffer::mtplx_bytes(u64::from(rows) * u64::from(width) * 4)?; let bn = width.div_ceil(4).next_power_of_two().clamp(32, 512); let segment = if rows == 1 { i32::MAX as u32 } else { width }; dispatch( &format!("c_block_sort_int32_int32_bn{bn}_tn4"), &[ tensor(0, &ids).input(rows as usize * width as usize), tensor(1, &sorted).output(rows as usize * width as usize), bytes(2, &width), bytes(3, &1_u32), bytes(4, &1_u32), bytes(5, &segment), bytes(6, &segment), ], [1, rows, 1], [bn, 1, 1], )?; Ok((sorted, ids)) } /// Untiled eager decode epilogues. The dead selected-mask expression in the /// Python source is not evaluated by these lazy output branches. #[cfg(test)] pub(super) fn qsa_eager_decode( top: QsaEagerTopk, total: u32, gather: bool, ) -> Result<(QsaSelection, u32), String> { if top.rows != 1 || top.pos_start.checked_add(1) != Some(total) || total / 4 != top.row_stride || top.row_stride <= 512 { return Err("invalid active QSA eager decode frontier".into()); } let tail_start = total / 4 * 4; let k = top.width; let (sorted, cast) = qsa_eager_sorted_ids(&top)?; let mut temporary = top._temporaries; temporary.extend(top.masked_scores); temporary.extend([ cast, top.indices, top.valid, top.positions, top.complete_blocks, ]); let (out, width) = if !gather { (sorted, k) } else { let ratio = scalar_buffer(&4_i32.to_le_bytes())?; qsa_vector( "vs", "Multiplyint32", &[ tensor(0, &sorted).input(k as usize), tensor(1, &ratio).input(1), tensor(2, &sorted).output(k as usize), bytes(3, &k), ], k, 4, )?; let ratio_range = Buffer::mtplx_bytes(16)?; dispatch_geometry( "arangeint32", &[ bytes(0, &0_u32), bytes(1, &1_u32), tensor(2, &ratio_range).output(4), ], &[], [4, 1, 1], [4, 1, 1], true, )?; let block_tokens = Buffer::mtplx_bytes(u64::from(k) * 16)?; let grid = [4, k, 1]; dispatch_geometry( "g2_Addint32", &[ tensor(0, &sorted).input(k as usize), tensor(1, &ratio_range).input(4), tensor(2, &block_tokens).output(k as usize * 4), bytes(3, &[1_u64, 0]), bytes(4, &[0_u64, 1]), ], &[], grid, block_dims(grid), true, )?; let tail_len = total - tail_start; let width = k * 4 + tail_len; let tail = if tail_len > 0 { let tail = Buffer::mtplx_bytes(u64::from(tail_len) * 4)?; dispatch_geometry( "arangeint32", &[ bytes(0, &tail_start), bytes(1, &1_u32), tensor(2, &tail).output(tail_len as usize), ], &[], [tail_len, 1, 1], [tail_len, 1, 1], true, )?; Some(tail) } else { None }; let out = Buffer::mtplx_bytes(u64::from(width) * 4)?; let concurrent = encoder::concurrent_scope(); qsa_copy_typed( Some(&block_tokens), &out, [1, 1, k * 4], [0, 0, 1], [0, 0, 1], "int32", (k * 4) as usize, )?; if let Some(tail) = tail { let dst = out.view(u64::from(k) * 16, u64::from(tail_len) * 4)?; qsa_copy_typed( Some(&tail), &dst, [1, 1, tail_len], [0, 0, 1], [0, 0, 1], "int32", (tail_len) as usize, )?; temporary.push(tail); } drop(concurrent); temporary.extend([sorted, ratio, ratio_range, block_tokens]); (out, width) }; Ok(( QsaSelection { outputs: vec![out], row_widths: vec![(width, 4)], row_strides: vec![width], _temporaries: temporary, }, tail_start, )) } #[cfg(test)] fn qsa_eager_cast_indices( top: &QsaEagerTopk, dtype: &str, bytes_per_item: u32, ) -> Result { let count = top.rows * top.width; let input_size = (top.rows as usize - 1) * top.index_row_stride as usize + top.width as usize; let output = Buffer::mtplx_bytes(u64::from(count) * u64::from(bytes_per_item))?; if top.rows == 1 || top.width == top.index_row_stride { qsa_vector( "v", &format!("copyuint32{dtype}"), &[ tensor(0, &top.indices).input(input_size), tensor(1, &output).output(count as usize), bytes(2, &count), ], count, bytes_per_item, )?; } else { let grid = [top.width, top.rows, 1]; dispatch_geometry( &format!("g2_copyuint32{dtype}"), &[ tensor(0, &top.indices).input(input_size), tensor(1, &output).output(count as usize), bytes(3, &[u64::from(top.index_row_stride), 1]), ], &[], grid, block_dims(grid), true, )?; } Ok(output) } /// _select_eager's rows-gather epilogue. Keeps argsort order (unlike the /// chronological flash block contract), then appends each row's visible tail. #[cfg(test)] pub(super) fn qsa_eager_gather_rows(top: QsaEagerTopk) -> Result { let rows = top.rows; let k = top.width; let count = rows * k; let width = k * 4 + 4; if rows <= 1 || top.row_stride <= 512 || rows.checked_mul(width).is_none_or(|n| n > i32::MAX as u32) { return Err("invalid active QSA gather-rows geometry".into()); } let idx64 = qsa_eager_cast_indices(&top, "int64", 8)?; let blk_ok = Buffer::mtplx_bytes(u64::from(count))?; let grid = [1, k, rows]; dispatch_geometry( "kernel_qwen_mtplx_gather_axis_bool_idxi64_int_11", &[ tensor(0, &top.valid).input(rows as usize * top.row_stride as usize), tensor(1, &idx64).input(count as usize), tensor(2, &blk_ok).output(count as usize), bytes(3, &rows), bytes(4, &u64::from(top.row_stride)), bytes(5, &u64::from(k)), bytes(6, &1_u64), bytes(7, &1_u32), bytes(8, &top.row_stride), bytes(9, &1_u64), bytes(10, &1_u64), ], &[], grid, block_dims(grid), true, )?; let idx32 = qsa_eager_cast_indices(&top, "int32", 4)?; let ratio = scalar_buffer(&4_i32.to_le_bytes())?; qsa_vector( "vs", "Multiplyint32", &[ tensor(0, &idx32).input(count as usize), tensor(1, &ratio).input(1), tensor(2, &idx32).output(count as usize), bytes(3, &count), ], count, 4, )?; let ratio_range = Buffer::mtplx_bytes(16)?; dispatch_geometry( "arangeint32", &[ bytes(0, &0_u32), bytes(1, &1_u32), tensor(2, &ratio_range).output(4), ], &[], [4, 1, 1], [4, 1, 1], true, )?; let tokens = Buffer::mtplx_bytes(u64::from(count) * 16)?; let blocks_ok = Buffer::mtplx_bytes(u64::from(count) * 4)?; let grid = [4, count, 1]; dispatch_geometry( "g2_Addint32", &[ tensor(0, &idx32).input(count as usize), tensor(1, &ratio_range).input(4), tensor(2, &tokens).output(count as usize * 4), bytes(3, &[1_u64, 0]), bytes(4, &[0_u64, 1]), ], &[], grid, block_dims(grid), true, )?; dispatch_geometry( "g2_copybool_bool_", &[ tensor(0, &blk_ok).input(count as usize), tensor(1, &blocks_ok).output(count as usize * 4), bytes(3, &[1_u64, 0]), ], &[], grid, block_dims(grid), true, )?; let tail_start = top.complete_blocks; let tail_ratio = scalar_buffer(&4_i32.to_le_bytes())?; qsa_vector( "vs", "Multiplyint32", &[ tensor(0, &tail_start).input(rows as usize), tensor(1, &tail_ratio).input(1), tensor(2, &tail_start).output(rows as usize), bytes(3, &rows), ], rows, 4, )?; let tail_range = Buffer::mtplx_bytes(16)?; dispatch_geometry( "arangeint32", &[ bytes(0, &0_u32), bytes(1, &1_u32), tensor(2, &tail_range).output(4), ], &[], [4, 1, 1], [4, 1, 1], true, )?; let tail_tokens = Buffer::mtplx_bytes(u64::from(rows) * 16)?; let tail_ok = Buffer::mtplx_bytes(u64::from(rows) * 4)?; let grid = [4, rows, 1]; dispatch_geometry( "g2_Addint32", &[ tensor(0, &tail_start).input(rows as usize), tensor(1, &tail_range).input(4), tensor(2, &tail_tokens).output(rows as usize * 4), bytes(3, &[1_u64, 0]), bytes(4, &[0_u64, 1]), ], &[], grid, block_dims(grid), true, )?; dispatch_geometry( "g2_LessEqualint32", &[ tensor(0, &tail_tokens).input(rows as usize * 4), tensor(1, &top.positions).input(rows as usize), tensor(2, &tail_ok).output(rows as usize * 4), bytes(3, &[4_u64, 1]), bytes(4, &[1_u64, 0]), ], &[], grid, block_dims(grid), true, )?; let ids = Buffer::mtplx_bytes(u64::from(rows) * u64::from(width) * 4)?; let valid = Buffer::mtplx_bytes(u64::from(rows) * u64::from(width))?; for (block, tail, out, dtype, b) in [ (&tokens, &tail_tokens, &ids, "int32", 4_u64), (&blocks_ok, &tail_ok, &valid, "bool_", 1), ] { let _concurrent = encoder::concurrent_scope(); qsa_copy_typed( Some(block), out, [1, rows, k * 4], [0, u64::from(k) * 4, 1], [0, u64::from(width), 1], dtype, (rows) as usize * (k * 4) as usize, )?; let offset = u64::from(k) * 4 * b; let dst = out.view(offset, u64::from(rows) * u64::from(width) * b - offset)?; qsa_copy_typed( Some(tail), &dst, [1, rows, 4], [0, 4, 1], [0, u64::from(width), 1], dtype, (rows) as usize * 4, )?; } let count = rows * width; let zero = scalar_buffer(&0_i32.to_le_bytes())?; qsa_vector( "vs", "Selectint32", &[ tensor(0, &valid).input(count as usize), tensor(1, &ids).input(count as usize), tensor(2, &zero).input(1), tensor(3, &ids).output(count as usize), bytes(4, &count), ], count, 4, )?; let mut temporary = top._temporaries; temporary.extend(top.masked_scores); temporary.extend([ idx64, idx32, blk_ok, blocks_ok, ratio, ratio_range, tail_ratio, tail_range, tokens, tail_start, tail_tokens, tail_ok, top.indices, top.valid, top.positions, ]); Ok(QsaSelection { outputs: vec![ids, valid], row_widths: vec![(width, 4), (width, 1)], row_strides: vec![width; 2], _temporaries: temporary, }) } /// Remaining dense-mask epilogue of _select_eager, after the active indexer /// threshold (N>512). Uses original ScatterAxis/Repeat/Concatenate operations. #[cfg(test)] pub(super) fn qsa_eager_dense(top: QsaEagerTopk, total: u32) -> Result { let rows = top.rows; let blocks = top.row_stride; if blocks <= 512 || total / 4 != blocks || top.pos_start.checked_add(rows) != Some(total) || total > i32::MAX as u32 || rows.checked_mul(total).is_none_or(|n| n > i32::MAX as u32) { return Err("invalid active QSA dense-mask geometry".into()); } let k = top.width; let index_count = rows * k; let count = rows * blocks; let indices64 = qsa_eager_cast_indices(&top, "int64", 8)?; let selected = Buffer::mtplx_bytes(u64::from(count))?; let zero = scalar_buffer(&[0_u8])?; let one = scalar_buffer(&[1_u8])?; qsa_vector( "s", "copybool_bool_", &[ tensor(0, &zero).input(1), tensor(1, &selected).output(count as usize), bytes(2, &count), ], count, 1, )?; let grid = [1, k, rows]; dispatch_geometry( if index_count == 1 { "kernel_qwen_mtplx_scatter_axis_bool_idxi64_int_11" } else { "kernel_qwen_mtplx_scatter_axis_bool_idxi64_int_01" }, &[ tensor(0, &one).input(1), tensor(1, &indices64).input(index_count as usize), tensor(2, &selected).output(count as usize), bytes(3, &rows), bytes(4, &0_u64), bytes(5, &u64::from(k)), bytes(6, &1_u64), bytes(7, &1_u32), bytes(8, &blocks), bytes(9, &0_u64), bytes(10, &1_u64), ], &[], grid, block_dims(grid), true, )?; qsa_vector( "vv", "BitwiseAndbool_", &[ tensor(0, &selected).input(count as usize), tensor(1, &top.valid).input(count as usize), tensor(2, &selected).output(count as usize), bytes(3, &count), ], count, 1, )?; // repeat inserts a broadcast axis and its final reshape is a General copy. let repeated = Buffer::mtplx_bytes(u64::from(count) * 4)?; let grid = [4, count, 1]; dispatch_geometry( "g2_copybool_bool_", &[ tensor(0, &selected).input(count as usize), tensor(1, &repeated).output(count as usize * 4), bytes(3, &[1_u64, 0]), ], &[], grid, block_dims(grid), true, )?; let mut temporary = top._temporaries; temporary.extend(top.masked_scores); let mask = if total == blocks * 4 { repeated } else { let pad_count = rows * (total - blocks * 4); let pad = Buffer::mtplx_bytes(u64::from(pad_count))?; let pad_zero = scalar_buffer(&[0_u8])?; qsa_vector( "s", "copybool_bool_", &[ tensor(0, &pad_zero).input(1), tensor(1, &pad).output(pad_count as usize), bytes(2, &pad_count), ], pad_count, 1, )?; let padded = Buffer::mtplx_bytes(u64::from(rows) * u64::from(total))?; let concurrent = encoder::concurrent_scope(); qsa_copy_typed( Some(&repeated), &padded, [1, rows, blocks * 4], [0, u64::from(blocks) * 4, 1], [0, u64::from(total), 1], "bool_", (rows) as usize * (blocks * 4) as usize, )?; let tail = padded.view( u64::from(blocks) * 4, u64::from(rows) * u64::from(total) - u64::from(blocks) * 4, )?; qsa_copy_typed( Some(&pad), &tail, [1, rows, total - blocks * 4], [0, u64::from(total - blocks * 4), 1], [0, u64::from(total), 1], "bool_", (rows) as usize * (total - blocks * 4) as usize, )?; drop(concurrent); temporary.extend([repeated, pad, pad_zero]); padded }; let tpos = Buffer::mtplx_bytes(u64::from(total) * 4)?; dispatch_geometry( "arangeint32", &[ bytes(0, &0_u32), bytes(1, &1_i32), tensor(2, &tpos).output(total as usize), ], &[], [total, 1, 1], [total.min(1024), 1, 1], true, )?; let tail_start = top.complete_blocks; let ratio = scalar_buffer(&4_i32.to_le_bytes())?; qsa_vector( if rows == 1 { "ss" } else { "vs" }, "Multiplyint32", &[ tensor(0, &tail_start).input(rows as usize), tensor(1, &ratio).input(1), tensor(2, &tail_start).output(rows as usize), bytes(3, &rows), ], rows, 4, )?; let count = rows * total; let tail = Buffer::mtplx_bytes(u64::from(count))?; let causal = Buffer::mtplx_bytes(u64::from(count))?; for (op, rhs, out) in [ ("GreaterEqualint32", &tail_start, &tail), ("LessEqualint32", &top.positions, &causal), ] { if rows == 1 { qsa_vector( "vs", op, &[ tensor(0, &tpos).input(total as usize), tensor(1, rhs).input(rows as usize), tensor(2, out).output(count as usize), bytes(3, &count), ], count, 4, )?; } else { let grid = [total, rows, 1]; dispatch_geometry( &format!("g2_{op}"), &[ tensor(0, &tpos).input(total as usize), tensor(1, rhs).input(rows as usize), tensor(2, out).output(count as usize), bytes(3, &[0_u64, 1]), bytes(4, &[1_u64, 0]), ], &[], grid, block_dims(grid), true, )?; } } qsa_vector( "vv", "BitwiseOrbool_", &[ tensor(0, &mask).input(count as usize), tensor(1, &tail).input(count as usize), tensor(2, &mask).output(count as usize), bytes(3, &count), ], count, 1, )?; qsa_vector( "vv", "BitwiseAndbool_", &[ tensor(0, &mask).input(count as usize), tensor(1, &causal).input(count as usize), tensor(2, &mask).output(count as usize), bytes(3, &count), ], count, 1, )?; temporary.extend([ selected, zero, one, ratio, indices64, tpos, tail_start, tail, causal, top.indices, top.valid, top.positions, ]); Ok(QsaSelection { outputs: vec![mask], row_widths: vec![(total, 1)], row_strides: vec![total], _temporaries: temporary, }) } /// Original TensorOps score producer, not a replacement QMM implementation. #[cfg(test)] pub(super) fn qsa_prefill_mpp_scores( [q, pooled]: [&Buffer; 2], [rows, blocks]: [u32; 2], q_strides: [u64; 3], pooled_strides: [u64; 2], ) -> Result { let tiles = rows .div_ceil(16) .checked_mul(blocks.div_ceil(32)) .and_then(|n| n.checked_mul(128)); if rows == 0 || blocks == 0 || rows > i32::MAX as u32 / 512 || blocks > i32::MAX as u32 || tiles.is_none() { return Err("invalid QSA MPP score geometry".into()); } for (b, shape, strides) in [ (q, [rows, 4, 128], q_strides), ( pooled, [1, blocks, 128], [0, pooled_strides[0], pooled_strides[1]], ), ] { let span = shape .into_iter() .zip(strides) .try_fold(1_u64, |n, (d, s)| { u64::from(d - 1) .checked_mul(s) .and_then(|v| n.checked_add(v)) }) .and_then(|n| n.checked_mul(2)); if span.is_none_or(|n| unsafe { ds4_gpu_tensor_bytes(b.raw()) } < n) { return Err("QSA MPP input outside backing".into()); } } use array::{Array, Dtype}; let inputs = [ buffer_array( q, &[1, rows as i32, 4, 128], &[0, q_strides[0], q_strides[1], q_strides[2]], Dtype::BF16, )?, buffer_array( pooled, &[1, blocks as i32, 128], &[0, pooled_strides[0], pooled_strides[1]], Dtype::BF16, )?, ]; let scores = Array::unallocated(&[rows as i32, blocks as i32], Dtype::F32)?; qsa_prefill::mpp_evaluate(&inputs, &scores)?; let buffer = scores.buffer().view(0, scores.layout().nbytes() as u64)?; Ok(buffer) } #[cfg(test)] impl QsaSelectPlan { fn prefill_plan(self) -> qsa_prefill::TopK { qsa_prefill::TopK { blocks: self.blocks, topk: self.topk, ratio: 4, dense_width: if self.mode == QsaSelectMode::DenseMask { self.dense_width } else { 0 }, mode: self.mode, } } pub(super) fn prefill_source(self) -> Result { self.prefill_plan().prefill_source() } } #[cfg(test)] pub(super) fn qsa_prefill_topk( scores: &Buffer, strides: [u64; 2], plan: QsaSelectPlan, ) -> Result { if plan.rows == 0 || plan.blocks == 0 || plan.rows > i32::MAX as u32 / 512 || !(1..=512).contains(&plan.topk) || plan.total > i32::MAX as u32 || plan .pos .checked_add(plan.rows) .is_none_or(|n| n > plan.total) || plan.logical > plan.blocks || plan.logical != plan.total / 4 || plan .rows .checked_mul(plan.blocks) .is_none_or(|n| n > i32::MAX as u32) || (plan.mode == QsaSelectMode::DenseMask && plan.dense_width < plan.total) { return Err("invalid QSA prefill selector geometry".into()); } let positions = [ scalar_buffer(&plan.pos.to_le_bytes())?, scalar_buffer(&plan.total.to_le_bytes())?, scalar_buffer(&plan.logical.to_le_bytes())?, ]; let mut out = qsa_prefill_topk_device( scores, strides, plan, [&positions[0], &positions[1], &positions[2]], )?; out._temporaries.extend(positions); Ok(out) } /// Original prefill top-k with moving frontiers kept on the GPU. #[cfg(test)] pub(super) fn qsa_prefill_topk_device( scores: &Buffer, strides: [u64; 2], plan: QsaSelectPlan, [pos, total, logical]: [&Buffer; 3], ) -> Result { if plan.rows == 0 || plan.blocks == 0 || plan.rows > i32::MAX as u32 / 512 || !(1..=512).contains(&plan.topk) || plan .rows .checked_mul(plan.blocks) .is_none_or(|n| n > i32::MAX as u32) || [pos, total, logical] .into_iter() .any(|b| unsafe { ds4_gpu_tensor_bytes(b.raw()) } < 4) { return Err("invalid QSA device prefill geometry or leaves".into()); } let span = u64::from(plan.rows - 1) .checked_mul(strides[0]) .and_then(|n| { u64::from(plan.blocks - 1) .checked_mul(strides[1]) .and_then(|m| n.checked_add(m)) }) .and_then(|n| n.checked_add(1)) .and_then(|n| n.checked_mul(4)); if span.is_none_or(|n| unsafe { ds4_gpu_tensor_bytes(scores.raw()) } < n) { return Err("QSA score view outside backing".into()); } use array::{Array, Dtype}; let inputs = [ buffer_array( scores, &[plan.rows as i32, plan.blocks as i32], &strides, Dtype::F32, )?, Array::new(&[1], Dtype::I32, pos.view(0, 4)?)?, Array::new(&[1], Dtype::I32, total.view(0, 4)?)?, Array::new(&[1], Dtype::I32, logical.view(0, 4)?)?, ]; let kernel = plan.prefill_plan(); let outputs = kernel .layouts(plan.rows as i32)? .into_iter() .map(|l| Array::unallocated(l.shape(), l.dtype())) .collect::, _>>()?; qsa_prefill::topk_evaluate(&inputs, &outputs, kernel)?; let outputs = outputs .iter() .map(|a| a.buffer().view(0, a.layout().nbytes() as u64)) .collect::, _>>()?; let widths = plan.widths(); Ok(QsaSelection { outputs, row_strides: widths.iter().map(|(w, _)| *w).collect(), row_widths: widths, _temporaries: Vec::new(), }) } /// qsa_indexer_prefill_metal on M5: BF16 pairs select TensorOps, otherwise the /// general FP32 expression. Dispatch failures never switch producers. #[cfg(test)] pub(super) fn qsa_prefill( input: [&Buffer; 2], q_strides: [u64; 3], pooled_strides: [u64; 2], plan: QsaSelectPlan, workspace: u64, ) -> Result { if plan.rows <= 1 || plan.rows > i32::MAX as u32 / 512 || plan .pos .checked_add(plan.rows) .is_none_or(|n| n > plan.total) || plan.logical > plan.blocks || plan.logical != plan.total / 4 || !(1..=512).contains(&plan.topk) { return Err("invalid QSA prefill input".into()); } let mpp = plan.input_f32 == [false; 2]; let chunk_rows = qsa_prefill_chunk_rows(plan.rows, plan.blocks, workspace, 32, mpp)?; let mut pooled_s = [0, pooled_strides[0], pooled_strides[1]]; let pooled_cast = if !mpp && !plan.input_f32[1] { Some(qsa_cast_f32( input[1], [1, plan.blocks, 128], &mut pooled_s, )?) } else { None }; let pooled = pooled_cast.as_ref().unwrap_or(input[1]); let mut chunks = Vec::new(); for start in (0..plan.rows).step_by(chunk_rows as usize) { let rows = chunk_rows.min(plan.rows - start); let offset = u64::from(start) .checked_mul(q_strides[0]) .and_then(|n| n.checked_mul(if plan.input_f32[0] { 4 } else { 2 })) .ok_or("QSA prefill offset overflow")?; let bytes = unsafe { ds4_gpu_tensor_bytes(input[0].raw()) } .checked_sub(offset) .ok_or("QSA prefill slice outside backing")?; let q = input[0].view(offset, bytes)?; let (scores, scratch) = if mpp { ( qsa_prefill_mpp_scores( [&q, pooled], [rows, plan.blocks], q_strides, pooled_strides, )?, Vec::new(), ) } else { qsa_prefill_f32_scores( [&q, pooled], [rows, plan.blocks], q_strides, [pooled_s[2], pooled_s[1]], !plan.input_f32[0], plan.tf32, )? }; let mut selected = qsa_prefill_topk( &scores, [u64::from(plan.blocks), 1], QsaSelectPlan { rows, pos: plan.pos + start, ..plan }, )?; selected._temporaries.push(scores); selected._temporaries.extend(scratch); chunks.push(selected); } let mut selected = qsa_concat_selection(chunks, plan, chunk_rows)?; selected._temporaries.extend(pooled_cast); Ok(selected) } #[cfg(test)] pub(super) fn qsa_prefill_cached( cache: &QsaCache, prepared_q: &Buffer, rows: u32, mode: QsaSelectMode, workspace: u64, ) -> Result { let total = cache .offset .checked_add(rows) .ok_or("QSA prefill cache position overflow")?; let logical = total / 4; if cache.pooled_len < logical { return Err("QSA prefill needs complete pooled keys".into()); } let pooled = cache .pooled .as_ref() .ok_or("QSA prefill needs pooled backing")?; // The large-prefill branch receives _extend_pooled's logical slice, not // the reserved cache capacity used by the legacy decode selector. qsa_prefill( [prepared_q, &pooled.buffer()], [512, 128, 1], [128, 1], QsaSelectPlan { rows, blocks: logical, topk: 512, pos: cache.offset, total, logical, dense_width: total, mode, tf32: true, input_f32: [false; 2], }, workspace, ) } #[cfg(test)] pub(super) fn qsa_select_cached( cache: &QsaCache, prepared_q: &Buffer, rows: u32, mode: QsaSelectMode, tf32: bool, ) -> Result { let total = cache .offset .checked_add(rows) .ok_or("QSA cache position overflow")?; if cache.pooled_len < total / 4 { return Err("QSA selector needs complete pooled keys".into()); } let pooled = cache .pooled .as_ref() .ok_or("QSA selector needs pooled backing")?; qsa_select_chunked( [prepared_q, &pooled.buffer()], [512, 128, 1], [128, 1], QsaSelectPlan { rows, blocks: cache.pooled_cap, topk: 512, pos: cache.offset, total, logical: total / 4, dense_width: 0, mode, tf32, input_f32: [false; 2], }, ) } /// Original eager _rope_cos_sin + _apply_partial_rope, for normalized BF16 /// QSA queries (H4) or pooled keys (H1). Every cast/concat stays explicit. #[cfg(test)] fn qsa_eager_rope( normalized: Buffer, freq: &Buffer, [rows, heads]: [u32; 2], [position, position_scale]: [i32; 2], attention_scale: f32, ) -> Result<(Buffer, Vec), String> { let count = rows * heads * 64; let positions = Buffer::mtplx_bytes(u64::from(rows) * 4)?; dispatch_geometry( "arangeint32", &[ bytes(0, &position), bytes(1, &1_i32), tensor(2, &positions).output(rows as usize), ], &[], [rows, 1, 1], [rows.min(1024), 1, 1], true, )?; if position_scale != 1 { let scale = scalar_buffer(&position_scale.to_le_bytes())?; qsa_vector( if rows == 1 { "ss" } else { "vs" }, "Multiplyint32", &[ tensor(0, &positions).input(rows as usize), tensor(1, &scale).input(1), tensor(2, &positions).output(rows as usize), bytes(3, &rows), ], rows, 4, )?; } let fp_positions = Buffer::mtplx_bytes(u64::from(rows) * 4)?; qsa_vector( "v", "copyint32float32", &[ tensor(0, &positions).input(rows as usize), tensor(1, &fp_positions).output(rows as usize), bytes(2, &rows), ], rows, 4, )?; let angles = Buffer::mtplx_bytes(u64::from(rows) * 32 * 4)?; if rows == 1 { qsa_vector( "sv", "Multiplyfloat32", &[ tensor(0, &fp_positions).input(rows as usize), tensor(1, freq).input(32), tensor(2, &angles).output(rows as usize * 32), bytes(3, &32_u32), ], 32, 4, )?; } else { let grid = [32, rows, 1]; dispatch_geometry( "g2_Multiplyfloat32", &[ tensor(0, &fp_positions).input(rows as usize), tensor(1, freq).input(32), tensor(2, &angles).output(rows as usize * 32), bytes(3, &[1_u64, 0]), bytes(4, &[0_u64, 1]), ], &[], grid, block_dims(grid), true, )?; } let emb = Buffer::mtplx_bytes(u64::from(rows) * 64 * 4)?; let concurrent = encoder::concurrent_scope(); for offset in [0, 32 * 4] { let dst = emb.view(offset, (u64::from(rows) * 64 - 32) * 4)?; qsa_copy_typed( Some(&angles), &dst, [1, rows, 32], [0, 32, 1], [0, 64, 1], "float32", (rows) as usize * 32, )?; } drop(concurrent); let cosine = Buffer::mtplx_bytes(u64::from(rows) * 64 * 4)?; let sine = Buffer::mtplx_bytes(u64::from(rows) * 64 * 4)?; for (op, out) in [("Cosfloat32float32", &cosine), ("Sinfloat32float32", &sine)] { qsa_vector( "v", op, &[ tensor(0, &emb).input(rows as usize * 64), tensor(1, out).output(rows as usize * 64), bytes(2, &(rows * 64)), ], rows * 64, 4, )?; if attention_scale != 1.0 { let scale = scalar_buffer(&attention_scale.to_le_bytes())?; qsa_vector( "vs", "Multiplyfloat32", &[ tensor(0, out).input(rows as usize * 64), tensor(1, &scale).input(1), tensor(2, out).output(rows as usize * 64), bytes(3, &(rows * 64)), ], rows * 64, 4, )?; } } let norm_bytes = u64::from(rows) * u64::from(heads) * 128 * 2; let x2 = normalized.view(32 * 2, norm_bytes - 32 * 2)?; let negative = Buffer::mtplx_bytes(u64::from(rows) * u64::from(heads) * 32 * 2)?; if rows * heads == 1 { qsa_vector( "v", "Negativebfloat16bfloat16", &[ tensor(0, &x2).input(((rows * heads - 1) * 128 + 32) as usize), tensor(1, &negative).output(rows as usize * heads as usize * 32), bytes(2, &32_u32), ], 32, 2, )?; } else { let grid = [32, rows * heads, 1]; dispatch_geometry( "gn1_Negativebfloat16bfloat16", &[ tensor(0, &x2).input(((rows * heads - 1) * 128 + 32) as usize), tensor(1, &negative).output(rows as usize * heads as usize * 32), bytes(2, &[rows * heads, 32]), bytes(3, &[128_u64, 1]), bytes(4, &2_u32), ], &[], grid, block_dims(grid), true, )?; } let rotated = Buffer::mtplx_bytes(u64::from(count) * 2)?; let concurrent = encoder::concurrent_scope(); for (src, stride, offset) in [(&negative, 32_u64, 0), (&normalized, 128, 32 * 2)] { let dst = rotated.view(offset, u64::from(count) * 2 - offset)?; qsa_copy_typed( Some(src), &dst, [1, rows * heads, 32], [0, stride, 1], [0, 64, 1], "bfloat16", (rows * heads) as usize * 32, )?; } drop(concurrent); let mut norm_strides = [u64::from(heads) * 128, 128, 1]; let x_float = qsa_cast_f32(&normalized, [rows, heads, 64], &mut norm_strides)?; let rotated_float = Buffer::mtplx_bytes(u64::from(count) * 4)?; cast_bf16_f32(&rotated, &rotated_float, count, true)?; for (x, table) in [(&x_float, &cosine), (&rotated_float, &sine)] { if heads == 1 { qsa_vector( "vv", "Multiplyfloat32", &[ tensor(0, x).input(count as usize), tensor(1, table).input(rows as usize * 64), tensor(2, x).output(count as usize), bytes(3, &count), ], count, 4, )?; } else if rows == 1 { let grid = [64, heads, 1]; dispatch_geometry( "g2_Multiplyfloat32", &[ tensor(0, x).input(count as usize), tensor(1, table).input(rows as usize * 64), tensor(2, x).output(count as usize), bytes(3, &[64_u64, 1]), bytes(4, &[0_u64, 1]), ], &[], grid, block_dims(grid), true, )?; } else { let grid = [64, heads, rows]; dispatch_geometry( "g3_Multiplyfloat32", &[ tensor(0, x).input(count as usize), tensor(1, table).input(rows as usize * 64), tensor(2, x).output(count as usize), bytes(3, &[u64::from(heads) * 64, 64, 1]), bytes(4, &[64_u64, 0, 1]), ], &[], grid, block_dims(grid), true, )?; } } qsa_vector( "vv", "Addfloat32", &[ tensor(0, &x_float).input(count as usize), tensor(1, &rotated_float).input(count as usize), tensor(2, &x_float).output(count as usize), bytes(3, &count), ], count, 4, )?; let rope = Buffer::mtplx_bytes(u64::from(count) * 2)?; cast_bf16_f32(&x_float, &rope, count, false)?; let output = Buffer::mtplx_bytes(norm_bytes)?; let pass = normalized.view(64 * 2, norm_bytes - 64 * 2)?; let concurrent = encoder::concurrent_scope(); for (src, stride, offset) in [(&rope, 64_u64, 0), (&pass, 128, 64 * 2)] { let dst = output.view(offset, norm_bytes - offset)?; qsa_copy_typed( Some(src), &dst, [1, rows * heads, 64], [0, stride, 1], [0, 128, 1], "bfloat16", (rows * heads) as usize * 64, )?; } drop(concurrent); Ok(( output, vec![ normalized, positions, fp_positions, angles, emb, cosine, sine, negative, rotated, x_float, rotated_float, rope, ], )) } #[cfg(test)] pub(super) fn qsa_prepare_queries_eager( [input, norm, freq]: [&Buffer; 3], rows: u32, strides: [u64; 3], position: i32, ) -> Result<(Buffer, Vec), String> { let span = u64::from(rows.saturating_sub(1)) .checked_mul(strides[0]) .and_then(|n| n.checked_add(3_u64.checked_mul(strides[1])?)) .and_then(|n| n.checked_add(127_u64.checked_mul(strides[2])?)) .and_then(|n| n.checked_add(1)) .and_then(|n| n.checked_mul(2)); if rows == 0 || rows > i32::MAX as u32 / 512 || position.checked_add(rows as i32 - 1).is_none() || span.is_none_or(|n| unsafe { ds4_gpu_tensor_bytes(input.raw()) } < n) || unsafe { ds4_gpu_tensor_bytes(freq.raw()) } < 128 { return Err("invalid eager QSA query preparation".into()); } // RMSNorm::eval_gpu materializes noncontiguous projection slices, then // donates that copy to its output. A contiguous caller input is borrowed. let copied = if strides[2] != 1 || strides[1] != 128 || (rows > 1 && strides[0] != 512) { Some(qsa_copy_general( input, [rows, 4, 128], strides, "bfloat16", "bfloat16", 2, )?) } else { None }; let normalized = if let Some(copy) = copied { rms_norm_bf16(©, Some(norm), ©, [rows * 4, 128], 1e-6)?; copy } else { let out = Buffer::mtplx_bytes(u64::from(rows) * 512 * 2)?; rms_norm_bf16(input, Some(norm), &out, [rows * 4, 128], 1e-6)?; out }; qsa_eager_rope(normalized, freq, [rows, 4], [position, 1], 1.0) } #[cfg(test)] pub(super) fn qsa_pool_keys_eager( [input, norm, freq]: [&Buffer; 3], blocks: u32, [row_stride, dim_stride]: [u64; 2], start: i32, ) -> Result<(Buffer, Vec), String> { if blocks == 0 || blocks > i32::MAX as u32 / 512 || start .checked_add(blocks as i32 - 1) .and_then(|n| n.checked_mul(4)) .is_none() || unsafe { ds4_gpu_tensor_bytes(freq.raw()) } < 128 { return Err("invalid eager QSA pooling".into()); } let mut strides = [ row_stride .checked_mul(4) .ok_or("QSA pool stride overflow")?, row_stride, dim_stride, ]; let fresh = qsa_cast_f32(input, [blocks, 4, 128], &mut strides)?; if strides != [512, 128, 1] { return Err("unsupported eager pool physical layout".into()); } let sum = Buffer::mtplx_bytes(u64::from(blocks) * 128 * 4)?; let ndim = u32::from(blocks > 1); dispatch( "col_reduce_small_1_reduce_sumfloat32", &[ tensor(0, &fresh).input(blocks as usize * 512), tensor(1, &sum).output(blocks as usize * 128), bytes(2, &4_u64), bytes(3, &128_u64), bytes(4, &if blocks > 1 { blocks } else { 0 }), bytes(5, &if blocks > 1 { 512_u64 } else { 0 }), bytes(6, &ndim), bytes(7, &4_u32), bytes(8, &128_u64), bytes(9, &1_u32), bytes(10, &1_u64), ], [1, blocks, 1], [32, 4, 1], )?; let count = blocks * 128; let mean_scale = scalar_buffer(&0.25_f32.to_le_bytes())?; qsa_vector( "vs", "Multiplyfloat32", &[ tensor(0, &sum).input(count as usize), tensor(1, &mean_scale).input(1), tensor(2, &sum).output(count as usize), bytes(3, &count), ], count, 4, )?; let pooled = Buffer::mtplx_bytes(u64::from(count) * 2)?; cast_bf16_f32(&sum, &pooled, count, false)?; rms_norm_bf16(&pooled, Some(norm), &pooled, [blocks, 128], 1e-6)?; let (out, mut temporary) = qsa_eager_rope(pooled, freq, [blocks, 1], [start, 4], 1.0)?; temporary.extend([fresh, sum]); Ok((out, temporary)) } /// Original installed QSA indexer geometry: H4, D128, rotary64, ratio4, /// epsilon1e-6 and attention scaling1. Strides are physical BF16 elements. #[cfg(test)] pub(super) fn qsa_prepare_queries( input: [&Buffer; 3], rows: u32, strides: [u64; 3], pos_start: i32, ) -> Result { if rows == 0 || rows > i32::MAX as u32 / 512 || pos_start.checked_add(rows as i32 - 1).is_none() { return Err("invalid QSA query position".into()); } let pos = scalar_buffer(&pos_start.to_le_bytes())?; qsa_prepare_queries_bound(input, rows, strides, tensor(6, &pos).input(1)) } #[cfg(test)] pub(super) fn qsa_prepare_queries_device( input: [&Buffer; 3], rows: u32, strides: [u64; 3], pos: &Buffer, ) -> Result { if unsafe { ds4_gpu_tensor_bytes(pos.raw()) } < 4 { return Err("invalid QSA device query position".into()); } qsa_prepare_queries_bound(input, rows, strides, tensor(6, pos).input(1)) } #[cfg(test)] fn qsa_prepare_queries_bound( [input, norm, inv_freq]: [&Buffer; 3], rows: u32, [row_stride, head_stride, dim_stride]: [u64; 3], pos_start: Binding<'_>, ) -> Result { let end = u64::from(rows.saturating_sub(1)) .checked_mul(row_stride) .and_then(|n| n.checked_add(3_u64.checked_mul(head_stride)?)) .and_then(|n| n.checked_add(127_u64.checked_mul(dim_stride)?)) .and_then(|n| n.checked_add(1)) .and_then(|n| n.checked_mul(2)); if rows == 0 || rows > i32::MAX as u32 / 512 || dim_stride == 0 || end.is_none_or(|n| unsafe { ds4_gpu_tensor_bytes(input.raw()) } < n) || unsafe { ds4_gpu_tensor_bytes(norm.raw()) } < 128 * 2 || unsafe { ds4_gpu_tensor_bytes(inv_freq.raw()) } < 32 * 4 { return Err("invalid MTPLX QSA query preparation buffers or shape".into()); } let output = Buffer::mtplx_bytes(u64::from(rows) * 512 * 2)?; dispatch( "kernel_qwen_mtplx_qsa_prepare_q_bf16", &[ tensor(0, input).input((end.unwrap() / 2) as usize), bytes(1, &[0_u64, row_stride, head_stride, dim_stride]), tensor(2, norm).input(128), bytes(3, &1_u64), tensor(4, inv_freq).input(32), bytes(5, &1_u64), pos_start, tensor(7, &output).output(rows as usize * 512), ], [rows * 4, 1, 1], [32, 1, 1], )?; Ok(output) } #[cfg(test)] pub(super) fn qsa_pool_keys( inputs: [&Buffer; 3], blocks: u32, strides: [u64; 2], block_start: i32, ) -> Result { if blocks == 0 || blocks > i32::MAX as u32 / 4 || block_start .checked_add(blocks as i32 - 1) .and_then(|n| n.checked_mul(4)) .is_none() { return Err("invalid MTPLX QSA pooled-key position".into()); } let start = scalar_buffer(&block_start.to_le_bytes())?; qsa_pool_keys_bound(inputs, blocks, strides, tensor(6, &start).input(1)) } #[cfg(test)] fn qsa_pool_keys_bound( [input, norm, inv_freq]: [&Buffer; 3], blocks: u32, [row_stride, dim_stride]: [u64; 2], block_start: Binding<'_>, ) -> Result { let tokens = u64::from(blocks) * 4; let end = tokens .saturating_sub(1) .checked_mul(row_stride) .and_then(|n| n.checked_add(127_u64.checked_mul(dim_stride)?)) .and_then(|n| n.checked_add(1)) .and_then(|n| n.checked_mul(2)); if blocks == 0 || tokens > i32::MAX as u64 || dim_stride == 0 || end.is_none_or(|n| unsafe { ds4_gpu_tensor_bytes(input.raw()) } < n) || unsafe { ds4_gpu_tensor_bytes(norm.raw()) } < 128 * 2 || unsafe { ds4_gpu_tensor_bytes(inv_freq.raw()) } < 32 * 4 { return Err("invalid MTPLX QSA pooled-key preparation buffers or shape".into()); } let output = Buffer::mtplx_bytes(u64::from(blocks) * 128 * 2)?; dispatch( "kernel_qwen_mtplx_qsa_pool_k_bf16", &[ tensor(0, input).input((end.unwrap() / 2) as usize), bytes(1, &[0_u64, row_stride, dim_stride]), tensor(2, norm).input(128), bytes(3, &1_u64), tensor(4, inv_freq).input(32), bytes(5, &1_u64), block_start, tensor(7, &output).output(blocks as usize * 128), ], [blocks, 1, 1], [32, 1, 1], )?; Ok(output) } fn qsa_compiled_clamp_name(max_new: u32, max_start: u32) -> String { format!("kernel_qwen_mtplx_qsa_clamp_n{max_new}_p{max_start}") } /// Original compiler's three constant-CSE layouts, with only shape constants /// and the exported symbol specialized. Dynamic frontier leaves stay inputs. pub(super) fn qsa_compiled_clamp_source(max_new: u32, max_start: u32) -> Result { if max_new == 0 || max_new > i32::MAX as u32 || max_start > i32::MAX as u32 { return Err("invalid compiled QSA clamp geometry".into()); } let bank: serde_json::Value = serde_json::from_str(include_str!( "../../../metal/mtplx-qsa-compiled-scalars.json" )) .map_err(|e| e.to_string())?; let kind = if max_start == 0 { "zero" } else if max_start == max_new { "equal" } else { "distinct" }; let variant = &bank["clamp"][kind]; let body = variant["kernels"] .as_str() .ok_or("missing original compiled QSA clamp")?; let original_name = body .split_once("host_name(\"") .and_then(|(_, s)| s.split_once('"')) .ok_or("invalid compiled QSA symbol")? .0; let mut body = body.replace(original_name, &qsa_compiled_clamp_name(max_new, max_start)); body = body.replace( &format!("tmp_D = static_cast({});", variant["max_new"]), &format!("tmp_D = static_cast({max_new});"), ); if kind == "distinct" { body = body.replace( &format!("tmp_F = static_cast({});", variant["max_start"]), &format!("tmp_F = static_cast({max_start});"), ); } Ok(body) } #[cfg(test)] fn qsa_compiled_frontiers( [logical, pooled_len]: [&Buffer; 2], [max_new, max_start]: [u32; 2], ) -> Result<[Buffer; 2], String> { let block_start = qsa_compiled_block_start([logical, pooled_len], [max_new, max_start])?; let raw_start = qsa_compiled_raw_start(&block_start)?; Ok([block_start, raw_start]) } #[cfg(test)] fn qsa_compiled_block_start( [logical, pooled_len]: [&Buffer; 2], [max_new, max_start]: [u32; 2], ) -> Result { qsa_compile::Scalar::Clamp { max_new, max_start }.buffer(&[logical, pooled_len]) } #[cfg(test)] fn qsa_compiled_raw_start(block_start: &Buffer) -> Result { qsa_compile::Scalar::Multiply(4).buffer(&[block_start]) } #[cfg(test)] fn qsa_retained_bf16_copy(input: &Buffer, count: u32) -> Result { let output = Buffer::mtplx_bytes(u64::from(count) * 2)?; let work = if count < 65536 { 1 } else { 4 }; let threads = count.div_ceil(work); dispatch_geometry( if work == 1 { "v_copybfloat16bfloat16" } else { "vn_copybfloat16bfloat16" }, &[ tensor(0, input).input(count as usize), tensor(1, &output).output(count as usize), bytes(2, &count), ], &[], [threads, 1, 1], [threads.min(1024), 1, 1], true, )?; Ok(output) } #[cfg(test)] pub(super) struct QsaCompiledCacheWindow { pub(super) raw: Buffer, pub(super) pooled: Buffer, pub(super) block_start: Buffer, pub(super) raw_start: Buffer, _temporaries: Vec, } /// Connected cache-maintenance subgraph of QSACompiledIndexerCore.from_qk_rows. /// This entry retains the old leaves, so the reference's non-donation path is /// required. Graph-bank ownership/donation and BFS scheduling are separate. /// Position/logical/frontier are validated int32[1] device leaves; no readback. #[cfg(test)] pub(super) fn qsa_compiled_cache_window( [qk, raw, pooled, norm, freq]: [&Buffer; 5], [pos, logical, pooled_len]: [&Buffer; 3], rows: u32, qk_stride: u64, [raw_cap, pooled_cap]: [u32; 2], ) -> Result { let max_new = rows.div_ceil(4); let max_start = (raw_cap / 4).min(pooled_cap).checked_sub(max_new); if rows == 0 || rows > raw_cap || qk_stride < 640 || max_start.is_none() || [raw_cap, pooled_cap] .into_iter() .any(|n| n < 256 || !n.is_power_of_two() || n > i32::MAX as u32 / 512) || [pos, logical, pooled_len] .into_iter() .any(|b| unsafe { ds4_gpu_tensor_bytes(b.raw()) } < 4) || unsafe { ds4_gpu_tensor_bytes(raw.raw()) } < u64::from(raw_cap) * 256 || unsafe { ds4_gpu_tensor_bytes(pooled.raw()) } < u64::from(pooled_cap) * 256 || u64::from(rows - 1) .checked_mul(qk_stride) .and_then(|n| n.checked_add(640)) .and_then(|n| n.checked_mul(2)) .is_none_or(|n| unsafe { ds4_gpu_tensor_bytes(qk.raw()) } < n) { return Err("invalid compiled QSA cache-window inputs or geometry".into()); } let raw_next = qsa_retained_bf16_copy(raw, raw_cap * 128)?; let k = qk.view(512 * 2, (u64::from(rows - 1) * qk_stride + 128) * 2)?; let mut temporary = qsa_dynamic_copy_rows( [&k, &raw_next], [qk_stride, 128], [rows, 128], [None, Some(pos)], [ ((rows - 1) as u64 * qk_stride + 128) as usize, raw_cap as usize * 128, ], )?; let [block_start, raw_start] = qsa_compiled_frontiers([logical, pooled_len], [max_new, max_start.unwrap()])?; let window = Buffer::mtplx_bytes(u64::from(max_new) * 4 * 128 * 2)?; temporary.extend(qsa_dynamic_copy_rows( [&raw_next, &window], [128, 128], [max_new * 4, 128], [Some(&raw_start), None], [raw_cap as usize * 128, max_new as usize * 512], )?); let pool_window = qsa_pool_keys_bound( [&window, norm, freq], max_new, [128, 1], tensor(6, &block_start).input(1), )?; let pooled_next = qsa_retained_bf16_copy(pooled, pooled_cap * 128)?; temporary.extend(qsa_dynamic_copy_rows( [&pool_window, &pooled_next], [128, 128], [max_new, 128], [None, Some(&block_start)], [max_new as usize * 128, pooled_cap as usize * 128], )?); temporary.extend([k, window, pool_window]); Ok(QsaCompiledCacheWindow { raw: raw_next, pooled: pooled_next, block_start, raw_start, _temporaries: temporary, }) } #[cfg(test)] pub(super) struct QsaProjected { pub(super) q: Buffer, pub(super) raw_keys: Buffer, _temporary: Vec, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub(super) enum QsaCompiledMode { UpdateOnly, Blocks, PrefillBlocks, RowTokens, DenseMask, } pub(super) fn qsa_compiled_row_position_source(start: u32) -> Result { if start > i32::MAX as u32 { return Err("invalid compiled QSA row offset".into()); } let bank: serde_json::Value = serde_json::from_str(include_str!( "../../../tests/fixtures/mtplx-qsa-select-jit.json" )) .map_err(|e| e.to_string())?; let body = bank[3]["kernels"] .as_str() .ok_or("missing original compiled row offset")?; let symbol = body .split_once("host_name(\"") .and_then(|(_, s)| s.split_once('"')) .ok_or("invalid compiled row offset symbol")? .0; Ok(body .replace(symbol, &format!("kernel_qwen_mtplx_qsa_pos_add_{start}")) .replace( "tmp_C = static_cast(3);", &format!("tmp_C = static_cast({start});"), )) } #[cfg(test)] fn qsa_compiled_row_position(pos: &Buffer, start: u32) -> Result { qsa_compile::Scalar::Add(start).buffer(&[pos]) } #[cfg(test)] pub(super) struct QsaIndexerWeights<'a> { pub(super) projection: [&'a Buffer; 3], pub(super) quant: [u32; 2], pub(super) q_norm: &'a Buffer, pub(super) k_norm: &'a Buffer, pub(super) inv_freq: &'a Buffer, } /// Resolved MTPLX switches for both indexer routes. Prefill's /// device-dependent AUTO value must be resolved before entering this path. pub(super) struct QsaIndexerOptions { pub(super) fused: bool, pub(super) compiled: bool, pub(super) prefill: bool, pub(super) phase_prefill: bool, pub(super) prefill_min_rows: u32, pub(super) prefill_compile_rows: u32, pub(super) prefill_min_context: u32, pub(super) prefill_workspace: u64, pub(super) tile_rows: u32, pub(super) flash: bool, pub(super) gather_decode: bool, pub(super) gather: bool, pub(super) gather_max_rows: u32, pub(super) gather_min_context: u32, #[cfg_attr(not(test), expect(dead_code, reason = "Reference diagnostic API"))] pub(super) tf32: bool, } impl QsaIndexerOptions { fn large_prefill(&self, rows: u32, pos: u32) -> bool { self.prefill && self.phase_prefill && rows >= self.prefill_min_rows && pos >= self.prefill_min_context } /// Original _compiled_mode; total is the post-update token frontier. pub(super) fn compiled_mode( &self, rows: u32, total: u32, ratio: u32, topk: u32, ) -> QsaCompiledMode { if total / ratio <= topk { QsaCompiledMode::UpdateOnly } else if rows == 1 && self.flash { QsaCompiledMode::Blocks } else if rows != 1 && self.large_prefill(rows, total.saturating_sub(rows)) { QsaCompiledMode::PrefillBlocks } else if rows != 1 && self.gather && rows <= self.gather_max_rows && total >= self.gather_min_context { QsaCompiledMode::RowTokens } else { QsaCompiledMode::DenseMask } } /// Cache/phase portion of _compiled_route_supported, BEFORE capacity /// bucketing. QsaCache fixes B1/BF16/D128/ratio4. This does not validate a /// source tensor, projection/norm dtype or device; those remain entry-point /// obligations. In particular it is not a generic tensor eligibility test. #[cfg(test)] pub(super) fn compiled_cache_mode( &self, cache: &QsaCache, rows: u32, pos: u32, ) -> Option { let total = pos.checked_add(rows)?; if !self.fused || !self.compiled || rows == 0 || pos != cache.offset { return None; } let mode = self.compiled_mode(rows, total, 4, 512); if rows != 1 { if mode == QsaCompiledMode::UpdateOnly && self.phase_prefill { return None; } if rows >= self.prefill_min_rows && (!matches!( mode, QsaCompiledMode::PrefillBlocks | QsaCompiledMode::UpdateOnly ) || rows != self.prefill_compile_rows) { return None; } } if pos > 0 && (cache.raw.is_none() || cache.raw_cap < pos) { return None; } if cache.pooled.is_none() { if cache.pooled_len != 0 { return None; } } else if cache.pooled_len > cache.pooled_cap { return None; } let logical = total / 4; if logical - cache.pooled_len.min(logical) > rows.div_ceil(4) { return None; } if rows == 1 && !matches!(mode, QsaCompiledMode::UpdateOnly | QsaCompiledMode::Blocks) && self.gather_decode { return None; } Some(mode) } } #[cfg(test)] pub(super) struct QsaIndexed { pub(super) selection: Option, pub(super) lane: &'static str, _temporaries: Vec, } /// Connected _call_rows host flow for the installed, typed B1/BF16 indexer. /// Replays the parameter-bound indexer graph with its exclusive cache state. /// Shared descriptors/Data retain the reference's copying path. /// Eligibility rejection selects eager; dispatch errors are returned, not hidden. #[allow(clippy::too_many_arguments)] // Explicit model inputs, cache and evaluator state. #[cfg(test)] pub(super) fn qsa_indexer_rows( weights: QsaIndexerWeights<'_>, hidden: &Buffer, supplied_qk: Option<(&Buffer, u64)>, rows: u32, cache: &mut QsaCache, options: &QsaIndexerOptions, commands: Option<&mut Commands>, graph: &mut QsaGraphBank, ) -> Result { let total = qsa_validate_indexer_options(rows, cache.offset, options)?; let Some(mode) = options.compiled_cache_mode(cache, rows, cache.offset) else { return qsa_indexer_rows_uncompiled( weights, hidden, supplied_qk, rows, cache, options, commands, ); }; cache.ensure_compiled_backings(rows)?; let logical = total / 4; let frontiers = [cache.offset, total, logical, cache.pooled_len.min(logical)] .map(|value| scalar_buffer(&(value as i32).to_le_bytes())); let [pos, end, blocks, frontier] = frontiers; let frontiers = [pos?, end?, blocks?, frontier?]; let budget = if mode == QsaCompiledMode::PrefillBlocks { options.prefill_workspace } else { 32 * 1024 * 1024 }; let geometry = [rows, cache.raw_cap, cache.pooled_cap]; let (updated, selected) = graph.run( weights, supplied_qk.map_or(hidden, |(q, _)| q), QsaCacheInput::State([cache.raw.as_mut().unwrap(), cache.pooled.as_mut().unwrap()]), frontiers.each_ref(), geometry, supplied_qk.map(|(_, stride)| stride), mode, budget, options.tf32, )?; // Commit leaves/frontier without waiting or reading GPU scalars. Attention // alone advances KV.offset. A former eager mirror is now invalid. cache.raw = Some(QsaArray::new(updated.raw, 0)?); cache.pooled = Some(QsaArray::new(updated.pooled, 0)?); cache.pooled_len = logical; cache.mirror = None; cache.mirror_cap = 0; cache.mirror_strides = [0; 2]; let mut temporary = updated._temporaries; temporary.extend(frontiers); let selection = if mode == QsaCompiledMode::UpdateOnly { None } else { let mut out = selected.ok_or("compiled QSA omitted its selection")?; Some(match mode { QsaCompiledMode::Blocks => { out._temporaries.extend(out.outputs.drain(1..)); out.row_widths.truncate(1); out.row_strides.truncate(1); QsaIndexerSelection::FlashBlocks(out, total / 4 * 4) } QsaCompiledMode::PrefillBlocks => { out._temporaries.extend(out.outputs.drain(2..)); out.row_widths.truncate(2); out.row_strides.truncate(2); QsaIndexerSelection::PrefillBlocks(out) } QsaCompiledMode::RowTokens => QsaIndexerSelection::RowTokens(out), QsaCompiledMode::DenseMask => { out.row_widths[0] = (total, 1); QsaIndexerSelection::Dense(out) } QsaCompiledMode::UpdateOnly => unreachable!(), }) }; Ok(QsaIndexed { selection, lane: "compiled", _temporaries: temporary, }) } #[cfg(test)] fn qsa_validate_indexer_options( rows: u32, pos: u32, options: &QsaIndexerOptions, ) -> Result { let total = pos .checked_add(rows) .filter(|n| rows > 0 && *n <= i32::MAX as u32 / 512) .ok_or("invalid QSA indexer frontier")?; if options.prefill_min_rows < 2 || options.prefill_compile_rows < 2 || options.prefill_min_context < 2049 || options.prefill_workspace < 1024 * 1024 || options.gather_max_rows < 2 { return Err("unresolved or invalid QSA indexer options".into()); } Ok(total) } /// _call_rows after compiled-route rejection, for the installed B1 BF16 model. /// Does not replace an eligible compiled route. Attention advances KV.offset /// later; this call only writes the indexer's raw/pool state. #[cfg(test)] pub(super) fn qsa_indexer_rows_uncompiled( weights: QsaIndexerWeights<'_>, hidden: &Buffer, supplied_qk: Option<(&Buffer, u64)>, rows: u32, cache: &mut QsaCache, options: &QsaIndexerOptions, commands: Option<&mut Commands>, ) -> Result { let total = qsa_validate_indexer_options(rows, cache.offset, options)?; let mut temporary = Vec::new(); let mut projected = None; let (qk, stride) = if let Some((qk, stride)) = supplied_qk { let span = u64::from(rows - 1) .checked_mul(stride) .and_then(|n| n.checked_add(640)) .and_then(|n| n.checked_mul(2)); if stride < 640 || span.is_none_or(|n| unsafe { ds4_gpu_tensor_bytes(qk.raw()) } < n) { return Err("invalid supplied QSA projection view".into()); } (qk, stride) } else { let output = Buffer::mtplx_bytes(u64::from(rows) * 640 * 2)?; let [w, s, b] = weights.projection; temporary.extend(affine_bf16( [w, s, b, hidden, &output], [rows, 640, 2560], weights.quant[0], weights.quant[1], true, )?); projected = Some(output); (projected.as_ref().unwrap(), 640) }; // In the dense==sparse regime q preparation is a dead lazy expression. // Projection/raw writes and completed-key pooling still belong to cache. let query = if total / 4 > 512 { if options.fused { Some(qsa_prepare_queries( [qk, weights.q_norm, weights.inv_freq], rows, [stride, 128, 1], cache.offset as i32, )?) } else { let (q, scratch) = qsa_prepare_queries_eager( [qk, weights.q_norm, weights.inv_freq], rows, [stride, 128, 1], cache.offset as i32, )?; temporary.extend(scratch); Some(q) } } else { None }; let raw_len = (u64::from(rows - 1) * stride + 128) * 2; let raw = qk.view(512 * 2, raw_len)?; cache.write_raw(&raw, rows, stride)?; temporary.extend(cache.extend_pooled( total, weights.k_norm, weights.inv_freq, !options.fused, )?); temporary.extend(projected); let Some(query) = query else { return Ok(QsaIndexed { selection: None, lane: "update_only", _temporaries: temporary, }); }; let decode = rows == 1; let large_prefill = options.large_prefill(rows, cache.offset); // All prepared B1/H4/D128 BF16 arrays meet the original M5 eligibility. let (selection, lane) = if !decode && large_prefill { let mut out = qsa_prefill_cached( cache, &query, rows, QsaSelectMode::Blocks, options.prefill_workspace, )?; out._temporaries.extend(out.outputs.drain(2..)); out.row_widths.truncate(2); out.row_strides.truncate(2); (QsaIndexerSelection::PrefillBlocks(out), "metal_prefill") } else if options.fused && (decode || rows < options.prefill_min_rows) && !(decode && options.gather_decode) { if decode && options.flash { let mut out = qsa_select_cached(cache, &query, rows, QsaSelectMode::Blocks, options.tf32)?; out._temporaries.extend(out.outputs.drain(1..)); out.row_widths.truncate(1); out.row_strides.truncate(1); ( QsaIndexerSelection::FlashBlocks(out, total / 4 * 4), "legacy_fused", ) } else if !decode && options.gather && rows <= options.gather_max_rows && total >= options.gather_min_context { ( QsaIndexerSelection::RowTokens(qsa_select_cached( cache, &query, rows, QsaSelectMode::RowTokens, options.tf32, )?), "legacy_fused", ) } else { ( QsaIndexerSelection::Dense(qsa_select_cached( cache, &query, rows, QsaSelectMode::DenseMask, options.tf32, )?), "legacy_fused", ) } } else { let pos = cache.offset; let (pooled, strides) = cache.pooled_f32_view(total / 4)?; let top = qsa_eager_topk( [&query, pooled], [512, 128, 1], strides, QsaSelectPlan { rows, blocks: total / 4, topk: 512, pos, total, logical: total / 4, dense_width: total, mode: QsaSelectMode::Blocks, tf32: options.tf32, input_f32: [false, true], }, options.tile_rows, commands, )?; ( qsa_eager_output( top, total, QsaEagerOptions { large_prefill, flash: options.flash, gather_decode: options.gather_decode, gather: options.gather, gather_max_rows: options.gather_max_rows, gather_min_context: options.gather_min_context, }, )?, "eager", ) }; temporary.push(query); Ok(QsaIndexed { selection: Some(selection), lane, _temporaries: temporary, }) } /// Shared-input indexer projection followed by the selected original fused or /// eager preparation. Raw keys retain the projection stride for cache.write_raw. #[cfg(test)] pub(super) fn qsa_project_prepare( pack: [&Buffer; 3], [norm, inv_freq]: [&Buffer; 2], input: &Buffer, rows: u32, quant: [u32; 2], pos_start: i32, eager: bool, ) -> Result { if rows == 0 || rows > i32::MAX as u32 / 640 { return Err("invalid MTPLX QSA projection rows".into()); } let projected = Buffer::mtplx_bytes(u64::from(rows) * 640 * 2)?; let [w, s, b] = pack; let mut temporary = affine_bf16( [w, s, b, input, &projected], [rows, 640, 2560], quant[0], quant[1], true, )?; let q = if eager { let (q, scratch) = qsa_prepare_queries_eager( [&projected, norm, inv_freq], rows, [640, 128, 1], pos_start, )?; temporary.extend(scratch); q } else { qsa_prepare_queries([&projected, norm, inv_freq], rows, [640, 128, 1], pos_start)? }; let raw_keys = projected.view(512 * 2, (u64::from(rows) * 640 - 512) * 2)?; temporary.push(projected); Ok(QsaProjected { q, raw_keys, _temporary: temporary, }) } #[cfg(test)] pub(super) enum GdnInputWeights<'a> { Fused { pack: [&'a Buffer; 3], quant: [u32; 2], }, /// Original qkv, z, b, a module order, each with its own quantization. Separate { packs: [[&'a Buffer; 3]; 4], quant: [[u32; 2]; 4], }, } #[cfg(test)] pub(super) struct GdnWeights<'a> { pub(super) input: GdnInputWeights<'a>, pub(super) output: [&'a Buffer; 3], pub(super) output_quant: [u32; 2], // bits, group pub(super) conv: &'a Buffer, pub(super) a_log: &'a Buffer, pub(super) dt_bias: &'a Buffer, pub(super) norm: &'a Buffer, } #[cfg(test)] struct GdnProjected { qkv: Buffer, z: Buffer, b: Buffer, a: Buffer, strides: [u32; 3], // qkv, z, a/b temporary: Vec, } #[cfg(test)] fn gdn_project( weights: &GdnInputWeights<'_>, input: &Buffer, rows: u32, ) -> Result { let count = u64::from(rows) * 16480; if rows == 0 || count > i32::MAX as u64 { return Err("invalid MTPLX GDN projection rows".into()); } let mut temporary = Vec::new(); match weights { GdnInputWeights::Fused { pack: [w, s, b], quant: [bits, group], } => { let projected = Buffer::mtplx_bytes(count * 2)?; temporary.extend(affine_bf16( [w, s, b, input, &projected], [rows, 16480, 2560], *bits, *group, true, )?); let qkv = projected.view(0, (count - 6240) * 2)?; let z = projected.view(10240 * 2, (count - 10336) * 2)?; let b = projected.view(16384 * 2, (count - 16432) * 2)?; let a = projected.view(16432 * 2, (count - 16432) * 2)?; temporary.push(projected); Ok(GdnProjected { qkv, z, b, a, strides: [16480; 3], temporary, }) } GdnInputWeights::Separate { packs, quant } => { let mut project = |index: usize, width| { let [w, s, b] = packs[index]; let [bits, group] = quant[index]; let output = Buffer::mtplx_bytes(u64::from(rows) * u64::from(width) * 2)?; temporary.extend(affine_bf16( [w, s, b, input, &output], [rows, width, 2560], bits, group, true, )?); Ok::<_, String>(output) }; // Do not sort these by width or coalesce independently quantized modules. let qkv = project(0, 10240)?; let z = project(1, 6144)?; let b = project(2, 48)?; let a = project(3, 48)?; Ok(GdnProjected { qkv, z, b, a, strides: [10240, 6144, 48], temporary, }) } } } #[cfg(test)] pub(super) struct GdnDecodeOutput { pub(super) hidden: Buffer, pub(super) conv: Buffer, pub(super) delta: Buffer, // Like the reference encoder's temporaries, live through command completion. _temporaries: Vec, } #[cfg(test)] pub(super) struct GdnStagedOutput { pub(super) hidden: Buffer, pub(super) prepared: ConvNormOutput, pub(super) recurrent: DeltaUpdateOutput, _norm: Option, _temporaries: Vec, } // Keep the fixed GPU-handle bundle inline, without an allocation per layer. #[allow(clippy::large_enum_variant)] #[cfg(test)] pub(super) enum GdnForwardOutput { Fused(GdnDecodeOutput), Staged(GdnStagedOutput), } /// GatedDeltaNet's inference branch order for the installed B=1 geometry. /// Flags: fused step, conv-single, conv-verify, fused output, verify capture. /// State bindings: BF16 conv, FP32 delta, optional INT32 valid length. #[cfg(test)] pub(super) fn gdn_forward( weights: &GdnWeights<'_>, input: &Buffer, rows: u32, cache: [Option<&Buffer>; 3], mask: Option<&Buffer>, flags: [bool; 5], has_cache: bool, ) -> Result { let [conv, delta, length] = if has_cache { cache } else { [None; 3] }; if rows == 1 && has_cache && flags[0] && !flags[4] && mask.is_none() && length.is_none() && let Some(delta) = delta { gdn_decode(weights, input, conv, delta).map(GdnForwardOutput::Fused) } else { gdn_staged( weights, input, rows, [conv, delta, length], mask, [flags[1], flags[2], flags[3]], has_cache, ) .map(GdnForwardOutput::Staged) } } /// Connected cold/prefill/verify forward with either input projection layout. /// Fused-step selection remains the caller's earlier branch; these are the /// conv-single, conv-verify and output-fusion flags from the actual model. #[cfg(test)] pub(super) fn gdn_staged( weights: &GdnWeights<'_>, input: &Buffer, rows: u32, [conv, delta, length]: [Option<&Buffer>; 3], mask: Option<&Buffer>, flags: [bool; 3], has_cache: bool, ) -> Result { let GdnProjected { qkv, z, b, a, strides, mut temporary, } = gdn_project(&weights.input, input, rows)?; let prepared = gdn_conv_norm( &qkv, weights.conv, [rows, strides[0]], [conv, length], mask, [flags[0], flags[1]], has_cache, )?; let recurrent = gated_delta_update( [&prepared.q, &prepared.k, &prepared.v], [&a, &b, weights.a_log, weights.dt_bias], [rows, strides[2]], delta, mask, )?; let hidden = Buffer::mtplx_bytes(u64::from(rows) * 2560 * 2)?; let norm = if rows == 1 && flags[2] && weights.output_quant[0] == 4 && [32, 64].contains(&weights.output_quant[1]) { let [w, s, b] = weights.output; dispatch( &format!( "kernel_qwen_mtplx_gdn_out_fused_gs{}_bf16", weights.output_quant[1] ), &[ tensor(0, &recurrent.hidden).input(6144), tensor(1, &z).input(6144), tensor(2, weights.norm).input(128), tensor(3, w).input(2560 * 6144 / 8), tensor(4, s).input(2560 * 6144 / weights.output_quant[1] as usize), tensor(5, b).input(2560 * 6144 / weights.output_quant[1] as usize), tensor(6, &hidden).output(2560), ], [2560_u32.div_ceil(32), 1, 1], [1024, 1, 1], )?; None } else { let norm = sigmoid_rms_norm( &recurrent.hidden, weights.norm, Some(&z), [rows, 48, 128, strides[1]], 1e-6, )?; let [w, s, b] = weights.output; temporary.extend(affine_bf16( [w, s, b, &norm.hidden, &hidden], [rows, 2560, 6144], weights.output_quant[0], weights.output_quant[1], true, )?); Some(norm) }; temporary.extend([qkv, z, b, a]); Ok(GdnStagedOutput { hidden, prepared, recurrent, _norm: norm, _temporaries: temporary, }) } /// The reference's live-state, unmasked, single-row fused-step branch. /// Caller checks the model branch gate; cold/prefill/verify use different graphs. /// Keep this result alive until the enclosing command batch completes. #[cfg(test)] pub(super) fn gdn_decode( weights: &GdnWeights<'_>, input: &Buffer, conv: Option<&Buffer>, delta: &Buffer, ) -> Result { for (buffer, size) in [ (delta, 48 * 128 * 128 * 4), (weights.conv, 10240 * 4 * 2), (weights.a_log, 48 * 2), (weights.dt_bias, 48 * 2), (weights.norm, 128 * 2), ] { if unsafe { ds4_gpu_tensor_bytes(buffer.raw()) } < size { return Err("MTPLX GDN state/weight binding is too small".into()); } } if conv.is_some_and(|conv| unsafe { ds4_gpu_tensor_bytes(conv.raw()) } < 3 * 10240 * 2) { return Err("MTPLX GDN conv state binding is too small".into()); } let GdnProjected { qkv, z, b, a, mut temporary, .. } = gdn_project(&weights.input, input, 1)?; let gated = Buffer::mtplx_bytes(6144 * 2)?; let next_conv = Buffer::mtplx_bytes(3 * 10240 * 2)?; let next_delta = Buffer::mtplx_floats(48 * 128 * 128)?; // CustomKernel allocates outputs before materializing a broadcast input. // Keep the cold conv copy after the input projection, as in the reference. let initial_conv = if conv.is_none() { let zero = Buffer::mtplx_bytes(3 * 10240 * 2)?; let scalar = scalar_buffer(&0_u16.to_le_bytes())?; dispatch_geometry( "g1_copybfloat16bfloat16", &[ tensor(0, &scalar).input(1), tensor(1, &zero).output(3 * 10240), bytes(3, &0_u64), ], &[], [3 * 10240, 1, 1], [1024, 1, 1], true, )?; Some(zero) } else { None }; let conv = conv.or(initial_conv.as_ref()).unwrap(); gdn::dispatch_step(&[ tensor(0, &qkv).input(10240), tensor(1, &z).input(6144), tensor(2, &a).input(48), tensor(3, &b).input(48), tensor(4, conv).input(3 * 10240), tensor(5, weights.conv).input(4 * 10240), tensor(6, weights.a_log).input(48), tensor(7, weights.dt_bias).input(48), tensor(8, delta).input(48 * 128 * 128), tensor(9, weights.norm).input(128), tensor(10, &gated).output(6144), tensor(11, &next_conv).output(3 * 10240), tensor(12, &next_delta).output(48 * 128 * 128), ])?; if let Some(initial_conv) = initial_conv { encoder::add_temporaries(std::slice::from_ref(&initial_conv)); temporary.push(initial_conv); } let hidden = Buffer::mtplx_bytes(2560 * 2)?; let [w, s, bias] = weights.output; temporary.extend(affine_bf16( [w, s, bias, &gated, &hidden], [1, 2560, 6144], weights.output_quant[0], weights.output_quant[1], true, )?); temporary.extend([qkv, z, b, a, gated]); Ok(GdnDecodeOutput { hidden, conv: next_conv, delta: next_delta, _temporaries: temporary, }) }