theory Allocation imports "Remybase.Checker" begin fun allocate :: "bool \ expression \ nat list \ opcode list" where "allocate free (Literal v) slots = [Immediate v]" | "allocate free (Input i) slots = [Move Rax (input_register i)]" | "allocate free (Variable i) slots = [Peek (slots ! i)]" | "allocate free (Binary op a b) slots = (if free then allocate True a slots @ [Move Rbx Rax] @ allocate False b slots @ [Move Rcx Rbx, Arithmetic op] else allocate False a slots @ [Push Rax] @ allocate False b (map Suc slots) @ [Pop Rcx, Arithmetic op])" | "allocate free (Cond c a b) slots = [Push Rbx] @ allocate True c (map Suc slots) @ [Push Rax] @ allocate True a (map (\i. Suc (Suc i)) slots) @ [Push Rax] @ allocate True b (map (\i. Suc (Suc (Suc i))) slots) @ [Pop Rcx, Pop Rbx, Conditional, Pop Rbx]" | "allocate free (Let a b) slots = allocate free a slots @ [Push Rax] @ allocate free b (0 # map Suc slots) @ [Pop Rcx]" definition allocated_result :: "bool \ expression \ pixel list \ machine \ machine \ bool" where "allocated_result free e env s q \ registers q Rax = evaluate e env (inputs s) \ stack q = stack s \ inputs q = inputs s \ (\ free \ registers q Rbx = registers s Rbx)" theorem allocate_correct: assumes "scoped (length env) e" "represents slots (stack s) env" shows "\q. run (allocate free e slots) s = Some q \ allocated_result free e env s q" using assms proof (induction e arbitrary: free slots env s) case (Literal v) then show ?case by (auto simp: allocated_result_def) next case (Input i) then show ?case by (auto simp: allocated_result_def inputs_def fun_eq_iff) next case (Variable i) then show ?case by (auto simp: allocated_result_def represents_def) next case (Binary op a b) obtain p where a: "run (allocate free a slots) s = Some p" and p: "allocated_result free a env s p" using Binary.IH(1)[of env slots s free] Binary.prems by auto show ?case proof (cases free) case True let ?p = "p\registers := (registers p)(Rbx := registers p Rax)\" obtain q where b: "run (allocate False b slots) ?p = Some q" and q: "allocated_result False b env ?p q" using Binary.IH(2)[of env slots ?p False] Binary.prems p by (auto simp: allocated_result_def) show ?thesis using a b p q True by (auto simp: allocated_result_def run_append; auto simp: inputs_def fun_eq_iff) next case False let ?p = "p\stack := registers p Rax # stack p\" obtain q where b: "run (allocate False b (map Suc slots)) ?p = Some q" and q: "allocated_result False b env ?p q" using Binary.IH(2)[of env "map Suc slots" ?p False] Binary.prems p represents_push[OF Binary.prems(2), of "registers p Rax"] by (auto simp: allocated_result_def) show ?thesis using a b p q False by (auto simp: allocated_result_def run_append; auto simp: inputs_def fun_eq_iff) qed next case (Cond c a b) have sc: "scoped (length env) c" and sa: "scoped (length env) a" and sb: "scoped (length env) b" using Cond.prems by auto let ?s = "s\stack := registers s Rbx # stack s\" have repc: "represents (map Suc slots) (stack ?s) env" using represents_push[OF Cond.prems(2)] by simp obtain p where c: "run (allocate True c (map Suc slots)) ?s = Some p" and p: "allocated_result True c env ?s p" using Cond.IH(1)[of env "map Suc slots" ?s True] sc repc by blast let ?p = "p\stack := registers p Rax # stack p\" have repa: "represents (map (\i. Suc (Suc i)) slots) (stack ?p) env" using Cond.prems(2) p by (auto simp: allocated_result_def represents_def) obtain q where a: "run (allocate True a (map (\i. Suc (Suc i)) slots)) ?p = Some q" and q: "allocated_result True a env ?p q" using Cond.IH(2)[of env "map (\i. Suc (Suc i)) slots" ?p True] sa repa by blast let ?q = "q\stack := registers q Rax # stack q\" have repb: "represents (map (\i. Suc (Suc (Suc i))) slots) (stack ?q) env" using Cond.prems(2) p q by (auto simp: allocated_result_def represents_def) obtain r where b: "run (allocate True b (map (\i. Suc (Suc (Suc i))) slots)) ?q = Some r" and r: "allocated_result True b env ?q r" using Cond.IH(3)[of env "map (\i. Suc (Suc (Suc i))) slots" ?q True] sb repb by blast show ?case using c a b p q r by (auto simp: allocated_result_def run_append; auto simp: inputs_def fun_eq_iff) next case (Let a b) obtain p where a: "run (allocate free a slots) s = Some p" and p: "allocated_result free a env s p" using Let.IH(1)[of env slots s free] Let.prems by auto let ?p = "p\stack := registers p Rax # stack p\" obtain q where b: "run (allocate free b (0 # map Suc slots)) ?p = Some q" and q: "allocated_result free b (registers p Rax # env) ?p q" using Let.IH(2)[of "registers p Rax # env" "0 # map Suc slots" ?p free] Let.prems p represents_bind[OF Let.prems(2), of "registers p Rax"] by (auto simp: allocated_result_def) show ?case using a b p q by (auto simp: allocated_result_def run_append; auto simp: inputs_def fun_eq_iff) qed definition allocated :: "expression \ opcode list" where "allocated e = transfers (allocate True (optimise e) [])" theorem allocated_return: "scoped 0 e \ \q. run (allocated e) s = Some q \ registers q Rax = evaluate e [] (inputs s) \ stack q = stack s \ inputs q = inputs s" using allocate_correct[where env="[]" and slots="[]" and free=True and e="optimise e"] optimise_scoped by (auto simp: allocated_def transfers_correct allocated_result_def represents_def optimise_correct) definition allocated_bytes :: "expression \ nat list" where "allocated_bytes e = concat (map encode (allocated e)) @ [195]" lemma allocated_add: "allocated (Binary Add (Input X) (Input Y)) = [Move Rax R8, Move Rbx Rax, Move Rax R9, Move Rcx Rbx, Arithmetic Add]" by eval end