The tiling vocabulary, precisely
A vector register on a TPU holds a fixed grid: 8 sublanes by 128 lanes. That grid is physical, not a convention, and it is the reason every vector<...> type printed in a lowered module has the shape it does. Sublanes run down the register, lanes run across it, and every value in a compiled kernel gets tiled into that grid before any op touches it. This section names the rule precisely: what the tile is, how dtype changes it, and where it shows up when a kernel breaks.
Change the dtype and the tile changes with it. Register width in bytes stays fixed, so narrower elements pack more rows into the same 8x128 footprint. f32 keeps the base tile at (8, 128). bf16 packs two elements per lane slot and doubles the sublane count to (16, 128). int8 packs four and lands at (32, 128). Rows and lanes are not free parameters you choose. They are consequences of how many bytes each element takes.
Open a lowered module and this rule stops being abstract. Every vector<...> type carries a tile-shaped trailing dimension pair that matches whichever dtype produced it, and MosaicThe MLIR dialect Pallas lowers to, and the last layer of the TPU stack you can read; only LLO below it is closed.taught in /l/mosaic → checks that pairing on every op. Break it, say by bitcasting an f32 value into an int8 layout without adjusting the tile, and the compiler does not fail quietly. It refuses the rewrite and quotes the exact packing rule back at you in the error text.
The captured module keeps both shapes side by side: the logical array shape you wrote in JAX, and the physical vector type MosaicThe MLIR dialect Pallas lowers to, and the last layer of the TPU stack you can read; only LLO below it is closed.taught in /l/mosaic → produced from it. Once you know the packing rule, that pairing stops looking arbitrary. A bf16[128, 256] operand does not lower into a register grid that matches its logical axes one for one. It lowers into a tile count built from (16, 128). The 128-lane width itself is not incidental: it matches the 128x128 systolic array on v5e, the same MXUThe systolic matmul array: 128x128 on v5e, 256x256 on v6e. Matmuls only; everything else is the VPU’s job.taught in /l/tpu → that consumes these tiles once they are packed.
Check yourself
01 Why does bf16 tile as (16, 128) when f32 tiles as (8, 128)?
Register width in bytes is fixed, so narrower elements pack more rows into the same footprint: half-width bf16 doubles the sublane count.
02 What two shapes does the captured module keep side by side, and what does the pairing teach?
The logical array shape you wrote in JAX and the physical vector type Mosaic derived from it. With the packing rule known, the pairing reads as a derivation rather than noise.
Readings
- Pallas TPU details ↗ the tiling constraints as the kernel author meets them
- Scaling book · All about TPUs ↗ the register file these tiles live in