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
MhaPrefillV2
struct MhaPrefillV2[config: MhaConfigV2]
8-warp MHA forward kernel parameterized by MhaConfigV2.
Each block runs config.num_warps wave64 warps that share K/V
SMEM via cooperative DMA. Warp w owns Q rows [w * q_block_size, (w + 1) * q_block_size) of the block's stripe and carries its own
register-resident attention state.
Parametersβ
- βconfig (
MhaConfigV2): Shape configuration (MhaConfigV2).
Implemented traitsβ
comptime membersβ
BMβ
comptime BM = (config * config)
D_FRAG_PER_LANEβ
comptime D_FRAG_PER_LANE = (Int((mul config.depth, config.q_block_size)) // Int(64))
DEPTHβ
comptime DEPTH = config.depth
k_swizzleβ
comptime k_swizzle = Optional(Swizzle(Int(1), Int(0), Int(4)))
k_swizzle2β
comptime k_swizzle2 = Optional(Swizzle(Int(1), Int(1), Int(4)))
KTileLoaderβ
comptime KTileLoader = SubTileLoaderLDS[config.dtype, MhaPrefillV2[config].k_swizzle, MhaPrefillV2[config].k_swizzle2]
KV_BLOCKβ
comptime KV_BLOCK = config.kv_block
NUM_HEADSβ
comptime NUM_HEADS = config.num_heads
NUM_KV_HEADSβ
comptime NUM_KV_HEADS = config.num_kv_heads
NUM_THREADSβ
comptime NUM_THREADS = (config * Int(64))
NUM_WARPSβ
comptime NUM_WARPS = config.num_warps
prescale_qβ
comptime prescale_q = not config.dtype.is_float8().__bool__()
Q_BLOCK_SIZEβ
comptime Q_BLOCK_SIZE = config.q_block_size
RESCALE_THRESHOLDβ
comptime RESCALE_THRESHOLD = config.rescale_threshold
v_swizzleβ
comptime v_swizzle = Optional(None)
VTileLoaderβ
comptime VTileLoader = SubTileLoaderLDS_st_8x32[config.dtype, config.kv_block, config.depth, Int(64) if (eq #pop.dtype_to_ui8<#lit.struct.extract<:!lit.struct<@std::@builtin::@dtype::@DType> #lit.struct.extract<:!lit.struct<@nn::@attention::@gpu::@amd_structured::@mha_mma_op::@MhaConfigV2> config, "dtype">, "_mlir_value">>, 73) if (eq #pop.dtype_to_ui8<#lit.struct.extract<:!lit.struct<@std::@builtin::@dtype::@DType> #lit.struct.extract<:!lit.struct<@nn::@attention::@gpu::@amd_structured::@mha_mma_op::@MhaConfigV2> config, "dtype">, "_mlir_value">>, 73) else (eq #pop.dtype_to_ui8<#lit.struct.extract<:!lit.struct<@std::@builtin::@dtype::@DType> #lit.struct.extract<:!lit.struct<@nn::@attention::@gpu::@amd_structured::@mha_mma_op::@MhaConfigV2> config, "dtype">, "_mlir_value">>, 74) or (eq #pop.dtype_to_ui8<#lit.struct.extract<:!lit.struct<@std::@builtin::@dtype::@DType> #lit.struct.extract<:!lit.struct<@nn::@attention::@gpu::@amd_structured::@mha_mma_op::@MhaConfigV2> config, "dtype">, "_mlir_value">>, 75) or (eq #pop.dtype_to_ui8<#lit.struct.extract<:!lit.struct<@std::@builtin::@dtype::@DType> #lit.struct.extract<:!lit.struct<@nn::@attention::@gpu::@amd_structured::@mha_mma_op::@MhaConfigV2> config, "dtype">, "_mlir_value">>, 76) or (eq #pop.dtype_to_ui8<#lit.struct.extract<:!lit.struct<@std::@builtin::@dtype::@DType> #lit.struct.extract<:!lit.struct<@nn::@attention::@gpu::@amd_structured::@mha_mma_op::@MhaConfigV2> config, "dtype">, "_mlir_value">>, 77) or (eq #pop.dtype_to_ui8<#lit.struct.extract<:!lit.struct<@std::@builtin::@dtype::@DType> #lit.struct.extract<:!lit.struct<@nn::@attention::@gpu::@amd_structured::@mha_mma_op::@MhaConfigV2> config, "dtype">, "_mlir_value">>, 78) else Int(32), Int((mul config.num_warps, 64))]
Methodsβ
load_qβ
static def load_q[layout: TensorLayout](q_warp_2d: TileTensor[config.dtype, layout, Storage=q_warp_2d.Storage, address_space=q_warp_2d.address_space, linear_idx_type=q_warp_2d.linear_idx_type]) -> TileTensor[config.dtype, Layout[*?, *?], MutUntrackedOrigin, address_space=AddressSpace.LOCAL]
Loads the warp's Q sub-tile from gmem into a row_l register tile via RegTileLoader.
BF16 (d=128, MMA_K=16): 8 K-tiles Γ 1 buffer_load_bf16x8 per
lane per K-tile = 8 loads Γ 16 B each. Per-lane fragment = 8
BF16 = 16 B fits in one buffer_load.
FP8 (d=128, MMA_K=64): 2 K-tiles, but each base tile per lane is 32 FP8 = 32 B which exceeds the 16-B buffer_load_lds max. Splits each K-tile load into 2 Γ 16-elt halves (16 B each) targeting the first / second half of the destination cell.
Parameters:
- βlayout (
TensorLayout): Layout ofq_warp_2d(inferred).
Args:
- βq_warp_2d (
TileTensor[config.dtype, layout, Storage=q_warp_2d.Storage, address_space=q_warp_2d.address_space, linear_idx_type=q_warp_2d.linear_idx_type]): Per-warp Q gmem sub-tile of shape(Q_BLOCK_SIZE, DEPTH)sliced from the per-head 2D Q view.
Returns:
TileTensor[config.dtype, Layout[*?, *?], MutUntrackedOrigin, address_space=AddressSpace.LOCAL]
runβ
static def run[k_t: MHAOperand, v_t: MHAOperand, mask_t: MHAMask, q_dtype: DType, output_dtype: DType, q_layout: TensorLayout, o_layout: TensorLayout, ragged: Bool = False, sink: Bool = False](q: TileTensor[q_dtype, q_layout, ImmutAnyOrigin], k: k_t, v: v_t, o: TileTensor[output_dtype, o_layout, MutAnyOrigin], mask_functor: mask_t, scale: Float32, num_keys: Int, start_pos: Int, sink_weights_ptr: Pointer[Scalar[q_dtype], ImmutAnyOrigin, _safe=False])
Multi-block 8-warp MHA forward (inference-only).
Grid: (NUM_HEADS, ceildiv(seq_len, BM), batch). Each block
owns one (batch, head, BM-tile) slice; the 8 warps within
split the BM-tile's Q rows.
Expected layouts / shapes:
q,o:(batch, seq_len, NUM_HEADS, DEPTH)row-major TileTensor.o's dtype matchesconfig.output_dtype: BF16 for the production dispatcher (which holds a BF16 output buffer) or FP32 if the caller wants the unnormalized accumulator.k,v: anyMHAOperandwhoseblock_paged_tile[KV_BLOCK]returns(KV_BLOCK, DEPTH)tiles per(batch, t*KV_BLOCK, kv_head, 0).LayoutTensorMHAOperandfor contiguous test / bench buffers;KVCacheMHAOperandfor paged production caches (page_size >= KV_BLOCK = 64).
batch and seq_len / num_keys may be dynamic;
NUM_HEADS, NUM_KV_HEADS, DEPTH must be static.
NUM_HEADS must be a multiple of NUM_KV_HEADS
(GROUP = NUM_HEADS // NUM_KV_HEADS).
Parameters:
- βk_t (
MHAOperand): K operand type (inferred); anyMHAOperandwhoseblock_paged_tilereturns(KV_BLOCK, DEPTH)tiles. - βv_t (
MHAOperand): V operand type (inferred); same tile contract ask_t. - βmask_t (
MHAMask): Mask functor type (inferred); selects the per-tile masking strategy (causal, sliding-window, null, etc.). - βq_dtype (
DType): Element dtype ofq(inferred); must equalconfig.dtype. - βoutput_dtype (
DType): Element dtype ofo(inferred); must equalconfig.output_dtype. - βq_layout (
TensorLayout): Layout of theqTileTensor (inferred). - βo_layout (
TensorLayout): Layout of theoTileTensor (inferred). - βragged (
Bool): Whetherqis a per-sequence slice in a packed ragged batch (defaults to False). - βsink (
Bool): Whether to seed the online softmax with attention-sink weights (defaults to False).
Args:
- βq (
TileTensor[q_dtype, q_layout, ImmutAnyOrigin]): Q tile tensor. - βk (
k_t): K operand (MHAOperand). - βv (
v_t): V operand (MHAOperand). - βo (
TileTensor[output_dtype, o_layout, MutAnyOrigin]): Output tile tensor (config.output_dtype, same shape asq). - βmask_functor (
mask_t): Per-tile mask predicate (causal, sliding-window, etc.). Evaluated inside the QKβsoftmax cluster; identity for unmasked attention. - βscale (
Float32): Softmax scale (1/sqrt(DEPTH)). - βnum_keys (
Int): Runtime length of the K/V sequence. - βstart_pos (
Int): Position of the first Q row in the global sequence: non-zero for prefill chunks of a longer generation. Used by the mask functor to compute the causal cutoff. - βsink_weights_ptr (
Pointer[Scalar[q_dtype], ImmutAnyOrigin, _safe=False]): Per-q-head attention-sink scalar weights. Read only when the comptimesinkparameter is True; the non-sink path comptime-elides the load, so callers may passUnsafePointer[...].unsafe_dangling()whensink=False. Indexed byhead_idxonce per block at init time, cast to FP32, multiplied bylog2eto land in the kernel's log2-units rowmax, and seeded intomax_vec/max_vec_prev/norm_vecso the hot loop stays sink-agnostic.
ragged_kernelβ
static def ragged_kernel[k_t: MHAOperand, v_t: MHAOperand, mask_t: MHAMask, qkv_dtype: DType, output_dtype: DType, cross_attention: Bool = False, sink: Bool = False](q_ptr: Pointer[Scalar[qkv_dtype], ImmutAnyOrigin, _safe=False], k: k_t, v: v_t, output_ptr: Pointer[Scalar[output_dtype], MutAnyOrigin, _safe=False], mask_functor: mask_t, scale: Float32, input_row_offsets_ptr: Pointer[UInt32, ImmutAnyOrigin, _safe=False], kv_input_row_offsets_ptr: Pointer[UInt32, ImmutAnyOrigin, _safe=False], sink_weights_ptr: Pointer[Scalar[qkv_dtype], ImmutAnyOrigin, _safe=False])
Ragged-batch GPU kernel entry: per-sequence setup + run.
The non-ragged equivalent is run itself (which takes
already-sliced per-batch TileTensors). For ragged, this
wrapper does the per-block ragged setup so the launcher can
pass a single packed Q pointer + input_row_offsets.
cross_attention=False (default): self-attention, where K/V
length equals Q length plus any cached prefix. num_keys
derives from start_pos + seq_len. kv_input_row_offsets_ptr
is unused (caller may pass any well-typed stub).
cross_attention=True: encoder-decoder style. K/V lengths come
from kv_input_row_offsets_ptr, independent of the Q-side
offsets. Mirrors the FA2 contract at mha.mojo:1755-1762.
Parameters:
- βk_t (
MHAOperand): K operand type (inferred); anyMHAOperandwhoseblock_paged_tilereturns(KV_BLOCK, DEPTH)tiles. - βv_t (
MHAOperand): V operand type (inferred); same tile contract ask_t. - βmask_t (
MHAMask): Mask functor type (inferred); selects the per-tile masking strategy. - βqkv_dtype (
DType): Element dtype of Q, K, and V (inferred); must equalconfig.dtype. - βoutput_dtype (
DType): Element dtype of the output buffer (inferred); must equalconfig.output_dtype. - βcross_attention (
Bool): Whether K/V length is independent of Q (encoder-decoder style) (defaults to False). - βsink (
Bool): Whether to seed the online softmax with attention-sink weights (defaults to False).
Args:
- βq_ptr (
Pointer[Scalar[qkv_dtype], ImmutAnyOrigin, _safe=False]): Pointer to the packed Q buffer, pre-offset per sequence byinput_row_offsets_ptr. - βk (
k_t): K operand (MHAOperand). - βv (
v_t): V operand (MHAOperand). - βoutput_ptr (
Pointer[Scalar[output_dtype], MutAnyOrigin, _safe=False]): Pointer to the output buffer, same packing asq_ptr. - βmask_functor (
mask_t): Per-tile mask predicate (causal, sliding-window, etc.). - βscale (
Float32): Softmax scale (1/sqrt(DEPTH)). - βinput_row_offsets_ptr (
Pointer[UInt32, ImmutAnyOrigin, _safe=False]): Cumulative uint32 row offsets for Q sequences, lengthbatch_size + 1. - βkv_input_row_offsets_ptr (
Pointer[UInt32, ImmutAnyOrigin, _safe=False]): Cumulative uint32 row offsets for K/V sequences; read only whencross_attentionis True. - βsink_weights_ptr (
Pointer[Scalar[qkv_dtype], ImmutAnyOrigin, _safe=False]): Per-q-head attention-sink scalar weights; read only whensinkis True.
Was this page helpful?
Thank you! We'll create more content like this.
Thank you for helping us improve!