rocq/backend/RegsProof.v
# Soundness proofs for Regs.v
Machine-checked invariants of the Gallina register allocator, validator, parallel-move compiler and 3-address selection in Regs.v (M7 of docs/gallina-backend.md):
1. **Interval and call-point tests** (hreg_eqb_spec,
[ivals_disjoint_sound], [ivals_hit_points_sound]): disjoint interval lists share no program point, and an interval list that misses the sorted call points contains none of them.
2. **Allocation validator simulation** (check_rinst_step_sound,
[check_rinsts_rev_sound], [poll_edge_clobber_sound], [callee_saves_restore_sound], [lower_key_never_hreg]): any register map accepted by [check_rinsts_rev] and [check_succs_polls] preserves temporary values across instructions, simultaneous definitions, caller-saved register clobbers (`%r10`, `%r11`) at calls and poll edges, restores all five callee-saved registers (`%rbx`, `%r12`–`%r15`) on exit, and keeps capability lowers in stack root slots.
3. **Parallel moves** (ready_pmove_step_sound,
[cycle_break_step_sound]): peeling an unread destination or saving a cycle head into `%rcx` preserves the simultaneous assignment of all non-scratch locations.
4. **3-address lea and immediate selection**
([imm32_add_mod_sound], [imm32_sub_lea_w_sound], [imm32_sub_lea_l_sound]): signed 32-bit immediates and negated `lea` displacements compute the exact modular sum and difference at both 32-bit (`w`, including `-2^31`) and 64-bit (`l`) widths.
1. Hardware register equality and interval disjointness
Proof 1 step Qed
Proof 5 steps Qed
Proof 3 steps Qed
Proof 3 steps Qed
Proof 3 steps Qed
Whether point p lies in some closed interval [lo, hi] of ivs.
Strictly ordered interval list: each interval ends before the next begins, and every interval satisfies lo ≤ hi.
Proof 7 steps Qed
Proof 3 steps Qed
Proof 34 steps Qed
Disjoint well-formed interval lists share no program point.
Proof 3 steps Qed
Proof 7 steps Qed
Proof 34 steps Qed
When ivals_hit_points returns false, no call point in pts falls inside ivs.
Proof 3 steps Qed
2. Validator soundness and forward simulation
Concrete register+slot state for a function body.
A call clobbers caller-saved registers (%r10, %r11) with arbitrary values arb while preserving callee-saved registers and stack slots.
State agreement on all temporaries in live (for mapped temporaries under dom = Somekm, and unconditionally on unmapped temporaries).
Proof 9 steps Qed
Proof 16 steps Qed
When no_dup_hregs holds on a duplicate-free list ts, distinct elements in ts never map to the same hreg.
Proof 21 steps Qed
Proof 10 steps Qed
Clobbering caller-saved registers preserves state_agrees on any set ts accepted by all_callee_saved.
Proof 13 steps Qed
Corollary for poll edges: when check_succs_polls accepts a Poll edge to block si, filc_pollcheck_slow clobbering caller-saved registers preserves every live-in and phi-defined temporary of si.
Proof 2 steps Qed
Proof 40 steps Qed
Helper predicates and state steps for check_rinst_step_sound, stated at top level so the theorem renders as an inference rule without nested let or match blocks.
Complete one-instruction simulation theorem: reading inputs uses, clobbering caller-saved registers according to call, and writing destination d preserves state_agrees whenever no_dup_hregs and all_callee_saved hold as checked by check_rinsts_rev.
Proof 43 steps Qed
Callee-saved save and restore invariant: every callee-saved register r is restored to its caller entry value entry_regsr, whether r was saved and restored from its dedicated save slot (because rm used r) or untouched throughout the body (because rm never assigned r and every call preserves callee-saved registers).
Proof 6 steps Qed
3. Parallel-move soundness
Abstract valuation of parallel-move locations.
Proof 4 steps Qed
Proof 7 steps Qed
Proof 10 steps Qed
Proof 20 steps Qed
Cycle-breaking step: saving old into PmCycleTmp (%rcx) and rewriting reads of old to PmCycleTmp preserves the target value of every move (provided PmCycleTmp was not previously read) and eliminates all reads of old, making old immediately ready on the next step.
Proof 26 steps Qed
4. Soundness of 3-address lea and immediate selection
integer_immediate produces a value congruent to n modulo 2 ^ 32 (half = true) or 2 ^ 64 (half = false).
Proof 16 steps Qed
Immediate add and lea disp(%rx) compute x + n mod M at both 32-bit and 64-bit widths.
Proof 8 steps Qed
Proof 4 steps Qed
Proof 4 steps Qed
64-bit Sub via leaq (-n)(%rx), %dst computes x − n mod 2 ^ 64.
Proof 3 steps Qed
5. Executable rejection examples for valid_alloc
Two live parameters mapped to the same register HRbx are rejected.
Proof 1 step Qed
A caller-saved register HR10 live across RCallAfterReads is rejected, while callee-saved HRbx is accepted.
Proof 1 step Qed
Input of RCallDuringReads (AStorePointer / ADispatch) in HR11 is rejected even when dead after the instruction.
Proof 1 step Qed
Proof 1 step Qed
Assigning a float temporary (Double) to a general register is rejected.