~james/remy

feat(compiler): prove exact peak stack demand

commit
72b2edbe209a48353896277c3695fd72e27facac browse tree
parent
a08d052613b63f659b70120516674bcf96f4684d
author
james <j@cpl0.zip>
signature
Verified ~james signed with a key registered by ~james
date
2026-09-13 11:00 UTC

3 files changed, +38 −2

src/Compiler.thy modified

@@ -179,6 +179,37 @@ next
179179 then show ?case by (simp add: check_append list_all_iff)
180180 qed
181181
182+theorem compiled_demand:
183+ assumes "scoped (length slots) e" "list_all (\<lambda>i. i < n) slots"
184+ shows "bounded limit (compile e slots) n \<longleftrightarrow> n + demand e \<le> limit"
185+ using assms
186+proof (induction e arbitrary: slots n)
187+ case (Literal v)
188+ then show ?case by auto
189+next
190+ case (Input i)
191+ then show ?case by auto
192+next
193+ case (Variable i)
194+ then show ?case by (auto simp: list_all_length)
195+next
196+ case (Binary op a b)
197+ then show ?case using demand_positive[of a] demand_positive[of b]
198+ by (auto simp: bounded_append compiled_height list_all_iff max_def; arith)
199+next
200+ case (Cond c a b)
201+ then show ?case using demand_positive[of c] demand_positive[of a] demand_positive[of b]
202+ by (auto simp: bounded_append compiled_height list_all_iff max_def; arith)
203+next
204+ case (Let a b)
205+ then show ?case using demand_positive[of a] demand_positive[of b]
206+ by (auto simp: bounded_append compiled_height list_all_iff max_def; arith)
207+qed
208+
209+corollary closed_demand:
210+ "scoped 0 e \<Longrightarrow> bounded limit (compile e []) 0 \<longleftrightarrow> demand e \<le> limit"
211+ using compiled_demand[where slots="[]" and n=0] by simp
212+
182213 fun snapshots :: "(input \<Rightarrow> pixel) \<Rightarrow> instruction list \<Rightarrow> pixel list \<Rightarrow> (pixel list list) option" where
183214 "snapshots inputs [] s = Some [s]"
184215 | "snapshots inputs (i # code) s = Option.bind (step inputs i s)

src/Examples.thy modified

@@ -51,6 +51,11 @@ lemma equal_branches:
5151 "optimise (Cond (Input T) (Input X) (Input X)) = Input X"
5252 by eval
5353
54+lemma stack_bound_tight:
55+ "bounded 2 (compile (Binary Add (Input X) (Input Y)) []) 0 \<and>
56+ \<not> bounded 1 (compile (Binary Add (Input X) (Input Y)) []) 0"
57+ by eval
58+
5459 lemma literal_code:
5560 "executable (Literal 42) = [72,184,42,0,0,0,0,0,0,0,80,88,195]"
5661 by eval

src/Frontend.thy modified

@@ -63,7 +63,7 @@ definition prepare :: "string \<Rightarrow> expression option" where
6363 Option.bind (parse 128 [] (lex s [] [])) (\<lambda>(e,rest).
6464 if rest = [] \<and> scoped 0 e \<and> nodes e \<le> 4096 then
6565 let code = compile (optimise e) [] in
66- if check code 0 = Some 1 \<and> bounded 512 code 0 \<and> list_all encodable (native code)
66+ if check code 0 = Some 1 \<and> demand (optimise e) \<le> 512 \<and> list_all encodable (native code)
6767 then Some e else None else None))"
6868
6969 lemma prepare_scoped: "prepare s = Some e \<Longrightarrow> scoped 0 e"
@@ -71,7 +71,7 @@ lemma prepare_scoped: "prepare s = Some e \<Longrightarrow> scoped 0 e"
7171
7272 lemma prepare_bounded:
7373 "prepare s = Some e \<Longrightarrow> bounded 512 (compile (optimise e) []) 0"
74- by (auto simp: prepare_def Let_def split: if_splits bind_splits prod.splits)
74+ by (auto simp: prepare_def Let_def closed_demand optimise_scoped split: if_splits bind_splits prod.splits)
7575
7676 lemma prepare_encodable:
7777 "prepare s = Some e \<Longrightarrow> list_all encodable (native (compile (optimise e) []))"