feat(vcr-ra): post-exhaustion code quality — the capability PR #659 named missing (#242) - #672
Merged
Merged
Conversation
…nst-div guards (#242, the PR #659 verdict) PR #659 held the SYNTH_SPILL_ON_EXHAUST flip on a measured i32-shape cycle regression and named the missing capability: post-exhaustion code quality on the optimized path. Root cause of the unreached allocation-time Belady slots: - fresh-monotonic slots defeat the overwrite-only frame-slot DCE (#515); - the eviction store's source is redefined immediately, defeating forward_stack_reloads; - spill_rechoice's rename deadness proof is segment-local — R2/R3 are never touched again on bridge streams, so "possibly live-out" declined them, and exact SegmentTrace equality rejected any fresh-register rename; - signed_div_const additionally paid for const-divisor trap guards the direct selector elides (#209 Opt 1a). Extensions, ALL scoped to functions the #580 machinery actually shaped (OptimizerBridge::spill_on_exhaust_fired — flag-on leaves every untouched function byte-identical, locked by vcr_ver_001_gate_242 + frozen 10/10 run in both flag states; flag-off is bit-for-bit the shipping pipeline): - scratch_dead_at: function-level R2/R3 exit-deadness (conservative at any branch/call/unmodeled op) feeding rename_kill_def; trace equality modulo provably-dead exit entries; per-pair pressure commit; byte-shrinking count-neutral folds admitted; - constant rematerialization of spilled single-instruction consts in spill_forward_segment (movt RMW kills the shape — the #582 discipline); - bounded fixpoint of the cleanup triple + late elide_dead_frame; - terminal-segment relaxed live-out pinning in range-realloc (only R0/R1 observable past bx lr pre-prologue; VCR-RA-003 validator run with the same exemptions; reload-free segments only); - const-divisor trap-guard elision in DivS/DivU/RemS/RemU (single-def Const scan, total-or-disabled def enumeration; c=0 keeps all, DivS c=-1 keeps the overflow guard). Cycle proxy (scripts/repro/postex_cycle_proxy.py, wasmtime-matched): spill_on_exhaust_242 +30.4%→+17.4%, spill_rung_581 +32.4%→+8.8%, high_pressure_i32 +8.0%→−24.0%, signed_div_const +120%→−33.3%, i64 pair/pool −16.4%/−2.9%. Two fixtures still miss ≤+5%: the residual is alloc_i32_scratch's fixed R4-R8 dest pool vs the direct selector's nine registers — the Track-A allocator replacement itself (see the gate doc's "residual, named" section; a reload-pool widening was tried and reverted, measured strictly worse). The flip stays HELD (#580). Gates: cargo test --workspace green; frozen anchors 10/10 + gate lock in BOTH flag states; r12_spill_496 / spill_on_exhaust_242 / i64_pair_exhaust_587 / i64_spill_pool_587 / spill_rung_581 differentials PASS flag-on; fmt + clippy -D warnings clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
avrabe
added a commit
that referenced
this pull request
Jul 8, 2026
… — merged ahead of the tag Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
avrabe
added a commit
that referenced
this pull request
Jul 8, 2026
…ed rules, 81 bridge Qed (#673) * chore(release): v0.36.0 — unreachable traps + sparse tables + 40 rules + 81 bridge Qed (#668/#669/#670/#671) Pin sweep 0.35.0 -> 0.36.0 + CHANGELOG. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore: fold #672 (post-exhaustion quality) into the v0.36.0 changelog — merged ahead of the tag Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
PR #659 demonstrated the VCR-VER-001 gate but held the
SYNTH_SPILL_ON_EXHAUSTflip on a measured i32-shape cycle regression, naming the missing capability: post-exhaustion code quality on the optimized path — allocation-time Belady spill slots (#580) were not reached by the existing cleanup passes. This PR diagnoses why, extends the passes' reach, and re-measures PR #659's cycle-proxy table. Full evidence appended toscripts/repro/vcr_ver_001_gate.md.Root cause of the unreached slots
eliminate_dead_frame_storesstructurally cannot fire:next_spill_offsetis fresh-monotonic, and the pass proves deadness only via a later same-slot overwrite (the feat(vcr-ra): frame-slot dead-store elimination behind SYNTH_STACK_FWD (flag-off) (#242) #515 overwrite-only discipline) — no overwrite can exist.forward_stack_reloadsstructurally cannot fire: the eviction store's source register is redefined immediately after the store (that is why the value was evicted).spill_rechoice_segmentdeclined every rename: the bridge draws scratch from R4-R8 only, so R2/R3 are never touched again — and the segment-local deadness proof rejects "never touched again" as possibly-live-out. Behind that, exactSegmentTraceequality rejected any rename onto a fresh register, and guard (b) rejected count-neutralldr→movfolds.signed_div_const(the +120% outlier) was a different gap: the optimized path emitted div-by-zero + INT_MIN/−1 trap guards even for constant divisors (the direct selector elides them since v0.11.17, perf: --relocatable direct selector bypasses synth-opt — general codegen optimization (research + stats tracking) #209 Opt 1a), plus a dead spill store the unread sweep couldn't reach past the guards' resolved branches (feat(vcr-ra)!: retire inline const aliasing; SYNTH_CONST_CSE default-on (#242) #604/AUDIT: spill-realloc passes delete instructions on resolved-offset streams — same branch-overshoot hazard class as the #604 const-CSE miscompile (default-on since v0.24.0) #606 discipline).Pass changes (all scoped, flag-off bit-identical)
Everything is reachable only on functions the #580 machinery actually shaped, via the new
OptimizerBridge::spill_on_exhaust_firedscoping — a flag-on compile leaves every untouched function byte-identical (guard elision on a non-spilling function triggers a rebuild with guards reinstated). Locked byvcr_ver_001_gate_242+ the frozen suite run in both flag states.scratch_dead_at: function-level R2/R3 exit-deadness (caller-saved, never return-carrying; conservative at any branch/call/unmodeled op), feedingrename_kill_def; trace equality taken modulo provably-dead exit entries; per-pair pool-pressure commit; count-neutral folds admitted when bytes strictly shrink.spill_forward_segment: a reload of a slot provably holding a single-instruction constant becomes the retargetedmov/movw;movt's RMW kills the tracked shape (the Direct selector spill rung miscompiles: ldr reads a never-stored frame slot after mul.w clobbers a live register (shipped path, wrong value) #581/fix(selector): spill rung stores before clobber — never reload a never-stored slot (#581) #582 discipline — a non-reproducible value is never treated as reproducible; the store-before-reload/is_const_materializationmachinery on the direct path is untouched).elide_dead_frameonce cleanup empties the frame.bx lrat the pre-prologue position; the VCR-RA-003 validator runs with the same exemptions (validate_segment_rewrite_exempting); restricted to reload-free segments so R2/R3 stay free for the rechoice pass.Constscan with total-or-disabled def enumeration (a redefined vreg poisons; any unenumerable op disables the map); c=0 keeps every guard, DivS c=−1 keeps the overflow guard.Before/after cycle proxy (
scripts/repro/postex_cycle_proxy.py, new)Dynamic instructions + data-memory accesses under unicorn, summed over the differential vectors; every run execution-matched wasmtime in both flag states.
spill_on_exhaust_242spill_rung_581high_pressure_i32signed_div_consti64_pair_exhaust_587i64_spill_pool_587The residual, named honestly
Two fixtures miss the bar. The residual is the allocation itself, not the cleanup:
alloc_i32_scratchdraws destinations from a fixed R4-R8 pool (5 regs) while the direct selector allocates over all nine of R0-R8 — the bridge evicts 5 values where Belady over 9 registers needs 1, and the post-hoc renamer recovers only what fits through the two forever-free caller-saved registers. A reload-pool widening was tried and reverted (measured strictly worse: rung +8.8 % → +14.7 % — it starves the renamer). Closing the last gap is dest allocation over the full pool, i.e. the Track-A VCR-RA/VCR-SEL allocator replacement — exactly the North-Star claim. The default-on flip stays HELD (#580) on that + gale G474RE cycles.Gates run
cargo test --workspacegreen (574 synthesis unit tests incl. 10 new; all suites)vcr_ver_001_gate_242lock in BOTH flag states (flag-off bit-identical by construction — every extension is behind the bridge-scopedpost_exhaustbool)r12_spill_496(both silicon victims,flight_algo = 0x07FDF307),spill_on_exhaust_242(8/8),i64_pair_exhaust_587(8/8),i64_spill_pool_587,spill_rung_581;high_pressure_i32+signed_div_constexecution-verified inside the proxy harnesscargo fmt --check+clippy --workspace --all-targets -- -D warningscleanRefs #242, #580, #496; the verdict this implements is PR #659's.
🤖 Generated with Claude Code