pub fn allocate_scalar_registers(code: &[Op]) -> Result<Vec<Op>, String>Expand description
Map a function-free scalar program’s registers onto the core’s sixteen by liveness. The VM numbers
registers freely (a fresh one per Let, named values above the temporaries that computed them); the
chip needs only as many as are ever live at once. Two registers may share a physical one unless one
is live where the other is written (a Move’s source does not count against its destination), and
the interference graph is coloured Chaitin–Briggs style — simplify below sixteen neighbours, else
optimistically, then colour in reverse — lowest register first, so the result is deterministic.
A program already within sixteen registers is returned unchanged, so an image that fits keeps its
encoding exactly. Err names the instruction where more than sixteen values are live at once; a
program with an op outside the scalar subset is also returned unchanged, for the encoder to refuse
with that op’s own reason.