For the complete documentation index, see llms.txt. Markdown versions of all pages are available by appending .md to any URL (e.g. /max/get-started.md).
Mojo struct
Matmul2dFp8
struct Matmul2dFp8[c_type: DType = DType.float32, elementwise_lambda_fn: Optional[def[dtype: DType, width: SIMDLength, *, alignment: Int = Int(1)](IndexList[Int(2)], SIMD[dtype, width]) capturing thin -> None] = None, block_m: Int = Int(64), block_n: Int = Int(64), block_k: Int = Int(16), sg_m: Int = Int(32), sg_n: Int = Int(32)]
W8A16 simdgroup-tiled GEMM: bf16 A x fp8 B -> fp32, direct DRAM B feed.
Mirrors AppleM5MatMul (the ~400 GB/s dense bf16 decode path) with the sole
change that the B (weight) operand is float8_e4m3fn via MmaOpApple's
b_type. A is bf16, C is c_type, accumulation fp32. No SMEM, no barrier:
each K-strip's B fragments load straight from DRAM (coalesced K-contiguous via
the col-major (K, N) view) and feed the native fp8-capable MMA.
Parametersβ
- βc_type (
DType): Output element type (fp16, bf16, fp32). Accumulation is fp32. - βelementwise_lambda_fn (
Optional[def[dtype: DType, width: SIMDLength, *, alignment: Int = Int(1)](IndexList[Int(2)], SIMD[dtype, width]) capturing thin -> None]): Optional fused epilogue (AMD's(row, col)contract). Currently unused on the interior store; the launcher routes fused-epilogue shapes elsewhere. - βblock_m (
Int): Threadgroup block rowsBM(multiple ofSG_M). - βblock_n (
Int): Threadgroup block colsBN(multiple ofSG_N). - βblock_k (
Int): K-strip depthBKper accumulate step (multiple of 16). - βsg_m (
Int): Simdgroup subtile rowsSG_M(multiple of 16). - βsg_n (
Int): Simdgroup subtile colsSG_N(multiple of 16).sg_m/16 * sg_n/16is the accumulator count;2x2 == 4is the M5 optimum (do NOT exceed).
Implemented traitsβ
comptime membersβ
b_typeβ
comptime b_type = DType.float8_e4m3fn
BKβ
comptime BK = block_k
BMβ
comptime BM = block_m
BNβ
comptime BN = block_n
in_typeβ
comptime in_type = DType.bfloat16
Mmaβ
comptime Mma = MmaOpApple[DType.float32, DType.bfloat16, Matmul2dFp8[c_type, elementwise_lambda_fn, block_m, block_n, block_k, sg_m, sg_n].NUM_MMA_M, Matmul2dFp8[c_type, elementwise_lambda_fn, block_m, block_n, block_k, sg_m, sg_n].NUM_MMA_N, b_type=DType.float8_e4m3fn]
NUM_MMA_Mβ
comptime NUM_MMA_M = (Matmul2dFp8[c_type, elementwise_lambda_fn, block_m, block_n, block_k, sg_m, sg_n].SG_M // Int(16))
NUM_MMA_Nβ
comptime NUM_MMA_N = (Matmul2dFp8[c_type, elementwise_lambda_fn, block_m, block_n, block_k, sg_m, sg_n].SG_N // Int(16))
NUM_SGβ
comptime NUM_SG = (Matmul2dFp8[c_type, elementwise_lambda_fn, block_m, block_n, block_k, sg_m, sg_n].NUM_SG_M * Matmul2dFp8[c_type, elementwise_lambda_fn, block_m, block_n, block_k, sg_m, sg_n].NUM_SG_N)
NUM_SG_Mβ
comptime NUM_SG_M = (Matmul2dFp8[c_type, elementwise_lambda_fn, block_m, block_n, block_k, sg_m, sg_n].BM // Matmul2dFp8[c_type, elementwise_lambda_fn, block_m, block_n, block_k, sg_m, sg_n].SG_M)
NUM_SG_Nβ
comptime NUM_SG_N = (Matmul2dFp8[c_type, elementwise_lambda_fn, block_m, block_n, block_k, sg_m, sg_n].BN // Matmul2dFp8[c_type, elementwise_lambda_fn, block_m, block_n, block_k, sg_m, sg_n].SG_N)
SG_Mβ
comptime SG_M = sg_m
SG_Nβ
comptime SG_N = sg_n
THREADS_PER_BLOCKβ
comptime THREADS_PER_BLOCK = (Matmul2dFp8[c_type, elementwise_lambda_fn, block_m, block_n, block_k, sg_m, sg_n].NUM_SG * _resolve_warp_size())
Methodsβ
run_groupedβ
static def run_grouped[c_layout: TensorLayout, a_layout: TensorLayout, b_layout: TensorLayout, ao_layout: TensorLayout, ei_layout: TensorLayout](c: TileTensor[c_type, c_layout, MutAnyOrigin], a: TileTensor[DType.bfloat16, a_layout, ImmutAnyOrigin], b: TileTensor[DType.float8_e4m3fn, b_layout, ImmutAnyOrigin], a_offsets: TileTensor[DType.uint32, ao_layout, ImmUnsafeAnyOrigin], expert_ids: TileTensor[DType.int32, ei_layout, ImmUnsafeAnyOrigin], N: Int, K: Int)
Grouped (MoE) W8A16 kernel entry: one expert group per block_idx.z.
Computes, for group z = block_idx.z,
C[a_offsets[z]:a_offsets[z+1], :] = A[a_offsets[z]:a_offsets[z+1], :] @ b[expert_ids[z], :, :]^T
i.e. the FP8 analog of naive_grouped_matmul_kernel but on the tiled
simdgroup MMA. c is the ragged output (total_M, N), a the ragged
bf16 activation (total_M, K), b the FP8 weight stack
(num_experts, N, K). Produces the RAW (unscaled) matmul; the per-expert
weight_scale is folded post-matmul by the graph lowering, exactly as on
the dense Apple FP8 Linear (a per-tensor scalar factors out of the sum).
Grid (ceil(N/BN), ceil(max_tokens_per_expert/BM), num_active_experts).
Per-group ragged M is a_offsets[z+1] - a_offsets[z]; empty groups
(M == 0) and fully-OOB M-tiles early-return in _gemm_body. An inactive
LoRA group (expert_ids[z] == -1) writes zeros for its rows.
The per-group base views use a base-pointer offset (a.ptr + a_start*K,
b.ptr + expert*N*K) -- the ragged-group addressing idiom shared by every
grouped matmul kernel in the tree (naive_grouped_matmul_kernel,
grouped_matmul_amd_kernel_launcher); TileTensor has no runtime-offset
ragged-slice primitive that keeps the inner (., K) dims static. All
element access inside _gemm_body is TileTensor-indexed (MMA fragment
loaders + guarded c.store).
Was this page helpful?
Thank you! We'll create more content like this.
Thank you for helping us improve!