Runtime-size validation
The same lowered binary must pass reference checks at several runtime sizes, including non-multiples of the tile.
One binary, many sizes
A dynamic path is correct only if it is correct at the sizes the tile arithmetic did not anticipate. Build once, hash the binary, then run the same artifact over a fixed size matrix:
sha256sum bin/matmul_dyn | tee results/<commit>/binary.sha256
for s in 1 7 63 64 65 127 128 129 511 512 513; do
qemu-riscv64 -cpu "$QEMU_CPU" ./bin/matmul_dyn --m "$s" --n "$s" --k "$s" \
--check || echo "FAIL $s"
done
The sizes are chosen for coverage, not for speed. 63 and 65 straddle the tile multiple; 1 catches an empty loop or a zero-size slice; 64 catches an epilogue that assumes a remainder exists; a size below one tile catches a mask that assumes an interior iteration ran first. The set is a parameterised test, and it belongs in the harness rather than in a shell history.
The reference has to be independent
Compare against a scalar reference that shares no code with the kernel under test, with a tolerance rather than equality. Floating-point addition is not associative, so a different accumulation order changes the low bits; an exact comparison rejects correct kernels and, worse, teaches you to loosen the check until it accepts incorrect ones. A relative tolerance scaled by K is the usual shape.
Print the size, the maximum relative error, and the reference checksum. A run that passes at <M> and fails at <M> + 1 is the tail bug the matrix exists to find.
Things that break
Rebuilding between sizes tests several binaries and calls it one. A reference check only at 512 hides every tail bug. A tolerance loose enough to hide a missing K tile is indistinguishable from passing. And a harness that reports only the first failure hides whether the bug is a tail case or something general; run and report every size in the matrix.
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
Why run the size matrix at 63 and 65 as well as 64?
Why compare against the reference with a tolerance instead of equality?
Why hash the binary before the size loop?