01 SME · GEMM microkernel
Microkernel
One kernel, three moves: pack fixes the layout, the K loop does ldr + fmopa, the store writes C out. Follow where each value goes.
pack ld1w / ldnt1w → st1w (A and B into packed panels)
loop ldr zA, [pa, #k, mul vl] ; ldr zB, [pb, #k, mul vl]
fmopa za0.s, p0/m, p0/m, zA.s, zB.s
prfm pldl2keep, [pb] ; prfm pldl1strm, [pc]
store st1w { za0h.s[w12, 0] }, p0, [pc] → stnt1w
Types: everything is f32. Deliberately small: C is one 4 × 4 ZA tile, A is 4 × 2, B is 2 × 4, K = 2 groups. The real kernel is the same choreography at 32 × 32 with a 2 × 2 tile grid, four load slots, and K_BLK = 512.
Pack · once per K blockchanges with the layout
A source · M×K row-major
A panel · one column per k
ld1w → ZA → st1w (transpose route)
B source · K×N row-major
B panel · one column per k
ldnt1w → st1w (straight copy)
Main loop · per k groupthe core · identical in all four states
Load slots
C · one 4 × 4 ZA tile
C → st1w → aligned buffer → stnt1w → memory
za0
C in memory · one slice per row
C = A × B · 4 × 4 · K accumulation
Ready. Pick the A and B layouts, then play: pack, K loop, store.
Arrow keys step, space plays or pauses.
This browser prefers reduced motion. Play still runs the instruction and jumps straight to the result.
Reading the picture
-
The smallest honest picture
The real kernel runs a 2 × 2 grid of tiles covering 32 × 32, four FMOPAs per k group, four load slots. Everything here is the same choreography, scaled down — one 4 × 4 tile, two k groups — so you can follow every single value. One shortcut is worth naming: the drawn tile starts at zero, so the loop only accumulates — a real kernel must clear ZA first (zero {za}) before its first FMOPA.
-
Transpose is absorbed by pack
Only the highlighted read pattern changes: gather takes one element per source row (row-strided ld1w, transposed in the ZA), copy takes one contiguous run (ldnt1w). Both produce the same panels, so the tagged core — the loop — never learns which layout you chose.
-
Software pipelining
Each load slot carries one k group; in the real kernel there are four, with pldl2keep pulling B into L2 and pldl1strm streaming C. A leftover K tail runs its own small ldr + fmopa loop, and C leaves through st1w slices plus a non-temporal stnt1w flush.
-
Words this page borrows
rank-1 layer — one outer product: a single A column times a single B row, one k's contribution added to every cell of C at once. k-major — K runs contiguously, one k per drawn panel column. mul vl — the byte length of one scalable vector at the current SVL (16 B here), so [pa, #1, mul vl] is the next vector along. non-temporal — a store that goes straight to memory without first fetching the line it overwrites (no read-for-ownership). w12 picks the ZA row a store cuts out; p0 is the predicate saying which of its four words are written.
A and B hold small integers; C = A × B.