API Reference¶
Use kernel operations inside @metile.kernel, where tracing records GPU
work. Use buffers, launchers and tuning APIs from host Python code. This page
indexes both; see Language Reference for tracing rules and
Memory Model for storage, dtypes and synchronization.
Install metile-kernels for ready-made operations under metile_kernels,
including metile_kernels.gemm.matmul and
metile_kernels.attention.attention_decode_kernel. Their source lives in
kernels/src/metile_kernels/. The library depends on the compiler, not the
other way around. See Installation.
Host-side decode attention is provided by
metile.backends.attention_runtime.attention_decode. This optional backend
requires the kernel library, but not MLX. See Decode Attention for
its launcher API and migration from the former kernel-package import.
Training and Manual VJPs¶
See Training kernels and gradients for examples, precision contracts, and saved-buffer lifetime rules, and Kernel coverage and training scope for the Liger parity checklist. These are native APIs, not automatic framework-autograd registrations.
Entry points |
Contract |
|---|---|
|
Unary or gated activations; separate gradients for both gate and up |
|
Full/partial RoPE with pre-expanded coefficient tables and all three input gradients |
|
FP32 statistics, input and affine-parameter gradients, residual cotangents |
|
FP32 two-dimensional dense products and optional activation derivatives |
|
Final-axis FP32 normalization and its explicit cotangent map |
|
Integer-label cross entropy, ignored labels, smoothing and optional z-loss |
|
Stable dense/causal/masked attention, MHA/GQA/MQA, and dQ/dK/dV |
|
Scalar/channel-decay recurrences with all six tensor-input gradients |
|
Three pre-rotated branches, one global normalization, and branch/K/V gradients |
|
Trace-time expression VJP; unsupported differentiated operators fail explicitly |
|
Explicit mutable per-lane state with |
Raw device implementations live in metile_kernels.training_activations,
rope, training_norms, training_losses, stable_attention,
gated_delta, and dual_chunk_attention. Allocation and dispatch logic
stays outside those kernel modules.
Kernel Definition & Launch¶
API |
Description |
|---|---|
|
Decorate a Python function for GPU compilation |
|
Launch kernel with given grid shape and compile-time constants |
|
Compile-time parameter annotation; pass values by keyword at launch |
|
Execute once, synchronize, and bind a reusable dispatcher to these arguments |
|
Enqueue work using the prepared buffers, scalar values, and grid |
Preparation can modify outputs. For a reusable dispatcher, pass explicit
Buffer objects: later calls do not repeat implicit NumPy conversion or
copy results back to the original arrays. The ordinary launch cache depends
on input dtypes and relevant compilation settings as well as constexprs.
Pass STRICT_MATH=True to disable Metal fast-math in both compilation paths.
This boolean is part of compilation cache identity. It does not override an
explicit fast intrinsic or change the selected matrix arithmetic precision.
Buffers¶
API |
Description |
|---|---|
|
Allocate shared Metal storage and copy the array’s contents into it |
|
Allocate a zeroed buffer with the requested shape and storage dtype |
|
Allocate a buffer whose initial contents are unspecified |
|
Copy a NumPy array into a new shared Metal buffer |
|
Synchronize pending GPU work and return a writable view of the allocation |
Keep the buffer alive until its NumPy view is no longer needed. Storage dtypes must be supported by the launcher and the selected operation; float64 arrays are not supported kernel inputs. Declaring a tensor view does not convert storage.
Program Identity¶
API |
Description |
|---|---|
|
Threadgroup index along |
|
Thread index within the threadgroup |
|
Lane index within the simdgroup (0-31) |
Index Generation¶
API |
Description |
|---|---|
|
Half-open integer range for constant bounds, with optional thread ownership |
|
Ceiling division: |
|
Smallest power of 2 >= |
For a traced scalar start, the current arange overload treats its
second argument as a length. Prefer offset + metile.arange(0, BLOCK) to
make a dynamic origin explicit.
Thread Ownership¶
API |
Description |
|---|---|
|
Immutable register/thread-to-logical-index bit permutation, with 1/2/4/8/16/32 values per thread |
|
Identity ownership for a power-of-two tile on 32–1024 threads |
|
Preserve logical values while redistributing physical owners |
See Thread Ownership and Software Staging for supported operations and communication rules.
Tensor Views¶
API |
Description |
|---|---|
|
Declare logical shape, memory layout, and access permissions |
|
Load coordinates with declared bounds and a scalar fill value |
|
Store coordinates within declared bounds |
See Tensor and Memory Contracts for tensor declarations, tiled matrix support, integer-range constraints, and compiler responsibilities. Strides are in elements. Bounds checks use the declared shape; the caller must supply enough storage for its valid addresses. Matrix tile loads currently require zero fill.
For Schedule(backend="simdgroup_inline"), device block_shape=(8, 8)
accesses require an explicit scratch tensor. It must directly reference
a shared allocation with shape (BLOCK // 4, 8), strides (8, 1),
read/write access and matching FP16 or FP32 storage dtype. Keep the allocation
exclusive to these accesses; the compiler handles its masked-tail copies and
SIMD-group barriers. Scalar and shared-memory accesses reject scratch.
Scalar shared-memory pointers in this backend must resolve to a declared
shared allocation through pointer offsets only; conditional pointer selection
is unsupported.
Device views have constant positive row-major or column-major strides and SIMD-uniform bases, logical extents and origins. Complete tiles access device memory directly; incomplete loads zero-fill and incomplete stores skip invalid coordinates. Bounds refer to valid data, not spare allocation capacity. A device allocation used by fragments cannot also be read and written through any alias within the kernel. Separate input/output parameters must reference disjoint storage at launch. See Execution Schedules and Fusion for a complete DSL example and the shared-memory fragment contract.
Element-wise Memory¶
API |
Description |
|---|---|
|
Load elements; masked-off lanes read 0 |
|
Store elements; masked-off lanes are skipped |
Tile Memory¶
API |
Description |
|---|---|
|
Legacy two-dimensional tile load with an element row stride |
|
Legacy two-dimensional tile store with an element row stride |
|
Zero-initialized tile (accumulator init) |
|
Return the tile matrix multiply-accumulate result |
For new matrix kernels, prefer tensor(..., block_shape=...) loads and
stores, which declare full logical bounds. Backend-specific dtype, tile, and
layout restrictions are described in Tile Operations and Hardware Mapping.
Control Flow¶
API |
Description |
|---|---|
|
Traced loop with an exclusive end; staging support depends on lowering |
|
Explicit scalar SSA value for loop-carried recurrences |
Math Operations¶
All operate element-wise on scalars and tiles:
API |
Description |
|---|---|
|
Exponential |
|
Base-two exponential |
|
Cosine in radians using Metal’s |
|
Exponential using Metal’s fast-math intrinsic |
|
Base-two exponential using Metal’s |
|
Sine in radians using Metal’s |
|
Fused multiply-add: |
|
Natural logarithm |
|
Square root |
|
Reciprocal square root using Metal’s |
|
Absolute value |
|
Hyperbolic tangent |
|
Conditional select |
|
Element-wise max |
|
Element-wise min |
|
Convert a scalar or tile to a supported IR dtype such as |
|
Reinterpret |
Supported Python arithmetic and comparisons build elementwise operations.
where selects between already-computed values; it does not make an
unmasked memory access safe. Mask the load itself or use a tensor view.
bitcast preserves all 32 bits of each element, including signed zero and
NaN payloads, using Metal’s as_type operation. The input must be an
explicitly typed scalar or tile proxy; use scalar(value, dtype=...) for
literals. Tile shape and thread ownership are unchanged. Identical source
and destination dtypes are an identity. Other widths, booleans, pointers,
and matrix-fragment reinterpretation are unsupported. Expression VJP rejects
bit reinterpretation rather than inventing a derivative.
rsqrt emits the reciprocal-square-root operation directly rather than
dividing by sqrt; their floating-point rounding can differ. For positive
finite inputs, its expression VJP uses -0.5 * rsqrt(x)**3 multiplied by
the incoming cotangent. This is the derivative of the real-valued function,
not of floating-point rounding.
The exp2 and fast_exp2 VJPs multiply the incoming cotangent by
ln(2) times the computed output.
The fast cosine and sine VJPs use -fast_sin(x) and fast_cos(x),
respectively, as real-function derivatives evaluated with the paired
intrinsic; they do not differentiate approximation or rounding errors.
fast_exp2 explicitly selects an approximate intrinsic without enabling
fast math for the rest of a STRICT_MATH=True kernel. Use it only when
the approximation is acceptable; it is not interchangeable with exp2
for bitwise comparisons.
fma explicitly requests Metal’s fused operation even under strict math.
This follows Apple’s guidance on explicit FMA without fast math.
It accepts matching f16 or f32 operands, equal-shaped tiles, and
scalar broadcasting; Python numeric literals adopt the proxy operands’
dtype. Cast mixed proxy dtypes explicitly. Its expression VJP contributes
cotangent * b, cotangent * a, and cotangent to the three inputs,
with reductions for broadcast scalar inputs. These are real-function
derivatives, not derivatives of rounding. Ordinary multiplication followed
by addition is not rewritten into fma under strict math.
For example, an online softmax can request these operations locally:
factor = metile.fast_exp2(previous_maximum - updated_maximum)
denominator = metile.fma(previous_denominator, factor, local_sum)
Reductions¶
API |
Description |
|---|---|
|
Sum-reduce tile to scalar |
|
Max-reduce tile to scalar |
|
Min-reduce tile to scalar |
These operations reduce a supported logical tile. By contrast, simd_sum
and simd_max below reduce only within the current SIMDgroup. Choose padding
that matches the reduction’s identity; see Softmax.
Simdgroup Operations¶
API |
Description |
|---|---|
|
Context manager: execute on a subset of simdgroups |
|
XOR-based lane exchange within a simdgroup |
|
Broadcast from one lane to all lanes |
|
Native sum across the current simdgroup |
|
Native maximum across the current simdgroup |
|
Synchronize participating threads and order threadgroup memory accesses |
|
Allocate uninitialized threadgroup memory |
All participating threads must reach a threadgroup barrier. Role regions do not synchronize with each other merely because they appear in source order.
Tile Scheduling¶
API |
Description |
|---|---|
|
Checked backend, SIMD-group, staging, vector-width and buffering requirements |
|
JSON report of the selected schedule and materialized compiler decisions |
|
Request automatic, linear, diagonal, grouped2/4/8, Morton, or Hilbert traversal |
Pass the immutable requirements as SCHEDULE=metile.Schedule(...) to a kernel
launch or prepare call. See Execution Schedules and Fusion for supported
combinations, inspection and pointwise GEMM fusion.
The opt-in simdgroup_inline backend composes multiple dot operations
inside scalar/loop DSL programs. It uses 8-by-8 shared or device tiles, explicit
scratch for device tails, and FP32 register-fragment accumulators. See the composable matrix
fragment example and restrictions in Execution Schedules and Fusion.
Autotuning¶
API |
Description |
|---|---|
|
Decorator for automatic parameter search |
|
Candidate constants and optional SIMDgroup/staging requests |
|
Select a configuration, execute preparation, and return a bound dispatcher |
Use a callable grid when candidates change tile dimensions. Tuning runs kernels and can modify their outputs; see Autotuning for cache keys and repeated-dispatch behavior.
Block Scaling¶
API |
Description |
|---|---|
|
Quantize a KxN weight to MXFP4 or MXFP8 with E8M0 group scales |
|
Reconstruct a dense NumPy array for inspection or reference checks |
|
Run the automatically tuned fused block-scaled MPP kernel |
|
Return a reusable dispatcher for the selected block-scaled tile family |
The block-scaled fast path requires Metal 4 tensor operations, two-dimensional activation/output buffers, M and N divisible by 64, and K divisible by 32. Quantization changes the represented weights; compare numerical results with an appropriate reference and tolerance.
Model Integration¶
metile.compile(model, *, verify=True, features=..., tolerance=...) modifies
a loaded MLX-LM model in place and returns a CompileReport listing accepted
and declined replacements. Call report.restore() to restore the previous
implementations. Verification checks a finite probe; it does not prove
correctness for every model input. See MLX-LM Backend for setup,
verification settings and the limits of that check.