Phase 2, week 9retrospective

Register blocking

Register blocking holds an MR by NR accumulator in vector registers, cutting loads per MAC; DRAM intensity is the cache tile's job.


The tile that stays in registers

Tiling decided which tile a core works on. Register blocking decides how much of that tile stays in vector registers across the whole K loop. You hold an MR by NR accumulator tile, stream K, and touch memory once per K step for each row and each column you keep:

for (int k = 0; k < K; ++k) {
  vfloat32m1_t b = __riscv_vle32_v_f32m1(B + k * N + j, vl);
  for (int m = 0; m < MR; ++m)
    acc[m] = __riscv_vfmacc_vf_f32m1(acc[m], A[(i + m) * K + k], b, vl);
}

Each acc[m] is one register group holding vl elements of one output row, so NR equals vl here. MR rows ship in MR groups, and the B vector is loaded once and multiplied against every row.

What the tile buys and what it costs

Per K step you move MR + NR elements and issue MR * NR multiply-accumulates, so loads per MAC fall as 1/MR + 1/NR. Doubling both dimensions halves load traffic per MAC. That is the entire return, and it is why the tile shape matters more than the tile size.

The cost is registers. A 4 by 32 f32 tile at vlen=256 is 128 accumulator elements, which is 16 of the 32 vector registers at e32,m1 before a B vector exists. The outer cache tile still decides what reaches L2; register blocking only decides what reaches the vector unit.

Things that break

The tile does not fit and the compiler spills vector registers to the stack inside the K loop. Look for vs1r.v and vl1re32.v against stack addresses between the vfmacc instructions in llvm-objdump -d. Results stay correct, so the loss looks like a bad tile choice rather than a register budget. Counting the groups before you compile is cheaper than discovering it in disassembly: one group per accumulator row, one for B, and whatever the epilogue keeps live.

Sources

A version records the documentation the claim was checked against, not a house pin. Confirm flags with --help on the release you installed.

Check yourself

What are the loads per MAC for an `MR` by `NR` register tile?

A register-blocked matmul spills. Where does that show first?

What does the outer cache tile still control after register blocking?

0 / 3 correct

← back to the map