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
Matmul2dFp4
struct Matmul2dFp4[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, num_sg_m: Int = Int(2), num_sg_n: Int = Int(2), tm: Int = Int(2), tn: Int = Int(2), smem_bk: Int = Int(16)]
W4A16 GEMM on the native 16x32x16 matmul2d MMA: coalesced NT FP4 decode.
Each 16x32x16 MMA is two native _mma_apple_transposable
(air.simdgroup_matrix_16x16x16) calls (matmul2d_mma_regc_bt_native) --
pure Mojo over _mma_apple, no external library or codegen dependency.
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; wired for parity. - βnum_sg_m (
Int): Simdgroup rows per threadgroup. - βnum_sg_n (
Int): Simdgroup cols per threadgroup. - βtm (
Int): Output 16x32 tiles per simdgroup along M (register-C accumulators). - βtn (
Int): Output 16x32 tiles per simdgroup along N.tm*tn == 4is the M5 register-cliff optimum; do NOT exceed 4 (measured collapse past it). - βsmem_bk (
Int): Cooperative-decode strip depth forrun_smem_decode(the bf16 weight sub-tile columns decoded per phase; one decode feedssmem_bk//16MMA K-steps). Unused by the per-lanerunkernel. The production launcher pins 256, the M5 optimum: a deeper strip amortizes the decode over more MMA work; 512 spills.
Implemented traitsβ
comptime membersβ
BKβ
comptime BK = smem_bk
BNβ
comptime BN = Matmul2dFp4[c_type, elementwise_lambda_fn, num_sg_m, num_sg_n, tm, tn, smem_bk].TG_N
BYTES_PER_THREADβ
comptime BYTES_PER_THREAD = (Matmul2dFp4[c_type, elementwise_lambda_fn, num_sg_m, num_sg_n, tm, tn, smem_bk].PACKED_COLS // (Int((mul _resolve_warp_size(), num_sg_m, num_sg_n)) // Int((mul num_sg_n, tn, 32))))
COLS_PER_THREADβ
comptime COLS_PER_THREAD = (((smem_bk // Int(2)) // (Int((mul _resolve_warp_size(), num_sg_m, num_sg_n)) // Int((mul num_sg_n, tn, 32)))) * Int(2))
in_typeβ
comptime in_type = DType.bfloat16
MMA_Kβ
comptime MMA_K = M2D_K
MMA_Mβ
comptime MMA_M = M2D_M
MMA_Nβ
comptime MMA_N = M2D_N
NUM_SGβ
comptime NUM_SG = (num_sg_m * num_sg_n)
PACKED_COLSβ
comptime PACKED_COLS = (Matmul2dFp4[c_type, elementwise_lambda_fn, num_sg_m, num_sg_n, tm, tn, smem_bk].BK // Int(2))
SFβ
comptime SF = NVFP4_SF_VECTOR_SIZE
TG_Mβ
comptime TG_M = ((Int(16) * num_sg_m) * tm)
TG_Nβ
comptime TG_N = ((Int(32) * num_sg_n) * tn)
THREADS_PER_BLOCKβ
comptime THREADS_PER_BLOCK = (Matmul2dFp4[c_type, elementwise_lambda_fn, num_sg_m, num_sg_n, tm, tn, smem_bk].NUM_SG * _resolve_warp_size())
THREADS_PER_ROWβ
comptime THREADS_PER_ROW = (Int((mul _resolve_warp_size(), num_sg_m, num_sg_n)) // Matmul2dFp4[c_type, elementwise_lambda_fn, num_sg_m, num_sg_n, tm, tn, smem_bk].BN)
Methodsβ
runβ
static def run[c_layout: TensorLayout, a_layout: TensorLayout, packed_layout: TensorLayout, scale_layout: TensorLayout](c: TileTensor[c_type, c_layout, MutAnyOrigin], a: TileTensor[DType.bfloat16, a_layout, ImmutAnyOrigin], packed: TileTensor[DType.uint8, packed_layout, ImmutAnyOrigin], scales: TileTensor[DType.float8_e4m3fn, scale_layout, ImmutAnyOrigin], M: Int, N: Int, K: Int)
W4A16 kernel entry. C (M, N), A (M, K) bf16, packed (N, K//2), scales (N, ceil(K/16)). Interior fast path (tile-aligned N, K%16==0).
Parameters:
- βc_layout (
TensorLayout): Layout of the outputC(M, N)view. - βa_layout (
TensorLayout): Layout of the activationA(M, K)view. - βpacked_layout (
TensorLayout): Layout of the packed FP4 weight(N, K//2)view. - βscale_layout (
TensorLayout): Layout of the block scales(N, ceil(K/16))view.
Args:
- βc (
TileTensor[c_type, c_layout, MutAnyOrigin]): OutputTileTensorview with shape(M, N). - βa (
TileTensor[DType.bfloat16, a_layout, ImmutAnyOrigin]): Bf16 activationTileTensorview with shape(M, K). - βpacked (
TileTensor[DType.uint8, packed_layout, ImmutAnyOrigin]): Packed FP4 weightTileTensorview with shape(N, K//2)(uint8, lo-nibble first). - βscales (
TileTensor[DType.float8_e4m3fn, scale_layout, ImmutAnyOrigin]): FP8-E4M3 block-scaleTileTensorview with shape(N, ceil(K/16)). - βM (
Int): Number of rows in the activation and the output. - βN (
Int): Number of columns in the output and rows of the weight. - βK (
Int): Reduction dimension; inner size ofaand the weight.
run_smem_decodeβ
static def run_smem_decode[c_layout: TensorLayout, a_layout: TensorLayout, packed_layout: TensorLayout, scale_layout: TensorLayout](c: TileTensor[c_type, c_layout, MutAnyOrigin], a: TileTensor[DType.bfloat16, a_layout, ImmutAnyOrigin], packed: TileTensor[DType.uint8, packed_layout, ImmutAnyOrigin], scales: TileTensor[DType.float8_e4m3fn, scale_layout, ImmutAnyOrigin], M: Int, N: Int, K: Int)
Cooperative-decode W4A16: coalesced FP4 decode -> SMEM -> register B.
The run kernel decodes per-lane, but each lane's transpose_right B
fragment reads 4 N-scattered rows (stride-K/2 in the packed (N, K//2)
weight) -> the packed + scale loads are uncoalesced gathers and dominate
(measured: they drop the ~60 TF/s pure-MMA feed to ~10). This kernel
COOPERATIVELY decodes the (BN, BK) weight sub-tile into SMEM with
ADJACENT threads reading ADJACENT packed bytes (coalesced K), then each
simdgroup reads its tn register B fragments from SMEM via the
transpose_right map (bt_frag_coord) and runs the native 16x32x16 MMA
(matmul2d_mma_regc_bt_native, two _mma_apple_transposable calls).
This is the committed AppleM5Fp4MatMul cooperative-decode idea on the
matmul2d tile shape -- the MMA stays REGISTER-fed (a plain
SMEM->register indexed load).
Interior fast path (tile-aligned N, K % BK == 0). A loads register-direct
from DRAM (base map, K contiguous). Bit-exact vs run / the materialize
oracle (same decode_e2m1_to_f32 * |scale|, same MMA), modulo the fp32
MMA reduction order (identical to run, so bit-exact vs run).
Parameters:
- βc_layout (
TensorLayout): Layout of the outputC(M, N)view. - βa_layout (
TensorLayout): Layout of the activationA(M, K)view. - βpacked_layout (
TensorLayout): Layout of the packed FP4 weight(N, K//2)view. - βscale_layout (
TensorLayout): Layout of the block scales(N, ceil(K/16))view.
Args:
- βc (
TileTensor[c_type, c_layout, MutAnyOrigin]): OutputTileTensorview with shape(M, N). - βa (
TileTensor[DType.bfloat16, a_layout, ImmutAnyOrigin]): Bf16 activationTileTensorview with shape(M, K). - βpacked (
TileTensor[DType.uint8, packed_layout, ImmutAnyOrigin]): Packed FP4 weightTileTensorview with shape(N, K//2)(uint8, lo-nibble first). - βscales (
TileTensor[DType.float8_e4m3fn, scale_layout, ImmutAnyOrigin]): FP8-E4M3 block-scaleTileTensorview with shape(N, ceil(K/16)). - βM (
Int): Number of rows in the activation and the output. - βN (
Int): Number of columns in the output and rows of the weight. - βK (
Int): Reduction dimension; inner size ofaand the weight.
Was this page helpful?
Thank you! We'll create more content like this.
Thank you for helping us improve!