Theory VeriComp.Compiler
section ‹Compiler Between Static Representations›
theory Compiler
imports Language Simulation
begin
definition option_comp :: "('a ⇒ 'b option) ⇒ ('c ⇒ 'a option) ⇒ 'c ⇒ 'b option" (infix ‹⇚› 50) where
"(f ⇚ g) x ≡ Option.bind (g x) f"
context
fixes f :: "('a ⇒ 'a option)"
begin
fun option_comp_pow :: "nat ⇒ 'a ⇒ 'a option" where
"option_comp_pow 0 = (λ_. None)" |
"option_comp_pow (Suc 0) = f" |
"option_comp_pow (Suc n) = (option_comp_pow n ⇚ f)"
end
locale compiler =
L1: language step1 final1 load1 +
L2: language step2 final2 load2 +
backward_simulation step1 final1 step2 final2 match order
for
step1 :: "'state1 ⇒ 'state1 ⇒ bool" and final1 and load1 :: "'prog1 ⇒ 'state1 ⇒ bool" and
step2 :: "'state2 ⇒ 'state2 ⇒ bool" and final2 and load2 :: "'prog2 ⇒ 'state2 ⇒ bool" and
match and
order :: "'index ⇒ 'index ⇒ bool" +
fixes
compile :: "'prog1 ⇒ 'prog2 option"
assumes
compile_load:
"compile p1 = Some p2 ⟹ load2 p2 s2 ⟹ ∃s1 i. load1 p1 s1 ∧ match i s1 s2"
begin
text ‹
The @{locale compiler} locale relates two languages, L1 and L2, by a backward simulation and provides a @{term compile} partial function from a concrete program in L1 to a concrete program in L2.
The only assumption is that a successful compilation results in a program which, when loaded, is equivalent to the loaded initial program.
›
subsection ‹Preservation of behaviour›
corollary behaviour_preservation:
assumes
compiles: "compile p1 = Some p2" and
behaves: "L2.prog_behaves p2 b2" and
not_wrong: "¬ is_wrong b2"
shows "∃b1 i. L1.prog_behaves p1 b1 ∧ rel_behaviour (match i) b1 b2"
proof -
obtain s2 where "load2 p2 s2" and "L2.state_behaves s2 b2"
using behaves L2.prog_behaves_def by auto
obtain i s1 where "load1 p1 s1" "match i s1 s2"
using compile_load[OF compiles ‹load2 p2 s2›]
by auto
then show ?thesis
using simulation_behaviour[OF ‹L2.state_behaves s2 b2› not_wrong ‹match i s1 s2›]
by (auto simp: L1.prog_behaves_def)
qed
end
subsection ‹Composition of compilers›
lemma compiler_composition:
assumes
"compiler step1 final1 load1 step2 final2 load2 match1 order1 compile1" and
"compiler step2 final2 load2 step3 final3 load3 match2 order2 compile2"
shows "compiler step1 final1 load1 step3 final3 load3
(rel_comp match1 match2) (lex_prodp order1⇧+⇧+ order2) (compile2 ⇚ compile1)"
proof (rule compiler.intro)
show "language step1 final1"
using assms(1)[THEN compiler.axioms(1)] .
next
show "language step3 final3"
using assms(2)[THEN compiler.axioms(2)] .
next
show "backward_simulation step1 final1 step3 final3
(rel_comp match1 match2) (lex_prodp order1⇧+⇧+ order2)"
using backward_simulation_composition[OF assms[THEN compiler.axioms(3)]] .
next
show "compiler_axioms load1 load3 (rel_comp match1 match2) (compile2 ⇚ compile1)"
proof unfold_locales
fix p1 p3 s3
assume
compile: "(compile2 ⇚ compile1) p1 = Some p3" and
load: "load3 p3 s3"
obtain p2 where c1: "compile1 p1 = Some p2" and c2: "compile2 p2 = Some p3"
using compile by (auto simp: bind_eq_Some_conv option_comp_def)
obtain s2 i' where l2: "load2 p2 s2" and "match2 i' s2 s3"
using assms(2)[THEN compiler.compile_load, OF c2 load]
by auto
moreover obtain s1 i where "load1 p1 s1" and "match1 i s1 s2"
using assms(1)[THEN compiler.compile_load, OF c1 l2]
by auto
ultimately show "∃s1 i. load1 p1 s1 ∧ rel_comp match1 match2 i s1 s3"
unfolding rel_comp_def by auto
qed
qed
lemma compiler_composition_pow:
assumes
"compiler step final load step final load match order compile"
shows "compiler step final load step final load
(rel_comp_pow match) (lexp order⇧+⇧+) (option_comp_pow compile n)"
proof (induction n rule: option_comp_pow.induct)
case 1
show ?case
using assms
by (auto intro: compiler.axioms compiler.intro compiler_axioms.intro backward_simulation_pow)
next
case 2
show ?case
proof (rule compiler.intro)
show "compiler_axioms load load (rel_comp_pow match) (option_comp_pow compile (Suc 0))"
proof unfold_locales
fix p1 p2 s2
assume
"option_comp_pow compile (Suc 0) p1 = Some p2" and
"load p2 s2"
thus "∃s1 i. load p1 s1 ∧ rel_comp_pow match i s1 s2"
using compiler.compile_load[OF assms(1)]
by (metis option_comp_pow.simps(2) rel_comp_pow.simps(2))
qed
qed (auto intro: assms compiler.axioms backward_simulation_pow)
next
case (3 n')
show ?case
proof (rule compiler.intro)
show "compiler_axioms load load (rel_comp_pow match) (option_comp_pow compile (Suc (Suc n')))"
proof unfold_locales
fix p1 p3 s3
assume
"option_comp_pow compile (Suc (Suc n')) p1 = Some p3" and
"load p3 s3"
then obtain p2 where
comp: "compile p1 = Some p2" and
comp_IH: "option_comp_pow compile (Suc n') p2 = Some p3"
by (auto simp: option_comp_def bind_eq_Some_conv)
obtain s2 i' where "load p2 s2" and "rel_comp_pow match i' s2 s3"
using compiler.compile_load[OF "3.IH" comp_IH ‹load p3 s3›]
by auto
moreover obtain s1 i where "load p1 s1" and "match i s1 s2"
using compiler.compile_load[OF assms comp ‹load p2 s2›]
by auto
moreover have "rel_comp_pow match (i # i') s1 s3"
using ‹rel_comp_pow match i' s2 s3› ‹match i s1 s2› rel_comp_pow.elims(2) by fastforce
ultimately show "∃s1 i. load p1 s1 ∧ rel_comp_pow match i s1 s3"
by blast
qed
qed (auto intro: assms compiler.axioms backward_simulation_pow)
qed
end