@@ -11,7 +11,9 @@ Every memory example in `interpreter/.../Examples/` is a concrete
1111downstream of the interpreter. This file closes that gap with the first proof
1212that a **loop** establishes a property of a **whole memory region for all `n`** :
1313the canonical fill loop writes `v` to each of the `n` `u64` slots of
14- `[base, base + 8n)`, and afterwards `mem.words64 base n = replicate n v`.
14+ `[base, base + 8n)`, and afterwards `mem.words64 base n = replicate n v` while
15+ every byte *outside* `[base, base + 8n)` is left untouched (the frame
16+ condition, so the theorem composes with facts about neighbouring memory).
1517
1618It exercises the invariant/variant loop rule (`wp_loop_cons`), the `MemRegion`
1719framing algebra, and the `words64` view together — the exact shape a
@@ -40,14 +42,16 @@ set_option maxHeartbeats 1000000 in
4042/-- Running `FillWords` on a store whose memory is large enough to hold the
4143array (and within the wasm32 page cap, so element addresses do not wrap)
4244terminates with `[base, base + 8n)` filled with `v` — stated over the whole
43- region via `Mem.words64`. -/
45+ region via `Mem.words64` — and every byte outside the region left unchanged . -/
4446theorem fillWords_spec (m : Module) (st : Store Unit) (base n : UInt32) (v : UInt64)
4547 (hbnd : base.toNat + 8 * n.toNat ≤ st.mem.pages * 65536 )
4648 (hpages : st.mem.pages ≤ 65536 ) :
4749 wp m FillWords
4850 (fun c => ∃ st' s', c = .Fallthrough st' s'
4951 ∧ st'.mem.words64 base n.toNat = List.replicate n.toNat v
50- ∧ st'.mem.pages = st.mem.pages)
52+ ∧ st'.mem.pages = st.mem.pages
53+ ∧ ∀ a : Nat, (a < base.toNat ∨ base.toNat + 8 * n.toNat ≤ a) →
54+ st'.mem.bytes a = st.mem.bytes a)
5155 st { params := [.i32 base, .i32 n, .i64 v], locals := [.i32 0 ], values := [] } := by
5256 have hcap : st.mem.pages * 65536 ≤ 4294967296 := by
5357 have := Nat.mul_le_mul_right 65536 hpages; omega
@@ -59,12 +63,14 @@ theorem fillWords_spec (m : Module) (st : Store Unit) (base n : UInt32) (v : UIn
5963 s' = ⟨[.i32 base, .i32 n, .i64 v], [.i32 i], []⟩
6064 ∧ i.toNat ≤ n.toNat
6165 ∧ st'.mem.words64 base i.toNat = List.replicate i.toNat v
62- ∧ st'.mem.pages = st.mem.pages)
66+ ∧ st'.mem.pages = st.mem.pages
67+ ∧ ∀ a : Nat, (a < base.toNat ∨ base.toNat + 8 * n.toNat ≤ a) →
68+ st'.mem.bytes a = st.mem.bytes a)
6369 (μ := fun _ s' => match s'.locals.headD (.i32 0 ) with | .i32 i => n.toNat - i.toNat | _ => 0 )
64- · -- initial: i = 0, region empty
65- exact ⟨0 , rfl, by simp, by simp [Mem.words64], rfl⟩
70+ · -- initial: i = 0, region empty, memory untouched
71+ exact ⟨0 , rfl, by simp, by simp [Mem.words64], rfl, fun a _ => rfl ⟩
6672 · -- step
67- rintro st' s' ⟨i, rfl, hile, hfill, hpg⟩
73+ rintro st' s' ⟨i, rfl, hile, hfill, hpg, hframe ⟩
6874 apply wp_block_cons
6975 apply wp_block_cons
7076 wp_run
@@ -76,19 +82,29 @@ theorem fillWords_spec (m : Module) (st : Store Unit) (base n : UInt32) (v : UIn
7682 have hmod1 : (1 + i.toNat) % 4294967296 = i.toNat + 1 := by
7783 rw [Nat.mod_eq_of_lt (by have := n.toNat_lt; omega)]; omega
7884 have hshlN : i.toNat <<< 3 = i.toNat * 8 := by rw [Nat.shiftLeft_eq]
79- have hshlU : i <<< 3 = 8 * i := by bv_decide
85+ -- The `(const 3) shl` address computation is the `MemRegion` slot bridge.
86+ have hshlU : i <<< 3 = 8 * i := MemRegion.shl3_eq_mul8 i
87+ have haddrU : i <<< 3 + base = base + 8 * UInt32.ofNat i.toNat := by
88+ rw [hshlU, hoi]; bv_decide
89+ have haddrN : (i <<< 3 + base).toNat = base.toNat + 8 * i.toNat := by
90+ rw [haddrU]; exact Mem.words64_slotAddr_toNat base i.toNat (by omega)
8091 simp only [hlt, ↓reduceIte, hshlN, hmod1]
81- refine ⟨?_, ⟨?_, ?_, hpg⟩, ?_⟩
92+ refine ⟨?_, ⟨?_, ?_, hpg, ?_ ⟩, ?_⟩
8293 · rw [Nat.mod_eq_of_lt (by omega)]; omega
8394 · omega
84- · rw [hshlU, show 8 * i + base = base + 8 * UInt32.ofNat i.toNat by rw [hoi]; bv_decide ]
95+ · rw [haddrU ]
8596 exact Mem.words64_write64_extend st'.mem base i.toNat v (by omega) hfill
97+ · -- frame: the write lands in `[base, base+8n)`, so bytes outside are kept
98+ intro a ha
99+ rw [Mem.write64_bytes_of_disjoint st'.mem (i <<< 3 + base) v a (by rw [haddrN]; omega)]
100+ exact hframe a ha
86101 · omega
87102 · -- exit: i ≥ n, so i = n; region already fully filled
88103 have hin : i.toNat = n.toNat := by
89104 have : ¬ i.toNat < n.toNat := hlt
90105 omega
91106 simp only [hlt, ↓reduceIte]
92- rw [← hin]; exact ⟨hfill, hpg⟩
107+ refine ⟨?_, hpg, hframe⟩
108+ rw [← hin]; exact hfill
93109
94110end Wasm
0 commit comments