ldmatrix / stmatrix#
Call parameters#
T.cuda.tile.apply(T.ptx[opcode], *operands, scope="thread", **parameters)
Operand order: dst_registers, src_shared for ldmatrix; dst_shared, src_registers for
stmatrix.
Parameter |
Type / default |
Meaning |
|---|---|---|
|
static str; default “thread” |
Execution scope; group axes follow Explicit CUDA tile patterns. It does not elect an issuing thread. |
Only the parameters listed here are instruction parameters. Opcode qualifiers are
written in T.ptx[opcode].
Data representation#
Both operands use scalar b32 containers (uint32/int32/float32 as bits). Each packs two b16 matrix elements. x1/x2/x4 selects N=1/2/4 b32 outputs per lane. Two halves of one output are fixed packing; a free register stride separates distinct b32 outputs.
Operand specification#
The tile patterns support m8n8.b16 with .x1, .x2, or .x4 and optional
.trans. Select the exact form in the opcode:
T.cuda.tile.apply(
T.ptx["ldmatrix.sync.aligned.m8n8.x2.shared.b16"],
registers, shared_words, scope="warp",
)
stmatrix reverses the operand order: shared_words, registers. The implementation
repeats the specified warp instruction, without picking a matrix count or transpose mode
from the layout.
Address providers and result owners#
Both regions end in (matrix,row,word)=(count,8,4) and use scalar 32-bit containers.
A container holds two adjacent 16-bit values. Use a dtype view to expose packed
half/bfloat16 storage as b32 words; this is not a conversion.
Each shared row has four consecutive words and a 16-byte-aligned start. Different rows may have gaps and may be interleaved with other matrices.
Lane
8*matrix+rowprovides that row’s shared address. For x1/x2, the remaining address providers repeat valid row addresses.Register word
(matrix,row,word)belongs to lane4*row+word. Each lane receivescountwords. Their register offsets need not be adjacent, and need not have the same order as another tensor declaration.
Thus, the lane supplying a shared address generally differs from the lanes receiving the values from that row. The contract checks both maps. All 32 lanes must participate, including those whose addresses are duplicates.
Parameterized layouts#
For one warp and one repeat axis, all storage strides below are in b32 words:
coordinates: (repeat, matrix, row, word)
smem: (K,N,8,4):(B, M, S, 1)
reg: (K,N,8,4):(P@m, R@m, 4@laneid, 1@laneid)
B/M/S separate repeats, matrices and shared rows; P/R separate repeats and outputs in each thread’s register storage. They are read from the layout, not supplied as keywords. S=16 means 64-byte row pitch; R=2 means every second b32 output slot. These slots do not specify machine register numbers. The more general row-address contract is:
byte_address(t,i,j,w) = row_address(t,i,j) + 4*w
Each row_address must be 16-byte aligned; it need not have constant stride across j. A nonzero region start is included before applying the layout. For .trans the b16 image satisfies:
register_image[i,j,2*w+h] = shared_matrix[i,2*w+h,j]
Without .trans, the right-hand side is shared_matrix[i,j,2*w+h].
Legality conditions#
Both regions end in (N,8,4), after matching group/repeat axes. Each shared row has four consecutive words and a 16-byte-aligned start. Different rows have independent starts. Register word (i,j,w) belongs to lane 4*j+w; loaded slots are distinct. All 32 lanes participate; scope=”warp” has no group prefix, and wider scopes add warp groups. No opcode-specific keyword, including pred, is accepted.
Code generation#
For each repeat t, every lane l executes the following expansion:
address = &smem[t, (l // 8) % N, l % 8, 0]
registers = [reg[t, i, l // 4, l % 4] for i in range(N)]
emit_selected_instruction(registers, address) # ld; reversed for st
The first 8*N lanes supply the N matrices’ row addresses; unused address providers repeat valid addresses. Each repeat emits one warp-wide .xN instruction. Initialization and synchronization are caller operations. .trans changes the b16 semantic image, as specified in the operand specification.
Examples#
Transpose and stores#
.trans transposes each 8x8 matrix of 16-bit elements, not a matrix of b32 words.
Register image element (row,2*word+half) comes from shared element
(2*word+half,row). The register word’s lane owner remains 4*row+word. Reorganize
operands with this image in mind; toggling .trans is a semantic change, not a layout
optimization hint.
stmatrix uses the corresponding register image as input and each provider’s shared
row address as output. Its supported architecture is checked by the PTX compiler.
Synchronize before a load consumes another thread’s shared stores, and after a store
before other threads consume or reuse that shared storage. No fence or barrier is
inserted by the pattern.
An insufficiently aligned row, wrong register owner, overlapping loaded registers, or a partially active warp is rejected. Gaps between rows or register slots are legal; gaps within a shared 16-byte row are not.
Implementation: python/tvm/backend/cuda/tile/patterns/ldmatrix.py.