Download backend/wasm/Wasm/SimExec.lean from Snapkitty/ai-free: direct link, hf CLI and curl.
- Browser
- Download file 16.3 kB
-
https://huggingface.co/Snapkitty/ai-free/resolve/main/backend/wasm/Wasm/SimExec.lean
- Command line
-
hf download hf://Snapkitty/ai-free/backend/wasm/Wasm/SimExec.lean
-
curl -L -o SimExec.lean https://huggingface.co/Snapkitty/ai-free/resolve/main/backend/wasm/Wasm/SimExec.lean
16.3 kB
| import Wasm.SimAux | |
| /-! | |
| # Wasm.SimExec | |
| One IR step is simulated by the function the lowering emits for the instruction, for every | |
| instruction and every outcome (`next`, `halted`, `trapped`). This is the case analysis over the | |
| whole instruction set that the dispatch-loop theorem (`Wasm.Correct`) iterates. | |
| Trap codes (the argument of `proc_exit`): 1 `stackUnderflow`, 2 `badAddress`, 3 `divideByZero`, | |
| 4 `badPc`, 5 `returnUnderflow` (an empty return stack on `ret`, or an empty auxiliary stack on | |
| `fromr`/`rfetch`). | |
| Every instruction that grows a stack first checks for room, and exits with code 6 when the stack | |
| is full. So `sim_step` has no capacity hypothesis: the code either simulates the IR step, or the | |
| stack lacks the headroom `Fits` describes and the code exits 6. Code 6 has no IR counterpart (IR | |
| stacks are unbounded); it reports that the run exceeded the target's capacity. | |
| -/ | |
| namespace WordDialect | |
| namespace Wasm | |
| def trapCode : Trap → Nat | |
| | .stackUnderflow => 1 | |
| | .badAddress => 2 | |
| | .divideByZero => 3 | |
| | .badPc => 4 | |
| | .returnUnderflow => 5 | |
| /-- Headroom for one step: room to push one data word, one return index and one auxiliary word. | |
| With this headroom no overflow guard fires. -/ | |
| def Fits (c : Cfg) (s : State 64) : Prop := | |
| c.dBase + 8 * (s.dstack.length + 1) ≤ c.dEnd ∧ c.rBase + 8 * (s.rstack.length + 1) ≤ c.rEnd ∧ | |
| c.aBase + 8 * (s.astack.length + 1) ≤ c.aEnd | |
| /-- What simulating one IR outcome means for the body of one dispatched function. On `next`, the | |
| function returns the (clamped) next IR index, and every return index stays within the program. -/ | |
| def StepSim (c : Cfg) (fs : Funcs) (n : Nat) (body : List WI) (w : WState) : Outcome 64 → Prop | |
| | .next s' => (∀ a ∈ s'.rstack, a ≤ n) ∧ | |
| ∃ w', Run fs body w (.normal w') ∧ Rel0 c s' w' ∧ w'.stack = [.i32 (ofN (min s'.pc n))] | |
| | .halted s' => ∃ w', Run fs body w (.halted w') ∧ Rel0 c s' w' | |
| | .trapped t => Run fs body w (.exit (trapCode t)) | |
| section Step | |
| variable {c : Cfg} {s : State 64} {w : WState} {fs : Funcs} {n : Nat} | |
| theorem Rel0.setPc (h : Rel0 c s w) (q : Nat) : Rel0 c { s with pc := q } w := | |
| { sp := h.sp, rp := h.rp, stack := h.stack, regs := h.regs, mem := h.mem, rs := h.rs, | |
| irvalid := h.irvalid, size := h.size, capD := h.capD, capR := h.capR, ap := h.ap, aux := h.aux, | |
| capA := h.capA } | |
| theorem next_sim {body : List WI} {s1 : State 64} {q : Nat} (hrs : ∀ a ∈ s1.rstack, a ≤ n) | |
| (h : Sim1 c fs body s1 w (min q n)) : StepSim c fs n body w (.next { s1 with pc := q }) := by | |
| obtain ⟨w', hr, h0, hst⟩ := h | |
| exact ⟨hrs, w', hr, h0.setPc q, hst⟩ | |
| theorem fall_sim {body : List WI} {d : List W} (hlt : s.pc < n) (hrs : ∀ a ∈ s.rstack, a ≤ n) | |
| (h : Sim1 c fs body { s with dstack := d } w (s.pc + 1)) : StepSim c fs n body w (s.fall d) := by | |
| rw [← Nat.min_eq_left (show s.pc + 1 ≤ n by omega)] at h | |
| exact next_sim (s1 := { s with dstack := d }) hrs h | |
| theorem shape1 {l : List W} (h : 1 ≤ l.length) : ∃ a d, l = a :: d := by | |
| cases l with | |
| | nil => simp at h | |
| | cons a d => exact ⟨a, d, rfl⟩ | |
| theorem shape2 {l : List W} (h : 2 ≤ l.length) : ∃ b a d, l = b :: a :: d := by | |
| rcases l with _ | ⟨b, _ | ⟨a, d⟩⟩ | |
| · simp at h | |
| · simp at h | |
| · exact ⟨b, a, d, rfl⟩ | |
| theorem shape3 {l : List W} (h : 3 ≤ l.length) : ∃ x y z d, l = x :: y :: z :: d := by | |
| rcases l with _ | ⟨x, _ | ⟨y, _ | ⟨z, d⟩⟩⟩ | |
| · simp at h | |
| · simp at h | |
| · simp at h | |
| · exact ⟨x, y, z, d, rfl⟩ | |
| /-- Every instruction that pops operands starts with the operand-count guard. -/ | |
| theorem lowerInstr_uf (L : Layout) (n k : Nat) (i : WordDialect.Instr 64) (h : 0 < i.pops) : | |
| ∃ rest, lowerInstr L n k i = uf L i.pops ++ rest ∧ i.pops ≤ 3 := by | |
| cases i <;> simp only [Instr.pops] at h ⊢ <;> | |
| first | |
| | exact absurd h (by decide) | |
| | exact ⟨_, by simp only [lowerInstr, binOp, shiftOp, List.append_assoc]; rfl, by decide⟩ | |
| theorem sim_step (hg : Geom c) (hs : Rel0 c s w) (hst : w.stack = []) | |
| {p : Prog 64} (hn : p.length < 2 ^ 32) (hrs : ∀ a ∈ s.rstack, a ≤ p.length) | |
| {i : WordDialect.Instr 64} (hi : p[s.pc]? = some i) | |
| (hreg : ∀ r, (i = .push r ∨ i = .pop r) → r < c.nregs) : | |
| StepSim c fs p.length (lowerInstr c.layout p.length s.pc i) w (exec i s) ∨ | |
| (¬ Fits c s ∧ Run fs (lowerInstr c.layout p.length s.pc i) w (.exit 6)) := by | |
| have nfD : ¬ c.dBase + 8 * (s.dstack.length + 1) ≤ c.dEnd → ¬ Fits c s := fun h hf => h hf.1 | |
| have nfR : ¬ c.rBase + 8 * (s.rstack.length + 1) ≤ c.rEnd → ¬ Fits c s := fun h hf => h hf.2.1 | |
| have nfA : ¬ c.aBase + 8 * (s.astack.length + 1) ≤ c.aEnd → ¬ Fits c s := fun h hf => h hf.2.2 | |
| have hlt : s.pc < p.length := by | |
| by_cases h : s.pc < p.length | |
| · exact h | |
| · rw [List.getElem?_eq_none (by omega)] at hi; simp at hi | |
| by_cases hk : s.dstack.length < i.pops | |
| · rw [exec_underflow i s hk] | |
| obtain ⟨rest, hlow, h3⟩ := lowerInstr_uf c.layout p.length s.pc i (by omega) | |
| rw [hlow] | |
| exact .inl <| run_append_abrupt _ (uf_trap hg hs (by omega) h3 hk) trivial | |
| have hk' : i.pops ≤ s.dstack.length := by omega | |
| cases i with | |
| | word v => | |
| by_cases hf : c.dBase + 8 * (s.dstack.length + 1) ≤ c.dEnd | |
| · exact .inl <| fall_sim hlt hrs (sim_word _ _ hg hs hst v hf) | |
| · exact .inr ⟨nfD hf, sim_word_ovf _ _ hg hs v hf⟩ | |
| | ptr q => | |
| by_cases hf : c.dBase + 8 * (s.dstack.length + 1) ≤ c.dEnd | |
| · exact .inl <| fall_sim hlt hrs (sim_ptr _ _ hg hs hst q hf) | |
| · exact .inr ⟨nfD hf, sim_ptr_ovf _ _ hg hs q hf⟩ | |
| | load => | |
| obtain ⟨a, d, hd⟩ := shape1 (by simpa [Instr.pops] using hk') | |
| by_cases ha : a.toNat < c.M | |
| · have hv : s.mem.valid a = true := (valid_iff hs a).mpr ha | |
| have hex : exec .load s = s.fall (s.mem.cell a :: d) := by | |
| simp [exec, hd, Memory.read?, hv] | |
| rw [hex] | |
| exact .inl <| fall_sim hlt hrs (sim_load _ _ hg hs hst hd ha) | |
| · have hv : s.mem.valid a = false := by | |
| cases h : s.mem.valid a | |
| · rfl | |
| · exact absurd ((valid_iff hs a).mp h) ha | |
| have hex : exec .load s = .trapped .badAddress := by | |
| simp [exec, hd, Memory.read?, hv] | |
| rw [hex] | |
| exact .inl <| sim_load_trap _ _ hg hs hd (by omega) | |
| | store => | |
| obtain ⟨a, v, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| cases hw : s.mem.write? a v with | |
| | none => | |
| have hv : s.mem.valid a = false := (Memory.write?_none_iff s.mem a v).mp hw | |
| have ha : ¬ a.toNat < c.M := fun h => by rw [(valid_iff hs a).mpr h] at hv; simp at hv | |
| have hex : exec .store s = .trapped .badAddress := by simp [exec, hd, hw] | |
| rw [hex] | |
| exact .inl <| sim_store_trap _ _ hg hs hd (by omega) | |
| | some im => | |
| have hex : exec .store s = .next { { s with dstack := d, mem := im } with pc := s.pc + 1 } := by | |
| simp [exec, hd, hw] | |
| rw [hex] | |
| have h := sim_store (fs := fs) p.length s.pc hg hs hst hd hw | |
| rw [← Nat.min_eq_left (show s.pc + 1 ≤ p.length by omega)] at h | |
| exact .inl <| next_sim hrs h | |
| | add => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| rw [show exec .add s = s.fall ((a + b) :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_add _ _ hg hs hst hd) | |
| | sub => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| rw [show exec .sub s = s.fall ((a - b) :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_sub _ _ hg hs hst hd) | |
| | mul => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| rw [show exec .mul s = s.fall ((a * b) :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_mul _ _ hg hs hst hd) | |
| | div => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| by_cases hb : b = 0#64 | |
| · subst hb | |
| rw [show exec .div s = .trapped .divideByZero by simp [exec, hd]] | |
| exact .inl <| sim_div_trap _ _ hg hs hd | |
| · rw [show exec .div s = s.fall (a.udiv b :: d) by simp [exec, hd, hb]] | |
| exact .inl <| fall_sim hlt hrs (sim_div _ _ hg hs hst hd hb) | |
| | sdiv => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| by_cases hb : b = 0#64 | |
| · subst hb | |
| rw [show exec .sdiv s = .trapped .divideByZero by simp [exec, hd]] | |
| exact .inl <| sim_sdiv_trap _ _ hg hs hd | |
| · rw [show exec .sdiv s = s.fall (a.sdiv b :: d) by simp [exec, hd, hb]] | |
| exact .inl <| fall_sim hlt hrs (sim_sdiv _ _ hg hs hst hd hb) | |
| | and => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| rw [show exec .and s = s.fall ((a &&& b) :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_and _ _ hg hs hst hd) | |
| | or => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| rw [show exec .or s = s.fall ((a ||| b) :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_or _ _ hg hs hst hd) | |
| | xor => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| rw [show exec .xor s = s.fall ((a ^^^ b) :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_xor _ _ hg hs hst hd) | |
| | not => | |
| obtain ⟨a, d, hd⟩ := shape1 (by simpa [Instr.pops] using hk') | |
| rw [show exec .not s = s.fall ((~~~a) :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_not _ _ hg hs hst hd) | |
| | shl => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| rw [show exec .shl s = s.fall (Word.shl a b :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_shl _ _ hg hs hst hd) | |
| | shr => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| rw [show exec .shr s = s.fall (Word.shr a b :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_shr _ _ hg hs hst hd) | |
| | rotl => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| rw [show exec .rotl s = s.fall (Word.rotl a b :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_rotl _ _ hg hs hst hd) | |
| | rotr => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| rw [show exec .rotr s = s.fall (Word.rotr a b :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_rotr _ _ hg hs hst hd) | |
| | cmp cd => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| rw [show exec (.cmp cd) s = s.fall (Word.ofBool (cd.eval a b) :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_cmp _ _ cd hg hs hst hd) | |
| | select => | |
| obtain ⟨cc, y, x, d, hd⟩ := shape3 (by simpa [Instr.pops] using hk') | |
| rw [show exec .select s = s.fall ((if Word.isTrue cc then x else y) :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_select _ _ hg hs hst hd) | |
| | jmp t => | |
| rw [show exec (.jmp t) s = .next { s with pc := t } by simp [exec]] | |
| exact .inl <| next_sim hrs (sim_jmp _ _ t hs hst) | |
| | branch t => | |
| obtain ⟨cv, d, hd⟩ := shape1 (by simpa [Instr.pops] using hk') | |
| have h := sim_branch (fs := fs) p.length s.pc t hg hs hst hd | |
| by_cases hc : Word.isTrue cv = true | |
| · rw [show exec (.branch t) s = .next { { s with dstack := d } with pc := t } by simp [exec, hd, hc]] | |
| simp only [hc, ↓reduceIte] at h | |
| exact .inl <| next_sim hrs h | |
| · rw [show exec (.branch t) s = s.fall d by simp [exec, hd, hc]] | |
| have hc' : Word.isTrue cv = false := by simpa using hc | |
| simp only [hc', Bool.false_eq_true, ↓reduceIte] at h | |
| exact .inl <| fall_sim hlt hrs h | |
| | call t => | |
| rw [show exec (.call t) s = .next { { s with rstack := (s.pc + 1) :: s.rstack } with pc := t } by simp [exec]] | |
| by_cases hf : c.rBase + 8 * (s.rstack.length + 1) ≤ c.rEnd | |
| · refine .inl (next_sim ?_ (sim_call _ _ t hg hs hst hf)) | |
| intro a ha | |
| simp only [List.mem_cons] at ha | |
| rcases ha with ha | ha | |
| · omega | |
| · exact hrs a ha | |
| · exact .inr ⟨nfR hf, sim_call_ovf _ _ t hg hs hf⟩ | |
| | ret => | |
| cases hr : s.rstack with | |
| | nil => | |
| rw [show exec .ret s = .trapped .returnUnderflow by simp [exec, hr]] | |
| exact .inl <| sim_ret_trap _ _ hs hst hr | |
| | cons a rs => | |
| rw [show exec .ret s = .next { { s with rstack := rs } with pc := a } by simp [exec, hr]] | |
| have ha : a ≤ p.length := hrs a (by simp [hr]) | |
| have h := sim_ret (fs := fs) p.length s.pc hg hs hst hr (by omega) | |
| rw [← Nat.min_eq_left ha] at h | |
| exact .inl <| next_sim (fun b hb => hrs b (by simp [hr, hb])) h | |
| | push r => | |
| rw [show exec (.push r) s = s.fall (s.regs r :: s.dstack) by simp [exec]] | |
| by_cases hf : c.dBase + 8 * (s.dstack.length + 1) ≤ c.dEnd | |
| · exact .inl <| fall_sim hlt hrs (sim_push _ _ hg hs hst (hreg r (.inl rfl)) hf) | |
| · exact .inr ⟨nfD hf, sim_push_ovf _ _ hg hs r hf⟩ | |
| | pop r => | |
| obtain ⟨a, d, hd⟩ := shape1 (by simpa [Instr.pops] using hk') | |
| rw [show exec (.pop r) s = | |
| .next { { s with dstack := d, regs := State.setReg s.regs r a } with pc := s.pc + 1 } by | |
| simp [exec, hd]] | |
| have h := sim_pop (fs := fs) p.length s.pc hg hs hst (hreg r (.inr rfl)) hd | |
| rw [← Nat.min_eq_left (show s.pc + 1 ≤ p.length by omega)] at h | |
| exact .inl <| next_sim hrs h | |
| | dup => | |
| obtain ⟨a, d, hd⟩ := shape1 (by simpa [Instr.pops] using hk') | |
| rw [show exec .dup s = s.fall (a :: a :: d) by simp [exec, hd]] | |
| by_cases hf : c.dBase + 8 * (s.dstack.length + 1) ≤ c.dEnd | |
| · exact .inl <| fall_sim hlt hrs (sim_dup _ _ hg hs hst hd hf) | |
| · exact .inr ⟨nfD hf, sim_dup_ovf _ _ hg hs hd hf⟩ | |
| | drop => | |
| obtain ⟨a, d, hd⟩ := shape1 (by simpa [Instr.pops] using hk') | |
| rw [show exec .drop s = s.fall d by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_drop _ _ hg hs hst hd) | |
| | swap => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| rw [show exec .swap s = s.fall (a :: b :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_swap _ _ hg hs hst hd) | |
| | over => | |
| obtain ⟨b, a, d, hd⟩ := shape2 (by simpa [Instr.pops] using hk') | |
| rw [show exec .over s = s.fall (a :: b :: a :: d) by simp [exec, hd]] | |
| by_cases hf : c.dBase + 8 * (s.dstack.length + 1) ≤ c.dEnd | |
| · exact .inl <| fall_sim hlt hrs (sim_over _ _ hg hs hst hd hf) | |
| · exact .inr ⟨nfD hf, sim_over_ovf _ _ hg hs hd hf⟩ | |
| | rot => | |
| obtain ⟨x, y, z, d, hd⟩ := shape3 (by simpa [Instr.pops] using hk') | |
| rw [show exec .rot s = s.fall (z :: x :: y :: d) by simp [exec, hd]] | |
| exact .inl <| fall_sim hlt hrs (sim_rot _ _ hg hs hst hd) | |
| | tor => | |
| obtain ⟨a, d, hd⟩ := shape1 (by simpa [Instr.pops] using hk') | |
| rw [show exec .tor s = .next { { s with dstack := d, astack := a :: s.astack } with pc := s.pc + 1 } by | |
| simp [exec, hd]] | |
| by_cases hf : c.aBase + 8 * (s.astack.length + 1) ≤ c.aEnd | |
| · have h := sim_tor (fs := fs) p.length s.pc hg hs hst hd hf | |
| rw [← Nat.min_eq_left (show s.pc + 1 ≤ p.length by omega)] at h | |
| exact .inl <| next_sim hrs h | |
| · exact .inr ⟨nfA hf, sim_tor_ovf _ _ hg hs hd hf⟩ | |
| | fromr => | |
| cases ha : s.astack with | |
| | nil => | |
| rw [show exec .fromr s = .trapped .returnUnderflow by simp [exec, ha]] | |
| exact .inl <| sim_fromr_trap _ _ hs ha | |
| | cons a as => | |
| rw [show exec .fromr s = | |
| .next { { s with dstack := a :: s.dstack, astack := as } with pc := s.pc + 1 } by | |
| simp [exec, ha]] | |
| by_cases hf : c.dBase + 8 * (s.dstack.length + 1) ≤ c.dEnd | |
| · have h := sim_fromr (fs := fs) p.length s.pc hg hs hst ha hf | |
| rw [← Nat.min_eq_left (show s.pc + 1 ≤ p.length by omega)] at h | |
| exact .inl <| next_sim hrs h | |
| · exact .inr ⟨nfD hf, sim_fromr_ovf _ _ hg hs ha hf⟩ | |
| | rfetch => | |
| cases ha : s.astack with | |
| | nil => | |
| rw [show exec .rfetch s = .trapped .returnUnderflow by simp [exec, ha]] | |
| exact .inl <| sim_rfetch_trap _ _ hs ha | |
| | cons a as => | |
| rw [show exec .rfetch s = s.fall (a :: s.dstack) by simp [exec, ha]] | |
| by_cases hf : c.dBase + 8 * (s.dstack.length + 1) ≤ c.dEnd | |
| · exact .inl <| fall_sim hlt hrs (sim_rfetch _ _ hg hs hst ha hf) | |
| · exact .inr ⟨nfD hf, sim_rfetch_ovf _ _ hg hs ha hf⟩ | |
| | halt => | |
| rw [show exec .halt s = .halted s by simp [exec]] | |
| exact .inl <| ⟨w, sim_halt _ _, hs⟩ | |
| end Step | |
| end Wasm | |
| end WordDialect | |