No history yet

CuTe Layout Algebra

The Algebra of Layouts

CUTLASS 3.x introduces a fundamental shift away from the iterator-based design of its predecessors. At its core is CuTe, a library that treats the mapping of data as a problem of applied mathematics. This approach enables a more expressive and flexible way to describe data arrangements in memory, moving far beyond simple row-major or column-major layouts.

The central idea in is the Layout. A Layout is a bijective function that maps a high-dimensional logical coordinate to a one-dimensional memory index. It formalises what was previously an implicit and often rigid aspect of GPU programming. Every Layout is defined by two key components: a Shape and a Stride.

Layout: A function from a logical coordinate Coord to a physical memory index Int.

Both Shape and Stride are represented as tuples of integers. The Shape defines the extent of each dimension (or mode) of the logical tensor, while the Stride defines the memory offset to move one step along each corresponding dimension.

// A 4x8 tile of 32-bit floats in row-major order
// Shape: (Rows, Columns)
using Shape = cute::Shape<cute::Int<4>, cute::Int<8>>;

// Stride: (Stride for Rows, Stride for Columns)
// To move 1 row, jump 8 elements. To move 1 column, jump 1 element.
using Stride = cute::Stride<cute::Int<8>, cute::Int<1>>;

// The Layout combines Shape and Stride
auto layout = cute::Layout<Shape, Stride>{};

The crd2idx function embodies the core mapping logic. Given a coordinate, the layout applies a dot product between the coordinate and the stride vector to compute the final 1D index.

index=icoordi×stridei\text{index} = \sum_{i} \text{coord}_i \times \text{stride}_i

Functional Composition

The true power of CuTe emerges when we treat Layouts as functions that can be composed. If you have two layouts, A and B, the composition A ∘ B creates a new, more complex layout. This is the mechanism that decouples algorithmic intent from hardware-specific data movement.

Imagine LayoutB arranges logical elements into a tile, and LayoutA positions that tile within a larger memory space. Composing them, LayoutA(LayoutB(coord)), gives you the final memory address of an element from a single logical coordinate. CuTe overloads the | operator for this composition, though the cute::composition function is also available.

This principle allows for building complex, hierarchical, and multi-modal layouts from simple, reusable components. For instance, you can define a layout for a vector, then compose it with a layout that describes how vectors are arranged to form a matrix, which can then be composed with a layout that describes how matrices are batched. This is how CUTLASS achieves such high performance while remaining adaptable to new hardware architectures. The algorithm is expressed in terms of logical operations on tensors, while the compositions translate these into efficient physical memory accesses tailored to the GPU.

Advanced Layout Operations

CuTe provides several operations to manipulate layouts. Two of the most fundamental are logical_divide and logical_product. These are not simple arithmetic; they are transformations on the logical coordinate system itself.

logical_divide(L, S) partitions a layout L with a shape S. This is akin to tiling. It transforms a single logical mode into two: a 'major' mode for the tile coordinate and a 'minor' mode for the coordinate within the tile. This is critical for mapping a large problem onto a grid of thread blocks and mapping tiles of data onto threads within a block.

// Start with a flat layout of 1024 elements
auto layout_1d = make_layout(Shape<Int<1024>>{});

// Tile this into 8 tiles of 128 elements each
// The new shape is (tile_id, element_in_tile)
// Shape: (Int<8>, Int<128>)
auto tiled_layout = logical_divide(layout_1d, Shape<Int<128>>{});

Conversely, logical_product(L, M) merges modes. Given two layouts L and M, it creates a new layout whose shape and stride are concatenations of the inputs. This is useful for combining disparate layouts or flattening a hierarchical layout back into a simpler form.

These operations, combined with composition, form a powerful algebra for defining how threads access data. A complex GEMM kernel, for example, will use logical_divide multiple times to map the logical M, N, and K dimensions onto the SMEM tiles and register files of individual threads in a -synchronous manner.

By formalising data mapping with this layout algebra, CUTLASS 3.x achieves a design that is not just performant but also provably correct and vastly more extensible than the brittle pointer-based logic it replaces.

Let's test your understanding of these core CuTe concepts.

Quiz Questions 1/5

What is the fundamental concept in CuTe that describes a bijective function mapping a multi-dimensional logical coordinate to a one-dimensional memory index?

Quiz Questions 2/5

A CuTe Layout is defined by which two primary components?

Mastering this algebra is the key to unlocking the full potential of modern CUTLASS, enabling you to write code that is both abstract and highly tuned to the underlying hardware.