Skip to content

feat(coq): add i64 pseudo-op result-correspondence axioms + discharge 5 v0.8.0 admits (v0.9.0 precursor)#153

Merged
avrabe merged 2 commits into
mainfrom
feat/v0.9.0-discharge-i64-admits
May 27, 2026
Merged

feat(coq): add i64 pseudo-op result-correspondence axioms + discharge 5 v0.8.0 admits (v0.9.0 precursor)#153
avrabe merged 2 commits into
mainfrom
feat/v0.9.0-discharge-i64-admits

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented May 27, 2026

TL;DR — precursor + discharge (5/5 Qed)

This PR was re-scoped from a smoke-test/findings PR (commit bb50413 surfaced
an axiom-shape blocker) into the full precursor + discharge for the
v0.9.0 i64 lift queue (umbrella #152).

Net: +5 Qed, -5 Admitted. Total 233 Qed / 10 Admitted.

Linked: umbrella #152.

Falsification clauses (from umbrella #152) this PR speaks to

v0.9.0 would be wrong if:

This PR discharges all 5. The discharges depend on the new _spec axioms;
those axioms are themselves load-bearing claims and the umbrella's own clause
on "newly-added axioms" applies: they must be falsifiable by the fuzz
harness. Each axiom is cross-referenced to the per-op codegen survey
(docs/analysis/I64_CODEGEN_SURVEY.md) so that the spec can be checked
against the Rust compiler's actual output.

Full list of new _spec axioms

All in coq/Synth/ARM/ArmSemantics.v, immediately after the existing v0.8.0
type-only axiom block. Each spec uses combine_i32, lo_of_i64, hi_of_i64
helpers added to coq/Synth/Common/Integers.v:

Definition lo_of_i64 (n : I64.int) : I32.int := I32.repr (I64.unsigned n mod I32.modulus).
Definition hi_of_i64 (n : I64.int) : I32.int := I32.repr (I64.unsigned n / I32.modulus).
Definition combine_i32 (lo hi : I32.int) : I64.int :=
  I64.repr (I32.unsigned lo + I32.modulus * I32.unsigned hi).

Constants (load-bearing for i64_const_correct)

Axiom Equation Survey ref
i64_const_lo_spec i64_const_lo n = lo_of_i64 n §8 (instruction_selector.rs:1393–1399)
i64_const_hi_spec i64_const_hi n = hi_of_i64 n §8 (instruction_selector.rs:1393–1399)

Division / remainder (load-bearing for the 4 div/rem discharges)

Axiom Equation Survey ref
i64_divs_pair_spec i64_divs_pair lo1 hi1 lo2 hi2 = option_map (..) (I64.divs (combine_i32 lo1 hi1) (combine_i32 lo2 hi2)) §7 (lines 1737–1746)
i64_divu_pair_spec same shape over I64.divu §7 (1748–1757)
i64_rems_pair_spec same shape over I64.rems (newly defined in Integers.v) §7 (1759–1768)
i64_remu_pair_spec same shape over I64.remu (newly defined in Integers.v) §7 (1770–1779)

Multiply

Axiom Equation Survey ref
i64_mul_lo_bits_spec i64_mul_lo_bits ... = lo_of_i64 (I64.mul (combine_i32 lo1 hi1) (combine_i32 lo2 hi2)) §4 (1646–1655)
i64_mul_hi_bits_spec corresponding hi_of_i64 §4

Shifts / rotates

Axiom Equation Survey ref
i64_shl_{lo,hi}_bits_spec over I64.shl with combine_i32 cnt I32.zero §5 (1658–1667)
i64_shru_{lo,hi}_bits_spec over I64.shru §5 (1669–1678)
i64_shrs_{lo,hi}_bits_spec over I64.shrs §5 (1680–1689)
i64_rotl_{lo,hi}_bits_spec over I64.rotl §5 (1691–1699)
i64_rotr_{lo,hi}_bits_spec over I64.rotr §5 (1701–1709)

Bit manipulation

Axiom Equation Survey ref
i64_clz_bits_spec i64_clz_bits lo hi = i64_to_i32 (I64.clz (combine_i32 lo hi)) §6 (1712–1718)
i64_ctz_bits_spec corresponding I64.ctz §6 (1720–1726)
i64_popcnt_bits_spec corresponding I64.popcnt §6 (1728–1734)

Comparisons

Axiom Equation Survey ref
i64_setcond_bits_spec parametric over ARM condition; mapping fixed by Compilation.v (Cond_EQ→I64.eq, Cond_CC→I64.ltu, Cond_HI→I64.gtu, Cond_LS→I64.leu, Cond_CS→I64.geu, etc.) §3 (1535–1643)
i64_setcondz_bits_spec i64_setcondz_bits lo hi = if I64.eq (combine_i32 lo hi) I64.zero then I32.one else I32.zero §3 (1527–1533)

Conversions / memory

Axiom Equation Survey ref
i64_extend_s_hi_spec i64_extend_s_hi rn = I32.shrs rn 31 (sign bit replicated) §8 (1425–1431, ASR R1, R0, #31)
i64_load_lo_spec i64_load_lo m a = m a (TODO #152: lifts when memory model lifts) §9 (1782)
i64_load_hi_spec i64_load_hi m a = m (a + 4) (TODO #152) §9 (1782)

Total: 26 new _spec axioms. Existing type-only axioms in ArmSemantics.v are unchanged.

Per-theorem outcome for the 5 prior admits

Theorem File Outcome Discharge
i64_const_correct CorrectnessSimple.v Qed unfold + simpl, rewrite via i64_const_{lo,hi}_spec
i64_divs_correct CorrectnessI64.v Qed unfold + simpl, rewrite registers + i64_divs_pair_spec + Hdivs, simpl
i64_divu_correct CorrectnessI64.v Qed same shape via i64_divu_pair_spec
i64_rems_correct CorrectnessI64.v Qed same shape via i64_rems_pair_spec
i64_remu_correct CorrectnessI64.v Qed same shape via i64_remu_pair_spec

Theorem restatement (sound shape)

All 5 theorems were restated to fix the structural problems flagged by the
smoke-test report:

Theorem i64_divs_correct : forall astate lo1 hi1 lo2 hi2 result,
  get_reg astate R0 = lo1 ->                          (* operand 1 low half *)
  get_reg astate R1 = hi1 ->                          (* operand 1 high half — NEW: pinned *)
  get_reg astate R2 = lo2 ->                          (* operand 2 low half *)
  get_reg astate R3 = hi2 ->                          (* operand 2 high half — NEW: pinned *)
  I64.divs (combine_i32 lo1 hi1) (combine_i32 lo2 hi2) = Some result ->  (* NEW: I64-typed *)
  exists astate',
    exec_program (compile_wasm_to_arm I64DivS) astate = Some astate' /\
    get_reg astate' R0 = lo_of_i64 result /\           (* NEW: low half *)
    get_reg astate' R1 = hi_of_i64 result.             (* NEW: high half *)

Changes from the v0.8.0 statement:

  1. Operand types are now I32.int (register halves) with explicit recombination via combine_i32, instead of the incoherent v1, v2 : I64.int + I32.divs v1 v2 shape.
  2. Both halves of each operand are pinned.
  3. Both halves of the result are checked in the post-condition.
  4. The vacuous exec_wasm_instr I64DivS wstate = Some ... hypothesis (which was always False since exec_wasm_instr returns None for unmodeled instructions) is removed. The new shape is a direct value-level correspondence.

i64_const_correct got an analogous dual-register post-condition (R0 = lo_of_i64 n /\ R1 = hi_of_i64 n instead of only R0 = ...).

Uncertainty / TODO markers

  • i64_load_{lo,hi}_spec: the spec is the weakest form (i64_load_lo m a = m a, no endianness or bounds-check modelling) consistent with the current Coq memory model. Marked TODO #152 in the file — PR 5 of the umbrella will revisit when the memory model lifts. The 5 admits this PR discharges do not depend on these axioms, so any uncertainty here is contained.
  • i64_setcond_bits_spec: uses a catch-all _ => false for ARM conditions other than the 10 emitted by Compilation.v for i64 comparisons. This is sound because no i64 comparison emits those conditions; if a future codegen change uses, e.g., Cond_MI for an i64 op, the spec would need extending.

No axioms are marked uncertain in a way that affects the 5 discharges.

Fan-out readiness for v0.9.0 PRs 2-5

Status: YES, with one caveat.

After this PR lands, the remaining T2→T1 lifts (i64 Add, Sub, Mul, And, Or, Xor, Shl, ShrU, ShrS, Rotl, Rotr, Clz, Ctz, Popcnt, all 11 comparisons) become mechanical: each compiles to a single pseudo-op (or, for And/Or/Xor, to two parallel real ARM instructions), and each new _spec axiom rewrites the result function to a WASM-spec form. The pattern is:

intros; unfold compile_wasm_to_arm; simpl;
rewrite <register-hypotheses>;
rewrite <op>_lo_bits_spec, <op>_hi_bits_spec;
eexists; split; [reflexivity | split];
rewrite get_set_reg_neq by discriminate; rewrite get_set_reg_eq; reflexivity (* lo *)
rewrite get_set_reg_eq; reflexivity. (* hi *)

Caveat: PRs 2-5 need to restate their theorems with the same dual-register shape as the 5 in this PR. The current i64_add_correct etc. in CorrectnessI64.v are T2 existence proofs with a (vacuous) exec_wasm_instr hypothesis. T1 lifts need to drop that hypothesis and add high-half register pinning + dual-register post-conditions, parallel to what this PR did for the 5 div/rem/const theorems.

Recommended sequencing:

  • PR 2: arithmetic + bitwise (Add, Sub, Mul, And, Or, Xor) — 6 lifts.
  • PR 3: shifts and rotates (Shl, ShrU, ShrS, Rotl, Rotr) — 5 lifts.
  • PR 4: comparisons (Eqz + 10 binary) — 11 lifts.
  • PR 5: bit-manip + extend/wrap + loads/stores (Clz, Ctz, Popcnt, ExtendI32S/U, WrapI64, Load, Store) — 7 lifts.

Each PR is independent and can fan out to a parallel agent.

Verification

Local: bazel test //coq:verify_proofs not run — this worktree's Bazel
toolchain requires Nix per CLAUDE.md, and Nix is not available in this
environment. CI on this push will confirm. The proofs use only standard
tactics (unfold, simpl, rewrite, discriminate, reflexivity) and
the get_set_reg_{eq,neq} lemmas in ArmState.v; the same pattern already
works for i32 ops in CorrectnessI32.v.

If CI surfaces issues with the proof tactics, follow-up commits will fix them
without touching the axiom layer (which is the load-bearing precursor that
PRs 2-5 will depend on).

Files changed

  • coq/Synth/ARM/ArmSemantics.v (+211): 26 new _spec axioms, no existing edits.
  • coq/Synth/Common/Integers.v (+33): I64.rems, I64.remu, combine_i32, lo_of_i64, hi_of_i64.
  • coq/Synth/Synth/CorrectnessSimple.v (+11/-25): i64_const_correct restated and discharged.
  • coq/Synth/Synth/CorrectnessI64.v (+98/-115): file-header + 4 div/rem theorems restated and discharged, summary updated.
  • coq/STATUS.md (+22/-31): updated to reflect 233 Qed / 10 Admitted.
  • CHANGELOG.md (+21): new ### Added entry under [Unreleased].

Generated with Claude Code

The 5 strategic admits introduced by v0.8.0 #150 (4 div/rem in
CorrectnessI64.v + i64_const_correct in CorrectnessSimple.v) cannot
be discharged under the v0.8.0 axiom shape. The `i64_divs_pair` /
`i64_divu_pair` / `i64_rems_pair` / `i64_remu_pair` / `i64_const_lo`
/ `i64_const_hi` axioms are pure type declarations with no result
equations connecting them to `I64.divs` / `I64.divu` / `I64.rems` /
`I64.remu` / `I32.repr ((I64.unsigned n) mod I32.modulus)`.

Additional gaps in the theorem statements (carried from PR #150):
- div/rem theorems use `I32.divs v1 v2 = Some result` as hypothesis
  where v1, v2 : I64.int (typechecks only because I32.int = I64.int = Z,
  but semantically incoherent)
- div/rem theorems don't pin the high-half register values (R1, R3),
  so the pseudo-op input is underspecified

Documents the smoke-test outcome in the file headers and STATUS.md.
No theorems closed; no theorems opened. Numbers unchanged.

Same axiom-shape gap blocks the 30 T2->T1 lifts scheduled for
v0.9.0 PRs 2-5. A precursor PR strengthening the axioms (and
restating the theorems with I64-typed hypotheses + high-half register
pinning) must land before fan-out is safe.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@temper-pulseengine
Copy link
Copy Markdown

Automated review for PR #153

pulseengine/synth:feat/v0.9.0-discharge-i64-admits → pulseengine/synth:main

Verdict: 💬 Comment

Summary: The PR introduces a significant architectural finding that requires further work before it can be merged. The reviewer suggests requeuing the changes for future consideration.

Findings: 0 mechanical (rivet) · 1 from local AI model.

Findings (1):

  1. coq/Synth/ARM/ArmSemantics.v:127
    Theorem i64_divs_correct : forall wstate astate v1 v2 stack' result,
    
    The axioms in coq/Synth/ARM/ArmSemantics.v are pure type declarations with no equation tying their results to I64.divs / I64.divu / I64.rems / I64.remu / I32.repr ((I64.unsigned n) mod I32.modulus).

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 bb50413

Re-scopes v0.9.0 PR 1 from a smoke-test/findings PR into the full
precursor + discharge PR per the smoke-test outcome (axiom shape
blocker identified at bb50413).

Precursor — coq/Synth/ARM/ArmSemantics.v
  Adds 26 result-equation axioms (the `_spec` family) that pin each
  v0.8.0 i64 pseudo-op result function (introduced as opaque types
  by #150) to the WASM-spec operation on the combined 64-bit operand
  pair. Each axiom is cross-referenced to docs/analysis/I64_CODEGEN_SURVEY.md
  with the `instruction_selector.rs` line numbers that emit the
  pseudo-op. Existing axioms are unchanged.

  - i64_const_lo_spec, i64_const_hi_spec
  - i64_{divs,divu,rems,remu}_pair_spec
  - i64_mul_{lo,hi}_bits_spec
  - i64_{shl,shru,shrs,rotl,rotr}_{lo,hi}_bits_spec
  - i64_{clz,ctz,popcnt}_bits_spec
  - i64_setcond_bits_spec (parametric over ARM condition)
  - i64_setcondz_bits_spec
  - i64_extend_s_hi_spec
  - i64_load_{lo,hi}_spec

Supporting infrastructure — coq/Synth/Common/Integers.v
  Adds `combine_i32 : I32.int -> I32.int -> I64.int` and projection
  helpers `lo_of_i64 / hi_of_i64`. Adds `I64.rems` / `I64.remu`
  definitions (previously only I32 had remainder ops). All additive,
  no existing definitions changed.

Discharges — 5 admits closed as Qed
  - i64_const_correct (CorrectnessSimple.v): dual-register postcondition
    on (R0 = lo_of_i64 n, R1 = hi_of_i64 n).
  - i64_divs_correct, i64_divu_correct, i64_rems_correct, i64_remu_correct
    (CorrectnessI64.v): restated with I64-typed hypotheses on combined
    operand pairs, high-half register pinning (R1 for v1's hi, R3 for v2's
    hi), and dual-register postconditions (R0 = lo_of_i64 result,
    R1 = hi_of_i64 result).

Removes the vacuous `exec_wasm_instr I64DivS wstate = Some ...`
hypothesis from the four div/rem theorems (the WASM model returns None
for I64Div/Rem, making the prior hypothesis False). The new shape is a
value-level correspondence between `I64.divs` and the ARM execution
result, without routing through `exec_wasm_instr`.

After this PR, fan-out PRs 2-5 of umbrella #152 (the remaining
T2->T1 lifts for I64 add/sub/mul/and/or/xor/shifts/rotates/comparisons/
clz/ctz/popcnt) become mechanical `unfold; rewrite <op>_spec; reflexivity`.

Net: +5 Qed, -5 Admitted. Total 233 Qed / 10 Admitted.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@avrabe avrabe changed the title feat(coq): discharge v0.8.0's 5 strategic i64 admits (v0.9.0 smoke test) feat(coq): add i64 pseudo-op result-correspondence axioms + discharge 5 v0.8.0 admits (v0.9.0 precursor) May 27, 2026
@avrabe avrabe merged commit 5782b1c into main May 27, 2026
7 checks passed
@avrabe avrabe deleted the feat/v0.9.0-discharge-i64-admits branch May 27, 2026 04:19
@codecov
Copy link
Copy Markdown

codecov Bot commented May 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

avrabe added a commit that referenced this pull request May 27, 2026
Restate Add/Sub/Mul/And/Or/Xor to the umbrella's required T1 shape:
I64-typed hypotheses on combined operand pairs, high-half register
pinning (R0:R1, R2:R3), and dual-register post-conditions (R0 =
lo_of_i64 result, R1 = hi_of_i64 result).

- i64_mul_correct: Qed via i64_mul_lo_bits_spec / i64_mul_hi_bits_spec
  (PR 1 axioms, mirrors the div/rem discharge template).
- i64_add_correct / i64_sub_correct: Admitted. Closing requires a
  carry-/borrow-propagation lemma over the existing ArmSemantics.v
  ADDS+ADC and SUBS+SBC pairs (provable, but the helper does not yet
  exist). No new spec axiom introduced.
- i64_and_correct / i64_or_correct / i64_xor_correct: Admitted. Closing
  requires halves-distribute-over-bitwise decomposition lemmas in
  Common/Integers.v (lo_of_i64 (I64.and a b) = I32.and (lo_of_i64 a)
  (lo_of_i64 b), etc.). Blocked by the same Rocq 9 Z.mod_mod rewrite
  obstacle that already keeps i64_to_i32_to_i64_wrap Admitted.

Net change vs main: +1 T1 Qed (i64_mul_correct), 5 prior existence
proofs (Add/Sub/And/Or/Xor) restated to the umbrella's required T1
shape and Admitted with explicit gap citations. No new spec axioms.

Refs #152, follows #153.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
avrabe added a commit that referenced this pull request May 27, 2026
Lifts the 11 i64 comparison T2 (existence-only) theorems in
CorrectnessI64Comparisons.v to T1 (result-correspondence) using the
`i64_setcond_bits_spec` and `i64_setcondz_bits_spec` axioms shipped in
v0.9.0 PR 1 (#153).

Each theorem is restated with:
- **I64-typed hypotheses**: operands pinned via lo/hi halves in
  (R0:R1) and (R2:R3) for binops, just (R0:R1) for `i64.eqz`.
  The combined 64-bit operand is `combine_i32 lo hi`.
- **Single-register post-condition**:
    `get_reg astate' R0 = if I64.<cmp> v1 v2 then I32.one else I32.zero`
  (WASM i64 comparison returns an i32 boolean, so only R0 is pinned.)
- **No `exec_wasm_instr` hypothesis** (vacuous per PR #153's pattern —
  WasmSemantics.v does not model i64 cmps; the prior T2 theorems were
  vacuously true on a False premise).

Theorem-by-theorem dispatch (all Qed via `i64_setcond_bits_spec`,
except `i64_eqz_correct` which uses `i64_setcondz_bits_spec`):

| Theorem            | Spec axiom                  | Outcome |
|--------------------|-----------------------------|---------|
| i64_eqz_correct    | i64_setcondz_bits_spec      | Qed     |
| i64_eq_correct     | i64_setcond_bits_spec Cond_EQ | Qed   |
| i64_ne_correct     | i64_setcond_bits_spec Cond_NE | Qed   |
| i64_lts_correct    | i64_setcond_bits_spec Cond_LT | Qed   |
| i64_ltu_correct    | i64_setcond_bits_spec Cond_CC | Qed   |
| i64_gts_correct    | i64_setcond_bits_spec Cond_GT | Qed   |
| i64_gtu_correct    | i64_setcond_bits_spec Cond_HI | Qed   |
| i64_les_correct    | i64_setcond_bits_spec Cond_LE | Qed   |
| i64_leu_correct    | i64_setcond_bits_spec Cond_LS | Qed   |
| i64_ges_correct    | i64_setcond_bits_spec Cond_GE | Qed   |
| i64_geu_correct    | i64_setcond_bits_spec Cond_CS | Qed   |

Proof body uniformly:
  intros astate lo1 hi1 lo2 hi2 HR0 HR1 HR2 HR3.
  unfold compile_wasm_to_arm; simpl.
  rewrite HR0, HR1, HR2, HR3.
  rewrite i64_setcond_bits_spec; simpl.
  eexists. split; [reflexivity | apply get_set_reg_eq].

Architectural finding: the i64 flag-correspondence lemmas introduced in
#149 (`z_flag_sub_eq_i64`, `flags_ne_i64`, ..., `z_flag_sub_eqz_i64`)
and the `synth_cmp_binop_proof_i64` / `synth_cmp_unop_proof_i64` tactics
are NOT USED by this PR. Those presupposed i64 cmps would lower to a
CMP+MOV+conditional-MOV sequence (mirroring the i32 path) requiring
ARM N/Z/C/V flag bridging back to WASM cmp semantics. Under the actual
v0.8.0 codegen, i64 cmps lower to a single `I64SetCond` pseudo-op whose
semantic axiom already returns the WASM-spec result directly. The flag
lemmas remain in `ArmFlagLemmas.v` for the i32 path (which still uses
them via the i32 CMP+MOV+CMOV pattern) and for any future direct
dual-precision CMP/SBC modeling.

Bit-manipulation (clz/ctz/popcnt) and shift/rotate (shl/shru/shrs/
rotl/rotr) T2 proofs further down this file are retained unchanged —
those belong to PRs 3 and 5 of umbrella #152 (CorrectnessI64.v lanes).

No new spec axioms, no new flag lemmas, no new Admitted proofs. Net:
+11 T1 (was +11 T2), totals unchanged at 233 Qed / 10 Admitted because
the lifted theorems were already Qed under their T2 statements.

Refs: #152 (umbrella), #149 (i64 flag lemmas — unused under pseudo-op),
      #153 (precursor spec axioms — used)

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
avrabe added a commit that referenced this pull request May 27, 2026
Lifts the 5 i64 shift/rotate T2 (existence-only) theorems in
CorrectnessI64.v (Shl/ShrU/ShrS/Rotl/Rotr) to T1 (result-correspondence)
using the `i64_{shl,shru,shrs,rotl,rotr}_{lo,hi}_bits_spec` axioms
shipped in v0.9.0 PR 1 (#153).

Each theorem is restated with:
- **I64-typed hypotheses**: operand lo/hi pinned in (R0:R1), 32-bit
  shift/rotate count pinned in R2. The combined 64-bit operand is
  `combine_i32 lo1 hi1`; the second WASM operand is
  `combine_i32 cnt I32.zero` (high half is logically zero since
  WASM masks the count modulo 64, and the encoder relies on this).
- **Dual-register post-condition**:
    R0 = lo_of_i64 (I64.<op> v1 (combine_i32 cnt I32.zero))
    R1 = hi_of_i64 (I64.<op> v1 (combine_i32 cnt I32.zero))
- **No `exec_wasm_instr` hypothesis** (per PR-1/PR-2/PR-4 pattern —
  the new shape gives a direct value-level correspondence between
  the WASM-spec function and the ARM execution result without
  routing through `exec_wasm_instr`).

Theorem-by-theorem dispatch (all Qed):

| Theorem            | Spec axioms                                       | Outcome |
|--------------------|---------------------------------------------------|---------|
| i64_shl_correct    | i64_shl_lo_bits_spec  + i64_shl_hi_bits_spec      | Qed     |
| i64_shru_correct   | i64_shru_lo_bits_spec + i64_shru_hi_bits_spec     | Qed     |
| i64_shrs_correct   | i64_shrs_lo_bits_spec + i64_shrs_hi_bits_spec     | Qed     |
| i64_rotl_correct   | i64_rotl_lo_bits_spec + i64_rotl_hi_bits_spec     | Qed     |
| i64_rotr_correct   | i64_rotr_lo_bits_spec + i64_rotr_hi_bits_spec     | Qed     |

Proof body uniformly:
  intros astate lo1 hi1 cnt HR0 HR1 HR2.
  unfold compile_wasm_to_arm; simpl.
  rewrite HR0, HR1, HR2.
  rewrite <op>_lo_bits_spec, <op>_hi_bits_spec; simpl.
  eexists. split; [reflexivity | split].
  - rewrite get_set_reg_neq by discriminate. rewrite get_set_reg_eq. reflexivity.
  - rewrite get_set_reg_eq. reflexivity.

Architectural finding: `WasmSemantics.v` *does* model i64 shifts/rotates
(`I64.shl/shru/shrs/rotl/rotr` via `pop2_i64`), but the new T1 shape
still drops the `exec_wasm_instr` hypothesis — matching PR #155 (i64
comparisons), where the cmps are likewise modeled but the lifted
theorems give a direct value-level correspondence to the WASM-spec
function. This is sound because the ARM execution result is what the
WASM stack would observe; routing through `exec_wasm_instr` would only
add a redundant `pop2_i64` plumbing layer.

Net change: +5 T1 (was +5 T2), totals shift on CorrectnessI64.v:
shift/rotate goes from 0 T1 / 5 T2 to 5 T1 / 0 T2. Project-wide
Qed count unchanged at 233 (the 5 existence Qeds become 5 result-
correspondence Qeds). No new spec axioms, no new Admitted proofs.

Bazel/Nix note: full `bazel test //coq:verify_proofs` is gated on
`nix-build` which is not available on this host. The proofs follow
the exact mechanical template proven by `i64_mul_correct` and
`i64_divs_correct` et al. (which use identical
`rewrite spec; eexists; split; get_set_reg_*` discharge).
CI will verify on Linux via the Nix-provisioned Rocq toolchain.

Refs: #152 (umbrella), #153 (precursor spec axioms — used),
      #154 (v0.9.0 PR 2 arith+bitwise pattern),
      #155 (v0.9.0 PR 4 comparison pattern)

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
avrabe added a commit that referenced this pull request May 27, 2026
Lifts the 3 i64 bit-manipulation T2 (existence-only) theorems in
CorrectnessI64.v to T1 (result-correspondence) using the
i64_{clz,ctz,popcnt}_bits_spec axioms shipped in v0.9.0 PR 1 (#153).

Each theorem is restated with:
- **I64-typed hypotheses**: operand pinned via lo/hi halves in (R0:R1).
  The combined 64-bit operand is `combine_i32 lo hi`.
- **Single-register post-condition**:
    `get_reg astate' R0 = i64_to_i32 (I64.<op> (combine_i32 lo hi))`
  (clz/ctz/popcnt of an i64 fit in 32 bits, so the codegen produces
  just R0; `i64_to_i32` captures the 32-bit return convention of the
  pseudo-op).
- **No `exec_wasm_instr` hypothesis** (per the PR-1..PR-4 pattern —
  the lifted theorems give a direct value-level correspondence to the
  WASM-spec function `I64.{clz,ctz,popcnt}` without routing through
  `exec_wasm_instr`).

| Theorem               | Spec axiom              | Outcome |
|-----------------------|-------------------------|---------|
| `i64_clz_correct`     | `i64_clz_bits_spec`     | Qed     |
| `i64_ctz_correct`     | `i64_ctz_bits_spec`     | Qed     |
| `i64_popcnt_correct`  | `i64_popcnt_bits_spec`  | Qed     |

All three discharge via the mechanical
  intros; unfold compile_wasm_to_arm; simpl; rewrite Hregs;
  rewrite <op>_bits_spec; eexists; split;
  [reflexivity | apply get_set_reg_eq]
template — same shape as `i64_eqz_correct` (#155) for the
single-register unary case. No new spec axioms, no new Admitted proofs.

| Before (T2) | After (T1) |
|-------------|------------|
| 0 T1 / 3 T2 | 3 T1 / 0 T2 |

Project-wide Qed count is unchanged at 233 (the 3 existence Qeds
become 3 result-correspondence Qeds).

This PR completes the v0.9.0 lift queue for the i64 op surface. With
this and the in-flight #156 (shifts/rotates), every i64 op in
CorrectnessI64.v and CorrectnessI64Comparisons.v is now T1
result-correspondence (modulo the 5 Admitted carry-/borrow-/halves-
distribute gaps documented in PR #154, which have explicit follow-up
plans against existing infrastructure — no new axioms needed).

Full `bazel test //coq:verify_proofs` is gated on `nix-build`, which
is not available on this dev host (`nix-build not found in PATH`).
Local `rocq`/`coqc` likewise unavailable. The proofs follow the exact
mechanical template proven by `i64_eqz_correct` (#155) and the div/rem
proofs already on `main`. CI on Linux (with the Nix-provisioned Rocq
toolchain) will verify.

Refs: #152 (umbrella), #153 (precursor spec axioms — used),
      #154 (v0.9.0 PR 2 arith+bitwise pattern),
      #155 (v0.9.0 PR 4 comparison pattern — single-register unary
            template via `i64_eqz_correct`)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
avrabe added a commit that referenced this pull request May 27, 2026
)

Lifts the 3 i64 bit-manipulation T2 (existence-only) theorems in
CorrectnessI64.v to T1 (result-correspondence) using the
i64_{clz,ctz,popcnt}_bits_spec axioms shipped in v0.9.0 PR 1 (#153).

Each theorem is restated with:
- **I64-typed hypotheses**: operand pinned via lo/hi halves in (R0:R1).
  The combined 64-bit operand is `combine_i32 lo hi`.
- **Single-register post-condition**:
    `get_reg astate' R0 = i64_to_i32 (I64.<op> (combine_i32 lo hi))`
  (clz/ctz/popcnt of an i64 fit in 32 bits, so the codegen produces
  just R0; `i64_to_i32` captures the 32-bit return convention of the
  pseudo-op).
- **No `exec_wasm_instr` hypothesis** (per the PR-1..PR-4 pattern —
  the lifted theorems give a direct value-level correspondence to the
  WASM-spec function `I64.{clz,ctz,popcnt}` without routing through
  `exec_wasm_instr`).

| Theorem               | Spec axiom              | Outcome |
|-----------------------|-------------------------|---------|
| `i64_clz_correct`     | `i64_clz_bits_spec`     | Qed     |
| `i64_ctz_correct`     | `i64_ctz_bits_spec`     | Qed     |
| `i64_popcnt_correct`  | `i64_popcnt_bits_spec`  | Qed     |

All three discharge via the mechanical
  intros; unfold compile_wasm_to_arm; simpl; rewrite Hregs;
  rewrite <op>_bits_spec; eexists; split;
  [reflexivity | apply get_set_reg_eq]
template — same shape as `i64_eqz_correct` (#155) for the
single-register unary case. No new spec axioms, no new Admitted proofs.

| Before (T2) | After (T1) |
|-------------|------------|
| 0 T1 / 3 T2 | 3 T1 / 0 T2 |

Project-wide Qed count is unchanged at 233 (the 3 existence Qeds
become 3 result-correspondence Qeds).

This PR completes the v0.9.0 lift queue for the i64 op surface. With
this and the in-flight #156 (shifts/rotates), every i64 op in
CorrectnessI64.v and CorrectnessI64Comparisons.v is now T1
result-correspondence (modulo the 5 Admitted carry-/borrow-/halves-
distribute gaps documented in PR #154, which have explicit follow-up
plans against existing infrastructure — no new axioms needed).

Full `bazel test //coq:verify_proofs` is gated on `nix-build`, which
is not available on this dev host (`nix-build not found in PATH`).
Local `rocq`/`coqc` likewise unavailable. The proofs follow the exact
mechanical template proven by `i64_eqz_correct` (#155) and the div/rem
proofs already on `main`. CI on Linux (with the Nix-provisioned Rocq
toolchain) will verify.

Refs: #152 (umbrella), #153 (precursor spec axioms — used),
      #154 (v0.9.0 PR 2 arith+bitwise pattern),
      #155 (v0.9.0 PR 4 comparison pattern — single-register unary
            template via `i64_eqz_correct`)

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
avrabe added a commit that referenced this pull request May 27, 2026
Bumps workspace version 0.8.0 → 0.9.0 and sweeps the intra-workspace
path-dep version pins (per the saved v0.7.0 release-tail lesson) plus
MODULE.bazel. Promotes the [Unreleased] section to [0.9.0] with theme
re-framing and the v0.9.0 falsification statement.

Theme: v0.9.0 picks up what v0.8.0's honest-foundation release set up.
26 new _spec axioms layered on the 26 type-only axioms from v0.8.0,
then 30 T2 i64 theorems lifted to T1 + 5 v0.8.0 admits discharged.
Net: 35 new i64 T1 Qeds; 5 honest Admitted carry-overs (Add/Sub on
ADDS/ADC carry-prop; And/Or/Xor on Rocq 9 Z.mod_mod halves-distribute).

PRs included:
  #153 feat(coq): i64 pseudo-op result-correspondence axioms + discharge 5 v0.8.0 admits
  #154 feat(coq): i64 arithmetic + bitwise T1 lifts
  #155 feat(coq): i64 comparison T1 lifts
  #156 feat(coq): i64 shifts + rotates T1 lifts
  #157 feat(coq): i64 bit-manip T1 lifts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant