Tile coverage, remainders, and legal interchange
Partition iteration domains without dropping tails or reversing dependencies in the pursuit of reuse.
On this page
The question for today
What you’ll understand
- Map a logical iteration into tile and intra-tile coordinates.
- Count partial tiles and guard their valid elements.
- Separate locality-oriented schedule choices from legality and numerical constraints.
Tiling groups nearby iterations so a bounded set of values can be reused before execution moves on. It introduces another level of coordinates and, for irregular dimensions, partial tiles. Those boundaries are where attractive optimizations often become incorrect. Cover each original iteration exactly once, avoid out-of-range accesses, and preserve dependencies. Interchange can improve traversal order only after the resulting schedule remains legal.
A partition must cover exactly the original domain
For a positive tile size T, write an index as a tile base qT plus an intra-tile remainder r. Full tiles use all T positions, while the final tile may have fewer valid iterations. A loop upper bound such as min(base+T, N) preserves the original one-dimensional domain when N is nonnegative. Multi-dimensional tiling applies that reasoning to each dimension and must keep guards consistent with actual memory operations, not merely suppress an invalid final store.
Padding is another strategy, but its semantics need an identity or neutral value appropriate to the operation. Zero padding that is harmless for one sum can change a maximum, division, normalization, or masked reduction. Allocating padded storage can make an access in bounds without making the padded arithmetic mathematically correct. State both the physical allocation and logical validity domain. Include shapes smaller than one tile and dimensions equal to zero if the source operation permits them.
Reuse competes with resource budgets
A larger tile can reduce repeated data movement but requires more live inputs, outputs, accumulators, or staging buffers. The useful size depends on cache or shared-memory budgets, vector shape, occupancy, and the access pattern. Count all simultaneously live tiles and double buffers rather than only one input. A tile that exceeds a resource limit may fail compilation or spill, and a tile that nominally fits can still lose because of conflicts, scheduling, or excess boundary work.
Interchanging tile or point loops changes execution order. Check the original dependence relations under that schedule, including aliasing and effectful operations. A matrix-product reduction also has numerical-order requirements: reassociation may be permitted only by an explicit floating-point contract. Do not infer legality from a faster benchmark or exact-real algebra. An elementwise independent loop has different freedoms from a recurrence or reduction, even when all share the same rectangular bounds.
Choose boundary cases before timing
Validate dimensions just below, equal to, and just above tile multiples, as well as small and non-square shapes. Count coverage or use a reference that exposes missing and duplicate outputs. Exercise slices and layout variants so a contiguous default does not conceal incorrect indexing. After correctness, measure total work, transferred bytes, and resource usage on representative dimensions; a large padded square benchmark can hide poor tail efficiency that dominates real small batches.
The cache lab illustrates abstract reuse only. Reset and set both C=4, s=4, predict twelve hits in its initial sixteen requests, then Step. Reset and re-set C=3, s=4, predicting no hits for the four-address cycle. The empty-start fully associative LRU trace caps at 4096 requests and has no tile domain, loop order, or boundary guards. Use it to discuss a working set that fits versus one that does not, while keeping the actual tiling-coverage proof separate.
Work it through
A five-by-seven domain in four-by-four tiles
Tile an independent 5×7 elementwise operation with 4×4 rectangular tiles. Assume each padded tile launch has sixteen logical lane slots, but only valid domain elements may access unpadded storage.
There are ceil(5/4)=2 tile rows and ceil(7/4)=2 tile columns, giving four tiles and 64 nominal lane slots.
Their valid element counts are 16,12,4, and 3, totaling 35=5×7. The remaining 29 slots must be masked or excluded under the chosen lowering.
Every valid element is covered once by its tile coordinates. This count does not permit speculative out-of-bounds loads in inactive slots; masking must apply to the relevant memory operations with supported target semantics.
Correct tiling preserves all thirty-five elements while handling partial tiles explicitly. Lane-slot arithmetic is not a license to read padded data that does not exist.
The living notebook
Explore the model
Interactive lab · cache
A bounded working set can retain reuse
Reset, set C=4, s=4;predict 12 hits in 16 requests. Reset and re-set C=3, s=4;predict 0 hits. This capped 4096-request LRU model does not tile a loop, check dependence legality, or handle array tails.
- Hits / requests
- 0 / 16
- Hit rate
- 0%
- Address-stream period
- 16 addresses
A fully associative LRU cache starts empty and requests address (i·s) mod 16. Hits move an address to the newest position; misses evict the oldest when full. Playback starts with 16 requests and adds two per second, capped at 4096 explicitly simulated requests. This toy stream is not a processor-cache benchmark. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forReuse capacity motivates tiling, while domain coverage and dependency checks establish legality.
Pause & reason
Check your understanding
Your turn
Try it yourself
A length 33 independent loop uses tile size eight. Count tiles, nominal slots, and valid elements in the last tile. Then compute the payload of three 8×8 four-byte tiles retained together.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Separate one-dimensional coverage from the independent square-tile storage estimate.
Compare with the solution
There are ceil(33/8)=5 tiles and 40 nominal slots. The first four cover 32 elements, leaving one valid element in the last tile and seven inactive slots. Three 8×8 four-byte arrays require 3×64×4=768 payload bytes. Actual resource usage can be higher with padding, metadata, wider accumulators, or double buffering, and legality still depends on memory and dependence rules.
Keep the idea
Take it with you
- Tiling must cover each valid iteration exactly once.
- Partial tiles require correct memory bounds and neutral-value semantics.
- Resource fit and locality benefits do not replace dependence or numerical legality.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.