Layout IR#
Layouts describe how logical tensor coordinates map to storage and execution axes. See Tensor Layout for the programming model and worked examples.
The primary classes are re-exported from tvm.tirx, but are defined in this
module:
- class tvm.tirx.layout.Layout
- verify_well_formed() bool
Verify if the layout is well-formed.
- Returns:
True if the layout is well-formed, False otherwise
- Return type:
- size(axis_name: str | None = None)
Get the size of the layout.
- Parameters:
axis_name (Optional[str]) – The name of the axis to get the size of. If not provided, the default input size will be returned.
- span(axis_name: str | None = None)
Get the span of the layout.
- Parameters:
axis_name (Optional[str]) – The name of the axis to get the span of. If not provided, the default span will be returned.
- apply(*coord: list[Expr], shape: list[Expr] | None = None) dict[str, Expr]
Apply the layout on the input coordinate and get the mapped output.
Input cases: - coord is a single element -> will be treated as a 1D coordinate - coord is a list of elements -> will be treated as a multi-dimensional coordinate - shape is provided -> turn the coord with shape into a 1D coordinate - shape is not provided -> use the default shape
- apply_to_shape(coord: list[Expr], input_shape: list[Expr]) list[Expr]
Compute the per-shard value that each shard would take if
coordwere interpreted againstinput_shape.Tries
self.group(input_shape)first. On success, each group owns exactly oneinput_shapeentry, socoord[d]can be split within that group’s shard extents (bounds stay local to one input dim — simpler analyzer simplification, no cross-dim complications).Falls back to
FlattenCoord(coord, input_shape)+SplitCoordonself’s raw shard shape when the group call fails (e.g. wheninput_shapedoes not align with the layout’s factor boundaries).Returns a list of length
len(self.shard); each entry is the value that shard would iterate.
- canonicalize() Layout
Canonicalize the layout by simplifying and fusing iterators where possible.
- Returns:
The canonicalized layout
- Return type:
Layout
- tile(outer: TileLayout, outer_shape: list[Expr], inner_shape: list[Expr]) TileLayout | ComposeLayout
Tile the current layout with an outer layout.
- direct_sum(left: TileLayout, left_shape: list[Expr], right_shape: list[Expr]) TileLayout | ComposeLayout
Direct-sum on the tiling domain (unscaled composition): A + B.
This layout is treated as the right addend B grouped by right_shape. The left layout is treated as A grouped by left_shape. The resulting layout is evaluated over the interleaved domain S_A ⊗ S_B, without span scaling (unlike tiling).
- is_tile_inner(tile_layout: TileLayout | ComposeLayout, tiled_shape: list[Expr], inner_shape: list[Expr]) TileLayout | None
Check if a layout is the inner layout of a tiled layout.
- Parameters:
- Returns:
The outer layout if it is the inner layout of the tiled layout, None otherwise
- Return type:
Optional[TileLayout]
- is_tile_outer(tile_layout: TileLayout | ComposeLayout, tiled_shape: list[Expr], outer_shape: list[Expr]) Layout | None
Check if a layout is the outer layout of a tiled layout.
- Parameters:
- Returns:
The inner layout if it is the outer layout of the tiled layout, None otherwise
- Return type:
Optional[Layout]
- is_direct_sum_right(sum_layout: TileLayout | ComposeLayout, interleaved_shape: list[Expr], right_shape: list[Expr]) TileLayout | None
Check if this layout is the right addend B in a direct-sum A + B.
Returns the left addend A if recognized, otherwise None.
- is_direct_sum_left(sum_layout: TileLayout | ComposeLayout, interleaved_shape: list[Expr], left_shape: list[Expr]) Layout | None
Check if this layout is the left addend A in a direct-sum A + B.
Returns the right addend B if recognized, otherwise None.
- slice(shape: list[Expr], region: list[tuple[Expr, Expr]]) Layout | None
Slice the layout with a given shape and region.
- Parameters:
shape (List[Expr]) – The shape of the layout
region (List[Tuple[Expr, Expr], tvm.ir.Range]) – The region to slice, each element is (begin, end)
- Returns:
The sliced layout, or None if slicing is not possible
- Return type:
Optional[Layout]
- tile_to(to_shape: list[Expr], current_shape: list[Expr]) Layout
Tile the current layout to the given shape.
- is_swizzle() bool
Check if the layout is a bare swizzle (ComposeLayout over a trivial tile).
- is_trivial() bool
Check if the layout is trivial.
- is_trainium() bool
Check if the layout is trainium layout.
- unpack(num: int) Layout
Unpack the layout, where a single element in the layout is unpacked into num contiguous elements.
- Parameters:
num (int) – The number of elements to unpack into
- Returns:
The unpacked layout
- Return type:
Layout
- broadcast(num: int, position: int = -1, axis: 'Axis' | str = 'm') Layout
Insert a stride-0 broadcast dim of extent
numatposition.positionfollows Python list-insert semantics (negative indices count from the end;-1appends after the last shard dim). The new dim has stride 0 — accessing along it doesn’t move the byte offset, so the same physical element is “seen”numtimes.Useful for layouts where a consumer reads the same SMEM datum multiple times (e.g.
sf_reuseover MMA-K steps).
- class tvm.tirx.layout.Axis(*args, **kwargs)
Layout axis wrapper.
- static get(name: str) Axis
Get or create an axis by name. Unknown names are auto-registered.
- is_thread() bool
Check if the axis is a thread axis.
- is_memory() bool
Check if the axis is a memory axis.
- get_scope() ExecScope | None
Get the scope of the axis.
- get_subscope() ExecScope | None
Get the subscope of the axis.
- class tvm.tirx.layout.Iter(extent: Expr, stride: Expr, axis: Axis | str)
A memory layout that tiles data across devices.
- class tvm.tirx.layout.TileLayout(spec: _LayoutSpec)
A memory layout that tiles data across devices.
- static from_iters(shard: Sequence[Iter] = (), replica: Sequence[Iter] = (), offset: dict[Axis | str, Expr] | None = None) TileLayout
Construct a TileLayout from pre-built Iter objects.
- is_trivial() bool
Check if the layout is trivial.
- group_many(shapes: Sequence[Sequence[Expr]]) tuple[TileLayout, list[list[int]]]
Group the layout by the minimal common refinement of several shapes.
Repeated cumulative product boundaries are retained, so an extent-one dimension in any input shape becomes a real unit iterator in the refined layout. This operation only splits existing shard iterators; it does not canonicalize or reorder the layout.
- classmethod trainium(annotation: str, shape: tuple[Expr], is_psum: bool = False) TileLayout
Create a TileLayout from an annotation string and a shape.
- to_psum() TileLayout
Convert the layout to a psum layout.
- class tvm.tirx.layout.ComposeLayout(per_element: int, swizzle_len: int, atom_len: int, tile_layout: TileLayout, swizzle_inner: bool = True)
A memory layout that swizzles a tile layout.
per_element/swizzle_len/atom_len/swizzle_innercarry the swizzle (formerly the standaloneSwizzleLayout);tile_layoutis the tiled memory map the swizzle is applied to. A bare swizzle is aComposeLayoutover a trivial identity tile.
S[...] and R[...] build shard and replica layout specifications,
respectively. Named axes such as laneid, warpid, tid_in_wg,
TLane, and TCol are resolved lazily by this module.
Definition of layout.
- tvm.tirx.layout.tcgen05_atom_layout(instr_shape: str, tensor_shape: tuple[int, int], dtype) TileLayout
Register-side
TileLayoutfortcgen05.ld/tcgen05.statoms.Describes the per-warpgroup register tile that
Tx.copy_asyncproduces when reading a TMEM fragment viatcgen05.{ld,st}.<instr_shape>.xN.rep(the.xNqualifier) is inferred fromtensor_shape.Fragment row count is determined by
instr_shape:.32x32bnormally covers an M=128 fragment (128 rows per warpgroup), and.16x{64,128,256}bcovers an M=64 fragment (64 rows per warpgroup).("32x32b", (64, N))is the fp32 Layout B readback image for a.cta_group::2M=64 accumulator.TMEM is kept dense for 16-bit dtypes: two 16-bit elements per 32-bit TMEM cell (matching the existing
.32x32bconvention). The PTX op is issued with the plain.b32form (no.pack::16bqualifier), and the returned layout describes the per-thread register file with two packed 16-bit elements per 32-bit register.- Parameters:
instr_shape (str) – The PTX atom’s
.shapequalifier. One of"32x32b","16x64b","16x128b","16x256b".tensor_shape (tuple[int, int]) –
The logical fragment shape in element units. Must be
(frag_rows, K)wherefrag_rowsis128for.32x32band64for the other shapes. The fp32 Layout B image is the exception: it uses("32x32b", (64, N)). The column extent is divisible by the per-warp column factor for the chosen instr_shape and dtype:K must be a power-of-two multiple of (factor_fp32 * elem_per_32b)
where
factor_fp32is1/2/4/8for.32x32b/.16x64b/.16x128b/.16x256b, andelem_per_32bis1for fp32 and2for fp16/bf16. The inferred rep must be in PTX Table 49’s supported set for the chosen instr_shape.dtype (str | tvm.DataType) – Element dtype.
"float32","float16", or"bfloat16".
- Returns:
A
tensor_shape-shaped tile layout. The factory builds it as a sequence of fine-grained iters describing the per-(lane, register) destination position.- Return type:
TileLayout
Examples
tcgen05_atom_layout("16x64b", (64, 64), "float32")→.16x64b.x32(rep=32, fp32).tcgen05_atom_layout("16x128b", (64, 256), "float16")→.16x128b.x32(rep=32, fp16; two fp16 elements packed per 32-bit register and per 32-bit TMEM cell).
- tvm.tirx.layout.tmem_datapath_layout(datapath: str, rows: int, cols: int, sub_slab: int = 0) TileLayout
Return the
TileLayoutfor a tcgen05 MMA datapath.See PTX ISA §9.7.16.10.5 for the datapath enumeration. The returned layout is shape-compatible with a buffer of
(rows, cols)and encodes the logical-row → physical-TMEM-lane mapping that the corresponding MMA writes to (and that the matching.16x*b/.32x32batom expects to read).- Parameters:
datapath (str) –
PTX data path layout letter (all cta_group::2 layouts are the per-CTA view of the M-rows this CTA of the pair owns):
"A": M=256,.cta_group::2— identity over 128 rows."B": M=128,.cta_group::2, dense A — 64 rows, column halves folded across the two 64-lane halves."C": M=128,.cta_group::2, sparse A — 64 rows scattered 16-per-warp, half datapath (same organization as F)."D": M=128,.cta_group::1— identity, full datapath."E": M=64,.ws— 64 rows, column halves folded (same organization as B)."F": M=64, non-.ws— 64 rows scattered 16-per-warp, half datapath."G": M=32,.ws— 32 rows, column quarters folded across the four 32-lane warp slabs.
rows (int) – Logical row count of the TMEM buffer. Must match the datapath’s M dimension: 128 for A/D, 64 for B/C/E/F, 32 for G.
cols (int) – Logical column count. Datapath B requires an even count because its columns split into two equal lane halves.
sub_slab (int) – For Layout F, select the lower (
0) or upper (1) 16-lane half of each warp’s 32-lane TMEM partition. The upper half is useful as a 64-row read/write view of the high half-slab of a Layout D accumulator. Layouts D and B already span both halves and therefore only accept0.
- Returns:
Buffer-shape-compatible layout for
(rows, cols).- Return type:
TileLayout
- tvm.tirx.layout.tmem_mma_operand_layout(operand, shape, dtype, *, M, cta_group, ws=False, sparse=False, group=None)
Resolve the TMEM
TileLayoutfor a tcgen05 MMA operand from operand role + instruction params.operand:"A"(A-in-TMEM) or"D"(accumulator / C).Mis the PTXtcgen05.mmainstruction M (256/128/64), NOT the per-CTA buffer rows;per_cta_rows = M // cta_group. Physical 32-bit column count is left to the pool’s_resolve_cols(layout-aware).Reproduces the hand-written layouts the three FlashMLA kernels use; the supported/reject domain is spec’d in
localdoc/claude_plan.txtS3a.
- tvm.tirx.layout.wg_local_layout(cols, rows=128)
Return a warpgroup-local register layout.
The logical
(rows, cols)tile is distributed ontid_in_wgalong rows, so each thread owns one row and contiguouscolslocal elements.