libmir-metal 0.1.0

Metal inference backend for libmir
mod gated_delta;
mod page_write;
mod paged_attention;

pub(super) use page_write::{PageWriteOptions, PreparedPageWrite};

use super::Result;

mirtal::metal_kernel! {
    fn gated_delta_gates {
        name: "mirmir_gated_delta_gates",
        templates: [HV: int = 16],
        inputs: [alpha: float, beta: float, a_log: float, dt_bias: float],
        outputs: [decay: f32, update: f32],
        source: file "kernels/gated_delta_gates.metal",
        header: inline "",
        row_contiguous: true,
        atomic_outputs: false,
    }
}

mirtal::metal_library! {
    fn paged_kv_library {
        name: "mirmir_paged_kv",
        source: file "kernels/paged_kv.metal",
    }
}

mirtal::metal_kernel! {
    fn gated_delta_recurrence {
        name: "mirmir_gated_delta",
        templates: [
            InT: dtype = bf16, StT: dtype = f32, DK: int = 128, DV: int = 128,
            HK: int = 8, HV: int = 16, STEPS: int = 4,
        ],
        inputs: [query: InT, key: InT, value: InT, decay: f32, update: f32, state: StT],
        outputs: [output: InT, next_state: StT],
        source: file "kernels/gated_delta_recurrence.metal",
        header: inline "",
        row_contiguous: true,
        atomic_outputs: false,
    }
}

mirtal::metal_kernel! {
    fn gated_delta_decode {
        name: "mirmir_gated_delta_decode_headwide_gates",
        templates: [
            InT: dtype = bf16, StT: dtype = f32, DK: int = 128, DV: int = 128,
            HK: int = 8, HV: int = 16, NORMALIZE: bool = true,
        ],
        inputs: [
            query: InT, key: InT, value: InT, alpha: float, beta: float,
            a_log: float, dt_bias: float, state: StT,
        ],
        outputs: [output: InT, next_state: StT],
        source: file "kernels/gated_delta_decode.metal",
        header: inline "",
        row_contiguous: true,
        atomic_outputs: false,
    }
}

mirtal::metal_kernel! {
    fn paged_attention {
        name: "mirmir_paged_sdpa",
        templates: [
            T: dtype = bf16, QUERY_HEADS: int = 32, KV_HEADS: int = 16,
            PAGE_CAPACITY: int = 128, HEAD_DIM: int = 128,
            QK_PER_THREAD: int = 4, V_PER_THREAD: int = 4, PAGE_SIZE: int = 64,
        ],
        inputs: [
            queries: T, key_pages: T, value_pages: T, page_table: u32,
            page_dependency: u32, attention_scale: scalar<f32>,
        ],
        outputs: [output: T],
        source: file "kernels/paged_attention.metal",
        header: inline "",
        row_contiguous: true,
        atomic_outputs: false,
    }
}

mirtal::metal_library! {
    fn paged_attention_partial_library {
        name: "mirmir_paged_sdpa_partial",
        source: file "kernels/paged_attention/partial.metal",
    }
}

mirtal::metal_kernel! {
    fn paged_attention_reduce {
        name: "mirmir_paged_sdpa_reduce",
        templates: [T: dtype = bf16, HEAD_DIM: int = 128, BLOCKS: int = 64],
        inputs: [partials: T, sums: f32, maximums: f32],
        outputs: [output: T],
        source: file "kernels/paged_attention/reduce.metal",
        header: inline "",
        row_contiguous: true,
        atomic_outputs: false,
    }
}

#[derive(Debug)]
pub(super) struct Kernels {
    gated_delta_gates: mirtal::MetalKernel<4, 2>,
    gated_delta_recurrence: mirtal::MetalKernel<6, 2>,
    gated_delta_decode: mirtal::MetalKernel<8, 2>,
    paged_attention: mirtal::MetalKernel<6, 1>,
    paged_attention_partial: mirtal::MetalLibrary,
    paged_attention_reduce: mirtal::MetalKernel<3, 1>,
    paged_kv: mirtal::MetalLibrary,
}

impl Kernels {
    pub(super) fn new() -> Result<Self> {
        Ok(Self {
            gated_delta_gates: gated_delta_gates()?,
            gated_delta_recurrence: gated_delta_recurrence()?,
            gated_delta_decode: gated_delta_decode()?,
            paged_attention: paged_attention()?,
            paged_attention_partial: paged_attention_partial_library()?,
            paged_attention_reduce: paged_attention_reduce()?,
            paged_kv: paged_kv_library()?,
        })
    }
}

fn template(name: &'static str, value: usize) -> Result<mirtal::TemplateArg> {
    Ok(mirtal::TemplateArg::int(name, i32::try_from(value)?))
}

pub(super) fn new_gated_delta_decode_kernel() -> Result<mirtal::MetalKernel<8, 2>> {
    Ok(gated_delta_decode()?)
}