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
MmaOpApple
struct MmaOpApple[out_type: DType, in_type: DType, num_m_mmas: Int, num_n_mmas: Int, *, b_type: DType = in_type, transpose_a: Bool = False, transpose_b: Bool = False]
Apple Silicon simdgroup-level MMA abstraction for tile-based matrix multiply.
Each simdgroup (32 threads) owns one instance and accumulates a
(num_m_mmas * 16) x (num_n_mmas * 16) output tile using Apple simdgroup
matrix multiply-accumulate instructions. Supports both dense and fused
online-im2col A-operand paths.
Parametersβ
- βout_type (
DType): Element type for the output accumulator (float32 or float16). - βin_type (
DType): Element type for the A operand. - βnum_m_mmas (
Int): Number of 16x16 MMA tiles along the M dimension. - βnum_n_mmas (
Int): Number of 16x16 MMA tiles along the N dimension. - βb_type (
DType): Element type for the B operand; defaults to in_type. - βtranspose_a (
Bool): When True, the A tile is stored in transposed (K, M) layout. - βtranspose_b (
Bool): When True, the B tile is stored in transposed (N, K) layout.
Fieldsβ
- βrb (
Int): - βcb (
Int):
Implemented traitsβ
comptime membersβ
AccumTypeβ
comptime AccumType = Array[SIMD[out_type, SIMDLength(8)], MmaOpApple[out_type, in_type, num_m_mmas, num_n_mmas, b_type=b_type, transpose_a=transpose_a, transpose_b=transpose_b].num_accum]
FRAG_SIZEβ
comptime FRAG_SIZE = 8
MMA_Kβ
comptime MMA_K = 16
MMA_Mβ
comptime MMA_M = 16
MMA_Nβ
comptime MMA_N = 16
num_accumβ
comptime num_accum = (num_m_mmas * num_n_mmas)
Methodsβ
__init__β
def __init__(out self)
zero_accumβ
static def zero_accum() -> Self.AccumType
Returns:
Self.AccumType
load_fragmentβ
def load_fragment[dtype: DType, bounded: Bool = False](self, tile: TileTensor[dtype, Storage=tile.Storage, address_space=tile.address_space, linear_idx_type=tile.linear_idx_type], valid_rows: Int = Int(16)) -> SIMD[dtype, SIMDLength(8)]
Loads one 16x16 simdgroup fragment from a TileTensor sub-tile.
The _apple_frag_layout bit-scatter is owned here at the MmaOpApple
layer, not via a TileTensor distribute (KB
exceptions/apple-mma-fragment-is-not-distribute-expressible). Used for
the V operand of a P.V MMA, where A (P) is a register-resident score
fragment and so cannot go through mma().
bounded=True zero-fills rows >= valid_rows instead of reading them
-- needed for the V load on the last KV sub-tile when num_keys % 16 != 0, where reading an OOB row makes 0 * V_oob == NaN and poisons the
fp32 PV accumulator (KB kernels/apple-m5-fa-prefill). Depth columns are
always in-bounds, so only rows are predicated.
Parameters:
- βdtype (
DType): The element dtype of the source tile. - βbounded (
Bool): When True, zero-fill rows>= valid_rows.
Args:
- βtile (
TileTensor[dtype, Storage=tile.Storage, address_space=tile.address_space, linear_idx_type=tile.linear_idx_type]): A 16x16 source view (row- or col-major). - βvalid_rows (
Int): Valid rows from the sub-tile origin (only when bounded).
Returns:
SIMD[dtype, SIMDLength(8)]: This lane's 8-element fragment.
mmaβ
def mma[bounded: Bool = False](self, mut accum: Array[SIMD[out_type, SIMDLength(8)], Self.num_accum], a_tile: TileTensor[in_type, Storage=a_tile.Storage, address_space=a_tile.address_space, linear_idx_type=a_tile.linear_idx_type], b_tile: TileTensor[b_type, Storage=b_tile.Storage, address_space=b_tile.address_space, linear_idx_type=b_tile.linear_idx_type], a_valid_rows: Int = (num_m_mmas * Int(16)), b_valid_cols: Int = (num_n_mmas * Int(16)), k_valid: Int = a_tile.LayoutType.static_shape[Int(1)])
Process K elements across all M/N tile positions.
The K depth is inferred from the A tile's column dimension and must be a multiple of 16. For K=16 this is one MMA step; for K=32 this is two steps, etc. The struct iterates K internally.
Tiles may be row-major or col-major. The stride layout is detected from static_stride and the hardware transpose flag is derived via XOR with the transpose parameter: hw_flag = is_col_major XOR transpose_param.
Use mma() (bounded=False) for interior tiles where all memory is in-bounds. Use mmabounded=True for edge tiles -- zero-fills OOB elements. The kernel should check once per simdgroup, not per load.
Parameters:
- βbounded (
Bool): When True, zero-fill out-of-bounds A/B elements instead of reading them (defaults to False).
Args:
- βaccum (
Array[SIMD[out_type, SIMDLength(8)], Self.num_accum]): Caller-owned Array of SIMD[out_type, 8] accumulators, one per (num_m_mmas * num_n_mmas) tile. - βa_tile (
TileTensor[in_type, Storage=a_tile.Storage, address_space=a_tile.address_space, linear_idx_type=a_tile.linear_idx_type]): A operand, shape (num_m_mmas * 16, K). - βb_tile (
TileTensor[b_type, Storage=b_tile.Storage, address_space=b_tile.address_space, linear_idx_type=b_tile.linear_idx_type]): B operand, shape (K, num_n_mmas * 16) or (num_n_mmas * 16, K) if transpose_b. - βa_valid_rows (
Int): Valid rows from tile origin (bounded path only). - βb_valid_cols (
Int): Valid cols from tile origin (bounded path only). - βk_valid (
Int): Valid K elements across all steps (bounded path only). Defaults to the tile's full K dimension.
mma_dense_x2β
def mma_dense_x2[bounded: Bool = False](self, mut accum: Array[SIMD[out_type, SIMDLength(8)], Self.num_accum], a_tile: TileTensor[in_type, Storage=a_tile.Storage, address_space=a_tile.address_space, linear_idx_type=a_tile.linear_idx_type], b_tile: TileTensor[b_type, Storage=b_tile.Storage, address_space=b_tile.address_space, linear_idx_type=b_tile.linear_idx_type], a_valid_rows: Int = (num_m_mmas * Int(16)), b_valid_cols: Int = (num_n_mmas * Int(16)), k_valid: Int = Int(32))
BK=32 "double-strip" dense NT MMA: process 32 K per call.
A (SG_M, 32) row-major and B (32, SG_N) col-major are both K
contiguous, so one call reads two BK=16 strips' worth of K -- halving
the K-loop's iteration count -- via native load[width=4]s (see
_load_frag_x2).
Correctness: the 2*cb split permutes K identically on both operands
(f0 = K-cols {2cb..2cb+3}, f1 = {2cb+4..2cb+7}), and matmul
contraction is K-permutation-invariant, so f0+f1 sum to the full
32-K contraction -- the same trick mma_im2col's width-8 gather uses.
Args:
- βaccum (
Array[SIMD[out_type, SIMDLength(8)], Self.num_accum]): Caller-owned accumulators (one per num_m_mmas * num_n_mmas). - βa_tile (
TileTensor[in_type, Storage=a_tile.Storage, address_space=a_tile.address_space, linear_idx_type=a_tile.linear_idx_type]): A operand,(num_m_mmas*16, 32)row-major. - βb_tile (
TileTensor[b_type, Storage=b_tile.Storage, address_space=b_tile.address_space, linear_idx_type=b_tile.linear_idx_type]): B operand,(32, num_n_mmas*16)col-major (NT). - βa_valid_rows (
Int): Valid M rows from the tile origin (bounded path only). - βb_valid_cols (
Int): Valid N cols from the tile origin (bounded path only). - βk_valid (
Int): Valid K elements in this 32-strip (partial-K tail only).
mma_im2colβ
def mma_im2col[input_origin: ImmOrigin, bounded: Bool = True, c_aligned: Bool = False](self, mut accum: Array[SIMD[out_type, SIMDLength(8)], Self.num_accum], input_ptr: Pointer[Scalar[in_type], input_origin, _safe=False], conv: ConvIm2colParams, b_tile: TileTensor[b_type, Storage=b_tile.Storage, address_space=b_tile.address_space, linear_idx_type=b_tile.linear_idx_type], h_base: Array[Int32, (num_m_mmas * Int(2))], w_base: Array[Int32, (num_m_mmas * Int(2))], batch_base: Array[Int32, (num_m_mmas * Int(2))], c0: Int32, r: Int32, s: Int32, k_base: Int32, m_valid: Int32, k_total: Int32, b_valid_cols: Int, k_valid: Int)
Fused-conv MMA step: A from online im2col gather, B as in mma.
The A row anchors (h_base, w_base, batch_base) are prebaked by the
loader (K-invariant m -> pixel decomposition, hoisted out of the
K-loop); indexed per (mi, half) as ri = mi*2 + half. The strip's
K-decomposition (c0, r, s) (= k0base -> tap/channel) is carried by
the loader and passed in, so the gather does no ///% on the K axis.
Apple M5 has no LDS stage, so the A operand is gathered per fragment
rather than staged. Design: KB kernels/apple-conv2d-im2col.
Parameters:
- βinput_origin (
ImmOrigin): Memory origin of the NHWC input pointer (inferred). - βbounded (
Bool): When True, zero-fill out-of-bounds A/B elements instead of reading them (defaults to True). - βc_aligned (
Bool): When True, assumeconv.Cis a multiple of 8 so the channel run is contiguous and a single width-8 load suffices (defaults to False).
Args:
- βaccum (
Array[SIMD[out_type, SIMDLength(8)], Self.num_accum]): Caller-owned accumulators (one per num_m_mmas * num_n_mmas). - βinput_ptr (
Pointer[Scalar[in_type], input_origin, _safe=False]): NHWC input base pointer. - βconv (
ConvIm2colParams): Conv geometry for the im2col gather. - βb_tile (
TileTensor[b_type, Storage=b_tile.Storage, address_space=b_tile.address_space, linear_idx_type=b_tile.linear_idx_type]): B operand,(K, num_n_mmas*16)or(num_n_mmas*16, K)if transpose_b -- same contract asmma. - βh_base (
Array[Int32, (num_m_mmas * Int(2))]): Prebaked per-row input-row anchor, indexedri = mi*2+half. - βw_base (
Array[Int32, (num_m_mmas * Int(2))]): Prebaked per-row input-col anchor. - βbatch_base (
Array[Int32, (num_m_mmas * Int(2))]): Prebaked per-row batch offset into the NHWC input. - βc0 (
Int32): Carried channel base of this strip's K origin. - βr (
Int32): Carried filter-row tap of this strip's K origin. - βs (
Int32): Carried filter-col tap of this strip's K origin. - βk_base (
Int32): Absolute K (RSC) column where this BK strip starts. - βm_valid (
Int32): Valid M rows from the simdgroup origin (ragged-M edge). - βk_total (
Int32): Total K extent (RSC); A cols at or past it zero-fill. - βb_valid_cols (
Int): Valid N cols from the B tile origin (edge zero-fill). - βk_valid (
Int): Valid K elements in this strip (partial-K tail zero-fill).
storeβ
def store(self, accum: Array[SIMD[out_type, SIMDLength(8)], Self.num_accum], d_tile: TileTensor[out_type, Storage=d_tile.Storage, address_space=d_tile.address_space, linear_idx_type=d_tile.linear_idx_type])
Store all accumulators to output tile (unconditional).
Caller guarantees all elements are in-bounds.
Args:
- βaccum (
Array[SIMD[out_type, SIMDLength(8)], Self.num_accum]): Caller-owned accumulators to write, one per (num_m_mmas * num_n_mmas) tile. - βd_tile (
TileTensor[out_type, Storage=d_tile.Storage, address_space=d_tile.address_space, linear_idx_type=d_tile.linear_idx_type]): Output tile of shape (num_m_mmas * 16, num_n_mmas * 16).
store_boundedβ
def store_bounded(self, accum: Array[SIMD[out_type, SIMDLength(8)], Self.num_accum], d_tile: TileTensor[out_type, Storage=d_tile.Storage, address_space=d_tile.address_space, linear_idx_type=d_tile.linear_idx_type], valid_rows: Int, valid_cols: Int)
Stores accumulators where (row < valid_rows) and (col < valid_cols).
Assumes row-major d_tile; for col-major, mirror _do_load's swap.
Args:
- βaccum (
Array[SIMD[out_type, SIMDLength(8)], Self.num_accum]): Caller-owned accumulators to write, one per (num_m_mmas * num_n_mmas) tile. - βd_tile (
TileTensor[out_type, Storage=d_tile.Storage, address_space=d_tile.address_space, linear_idx_type=d_tile.linear_idx_type]): Row-major output tile of shape (num_m_mmas * 16, num_n_mmas * 16). - βvalid_rows (
Int): Valid rows from the tile origin; rows at or past this are skipped. - βvalid_cols (
Int): Valid cols from the tile origin; cols at or past this are skipped.
load_accumβ
def load_accum(self, d_tile: TileTensor[out_type, Storage=d_tile.Storage, address_space=d_tile.address_space, linear_idx_type=d_tile.linear_idx_type]) -> Self.AccumType
Inverse of store: seed an accumulator from a previously-written output tile (chained-accumulate split-K, e.g. clamp_v2's second pass, instead of a separate partials buffer + reduce kernel).
Caller guarantees all elements are in-bounds.
Returns:
Self.AccumType
Was this page helpful?
Thank you! We'll create more content like this.
Thank you for helping us improve!