Skip to content

cleanup(riscv): allocator prefers caller-saved (lowest-free, not round-robin) — drops 6 needless s-reg spills on controller_step #230

Description

@avrabe

Audit-cycle finding (architectural drift in the allocation pool)

The RV32 temp allocator (synth-backend-riscv/src/selector.rs::alloc_temp) recycled the pool [t0..t6, s1..s6] with a monotonic next_temp round-robin counter. The code itself flagged it as a straight-line shortcut ("fine for straight-line code"). Even after #226 made it skip live registers, it kept marching forward into the callee-saved s-registers rather than reusing a just-freed low register.

Evidence (measured)

controller_step RV32 prologue, before:

addi sp, sp, -48
sw s1,12  sw s2,16  sw s3,20  sw s4,24  sw s5,28  sw s6,32   ← 6 callee-saved spills

The function never has more than ~4 values simultaneously live (the #226 liveness confirms this), yet round-robin walked into all six s-registers, each costing a save and restore (#220 prologue) plus frame space.

The drift

The pool accreted s-registers + a save/restore prologue (#220). With round-robin, the allocator consumed those reserves by accident. They should be a genuine overflow reserve.

Cleanup

alloc_temp returns the lowest-indexed free temp (caller-saved t-registers are listed first), keeping a function in t-registers whenever ≤7 values are live. Drops the next_temp field entirely.

Before / after

before after
controller_step .text 440 B 368 B (−72 B, −18 instrs)
callee-saved spills 6 0
frame 48 B 16 B

Oracle (behavior frozen)

All five differential fixtures bit-identical: ARM div_const 338/338, control_step 0x00210a55, flight_seam 0x07FDF307; RV32 control_step 0x00210a55, controller_step 0x05ff0000. 165 riscv unit tests pass (the #220 preservation test reworked to force s-register usage via 8 simultaneously-live values).

The broader local-regalloc / const-CSE Opt-3 work (gale #209) stays separate — this is only the round-robin → lowest-free revert.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions