use crate::backend::BackendError;
use crate::backend::honeycrisp::device::HoneycrispDevice;
pub const SIMDS_PER_GROUP: u32 = 16;
pub const LANES: u32 = 32;
pub const MSL: &str = r#"
#include <metal_stdlib>
using namespace metal;
struct Dims { uint batch; uint n_rows; uint n_blocks; uint pad; };
kernel void kmain(
device const float *x buffer(0),
device const uint8_t *w buffer(1),
device float *y buffer(2),
constant Dims &dims buffer(3),
uint gid thread_position_in_grid
) {
if (gid >= dims.batch * dims.n_rows) return;
uint b = gid / dims.n_rows;
uint row = gid % dims.n_rows;
device const uint8_t *w_row = w + row * dims.n_blocks * 144u;
device const float *x_b = x + b * dims.n_blocks * 256u;
float sum = 0.0f;
for (uint blk = 0; blk < dims.n_blocks; blk++) {
device const uint8_t *block = w_row + blk * 144u;
float d = float(as_type<half>((ushort)(uint(block[0]) | (uint(block[1]) << 8))));
float dmin = float(as_type<half>((ushort)(uint(block[2]) | (uint(block[3]) << 8))));
device const uint8_t *sc = block + 4u;
device const uint8_t *qs = block + 16u;
device const float *xb = x_b + blk * 256u;
for (uint j = 0; j < 8u; j++) {
uint s, m;
if (j < 4u) {
s = uint(sc[j]) & 0x3Fu;
m = uint(sc[j + 4]) & 0x3Fu;
} else {
s = (uint(sc[j + 4]) & 0x0Fu) | ((uint(sc[j - 4]) >> 6u) << 4u);
m = (uint(sc[j + 4]) >> 4u) | ((uint(sc[j]) >> 6u) << 4u);
}
float ds = d * float(s);
float dm = dmin * float(m);
uint qs_off = (j / 2u) * 32u;
uint shift = (j & 1u) * 4u;
device const float *xj = xb + j * 32u;
float nibble_dot = 0.0f, x_sum = 0.0f;
for (uint l = 0; l < 32u; l++) {
float nib = float((uint(qs[qs_off + l]) >> shift) & 0x0Fu);
nibble_dot += nib * xj[l];
x_sum += xj[l];
}
sum += ds * nibble_dot - dm * x_sum;
}
}
y[gid] = sum;
}
"#;
const SCALE_MIN_HELPER: &str = r#"
inline uint2 q4k_sm(device const uint8_t* sc, uint j) {
uint s, m;
if (j < 4u) {
s = uint(sc[j]) & 0x3Fu;
m = uint(sc[j+4u]) & 0x3Fu;
} else {
s = (uint(sc[j+4u]) & 0x0Fu) | ((uint(sc[j-4u]) >> 6u) << 4u);
m = (uint(sc[j+4u]) >> 4u) | ((uint(sc[j]) >> 6u) << 4u);
}
return uint2(s, m);
}
"#;
pub const MSL_NRM: &str = r#"
#include <metal_stdlib>
using namespace metal;
struct Dims { uint batch; uint n_rows; uint n_blocks; float eps; };
constant constexpr uint SPG = 16u; // SIMDs per threadgroup
constant constexpr uint LSIM = 32u; // lanes per SIMD
inline uint2 q4k_sm(device const uint8_t* sc, uint j) {
uint s, m;
if (j < 4u) {
s = uint(sc[j]) & 0x3Fu;
m = uint(sc[j+4u]) & 0x3Fu;
} else {
s = (uint(sc[j+4u]) & 0x0Fu) | ((uint(sc[j-4u]) >> 6u) << 4u);
m = (uint(sc[j+4u]) >> 4u) | ((uint(sc[j]) >> 6u) << 4u);
}
return uint2(s, m);
}
kernel void kmain(
device const float *x buffer(0),
device const float *norm_w buffer(1),
device const uint8_t *w buffer(2),
device float *y buffer(3),
constant Dims &dims buffer(4),
uint tgpig_x threadgroup_position_in_grid,
uint lane thread_index_in_simdgroup,
uint sgitg simdgroup_index_in_threadgroup
) {
uint row_global = tgpig_x * SPG + sgitg;
uint b = row_global / dims.n_rows;
uint row = row_global - b * dims.n_rows;
if (b >= dims.batch || row >= dims.n_rows) return;
uint k_floats = dims.n_blocks * 256u;
device const float *x_b = x + b * k_floats;
// Pass 1: RMSNorm โ stride-32 over k_floats, reduce within SIMD
float sq = 0.0f;
for (uint i = lane; i < k_floats; i += LSIM) {
float v = x_b[i]; sq += v * v;
}
float inv_rms = rsqrt(simd_sum(sq) / float(k_floats) + dims.eps);
// Pass 2: Q4K matmul with inline norm
device const uint8_t *w_row = w + row * dims.n_blocks * 144u;
float acc = 0.0f;
for (uint sb = 0u; sb < dims.n_blocks; sb++) {
device const uint8_t *blk = w_row + sb * 144u;
float d = float(as_type<half>((ushort)(uint(blk[0]) | (uint(blk[1]) << 8u))));
float dmin = float(as_type<half>((ushort)(uint(blk[2]) | (uint(blk[3]) << 8u))));
device const uint8_t *sc = blk + 4u;
device const uint8_t *qs = blk + 16u;
device const float *x_sb = x_b + sb * 256u;
device const float *n_sb = norm_w + sb * 256u;
for (uint grp = 0u; grp < 4u; grp++) {
uint2 sm0 = q4k_sm(sc, grp*2u);
uint2 sm1 = q4k_sm(sc, grp*2u+1u);
float ds0 = d*float(sm0.x), dm0 = dmin*float(sm0.y);
float ds1 = d*float(sm1.x), dm1 = dmin*float(sm1.y);
uint qb = uint(qs[grp*32u + lane]);
float n0 = float(qb & 0xFu), n1 = float(qb >> 4u);
uint xb = grp * 64u + lane;
float x0 = x_sb[xb] * inv_rms * n_sb[xb];
float x1 = x_sb[xb+32u] * inv_rms * n_sb[xb+32u];
acc += (ds0*n0 - dm0)*x0 + (ds1*n1 - dm1)*x1;
}
}
float r = simd_sum(acc);
if (lane == 0u) y[b * dims.n_rows + row] = r;
}
"#;
pub const MSL_DUAL_NRM: &str = r#"
#include <metal_stdlib>
using namespace metal;
struct Dims { uint batch; uint n_rows; uint n_blocks; float eps; };
constant constexpr uint SPG = 16u;
constant constexpr uint LSIM = 32u;
inline uint2 q4k_sm(device const uint8_t* sc, uint j) {
uint s, m;
if (j < 4u) {
s = uint(sc[j]) & 0x3Fu;
m = uint(sc[j+4u]) & 0x3Fu;
} else {
s = (uint(sc[j+4u]) & 0x0Fu) | ((uint(sc[j-4u]) >> 6u) << 4u);
m = (uint(sc[j+4u]) >> 4u) | ((uint(sc[j]) >> 6u) << 4u);
}
return uint2(s, m);
}
kernel void kmain(
device const float *x buffer(0),
device const float *norm_w buffer(1),
device const uint8_t *wa buffer(2),
device const uint8_t *wb buffer(3),
device float *ya buffer(4),
device float *yb buffer(5),
constant Dims &dims buffer(6),
uint tgpig_x threadgroup_position_in_grid,
uint lane thread_index_in_simdgroup,
uint sgitg simdgroup_index_in_threadgroup
) {
uint row_global = tgpig_x * SPG + sgitg;
uint b = row_global / dims.n_rows;
uint row = row_global - b * dims.n_rows;
if (b >= dims.batch || row >= dims.n_rows) return;
uint k_floats = dims.n_blocks * 256u;
device const float *x_b = x + b * k_floats;
// RMSNorm
float sq = 0.0f;
for (uint i = lane; i < k_floats; i += LSIM) {
float v = x_b[i]; sq += v * v;
}
float inv_rms = rsqrt(simd_sum(sq) / float(k_floats) + dims.eps);
device const uint8_t *wa_row = wa + row * dims.n_blocks * 144u;
device const uint8_t *wb_row = wb + row * dims.n_blocks * 144u;
float acc_a = 0.0f, acc_b = 0.0f;
for (uint sb = 0u; sb < dims.n_blocks; sb++) {
device const uint8_t *ba = wa_row + sb * 144u;
device const uint8_t *bb = wb_row + sb * 144u;
float da = float(as_type<half>((ushort)(uint(ba[0]) | (uint(ba[1]) << 8u))));
float dmina = float(as_type<half>((ushort)(uint(ba[2]) | (uint(ba[3]) << 8u))));
float db = float(as_type<half>((ushort)(uint(bb[0]) | (uint(bb[1]) << 8u))));
float dminb = float(as_type<half>((ushort)(uint(bb[2]) | (uint(bb[3]) << 8u))));
device const uint8_t *sca = ba + 4u, *qsa = ba + 16u;
device const uint8_t *scb = bb + 4u, *qsb = bb + 16u;
device const float *xs = x_b + sb * 256u;
device const float *ns = norm_w + sb * 256u;
for (uint grp = 0u; grp < 4u; grp++) {
uint2 sma0 = q4k_sm(sca, grp*2u), sma1 = q4k_sm(sca, grp*2u+1u);
uint2 smb0 = q4k_sm(scb, grp*2u), smb1 = q4k_sm(scb, grp*2u+1u);
uint qba = uint(qsa[grp*32u + lane]);
uint qbb = uint(qsb[grp*32u + lane]);
float na0 = float(qba & 0xFu), na1 = float(qba >> 4u);
float nb0 = float(qbb & 0xFu), nb1 = float(qbb >> 4u);
uint xb = grp * 64u + lane;
float x0 = xs[xb] * inv_rms * ns[xb];
float x1 = xs[xb+32u] * inv_rms * ns[xb+32u];
acc_a += (da*float(sma0.x)*na0 - dmina*float(sma0.y))*x0
+ (da*float(sma1.x)*na1 - dmina*float(sma1.y))*x1;
acc_b += (db*float(smb0.x)*nb0 - dminb*float(smb0.y))*x0
+ (db*float(smb1.x)*nb1 - dminb*float(smb1.y))*x1;
}
}
float ta = simd_sum(acc_a), tb = simd_sum(acc_b);
if (lane == 0u) {
uint oi = b * dims.n_rows + row;
ya[oi] = ta; yb[oi] = tb;
}
}
"#;
pub const MSL_GUS_NRM: &str = r#"
#include <metal_stdlib>
using namespace metal;
struct Dims { uint batch; uint n_rows; uint n_blocks; float eps; };
constant constexpr uint SPG = 16u;
constant constexpr uint LSIM = 32u;
inline uint2 q4k_sm(device const uint8_t* sc, uint j) {
uint s, m;
if (j < 4u) {
s = uint(sc[j]) & 0x3Fu;
m = uint(sc[j+4u]) & 0x3Fu;
} else {
s = (uint(sc[j+4u]) & 0x0Fu) | ((uint(sc[j-4u]) >> 6u) << 4u);
m = (uint(sc[j+4u]) >> 4u) | ((uint(sc[j]) >> 6u) << 4u);
}
return uint2(s, m);
}
kernel void kmain(
device const float *x buffer(0),
device const float *norm_w buffer(1),
device const uint8_t *wa buffer(2), // gate
device const uint8_t *wb buffer(3), // up
device float *y buffer(4),
constant Dims &dims buffer(5),
uint tgpig_x threadgroup_position_in_grid,
uint lane thread_index_in_simdgroup,
uint sgitg simdgroup_index_in_threadgroup
) {
uint row_global = tgpig_x * SPG + sgitg;
uint b = row_global / dims.n_rows;
uint row = row_global - b * dims.n_rows;
if (b >= dims.batch || row >= dims.n_rows) return;
uint k_floats = dims.n_blocks * 256u;
device const float *x_b = x + b * k_floats;
// RMSNorm
float sq = 0.0f;
for (uint i = lane; i < k_floats; i += LSIM) {
float v = x_b[i]; sq += v * v;
}
float inv_rms = rsqrt(simd_sum(sq) / float(k_floats) + dims.eps);
device const uint8_t *wa_row = wa + row * dims.n_blocks * 144u;
device const uint8_t *wb_row = wb + row * dims.n_blocks * 144u;
float acc_g = 0.0f, acc_u = 0.0f;
for (uint sb = 0u; sb < dims.n_blocks; sb++) {
device const uint8_t *bg = wa_row + sb * 144u;
device const uint8_t *bu = wb_row + sb * 144u;
float dg = float(as_type<half>((ushort)(uint(bg[0]) | (uint(bg[1]) << 8u))));
float dming = float(as_type<half>((ushort)(uint(bg[2]) | (uint(bg[3]) << 8u))));
float du = float(as_type<half>((ushort)(uint(bu[0]) | (uint(bu[1]) << 8u))));
float dminu = float(as_type<half>((ushort)(uint(bu[2]) | (uint(bu[3]) << 8u))));
device const uint8_t *scg = bg + 4u, *qsg = bg + 16u;
device const uint8_t *scu = bu + 4u, *qsu = bu + 16u;
device const float *xs = x_b + sb * 256u;
device const float *ns = norm_w + sb * 256u;
for (uint grp = 0u; grp < 4u; grp++) {
uint2 sg0 = q4k_sm(scg, grp*2u), sg1 = q4k_sm(scg, grp*2u+1u);
uint2 su0 = q4k_sm(scu, grp*2u), su1 = q4k_sm(scu, grp*2u+1u);
uint qbg = uint(qsg[grp*32u + lane]);
uint qbu = uint(qsu[grp*32u + lane]);
float ng0 = float(qbg & 0xFu), ng1 = float(qbg >> 4u);
float nu0 = float(qbu & 0xFu), nu1 = float(qbu >> 4u);
uint xb = grp * 64u + lane;
float x0 = xs[xb] * inv_rms * ns[xb];
float x1 = xs[xb+32u] * inv_rms * ns[xb+32u];
acc_g += (dg*float(sg0.x)*ng0 - dming*float(sg0.y))*x0
+ (dg*float(sg1.x)*ng1 - dming*float(sg1.y))*x1;
acc_u += (du*float(su0.x)*nu0 - dminu*float(su0.y))*x0
+ (du*float(su1.x)*nu1 - dminu*float(su1.y))*x1;
}
}
float gate = simd_sum(acc_g), up = simd_sum(acc_u);
if (lane == 0u) {
float s = gate / (1.0f + exp(-gate)); // silu
y[b * dims.n_rows + row] = s * up;
}
}
"#;
pub const MSL_LARGE: &str = r#"
#include <metal_stdlib>
using namespace metal;
struct Dims { uint batch; uint n_rows; uint n_blocks; uint pad; };
constant constexpr uint SPG = 16u;
constant constexpr uint LSIM = 32u;
inline uint2 q4k_sm(device const uint8_t* sc, uint j) {
uint s, m;
if (j < 4u) {
s = uint(sc[j]) & 0x3Fu;
m = uint(sc[j+4u]) & 0x3Fu;
} else {
s = (uint(sc[j+4u]) & 0x0Fu) | ((uint(sc[j-4u]) >> 6u) << 4u);
m = (uint(sc[j+4u]) >> 4u) | ((uint(sc[j]) >> 6u) << 4u);
}
return uint2(s, m);
}
kernel void kmain(
device const float *x buffer(0),
device const uint8_t *w buffer(1),
device float *y buffer(2),
constant Dims &dims buffer(3),
uint tgpig_x threadgroup_position_in_grid,
uint lane thread_index_in_simdgroup,
uint sgitg simdgroup_index_in_threadgroup
) {
uint row_global = tgpig_x * SPG + sgitg;
uint b = row_global / dims.n_rows;
uint row = row_global - b * dims.n_rows;
if (b >= dims.batch || row >= dims.n_rows) return;
uint k_floats = dims.n_blocks * 256u;
device const float *x_b = x + b * k_floats;
device const uint8_t *w_row = w + row * dims.n_blocks * 144u;
float acc = 0.0f;
for (uint sb = 0u; sb < dims.n_blocks; sb++) {
device const uint8_t *blk = w_row + sb * 144u;
float d = float(as_type<half>((ushort)(uint(blk[0]) | (uint(blk[1]) << 8u))));
float dmin = float(as_type<half>((ushort)(uint(blk[2]) | (uint(blk[3]) << 8u))));
device const uint8_t *sc = blk + 4u;
device const uint8_t *qs = blk + 16u;
device const float *xs = x_b + sb * 256u;
for (uint grp = 0u; grp < 4u; grp++) {
uint2 sm0 = q4k_sm(sc, grp*2u);
uint2 sm1 = q4k_sm(sc, grp*2u+1u);
float ds0 = d*float(sm0.x), dm0 = dmin*float(sm0.y);
float ds1 = d*float(sm1.x), dm1 = dmin*float(sm1.y);
uint qb = uint(qs[grp*32u + lane]);
float n0 = float(qb & 0xFu), n1 = float(qb >> 4u);
uint xb = grp * 64u + lane;
float x0 = xs[xb], x1 = xs[xb+32u];
acc += (ds0*n0 - dm0)*x0 + (ds1*n1 - dm1)*x1;
}
}
float r = simd_sum(acc);
if (lane == 0u) y[b * dims.n_rows + row] = r;
}
"#;
pub fn dispatch(
dev: &HoneycrispDevice,
pipeline: &aruminium::Pipeline,
x: &aruminium::Buffer,
w: &aruminium::Buffer,
batch: u32,
n_rows: u32,
n_blocks: u32,
) -> Result<aruminium::Buffer, BackendError> {
let total = batch * n_rows;
let out = dev.alloc((total * 4) as usize)?;
#[repr(C)]
#[derive(Clone, Copy)]
struct Dims { batch: u32, n_rows: u32, n_blocks: u32, pad: u32 }
let dims = Dims { batch, n_rows, n_blocks, pad: 0 };
unsafe {
aruminium::autorelease_pool(|| {
dev.dispatch.batch_raw(|enc| {
enc.bind(pipeline);
enc.bind_buffer(x, 0, 0);
enc.bind_buffer(w, 0, 1);
enc.bind_buffer(&out, 0, 2);
let bytes = std::slice::from_raw_parts(
&dims as *const Dims as *const u8,
std::mem::size_of::<Dims>(),
);
enc.push(bytes, 3);
let n = total as usize;
enc.launch_groups(((n + 63) / 64, 1, 1), (64, 1, 1));
});
});
}
Ok(out)
}
pub fn tg_count(n_rows: u32, batch: u32) -> usize {
let total = (n_rows * batch) as usize;
(total + SIMDS_PER_GROUP as usize - 1) / SIMDS_PER_GROUP as usize
}
pub fn tg_size() -> usize { (SIMDS_PER_GROUP * LANES) as usize }