feat(vcr-sel): increment 3 — the i64 register-pair rule family, 6 rules / 6 Qed, flag-off (#242) - #661
Conversation
…es / 6 Qed, flag-off (#242) The DSL steps into the family where this week's miscompiles clustered (#615/#632/#633/#643/#599 — all hand-written i64 paths; zero bugs in DSL-covered ops): i64 add/sub/and/or/xor as two-instruction pair rules (ADDS+ADC / SUBS+SBC / ANDx2 / ORRx2 / EORx2 over six register variables) plus i64.eqz (the I64SetCondZ shape). Model finding: the Rocq flat model needed ZERO extension for pairs — ADDS/ADC carry coupling and combine_i32/lo_of_i64/hi_of_i64 have carried the pair convention since v0.8.0. The increment is the pilot's fixed-to-universal register lift applied to CorrectnessI64.v's ancestors, with what was 'discriminate' on concrete registers becoming three explicit aliasing hypotheses per pair rule (the #632 lesson made structural): rd_hi<>rd_lo, rd_lo<>rn_hi, rd_lo<>rm_hi — runtime Ok-or-Err in the generated lowerings, never a silent misassemble. In-place rd=rn reuse stays admitted, so one Qed covers both selectors. - coq/Synth/Synth/VcrSelRules.v: +6 pair-result T1 theorems (both words proven), 27/27 Qed, no new axiom (carry/borrow via the existing ArmFlagLemmas lemmas; combine lemmas imported from CorrectnessI64). - sel_dsl: RegVar pair variables, Adds/Adc/Subs/Sbc/I64SetCondZ templates, i64_pair_rule dispatch, generator learns wrapped signatures; generated.rs regenerated (rustfmt fixpoint). - Delegation::Both behind SYNTH_SEL_DSL (default OFF): select_default's fixed R0:R1 op= R2:R3 arms + select_with_stack's allocated-pair arms. - Mirror-pins: select_default loop now 17 rules; dedicated sel_dsl_mirror_pin_i64_pair_rules_select_with_stack_242 (i64-typed probes, RMW-vacuity window check); side-condition Err test. - OFF ≡ baseline by construction; frozen .text byte gate 10/10 green both flag-off AND under SYNTH_SEL_DSL=1. Part of #242 (VCR-SEL-001). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Automated review for PR #661pulseengine/synth: Verdict: 💬 Comment Summary: The changes to the codebase and documentation are well-organized, clear, and align with the project's goals. The addition of i64 pair theorems in CorrectnessI64 is a significant improvement that enhances the robustness and reliability of the synthesis process. Findings: 0 mechanical (rivet) · 1 from local AI model. Findings (1):
Generated by a local AI model and post-validated against a strict JSON contract. Each finding includes the verbatim line being criticised — verify by reading the file at the cited location. Reviewed at |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
VCR-SEL-001 increment 3 (#242) — the i64 register-pair family
Extends the verified selector DSL (increments 1+2: PRs #623/#639) into the family where this week's miscompiles clustered — #615 A32 NOPs, #632 popcnt clobber, #633 div_s overflow, #643 globals, #599 pair shifts are all hand-written i64 paths; zero bugs landed in DSL-covered ops. Scope doc:
docs/design/vcr-sel-001-increment-3.md.Rules landed (6; 27 total)
rule_i64_addADDS rd_lo; ADC rd_hirule_i64_subSUBS rd_lo; SBC rd_hirule_i64_andAND ×2rule_i64_orORR ×2rule_i64_xorEOR ×2rule_i64_eqzI64SetCondZ(the SetCondZ shape)OUT (increment-4 territory, honest-subset): i64 mul/div/rem/shifts/rotates (pseudo-ops / multi-instruction with scratch + branches) and the binary i64 comparisons (
I64SetCond).Model-extension finding: none needed
The go/no-go question — can the Rocq model express register pairs? — came back yes, zero model extension.
ArmSemantics.vhas carried the pair convention since v0.8.0 (ADDS/ADC/SUBS/SBC with real NZCV carry coupling;combine_i32/lo_of_i64/hi_of_i64value pairing), andCorrectnessI64.vproves the fixed-register ancestors T1 atR0:R1 op= R2:R3. The increment is exactly the pilot's fixed→universal register lift applied to pairs.Aliasing side-condition design (the #632 lesson, made structural)
The low-half instruction writes
rd_loBEFORE the high-half instruction readsrn_hi/rm_hi— a rule format that cannot state "the result must not be clobbered before use" is how #632-class bugs happen. Three explicit hypotheses per pair rule (I64_PAIR_SIDE_CONDITIONS), enforced as runtimeErrin the generated lowerings:rd_hi ≠ rd_lo— the high write must not destroy the low result word;rd_lo ≠ rn_hi— the low write must not clobber operand 1's high half;rd_lo ≠ rm_hi— same for operand 2.In-place reuse (
rd_lo = rn_lo,rd_hi = rn_hi—select_default's fixed arms) is deliberately admitted by the universal quantifier, so one Qed per rule covers both selectors' assignments.Rocq: 27 rules ↔ 27 Qed, 0 Admitted, 0 holdouts among attempted rules
rd_lo = lo_of_i64 …ANDrd_hi = hi_of_i64 …), value-level like theirCorrectnessI64.vancestors.synth_i64_carry_pair_proof_poly— the fixed-register stepped proof register-generalized verbatim, fed by the existingi64_add_via_adds_adc/i64_sub_via_subs_sbc(no new axiom).synth_i64_bitwise_pair_proof_poly— combine lemmas imported fromCorrectnessI64.v, not duplicated (new:correctness_tacticsdep for//coq:vcr_sel_rules).i64_setcondz_bits_specrewrite.//coq:vcr_sel_rules_coveragenow checks 27 rules against the manifest (pinned toRULESby cargo test).Delegation + gates
Delegation::BothbehindSYNTH_SEL_DSL(default OFF):select_default's fixedR0:R1 op= R2:R3arms andselect_with_stack's allocated-pair arms (alloc_consecutive_pair'sextra_avoidsatisfies the side conditions by construction — a violation is a loudErr, never a silent misassemble).sel_dsl_mirror_pin_i64_pair_rules_select_with_stack_242(i64-typed probes, OFF≡ON full-sequence equality, RMW-vacuity window check on the selector's own six chosen registers);i64_pair_side_conditions_are_enforcedpins all threeErrs per rule..textbyte gate 10/10 green flag-off and underSYNTH_SEL_DSL=1(the migration is byte-invisible even ON).Flip-remaining statement (inc 1+2+3)
Of
select_default's 68 integer-compute ops (i32: 33, i64: 35 — arithmetic, bitwise, shifts/rotates, bit-count, comparisons/eqz, const, extends/wrap; excludes control flow, locals/globals/memory plumbing, and the FPU/Helium-gated families), 27 (~40%) are now DSL-served in at least one selector: 17 withinselect_defaultitself (25%) + the ten i32 comparisons servingselect_with_stack's load-bearing arm (select_default's comparison arms remain the documented production-unreachable holdout). The remaining hot i64 arms (mul/div/shifts/rotates/I64SetCondcomparisons) are pseudo-op or scratch+branch shapes — increment 4.Verification
bazel test //coq:verify_proofs— PASSED (rocq_proofs + 27-rule coverage gate)cargo test --workspace— 2043 passed / 0 failedSYNTH_SEL_DSL=1cargo fmt --checkclean (generated.rs stays a rustfmt fixpoint);cargo clippy --workspace --all-targets -- -D warningscleanPart of #242 (VCR-SEL-001, Track A).
🤖 Generated with Claude Code