Skip to content

processor: the Kami word instance is coqutil's Naive.word (stacked on #562) - #563

Draft
JasonGross wants to merge 11 commits into
mit-plv:masterfrom
JasonGross:fable/kami-naive-unify
Draft

JasonGross wants to merge 11 commits into
mit-plv:masterfrom
JasonGross:fable/kami-naive-unify

Conversation

@JasonGross

Copy link
Copy Markdown
Contributor

Stacked on #562 (which is stacked on #561); this branch contains their commits, and the new part is the last commit, d7805a7.

Follow-up to a review question on mit-plv/coqutil#186: with Kami's word now stdlib bits, the Kami-side word instance in processor/src/processor/KamiWord.v and coqutil's Naive.word agree on all 26 fields at widths 32 and 8 (division by zero, signed overflow, shift amounts at or above the width, sextend, the mulh* family, comparisons), as lemmas. So the hand-written instance is replaced by Naive.word field for field (the rep is still spelled as Kami's nat-indexed type, because a bare alias breaks Word.word ?sz unification at every Kami use site), word 32 = Naive.word 32 holds by reflexivity, word.ok comes from Naive.ok, and end2end/src/end2end/KamiRiscvWordProperties.v is deleted: word.riscv_ok now comes from the compiler's NaiveRiscvWordProperties.v. kunsigned is Zmod.unsigned; proofs that used to cbv through the instance rewrite with a few spelling lemmas instead. No theorem statement changes; Print Assumptions end2end_lightbulb is byte-identical (the same 8 axioms).

On the reviewer's question whether Naive's adjust_too_big_shift_amount is still needed: it is, but not for the lightbulb proof specifically. An unadjusted Naive.word violates riscv_ok's slu_ignores_hibits (counterexample at y = 1, z = 32, proved in the analysis), so the adjustment is what makes Naive.word satisfy the RISC-V shift convention for the compiler theorem. Before this change the lightbulb proof used the Kami-side instance's own mod width masking; after it, it relies on Naive's adjustment like every other Naive user.

make all passes in 9m21s (KamiRiscvStep.v 7m52s, faster than before the Kami port). Depends on mit-plv/kami#51 and #562.

Written by Claude Fable 5.1.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YJbiRBkJtM7x6PvYV6hmEm

@andres-erbsen

Copy link
Copy Markdown
Contributor

Please include this same in the same multi-repo PR set as removing the Word interface in favor of direct use of stdlib bits.

@JasonGross

Copy link
Copy Markdown
Contributor Author

Will do: the unification lands inside the word-removal set (the processor width is a concrete 32, so Kami's word 32 is convertible to bits 32 and this file's instance disappears with the interface); the plan is summarized on mit-plv/coqutil#186. This PR stays as is until that set replaces it.


Written by Claude Fable 5.1 via Claude Code (session https://claude.ai/code/session_01YJbiRBkJtM7x6PvYV6hmEm).

JasonGross and others added 11 commits September 15, 2026 07:38
deps/kami moves to the fable/word-on-bits branch (aff07cc), where
Kami.Lib.Word.word n is the standard library's bits (Z.of_nat n) and every
word operation is a simpl never wrapper specified through Zmod.unsigned.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJbiRBkJtM7x6PvYV6hmEm
Kami's word is no longer inductive, so the bridge no longer needs its own
induction and bit-blasting proofs: one lemma, Z.of_N (wordToN w) =
Zmod.unsigned w, carries every Kami unsigned_* fact onto the goals the
word.ok instance produces, and the file shrinks from 598 to 332 lines.

The instance itself is unchanged: rep, unsigned, signed, of_Z and all the
operations are the same Kami functions as before, so kunsigned, kofZ and
kword keep their spellings for the rest of processor/ and end2end/.

One thing to know when reading the ok proof: Zmod.unsigned's modulus is an
implicit argument that mentions 2 ^ Z.of_nat (Z.to_nat width), so rewriting
2 ^ Z.of_nat sz into 2 ^ width would be ill-typed; the proof only ever
rewrites the other way.

Ten helper lemmas that nothing outside this file referenced were dropped
rather than re-proved. No kept statement changed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJbiRBkJtM7x6PvYV6hmEm
uwordToZ is Zmod.unsigned now rather than Z.of_N (wordToN _), so the six
places that relied on it being kunsigned by conversion go through the new
KamiWord.uwordToZ_kunsigned instead.

word is not an inductive type, so injection on an equality of words takes the
Zmod record apart; riscvMemInit's NoDup proof projects out of the option with
f_equal instead. kami_evalSignExtendTrunc's zero-width case and the three
shift lemmas are re-proved at the unsigned interface.

End2EndPipeline.v needed two changes, both because reduction and lia now
behave differently under the Zmod-based word. Its base case used a bare cbv,
which reduces through Zmod.of_Z and duplicates subterms at every nesting
level; it is now a restricted cbn. And one arithmetic goal deep inside the
end2end proof took 140 s and built a certificate deep enough to overflow the
kernel stack at Qed, because Kami's Word.v registers ZifyNat and ZifyN
globally and lia then translates every nat and N hypothesis in a very large
context; it is now discharged by imem_heap_stack_lengths, the same goal stated
on its own, where lia takes two seconds. The file went from a stack overflow
to 28 s.

All theorem statements are unchanged; imem_heap_stack_lengths is new.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJbiRBkJtM7x6PvYV6hmEm
… 34 s)

`prove_states_related`'s pc branch is

    try (eapply pc_related_plus4; try eassumption; red; eauto; fail)

Over the 39 goals at one call site, the 37 eapply's that SUCCEED cost
0.000 s each; the 2 that fail cost 145.7 s and 13.0 s.  Plain eapply
unifies the goal against `pc_related_and_valid (?kpc ^+ $4) (word.add
?rpc (word.of_Z 4))`, so on a goal without that shape it descends into
the Zmod-based word operations and their proof field before concluding
"no".  `simple eapply` restricts unification, keeps the identical 37
success / 2 failure split, and fails instantly.

Measured on KamiRiscvStep.v with `rocq c -time`, cold:

                                    baseline   after port   now
  prove_states_related, all sites      8.4 s       1307 s    13 s
  sum of all command times             455 s       1842 s   513 s
  wall clock                        8m18s        27m27s     8m34s

It is NOT the `cbv [RegsToT pRegsToT]; kregmap_red; exact eq_refl`
branch: that costs 6 s across all 39 goals.  Kernel conversion over Zmod
records is cheap because it evaluates with sharing; the `of_Z`
duplication hazard only bites simpl/cbn/cbv, which rebuild terms.

KamiRiscvStep.v keeps its `From Stdlib Require Import Zmod.`: Kami.Lib.Word
does not re-export the Zmod prefix and this file uses
Zmod.unsigned/Zmod.signed in 9 places.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJbiRBkJtM7x6PvYV6hmEm
Kami's Lt/Slt now evaluate to Z.ltb on uwordToZ/wordToZ, so the word
instance's ltu/lts are spelled the same way, is_mmio_spec and the eight
branch cases decide the test from the riscv-side comparison fact, and
the deleted Kami lemma unsigned_inj is Zmod.unsigned_inj.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJbiRBkJtM7x6PvYV6hmEm
The word instance's fields are Zmod.add, Zmod.sub, ... directly (Kami's
names are notations for them now), kofZ and ksigned are eta-expanded
since ZToWord sz z is a notation, and the Kami lemmas that were stdlib
lemmas (wplus_comm, wplus_assoc, ZToWord_wordToZ, unsigned_ZToWord,
unsigned_wplus, weqb_true_iff, ...) are named by their Zmod.* / bits.*
names; KamiWord.v's own wnot_idempotent and ZToWord_zero were
bits.not_not and Zmod.of_Z_0.

KamiRiscvStep.v declares #[local] Arguments Z.pow / Z.of_nat : simpl
never so that its simpl/cbn calls keep the modulus 2 ^ Z.of_nat sz that
every Kami lemma is keyed on (they unfold the riscv and Kami evaluation
functions, not these two constants); with that, one hypothesis that
simpl used to close now survives and shifts the auto-generated names, so
the ten AddrAligned sites rewrite by the shape of the remu equation
instead of by name.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJbiRBkJtM7x6PvYV6hmEm
wrshifta is Zmod.srs, so wrshifta_ZToWord goes through Z.shiftr_div_pow2
instead of reflexivity; wordToZ_inj is Zmod.signed_inj; the shifts are
Zmod.slu/sru/srs at Z.of_nat n, one application deeper for f_equal in
kami_word_riscv_ok.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJbiRBkJtM7x6PvYV6hmEm
…are gone

wordToZ, uwordToZ, weqb, wzero, wnot, ZToWord, wlshift, wrshift and
wrshifta are Zmod.signed, Zmod.unsigned, Zmod.eqb, Zmod.zero, Zmod.not,
bits.of_Z (Z.of_nat sz), Zmod.slu, Zmod.sru and Zmod.srs (the shifts at
Z.of_nat n); End2EndPipeline.v imports Zmod for the name.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJbiRBkJtM7x6PvYV6hmEm
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJbiRBkJtM7x6PvYV6hmEm
KamiWord.word is now Naive.word with its rep spelled as Kami's nat-indexed
word type, so that Kami's API still unifies against it; KamiWord.word 32 =
Naive.word 32 holds by reflexivity. The hand-written instance, its word.ok
proof and end2end/KamiRiscvWordProperties.v are gone; the lightbulb proof
takes riscv_ok from the compiler's NaiveRiscvWordProperties.

kunsigned is now Zmod.unsigned (word.unsigned by conversion). Consistency.v
gains spelling lemmas (kunsigned_eq, kadd_eq, kofZ_eq, ...) and KamiWord.v
gains kunsigned_wordToN, ltu_eq and lts_eq; the processor proofs rewrite
with these where they used to cbv through the instance.

Print Assumptions end2end_lightbulb is unchanged: the same 8 axioms and the
same output.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJbiRBkJtM7x6PvYV6hmEm
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.

2 participants