TMA Transfers#

This guide shows how to use the Tensor Memory Accelerator (TMA) to move multidimensional tiles between global and shared memory. One thread issues the transfer using a TensorMap descriptor, which records the global shape, strides, element format, and tile configuration. TIRx prepares this descriptor in the host launcher from the tensor operand and explicit box parameters.

TMA requires a Hopper-or-later GPU. The Async Data Movement: TMA chapter explains its hardware role and layout support in detail.

A Tile Load, Computation, and Store#

The following kernel loads an (8, 32) float32 tile, adds one to each element, and stores it back to global memory. Lane 0 issues the transfers; all 32 lanes update one column each:

from tvm_tirx.script import tirx as T

@T.function
def tma_add_one(
    A: T.Tensor((8, 32), "float32", align=16),
    B: T.Tensor((8, 32), "float32", align=16),
):
    T.device_entry(launch=T.cuda.LaunchConfig(grid=1, block=32))
    lane = T.cuda.lane_id()
    shared = T.alloc_shared((8, 32), "float32", layout="default", align=128)
    mbar = T.alloc_shared((1,), "uint64", align=8)
    if lane == 0:
        T.ptx.mbarrier.init.shared.b64(mbar.ptr_to([0]), T.uint32(1))
        T.ptx.mbarrier.arrive.expect_tx.shared.b64(mbar.ptr_to([0]), T.uint32(1024))
    T.ptx.fence.proxy.async_.shared__cta()
    T.cuda.cta_sync()
    if lane == 0:
        T.cuda.tile.apply(
            T.ptx["cp.async.bulk.tensor.2d.shared::cta.global.tile.mbarrier::complete_tx::bytes"],
            shared, A, box=(8, 32), coords=(0, 0), mbar=mbar.ptr_to([0]),
        )
    T.cuda.mbarrier_wait(mbar.ptr_to([0]), 0)
    for row in range(8):
        shared[row, lane] = shared[row, lane] + 1
    T.ptx.fence.proxy.async_.shared__cta()
    T.cuda.cta_sync()
    if lane == 0:
        T.cuda.tile.apply(
            T.ptx["cp.async.bulk.tensor.2d.global.shared::cta.tile.bulk_group"],
            B, shared, box=(8, 32), coords=(0, 0),
        )
        T.ptx.cp.async_.bulk.commit_group()
        T.ptx.cp.async_.bulk.wait_group(0)
    T.cuda.cta_sync()

box=(8, 32) selects the tile dimensions and coords=(0, 0) selects its starting position in the global tensor, both in outer-to-inner order. The shared tensor has the same tile shape. layout="default" gives it contiguous row-major storage, and align=128 aligns its base. The load takes shared, A; the store reverses the direction with B, shared.

Load Completion#

The load reports completion through mbar, an eight-byte barrier object in shared memory. Its initialization expects one arrival per phase. arrive.expect_tx performs that arrival and registers the tile’s 8 * 32 * 4 = 1024 transaction bytes. The initial fence and CTA barrier publish the initialized barrier before lane 0 issues the transfer.

The TMA engine completes those transaction bytes as it fills shared memory. mbarrier_wait(..., 0) waits for the initial phase to finish, so each lane can then read and update its column. A phase completes when both its expected arrivals and transaction bytes have been satisfied. The mbarrier chapter explains phases and reuse across pipeline stages.

Store Completion#

After the updates, each thread executes the proxy fence to make its shared-memory writes visible to the asynchronous transfer. The CTA barrier then ensures all writers have finished their writes and fences before lane 0 issues the store.

A TMA store uses a bulk async group. Lane 0 commits its store with bulk.commit_group() and waits for completion with bulk.wait_group(0). The final CTA barrier holds the other threads until that wait finishes, allowing the shared buffer to be reused. These bulk groups are distinct from the ordinary copy groups used by Asynchronous Copies.

Compile and Run#

The host launcher needs tensor-map encoding support, available with an LLVM-enabled build or the CUDA C++ host backend. With LLVM enabled, the kernel can be compiled and checked as follows:

import torch
import tvm_tirx

a = torch.arange(256, dtype=torch.float32, device="cuda").reshape(8, 32)
b = torch.empty_like(a)
tvm_tirx.compile(tma_add_one, target="cuda")(a, b)
torch.testing.assert_close(b, a + 1)

The TMA instruction reference covers repeated boxes, coordinate steps, swizzles, multicast, reductions, and packed formats. For a complete multistage schedule, see Pipelining GEMM with TMA.