Expand description
★ THE IR PEEPHOLE ★ — a semantics-preserving CompiledProgram → CompiledProgram
transform: block-local forward copy-propagation followed by dead-move
elimination. It exists for the backends that lower the bytecode straight to a
final target with no downstream optimizing assembler — RISC-V asm, WASM, the
spatial fabric. gcc already performs exactly this coalescing for the C tier
(register-to-register moves fold away, dead copies vanish), so C does not need
it; the flat backends ship the VM compiler’s move cascades verbatim without it.
The measured target is the swap idiom. Set a to b. Set b to t. lowers to a
five-move cascade through fresh temps every loop iteration:
Move R10 = R8 Move R11 = R3 Move R1 = R11 Move R12 = R10 Move R3 = R12Copy-propagation rewrites the temp reads to their roots and the now-dead temp
moves fall to DCE, leaving the optimal Move R1 = R3. Move R3 = R8. — three
fewer ops in the hottest loop, per iteration.
§Soundness — the asymmetry that makes it safe
A wrong coalesce miscompiles every backend, so the register model is deliberately one-sided:
readsis a superset of the true reads (over-approximate). Liveness can then never under-count a use, so a still-needed value is never judged dead.killsis a subset of the registers an op FULLY overwrites (under-approximate). Liveness can then never over-count a def, so a live range is never cut short.clobbers=kills ∪ mutatesinvalidates a copy on BOTH its key and its value side. This is what keeps copy-propagation sound under LOGOS’s value-semantics collections: afterMove x = list, mutating OR reassigninglistmust kill thex = listfact, because a copy-on-write push makesxandlistdiverge.- The in-place-mutated collection/struct register is never rewritable — pushing
to
x(a copy oflist) is not the same as pushing tolistonce value semantics clone on write, so a read that is really an in-place mutation site is left untouched. - Only
Moveops are ever deleted (their semantics are total and side-effect free); and only when the destination is provably dead or the move is a self-copy.
Every register classifier below is EXHAUSTIVE on Op (no _ arm): a newly added
instruction fails to compile until it is classified, so no op can silently escape
the model. peephole_soundness_lock proves program_outcome(peephole(P)) == program_outcome(P) over the corpus + a fuzzer, and that the op count strictly drops
on the swap-idiom programs.
Functions§
- peephole
- Run the peephole to a fixpoint, in place. Copy-propagate once (a single forward pass fully resolves within-block chains, because the copy map stores roots), then iterate liveness + dead-move elimination until no move is removed.