Theory Residual_Edges
theory Residual_Edges
imports Residual_Location "Voblint_CFG.CFG_Exec"
begin
section ‹The next CFG edge of a located residual›
text ‹
If a residual is located at a node and the command about to run is a base one --- an
assignment, a check, a call, a return --- then the edge the compiler emitted for it
really is in the graph, and taking the source step re-locates the successor residual at
that edge's target. Every simulation step reads its edge off one of these facts.
‹intra_step› collects the source steps that stay inside one activation, and
‹intra_step_simulation› assembles the facts below into the statement that any such step
is matched by a run of \<^const>‹cstep›.
Six proofs here induct on \<^const>‹control_at› and repeat the same descent: project the
sub-fragment's compile tuple, apply the induction hypothesis, lift the result back through
‹control_at.SeqRight› / ‹IfLeft› / ‹IfRight›. It looks factorable and is not. A shared
∗‹descend to a base clause› lemma would have to carry the residual down unchanged, and
‹SeqLeft› and ‹WhileBody› rebuild it --- they relate the outer residual \<^term>‹Seq r c2› to
the inner ‹r›. So the descent survives only in the three clauses that pass the residual
through, which is half the cases in two of the six proofs and none of the rest.
›
subsection ‹Located base residuals emit their compiled edge›
text ‹A ∗‹base› residual is one the compiler turns into a single intra edge, rather than a
branch, a call, or a relocation. ‹emitted_action› is the action on that edge. An ordinary
\<^const>‹Call› has none, because it is compiled to a call edge instead; a \<^const>‹Call› that
\<^const>‹special_table› classifies is resolved in place, and ‹wf_source_com› fixes its
destination to \<^term>‹Some x›, so only that shape emits an action.›
text ‹The annotation of the statement a residual runs next. A step leaves the annotation of
the command it reduces on the \<^const>‹SKIP› it produces, so this is what the completed
residual carries.›
fun stmt_ann :: "'a acom ⇒ 'a" where
"stmt_ann (SKIP i) = i"
| "stmt_ann (Assign i x a) = i"
| "stmt_ann (VIMP_Proc.gcom.Check i l c) = i"
| "stmt_ann (Seq c1 c2) = stmt_ann c1"
| "stmt_ann (If i b c1 c2) = i"
| "stmt_ann (While i b c) = i"
| "stmt_ann (Call i dst q actuals) = i"
| "stmt_ann (Return i e) = i"
| "stmt_ann (Restore i) = i"
| "stmt_ann (Unwind i) = i"
fun emitted_action :: "'a acom ⇒ edge_action option" where
"emitted_action (Assign i x a) = Some (EA_Assign x a)"
| "emitted_action (VIMP_Proc.gcom.Check i l c) = Some (EA_Check l c)"
| "emitted_action (Call i (Some x) q actuals) =
(case special_table q of
None ⇒ None
| Some desc ⇒ map_option (λsc. EA_Special sc x) (classify_special desc actuals))"
| "emitted_action _ = None"
text ‹Which action it is does not matter to the recursive ‹control_at› cases: they only carry
an edge up through the enclosing fragment and re-locate the completed residual at the same
node. So one induction serves every base shape.›
lemma control_at_emitted_edge:
"control_at Π p c0 k n r v ⟹ emitted_action r = Some a ⟹
compile Π p c0 k n = (n', en, E, K) ⟹
∃j w. v = Statement j ∧ (Statement j, a, w) ∈ E
∧ control_at Π p c0 k n (SKIP (stmt_ann r)) w"
proof (induction arbitrary: n' en E K rule: control_at.induct)
case (Assign i x' a' k n0)
then show ?case by auto
next
case (Check i l b' k n0)
then show ?case by auto
next
case (CallHead i dst' q' actuals' k n0)
show ?case
proof (cases dst')
case None with CallHead.prems(1) show ?thesis by simp
next
case (Some x)
with CallHead.prems(1) obtain desc sc where
sp: "special_table q' = Some desc" and cl: "classify_special desc actuals' = Some sc"
and act: "a = EA_Special sc x"
by (auto split: option.splits)
have "(Statement n0, EA_Special sc x, k) ∈ E"
using CallHead.prems(2) sp cl Some by auto
with act show ?thesis by auto
qed
next
case (SeqRight c2 k n0 c1 r v)
from SeqRight.prems(2) obtain n2 E2 K2 where
c2c: "compile Π p c2 k (n0 + csize c1) = (n2, Statement (n0 + csize c1), E2, K2)"
and sub: "E2 ⊆ E"
by (rule compile_Seq_rightE)
from SeqRight.IH[OF SeqRight.prems(1) c2c] obtain j w where
jw: "v = Statement j" "(Statement j, a, w) ∈ E2"
"control_at Π p c2 k (n0 + csize c1) (SKIP (stmt_ann r)) w" by blast
have "control_at Π p (Seq c1 c2) k n0 (SKIP (stmt_ann r)) w"
using control_at.SeqRight[OF jw(3)] .
then show ?case using jw sub by blast
next
case (IfLeft c1 k n0 r v i b c2)
from IfLeft.prems(2) obtain n1 E1 K1 where
c1c: "compile Π p c1 k (Suc n0) = (n1, Statement (Suc n0), E1, K1)"
and sub: "E1 ⊆ E"
by (rule compile_If_leftE[OF _ IfLeft.hyps(2)])
from IfLeft.IH[OF IfLeft.prems(1) c1c] obtain j w where
jw: "v = Statement j" "(Statement j, a, w) ∈ E1"
"control_at Π p c1 k (Suc n0) (SKIP (stmt_ann r)) w" by blast
have "control_at Π p (If i b c1 c2) k n0 (SKIP (stmt_ann r)) w"
using control_at.IfLeft[OF jw(3) IfLeft.hyps(2)] .
then show ?case using jw sub by blast
next
case (IfRight c2 k n0 c1 r v i b)
from IfRight.prems(2) obtain n2 E2 K2 where
c2c: "compile Π p c2 k (Suc n0 + csize c1)
= (n2, Statement (Suc n0 + csize c1), E2, K2)"
and sub: "E2 ⊆ E"
by (rule compile_If_rightE[OF _ IfRight.hyps(2)])
from IfRight.IH[OF IfRight.prems(1) c2c] obtain j w where
jw: "v = Statement j" "(Statement j, a, w) ∈ E2"
"control_at Π p c2 k (Suc n0 + csize c1) (SKIP (stmt_ann r)) w" by blast
have "control_at Π p (If i b c1 c2) k n0 (SKIP (stmt_ann r)) w"
using control_at.IfRight[OF jw(3) IfRight.hyps(2)] .
then show ?case using jw sub by blast
qed simp_all
text ‹The check a residual runs next, when its leftmost command is one. A located residual
about to run a check sits at that check's \<^const>‹EA_Check› edge, however much sequencing
wraps it.›
fun next_check :: "'a acom ⇒ (check_label × exp) option" where
"next_check (VIMP_Proc.gcom.Check i l c) = Some (l, c)"
| "next_check (Seq c1 c2) = next_check c1"
| "next_check _ = None"
lemma control_at_next_check_edge:
"control_at Π p c0 k n r v ⟹ next_check r = Some (l, c) ⟹
compile Π p c0 k n = (n', en, E, K) ⟹ ∃w. (v, EA_Check l c, w) ∈ E"
proof (induction arbitrary: n' en E K rule: control_at.induct)
case (SeqLeft c1 n0 r v c2 k)
from SeqLeft.prems(2) obtain m F L
where "compile Π p c1 (Statement (n0 + csize c1)) n0 = (m, Statement n0, F, L)"
and "F ⊆ E"
by (rule compile_Seq_leftE)
with SeqLeft.IH SeqLeft.prems(1) show ?case by auto
next
case (SeqRight c2 k n0 c1 r v)
from SeqRight.prems(2) obtain m F L
where "compile Π p c2 k (n0 + csize c1) = (m, Statement (n0 + csize c1), F, L)"
and "F ⊆ E"
by (rule compile_Seq_rightE)
with SeqRight.IH SeqRight.prems(1) show ?case by blast
next
case (IfLeft c1 k n0 r v i b c2)
from IfLeft.prems(2) obtain m F L
where "compile Π p c1 k (Suc n0) = (m, Statement (Suc n0), F, L)" and "F ⊆ E"
by (rule compile_If_leftE[OF _ IfLeft.hyps(2)])
with IfLeft.IH IfLeft.prems(1) show ?case by blast
next
case (IfRight c2 k n0 c1 r v i b)
from IfRight.prems(2) obtain m F L
where "compile Π p c2 k (Suc n0 + csize c1) = (m, Statement (Suc n0 + csize c1), F, L)"
and "F ⊆ E"
by (rule compile_If_rightE[OF _ IfRight.hyps(2)])
with IfRight.IH IfRight.prems(1) show ?case by blast
next
case (WhileBody c n0 r v i b k)
from WhileBody.prems(2) obtain m F L
where "compile Π p c (Statement n0) (Suc n0) = (m, Statement (Suc n0), F, L)"
and "F ⊆ E"
by (rule compile_While_bodyE)
with WhileBody.IH WhileBody.prems(1) show ?case by auto
qed auto
text ‹A located conditional also arises from a loop unfolding (\<^const>‹While› steps to
‹If b (Seq c (While b c)) SKIP›), so the ‹WhileUnfolded› case is real: the true branch
re-locates the loop body followed by the loop, the false branch re-locates \<^const>‹SKIP› at
the loop's continuation.›
lemma control_at_if_edges:
"control_at Π p c0 k n r v ⟹ r = If i b c1 c2 ⟹ source_com r ⟹
compile Π p c0 k n = (n', en, E, K) ⟹
∃j en1 en2. v = Statement j
∧ (Statement j, EA_Assume b, en1) ∈ E ∧ (Statement j, EA_AssumeNot b, en2) ∈ E
∧ control_at Π p c0 k n c1 en1 ∧ control_at Π p c0 k n c2 en2"
proof (induction arbitrary: n' en E K rule: control_at.induct)
case (IfHead i b' c1' c2' k n0)
from IfHead.prems(1) have r: "b' = b" "c1' = c1" "c2' = c2" by auto
note E = compile_If_assume_edges[OF IfHead.prems(3)]
from IfHead.prems(2) r have src: "source_com c1'" "source_com c2'" by auto
have ca1: "control_at Π p (If i b' c1' c2') k n0 c1'
(if is_SKIP c1' then k else Statement (Suc n0))"
using src(1) by (cases "is_SKIP c1'") (auto intro: control_at_initial)
have ca2: "control_at Π p (If i b' c1' c2') k n0 c2'
(if is_SKIP c2' then k else Statement (Suc n0 + csize c1'))"
proof (cases "is_SKIP c2'")
case True then show ?thesis by auto
next
case False
have "control_at Π p (If i b' c1' c2') k n0 c2'
(Statement (Suc n0 + csize c1'))"
by (rule control_at.IfRight[OF control_at_initial[OF src(2)] False])
with False show ?thesis by simp
qed
from E ca1 ca2 r show ?case by auto
next
case (SeqRight c2' k n0 c1' r v)
from SeqRight.prems(3) obtain n2 E2 K2 where
c2c: "compile Π p c2' k (n0 + csize c1') = (n2, Statement (n0 + csize c1'), E2, K2)"
and sub: "E2 ⊆ E"
by (rule compile_Seq_rightE)
from SeqRight.IH[OF SeqRight.prems(1) SeqRight.prems(2) c2c] obtain j e1 e2 where
jw: "v = Statement j" "(Statement j, EA_Assume b, e1) ∈ E2"
"(Statement j, EA_AssumeNot b, e2) ∈ E2"
"control_at Π p c2' k (n0 + csize c1') c1 e1"
"control_at Π p c2' k (n0 + csize c1') c2 e2" by blast
have "control_at Π p (Seq c1' c2') k n0 c1 e1" "control_at Π p (Seq c1' c2') k n0 c2 e2"
using control_at.SeqRight[OF jw(4)]
control_at.SeqRight[OF jw(5)] .
then show ?case using jw sub by blast
next
case (IfLeft c1' k n0 r v i b' c2')
from IfLeft.prems(3) obtain n1 E1 K1 where
c1c: "compile Π p c1' k (Suc n0) = (n1, Statement (Suc n0), E1, K1)"
and sub: "E1 ⊆ E"
by (rule compile_If_leftE[OF _ IfLeft.hyps(2)])
from IfLeft.IH[OF IfLeft.prems(1) IfLeft.prems(2) c1c] obtain j e1 e2 where
jw: "v = Statement j" "(Statement j, EA_Assume b, e1) ∈ E1"
"(Statement j, EA_AssumeNot b, e2) ∈ E1"
"control_at Π p c1' k (Suc n0) c1 e1" "control_at Π p c1' k (Suc n0) c2 e2" by blast
have "control_at Π p (If i b' c1' c2') k n0 c1 e1" "control_at Π p (If i b' c1' c2') k n0 c2 e2"
using control_at.IfLeft[OF jw(4) IfLeft.hyps(2)] control_at.IfLeft[OF jw(5) IfLeft.hyps(2)] .
then show ?case using jw sub by blast
next
case (IfRight c2' k n0 c1' r v i b')
from IfRight.prems(3) obtain n2 E2 K2 where
c2c: "compile Π p c2' k (Suc n0 + csize c1')
= (n2, Statement (Suc n0 + csize c1'), E2, K2)"
and sub: "E2 ⊆ E"
by (rule compile_If_rightE[OF _ IfRight.hyps(2)])
from IfRight.IH[OF IfRight.prems(1) IfRight.prems(2) c2c] obtain j e1 e2 where
jw: "v = Statement j" "(Statement j, EA_Assume b, e1) ∈ E2"
"(Statement j, EA_AssumeNot b, e2) ∈ E2"
"control_at Π p c2' k (Suc n0 + csize c1') c1 e1"
"control_at Π p c2' k (Suc n0 + csize c1') c2 e2" by blast
have "control_at Π p (If i b' c1' c2') k n0 c1 e1" "control_at Π p (If i b' c1' c2') k n0 c2 e2"
using control_at.IfRight[OF jw(4) IfRight.hyps(2)] control_at.IfRight[OF jw(5) IfRight.hyps(2)]
.
then show ?case using jw sub by blast
next
case (WhileUnfolded i b'' c'' k n0)
from WhileUnfolded.prems(1)
have r: "b'' = b" "Seq c'' (While i b'' c'') = c1" "(SKIP i) = c2" by auto
note E = compile_While_assume_edges[OF WhileUnfolded.prems(3)]
from WhileUnfolded.prems(2) have src: "source_com c''" by auto
have ca1: "control_at Π p (While i b'' c'') k n0 (Seq c'' (While i b'' c'')) (Statement (Suc n0))"
by (rule control_at.WhileBody[OF control_at_initial[OF src]])
have ca2: "control_at Π p (While i b'' c'') k n0 (SKIP i) k"
by (rule control_at.WhileDone)
from E ca1 ca2 r show ?case by auto
qed simp_all
subsection ‹SKIP relocation to the continuation›
text ‹A located \<^const>‹SKIP› --- a completed sub-command --- is at its fragment's continuation
already, except for a source \<^const>‹SKIP›, which still has its own node and one
\<^term>‹EA_Nop› edge. ‹compile_control_at_SKIP_exit_path› already establishes that route as a
store-preserving \<^const>‹intra_path›; an intra path never touches the activation stack, so
‹intra_path_imp_cstep_star› reads it back as a ‹cstep› run at whatever stack is current.›
lemma control_at_skip_to_exit:
assumes "control_at Π p c0 k n r v" and "is_SKIP r"
and "compile Π p c0 k n = (n', en, E, K)" and "E ⊆ intra g"
shows "𝒢, g ⊢ (v, s, stk) →⇩c⇧* (k, s, stk)"
proof -
from assms(2) obtain j where r: "r = SKIP j" by auto
show ?thesis
using intra_path_imp_cstep_star[
OF compile_control_at_SKIP_exit_path[OF assms(1)[unfolded r] assms(3,4)],
where stk = stk]
by simp
qed
subsection ‹Completed-head sequence relocation›
text ‹Under continuation passing the head's own last edge already targets the entry of
\<^term>‹c2› --- or, when the continuation is the enclosing \<^const>‹While›, the loop head ---
so relocation is exactly ‹control_at_skip_to_exit›.›
lemma control_at_seq_skip_reloc:
"control_at Π p c0 k n r v ⟹ r = Seq (SKIP i) c2 ⟹
compile Π p c0 k n = (n', en, E, K) ⟹ E ⊆ intra g ⟹ source_com c0 ⟹
∃v'. control_at Π p c0 k n c2 v' ∧ 𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s, stk)"
proof (induction arbitrary: n' en E K rule: control_at.induct)
case (SeqLeft c1 n0 r_in v c2r k)
from SeqLeft.prems(1) have ri: "is_SKIP r_in" and c2eq: "c2r = c2" by auto
from SeqLeft.prems(2) obtain n1 E1 K1 where
c1c: "compile Π p c1 (Statement (n0 + csize c1)) n0 = (n1, Statement n0, E1, K1)"
and sub: "E1 ⊆ E"
by (rule compile_Seq_leftE)
have src2: "source_com c2r" using SeqLeft.prems(4) by simp
from control_at_skip_to_exit[OF SeqLeft.hyps(1) ri c1c subset_trans[OF sub SeqLeft.prems(3)]]
have sk: "𝒢, g ⊢ (v, s, stk) →⇩c⇧* (Statement (n0 + csize c1), s, stk)" .
have "control_at Π p (Seq c1 c2r) k n0 c2r (Statement (n0 + csize c1))"
by (rule control_at.SeqRight[OF control_at_initial[OF src2]])
then have "control_at Π p (Seq c1 c2r) k n0 c2 (Statement (n0 + csize c1))" using c2eq by simp
with sk show ?case by blast
next
case (WhileBody c n0 r_in v i b k)
from WhileBody.prems(1) have ri: "is_SKIP r_in" and c2eq: "c2 = While i b c" by auto
from WhileBody.prems(2) obtain n1 E1 K1 where
cc: "compile Π p c (Statement n0) (Suc n0) = (n1, Statement (Suc n0), E1, K1)"
and sub: "E1 ⊆ E"
by (rule compile_While_bodyE)
from control_at_skip_to_exit[OF WhileBody.hyps(1) ri cc subset_trans[OF sub WhileBody.prems(3)]]
have sk: "𝒢, g ⊢ (v, s, stk) →⇩c⇧* (Statement n0, s, stk)" .
have "control_at Π p (While i b c) k n0 (While i b c) (Statement n0)"
by (rule control_at.WhileHead)
then have "control_at Π p (While i b c) k n0 c2 (Statement n0)" using c2eq by simp
with sk show ?case by blast
next
case (SeqRight c2' k n0 c1 r v)
from SeqRight.prems(2) obtain n2 E2 K2 where
c2c: "compile Π p c2' k (n0 + csize c1) = (n2, Statement (n0 + csize c1), E2, K2)"
and sub: "E2 ⊆ E"
by (rule compile_Seq_rightE)
have src2: "source_com c2'" using SeqRight.prems(4) by simp
from SeqRight.IH[OF SeqRight.prems(1) c2c subset_trans[OF sub SeqRight.prems(3)] src2]
obtain v' where v': "control_at Π p c2' k (n0 + csize c1) c2 v'"
"𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s, stk)" by blast
have "control_at Π p (Seq c1 c2') k n0 c2 v'"
using control_at.SeqRight[OF v'(1)] .
with v'(2) show ?case by blast
next
case (IfLeft c1 k n0 r v i b c2')
from IfLeft.prems(2) obtain n1 E1 K1 where
c1c: "compile Π p c1 k (Suc n0) = (n1, Statement (Suc n0), E1, K1)"
and sub: "E1 ⊆ E"
by (rule compile_If_leftE[OF _ IfLeft.hyps(2)])
have src1: "source_com c1" using IfLeft.prems(4) by simp
from IfLeft.IH[OF IfLeft.prems(1) c1c subset_trans[OF sub IfLeft.prems(3)] src1]
obtain v' where v': "control_at Π p c1 k (Suc n0) c2 v'"
"𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s, stk)" by blast
have "control_at Π p (If i b c1 c2') k n0 c2 v'" using control_at.IfLeft[OF v'(1) IfLeft.hyps(2)]
.
with v'(2) show ?case by blast
next
case (IfRight c2' k n0 c1 r v i b)
from IfRight.prems(2) obtain n2 E2 K2 where
c2c: "compile Π p c2' k (Suc n0 + csize c1)
= (n2, Statement (Suc n0 + csize c1), E2, K2)"
and sub: "E2 ⊆ E"
by (rule compile_If_rightE[OF _ IfRight.hyps(2)])
have src2: "source_com c2'" using IfRight.prems(4) by simp
from IfRight.IH[OF IfRight.prems(1) c2c subset_trans[OF sub IfRight.prems(3)] src2]
obtain v' where v': "control_at Π p c2' k (Suc n0 + csize c1) c2 v'"
"𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s, stk)" by blast
have "control_at Π p (If i b c1 c2') k n0 c2 v'"
using control_at.IfRight[OF v'(1) IfRight.hyps(2)]
.
with v'(2) show ?case by blast
qed simp_all
subsection ‹The caller continuation after a call›
text ‹
A call site's caller has, after the call, a finite left-spine of residual continuations
\<^term>‹afters›: the source commands sequenced after the call, in execution order, collected
while descending the activation's left-associated \<^const>‹Seq› spine. \<^term>‹seq_after c afters›
wraps them around the active head ‹c›: \<^term>‹seq_after c [s3, s4] = Seq (Seq c s3) s4›.
A tail-position call has \<^term>‹afters = []› and the caller resumes at bare ‹c›. The list
holds pending commands ∗‹inside one activation›; suspended ∗‹caller activations› are
the recursive nesting of ‹csim› instead.
›
fun seq_after :: "'a acom ⇒ 'a acom list ⇒ 'a acom" where
"seq_after c [] = c"
| "seq_after c (a # as) = seq_after (Seq c a) as"
lemma seq_after_append: "seq_after (seq_after c xs) ys = seq_after c (xs @ ys)"
by (induction xs arbitrary: c) auto
lemma seq_after_snoc: "seq_after c (xs @ [a]) = Seq (seq_after c xs) a"
by (simp add: seq_after_append[symmetric])
lemma next_check_seq_after [simp]: "next_check (seq_after c afters) = next_check c"
by (induction afters arbitrary: c) auto
text ‹A \<^const>‹seq_after› spine equals a non-\<^const>‹Seq› atom only when its head does and the
continuation list is empty. These discriminators close the leaf cases of the spine
inductions.›
lemma seq_after_eq_iff [simp]:
"(seq_after c afters = SKIP i) = (c = SKIP i ∧ afters = [])"
"(SKIP i = seq_after c afters) = (c = SKIP i ∧ afters = [])"
"(seq_after c afters = Restore i) = (c = Restore i ∧ afters = [])"
"(Restore i = seq_after c afters) = (c = Restore i ∧ afters = [])"
"(seq_after c afters = Unwind i) = (c = Unwind i ∧ afters = [])"
"(Unwind i = seq_after c afters) = (c = Unwind i ∧ afters = [])"
"(seq_after c afters = Assign i x a) = (c = Assign i x a ∧ afters = [])"
"(Assign i x a = seq_after c afters) = (c = Assign i x a ∧ afters = [])"
"(seq_after c afters = VIMP_Proc.gcom.Check i l b) = (c = VIMP_Proc.gcom.Check i l b ∧ afters = [])"
"(VIMP_Proc.gcom.Check i l b = seq_after c afters) = (c = VIMP_Proc.gcom.Check i l b ∧ afters = [])"
"(seq_after c afters = If i b c1 c2) = (c = If i b c1 c2 ∧ afters = [])"
"(If i b c1 c2 = seq_after c afters) = (c = If i b c1 c2 ∧ afters = [])"
"(seq_after c afters = While i b cw) = (c = While i b cw ∧ afters = [])"
"(While i b cw = seq_after c afters) = (c = While i b cw ∧ afters = [])"
"(seq_after c afters = Return i e) = (c = Return i e ∧ afters = [])"
"(Return i e = seq_after c afters) = (c = Return i e ∧ afters = [])"
"(seq_after c afters = Call i dst q actuals) = (c = Call i dst q actuals ∧ afters = [])"
"(Call i dst q actuals = seq_after c afters) = (c = Call i dst q actuals ∧ afters = [])"
by (induction afters arbitrary: c; auto)+
lemma source_com_seq_afterD [dest]:
"source_com (seq_after c afters) ⟹
source_com c ∧ (∀a ∈ set afters. source_com a)"
proof (induction afters arbitrary: c)
case Nil
then show ?case by simp
next
case (Cons a afters)
have h: "source_com (seq_after (Seq c a) afters)"
using Cons.prems by simp
from Cons.IH[OF h] have h1: "source_com (Seq c a)"
and h2: "∀b ∈ set afters. source_com b" by blast+
from h1 h2 show ?case by auto
qed
lemma control_at_head_return_afters_no_Restore:
assumes "control_at Π p c0 k n (seq_after (Return i e) afters) v"
and "source_com c0"
shows "∀a ∈ set afters. ¬ is_Restore a"
proof (rule ballI)
fix a
assume ain: "a ∈ set afters"
from control_at_source_com[OF assms] source_com_seq_afterD
have "source_com a" using ain by blast
then show "¬ is_Restore a" by (rule source_com_no_Restore)
qed
text ‹A \<^const>‹Call› at the bottom-left of a \<^const>‹seq_after› spine still sits on the call
edge the compiler emitted at the call node, and the source step re-locates
\<^term>‹seq_after (SKIP i) afters› at the call's continuation node. The ‹SeqLeft› / ‹WhileBody›
cases peel the outermost continuation, the passthrough cases keep it.›
lemma control_at_seq_after_call_edge:
"control_at Π p c0 k n r v ⟹ r = seq_after (Call i dst q actuals) afters ⟹
compile Π p c0 k n = (n', en, E, K) ⟹ special_table q = None ⟹
∃j w. v = Statement j
∧ (Statement j, CallEdge dst (call_formals Π q) actuals,
FunctionEntry q, w) ∈ K
∧ control_at Π p c0 k n (seq_after (SKIP i) afters) w"
proof (induction arbitrary: afters n' en E K rule: control_at.induct)
case (CallHead ia dst' q' actuals' k n0 afters)
then show ?case by (auto simp: Let_def split: prod.splits)
next
case (SeqLeft c1 n0 r v c2 k afters)
obtain xs where afx: "afters = xs @ [c2]" and req: "r = seq_after (Call i dst q actuals) xs"
using SeqLeft.prems(1) by (cases afters rule: rev_cases) (auto simp: seq_after_snoc)
from SeqLeft.prems(2) obtain n1 E1 K1 where
c1c: "compile Π p c1 (Statement (n0 + csize c1)) n0 = (n1, Statement n0, E1, K1)"
and sub: "K1 ⊆ K"
by (rule compile_Seq_leftE)
from SeqLeft.IH[OF req c1c SeqLeft.prems(3)] obtain j w where
jw: "v = Statement j"
"(Statement j, CallEdge dst (call_formals Π q) actuals,
FunctionEntry q, w) ∈ K1"
"control_at Π p c1 (Statement (n0 + csize c1)) n0 (seq_after (SKIP i) xs) w" by blast
have "control_at Π p (Seq c1 c2) k n0 (seq_after (SKIP i) afters) w"
using control_at.SeqLeft[OF jw(3)] by (simp add: afx seq_after_snoc)
then show ?case using jw sub by blast
next
case (SeqRight c2 k n0 c1 r v afters)
from SeqRight.prems(2) obtain n2 E2 K2 where
c2c: "compile Π p c2 k (n0 + csize c1) = (n2, Statement (n0 + csize c1), E2, K2)"
and sub: "K2 ⊆ K"
by (rule compile_Seq_rightE)
from SeqRight.IH[OF SeqRight.prems(1) c2c SeqRight.prems(3)] obtain j w where
jw: "v = Statement j"
"(Statement j, CallEdge dst (call_formals Π q) actuals,
FunctionEntry q, w) ∈ K2"
"control_at Π p c2 k (n0 + csize c1) (seq_after (SKIP i) afters) w" by blast
have "control_at Π p (Seq c1 c2) k n0 (seq_after (SKIP i) afters) w"
using control_at.SeqRight[OF jw(3)] .
then show ?case using jw sub by blast
next
case (IfLeft c1 k n0 r v ia b c2 afters)
from IfLeft.prems(2) obtain n1 E1 K1 where
c1c: "compile Π p c1 k (Suc n0) = (n1, Statement (Suc n0), E1, K1)"
and sub: "K1 ⊆ K"
by (rule compile_If_leftE[OF _ IfLeft.hyps(2)])
from IfLeft.IH[OF IfLeft.prems(1) c1c IfLeft.prems(3)] obtain j w where
jw: "v = Statement j"
"(Statement j, CallEdge dst (call_formals Π q) actuals,
FunctionEntry q, w) ∈ K1"
"control_at Π p c1 k (Suc n0) (seq_after (SKIP i) afters) w" by blast
have "control_at Π p (If ia b c1 c2) k n0 (seq_after (SKIP i) afters) w"
using control_at.IfLeft[OF jw(3) IfLeft.hyps(2)] .
then show ?case using jw sub by blast
next
case (IfRight c2 k n0 c1 r v ia b afters)
from IfRight.prems(2) obtain n2 E2 K2 where
c2c: "compile Π p c2 k (Suc n0 + csize c1)
= (n2, Statement (Suc n0 + csize c1), E2, K2)"
and sub: "K2 ⊆ K"
by (rule compile_If_rightE[OF _ IfRight.hyps(2)])
from IfRight.IH[OF IfRight.prems(1) c2c IfRight.prems(3)] obtain j w where
jw: "v = Statement j"
"(Statement j, CallEdge dst (call_formals Π q) actuals,
FunctionEntry q, w) ∈ K2"
"control_at Π p c2 k (Suc n0 + csize c1) (seq_after (SKIP i) afters) w" by blast
have "control_at Π p (If ia b c1 c2) k n0 (seq_after (SKIP i) afters) w"
using control_at.IfRight[OF jw(3) IfRight.hyps(2)] .
then show ?case using jw sub by blast
next
case (WhileBody c n0 r v ia b k afters)
obtain xs where afx: "afters = xs @ [While ia b c]"
and req: "r = seq_after (Call i dst q actuals) xs"
using WhileBody.prems(1) by (cases afters rule: rev_cases) (auto simp: seq_after_snoc)
from WhileBody.prems(2) obtain n1 E1 K1 where
cc: "compile Π p c (Statement n0) (Suc n0) = (n1, Statement (Suc n0), E1, K1)"
and sub: "K1 ⊆ K"
by (rule compile_While_bodyE)
from WhileBody.IH[OF req cc WhileBody.prems(3)] obtain j w where
jw: "v = Statement j"
"(Statement j, CallEdge dst (call_formals Π q) actuals,
FunctionEntry q, w) ∈ K1"
"control_at Π p c (Statement n0) (Suc n0) (seq_after (SKIP i) xs) w" by blast
have "control_at Π p (While ia b c) k n0 (seq_after (SKIP i) afters) w"
using control_at.WhileBody[OF jw(3)] by (simp add: afx seq_after_snoc)
then show ?case using jw sub by blast
qed simp_all
lemma control_at_seq_after_return_edge:
"control_at Π p c0 k n r v ⟹ r = seq_after (Return i e) afters ⟹
compile Π p c0 k n = (n', en, E, K) ⟹
∃j. v = Statement j ∧ (Statement j, EA_Ret e p, FunctionResult p) ∈ E"
proof (induction arbitrary: afters n' en E K rule: control_at.induct)
case (ReturnHead i e' k n0 afters)
then show ?case by auto
next
case (SeqLeft c1 n0 r v c2 k afters)
obtain xs where afx: "afters = xs @ [c2]" and req: "r = seq_after (Return i e) xs"
using SeqLeft.prems(1) by (cases afters rule: rev_cases) (auto simp: seq_after_snoc)
from SeqLeft.prems(2) obtain n1 E1 K1 where
c1c: "compile Π p c1 (Statement (n0 + csize c1)) n0 = (n1, Statement n0, E1, K1)"
and sub: "E1 ⊆ E"
by (rule compile_Seq_leftE)
from SeqLeft.IH[OF req c1c] show ?case using sub by blast
next
case (SeqRight c2 k n0 c1 r v afters)
from SeqRight.prems(2) obtain n2 E2 K2 where
c2c: "compile Π p c2 k (n0 + csize c1) = (n2, Statement (n0 + csize c1), E2, K2)"
and sub: "E2 ⊆ E"
by (rule compile_Seq_rightE)
from SeqRight.IH[OF SeqRight.prems(1) c2c] show ?case using sub by blast
next
case (IfLeft c1 k n0 r v i b c2 afters)
from IfLeft.prems(2) obtain n1 E1 K1 where
c1c: "compile Π p c1 k (Suc n0) = (n1, Statement (Suc n0), E1, K1)"
and sub: "E1 ⊆ E"
by (rule compile_If_leftE[OF _ IfLeft.hyps(2)])
from IfLeft.IH[OF IfLeft.prems(1) c1c] show ?case using sub by blast
next
case (IfRight c2 k n0 c1 r v i b afters)
from IfRight.prems(2) obtain n2 E2 K2 where
c2c: "compile Π p c2 k (Suc n0 + csize c1)
= (n2, Statement (Suc n0 + csize c1), E2, K2)"
and sub: "E2 ⊆ E"
by (rule compile_If_rightE[OF _ IfRight.hyps(2)])
from IfRight.IH[OF IfRight.prems(1) c2c] show ?case using sub by blast
next
case (WhileBody c n0 r v ia b k afters)
obtain xs where afx: "afters = xs @ [While ia b c]" and req: "r = seq_after (Return i e) xs"
using WhileBody.prems(1) by (cases afters rule: rev_cases) (auto simp: seq_after_snoc)
from WhileBody.prems(2) obtain n1 E1 K1 where
cc: "compile Π p c (Statement n0) (Suc n0) = (n1, Statement (Suc n0), E1, K1)"
and sub: "E1 ⊆ E"
by (rule compile_While_bodyE)
from WhileBody.IH[OF req cc] show ?case using sub by blast
qed simp_all
lemma control_at_return_edge:
"control_at Π p c0 k n r v ⟹ r = Return i e ⟹
compile Π p c0 k n = (n', en, E, K) ⟹
∃j. v = Statement j ∧ (Statement j, EA_Ret e p, FunctionResult p) ∈ E"
by (rule control_at_seq_after_return_edge[where afters = "[]"]) simp_all
subsection ‹The intra-procedural source steps›
text ‹‹intra_step› is the fragment of \<^const>‹pstep› that stays inside one activation without
initiating a return: assignment, sequencing (head execution and head completion), both
conditionals, and the loop unfolding. It excludes \<^const>‹Call› (pushes a frame),
\<^const>‹Return› (produces \<^const>‹Unwind›), and the runtime-only \<^const>‹Restore› / \<^const>‹Unwind›
steps. Every intra step preserves the frame stack and keeps the residual source-shaped.›
inductive intra_step ::
"'a ptable ⇒ 'a acom × store × frame list ⇒ 'a acom × store × frame list ⇒ bool" for Π where
IAssign [intro]: "intra_step Π (Assign i x a, s, frs) (SKIP i, s(x := ⟦a⟧⇩e s), frs)"
| ISpecial [intro]: "special_table q = Some desc ⟹ classify_special desc actuals = Some sc ⟹
special_result sc s v ⟹
intra_step Π (Call i (Some x) q actuals, s, frs) (SKIP i, s(x := v), frs)"
| ICheck [intro]: "intra_step Π (VIMP_Proc.gcom.Check i l b, s, frs) (SKIP i, s, frs)"
| ISeq1 [intro]: "intra_step Π (Seq (SKIP i) c2, s, frs) (c2, s, frs)"
| ISeq2 [intro]: "intra_step Π (c1, s, frs) (c1', s', frs) ⟹
intra_step Π (Seq c1 c2, s, frs) (Seq c1' c2, s', frs)"
| IIfTrue [intro]: "truthy (⟦b⟧⇩e s) ⟹ intra_step Π (If i b c1 c2, s, frs) (c1, s, frs)"
| IIfFalse [intro]:"¬ truthy (⟦b⟧⇩e s) ⟹ intra_step Π (If i b c1 c2, s, frs) (c2, s, frs)"
| IWhile [intro]:
"intra_step Π (While i b c, s, frs) (If i b (Seq c (While i b c)) (SKIP i), s, frs)"
inductive_cases intra_SkipE [elim!]: "intra_step Π (SKIP i, s, frs) y"
inductive_cases intra_AssignE [elim!]: "intra_step Π (Assign i x a, s, frs) y"
inductive_cases intra_CheckE [elim!]: "intra_step Π (VIMP_Proc.gcom.Check i l b, s, frs) y"
inductive_cases intra_SeqE [elim]: "intra_step Π (Seq c1 c2, s, frs) y"
inductive_cases intra_IfE [elim!]: "intra_step Π (If i b c1 c2, s, frs) y"
inductive_cases intra_WhileE [elim]: "intra_step Π (While i b c, s, frs) y"
inductive_cases intra_CallE [elim]: "intra_step Π (Call i dst q actuals, s, frs) y"
inductive_cases intra_ReturnE [elim!]: "intra_step Π (Return i e, s, frs) y"
lemma intra_Seq_cases:
"intra_step Π (Seq c1 c2, s, frs) (c', s', frs') ⟹
(is_SKIP c1 ∧ c' = c2 ∧ s' = s ∧ frs' = frs) ∨
(∃c1'. c' = Seq c1' c2 ∧ frs' = frs ∧ intra_step Π (c1, s, frs) (c1', s', frs))"
by auto
lemma intra_If_cases:
"intra_step Π (If i b c1 c2, s, frs) (c', s', frs') ⟹
(truthy (⟦b⟧⇩e s) ∧ c' = c1 ∧ s' = s ∧ frs' = frs) ∨
(¬ truthy (⟦b⟧⇩e s) ∧ c' = c2 ∧ s' = s ∧ frs' = frs)"
by auto
lemma intra_step_any_frame:
"intra_step Π (c, s, frs) (c', s', frs') ⟹ intra_step Π (c, s, fr) (c', s', fr)"
by (induction "(c, s, frs)" "(c', s', frs')" arbitrary: c s frs c' s' frs'
rule: intra_step.induct) auto
lemma intra_step_frame_eq:
"intra_step Π (c, s, frs) (c', s', frs') ⟹ frs' = frs"
by (induction "(c, s, frs)" "(c', s', frs')" arbitrary: c s frs c' s' frs'
rule: intra_step.induct) auto
subsection ‹Intra-step simulation›
text ‹The base cases of that simulation, once: a located residual with an emitted action moves
along its own edge in one ‹cstep› and re-locates as a completed sub-command. Which action it
is only decides the store, which the caller supplies as ‹s' ∈ edge_step a s›.›
lemma control_at_base_step:
assumes loc: "control_at Π p c0 k n r v"
and act: "emitted_action r = Some a"
and cmp: "compile Π p c0 k n = (n', en, E, K)"
and sub: "E ⊆ intra g"
and stp: "s' ∈ edge_step a s"
obtains w where
"control_at Π p c0 k n (SKIP (stmt_ann r)) w"
"𝒢, g ⊢ (v, s, stk) →⇩c⇧* (w, s', stk)"
proof -
from control_at_emitted_edge[OF loc act cmp] obtain j w where
jw: "v = Statement j" "(Statement j, a, w) ∈ E"
"control_at Π p c0 k n (SKIP (stmt_ann r)) w" by blast
have "(Statement j, a, w) ∈ intra g" using jw(2) sub by blast
from cstep.Intra[OF this stp] have "𝒢, g ⊢ (Statement j, s, stk) →⇩c (w, s', stk)" .
then show ?thesis using jw(1) jw(3) that by auto
qed
text ‹A located conditional takes whichever assume edge the store selects and lands on the
branch located at that edge's target. \<^const>‹If› heads and loop unfoldings both reach it.›
lemma control_at_if_step:
assumes loc: "control_at Π p c0 k n (If i b c1 c2) v"
and stp: "intra_step Π (If i b c1 c2, s, frs) (c', s', frs')"
and cmp: "compile Π p c0 k n = (n', en, E, K)"
and sub: "E ⊆ intra g"
and src: "source_com (If i b c1 c2)"
shows "frs' = frs
∧ (∃v'. control_at Π p c0 k n c' v' ∧ 𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s', stk))"
proof -
from control_at_if_edges[OF loc refl src cmp] obtain j en1 en2 where
jj: "v = Statement j"
"(Statement j, EA_Assume b, en1) ∈ E" "(Statement j, EA_AssumeNot b, en2) ∈ E"
"control_at Π p c0 k n c1 en1" "control_at Π p c0 k n c2 en2" by blast
from intra_If_cases[OF stp] show ?thesis
proof (elim disjE conjE)
assume t: "truthy (⟦b⟧⇩e s)" "c' = c1" "s' = s" "frs' = frs"
have "(Statement j, EA_Assume b, en1) ∈ intra g" using jj(2) sub by blast
from star_step1[of "cstep 𝒢 g", OF cstep_assume[OF this t(1)]]
show ?thesis using t jj(1,4) by blast
next
assume f: "¬ truthy (⟦b⟧⇩e s)" "c' = c2" "s' = s" "frs' = frs"
have "(Statement j, EA_AssumeNot b, en2) ∈ intra g" using jj(3) sub by blast
from star_step1[of "cstep 𝒢 g", OF cstep_assume_not[OF this f(1)]]
show ?thesis using f jj(1,5) by blast
qed
qed
text ‹A located \<^term>‹Seq r c2› either has finished its head, and relocates to ‹c2›, or
steps inside ‹r›. Only the caller knows which sub-fragment ‹r› is located in, so it
supplies that second case.›
lemma control_at_seq_step:
assumes loc: "control_at Π p c0 k n (Seq r c2) v"
and stp: "intra_step Π (Seq r c2, s, frs) (c', s', frs')"
and cmp: "compile Π p c0 k n = (n', en, E, K)"
and sub: "E ⊆ intra g"
and src: "source_com c0"
and head: "⋀r'. intra_step Π (r, s, frs) (r', s', frs) ⟹
∃v'. control_at Π p c0 k n (Seq r' c2) v'
∧ 𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s', stk)"
shows "frs' = frs
∧ (∃v'. control_at Π p c0 k n c' v' ∧ 𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s', stk))"
using intra_Seq_cases[OF stp]
proof (elim disjE exE conjE)
assume r: "is_SKIP r" and out: "c' = c2" "s' = s" "frs' = frs"
then obtain j where rj: "r = SKIP j" by auto
from control_at_seq_skip_reloc[OF loc[unfolded rj] refl cmp sub src] show ?thesis
using out by blast
next
fix r' assume "c' = Seq r' c2" "frs' = frs" "intra_step Π (r, s, frs) (r', s', frs)"
with head show ?thesis by blast
qed
text ‹The theory's conclusion: an \<^const>‹intra_step› of a located residual leaves the frame
stack alone, and the graph follows it to a node at which the successor residual is located
again. This is the fact the simulation relation is preserved by.›
theorem intra_step_simulation:
"control_at Π p c0 k n c v ⟹
intra_step Π (c, s, frs) (c', s', frs') ⟹
compile Π p c0 k n = (n', en, E, K) ⟹ E ⊆ intra g ⟹ source_com c0 ⟹
frs' = frs
∧ (∃v'. control_at Π p c0 k n c' v'
∧ 𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s', stk))"
proof (induction arbitrary: c' s' frs' n' en E K rule: control_at.induct)
case (Skip i k n0) then show ?case by blast
next
case (Assign i x a k n0)
from Assign.prems(1) have out: "c' = (SKIP i)" "s' = s(x := ⟦a⟧⇩e s)" "frs' = frs"
by auto
have act: "emitted_action (Assign i x a) = Some (EA_Assign x a)" by simp
have mem: "s' ∈ edge_step (EA_Assign x a) s" using out(2) by simp
obtain w where "control_at Π p (Assign i x a) k n0 (SKIP i) w"
and "𝒢, g ⊢ (Statement n0, s, stk) →⇩c⇧* (w, s', stk)"
by (rule control_at_base_step[OF control_at.Assign act Assign.prems(2)
Assign.prems(3) mem]) auto
then show ?case using out(1,3) by auto
next
case (AssignDone i x a k n0) then show ?case by blast
next
case (Check i l b k n0)
from Check.prems(1) have out: "c' = (SKIP i)" "s' = s" "frs' = frs"
by auto
have act: "emitted_action (VIMP_Proc.gcom.Check i l b) = Some (EA_Check l b)" by simp
have mem: "s' ∈ edge_step (EA_Check l b) s" using out(2) by simp
obtain w where "control_at Π p (VIMP_Proc.gcom.Check i l b) k n0 (SKIP i) w"
and "𝒢, g ⊢ (Statement n0, s, stk) →⇩c⇧* (w, s', stk)"
by (rule control_at_base_step[OF control_at.Check act Check.prems(2)
Check.prems(3) mem]) auto
then show ?case using out(1,3) by auto
next
case (CheckDone i l b k n0) then show ?case by blast
next
case (SeqLeft c1 n0 r v c2 k)
from SeqLeft.prems(2) obtain n1 E1 K1 where
c1c: "compile Π p c1 (Statement (n0 + csize c1)) n0 = (n1, Statement n0, E1, K1)"
and sub: "E1 ⊆ E"
by (rule compile_Seq_leftE)
have src1: "source_com c1" using SeqLeft.prems(4) by simp
show ?case
by (rule control_at_seq_step[OF control_at.SeqLeft[OF SeqLeft.hyps] SeqLeft.prems])
(use SeqLeft.IH[OF _ c1c subset_trans[OF sub SeqLeft.prems(3)] src1] in blast)
next
case (SeqRight c2 k n0 c1 r v)
from SeqRight.prems(2) obtain n2 E2 K2 where
c2c: "compile Π p c2 k (n0 + csize c1) = (n2, Statement (n0 + csize c1), E2, K2)"
and sub: "E2 ⊆ E"
by (rule compile_Seq_rightE)
have src2: "source_com c2" using SeqRight.prems(4) by simp
from SeqRight.IH[OF SeqRight.prems(1) c2c subset_trans[OF sub SeqRight.prems(3)] src2]
have fr: "frs' = frs" and
"∃v'. control_at Π p c2 k (n0 + csize c1) c' v'
∧ 𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s', stk)" by auto
then obtain v' where v': "control_at Π p c2 k (n0 + csize c1) c' v'"
"𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s', stk)" by blast
have "control_at Π p (Seq c1 c2) k n0 c' v'"
using control_at.SeqRight[OF v'(1)] .
with fr v'(2) show ?case by blast
next
case (IfHead i b c1 c2 k n0)
show ?case by (rule control_at_if_step[OF control_at.IfHead IfHead.prems])
next
case (IfLeft c1 k n0 r v i b c2)
from IfLeft.prems(2) obtain n1 E1 K1 where
c1c: "compile Π p c1 k (Suc n0) = (n1, Statement (Suc n0), E1, K1)"
and sub1: "E1 ⊆ E"
by (rule compile_If_leftE[OF _ IfLeft.hyps(2)])
have src1: "source_com c1" using IfLeft.prems(4) by simp
from IfLeft.IH[OF IfLeft.prems(1) c1c subset_trans[OF sub1 IfLeft.prems(3)] src1]
have fr: "frs' = frs" and
"∃v'. control_at Π p c1 k (Suc n0) c' v'
∧ 𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s', stk)" by auto
then obtain v' where v': "control_at Π p c1 k (Suc n0) c' v'"
"𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s', stk)" by blast
have "control_at Π p (If i b c1 c2) k n0 c' v'" using control_at.IfLeft[OF v'(1) IfLeft.hyps(2)] .
with fr v'(2) show ?case by blast
next
case (IfRight c2 k n0 c1 r v i b)
from IfRight.prems(2) obtain n2 E2 K2 where
c2c: "compile Π p c2 k (Suc n0 + csize c1)
= (n2, Statement (Suc n0 + csize c1), E2, K2)"
and sub2: "E2 ⊆ E"
by (rule compile_If_rightE[OF _ IfRight.hyps(2)])
have src2: "source_com c2" using IfRight.prems(4) by simp
from IfRight.IH[OF IfRight.prems(1) c2c subset_trans[OF sub2 IfRight.prems(3)] src2]
have fr: "frs' = frs" and
"∃v'. control_at Π p c2 k (Suc n0 + csize c1) c' v'
∧ 𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s', stk)" by auto
then obtain v' where v': "control_at Π p c2 k (Suc n0 + csize c1) c' v'"
"𝒢, g ⊢ (v, s, stk) →⇩c⇧* (v', s', stk)" by blast
have "control_at Π p (If i b c1 c2) k n0 c' v'" using control_at.IfRight[OF v'(1) IfRight.hyps(2)]
.
with fr v'(2) show ?case by blast
next
case (IfDone i b c1 j c2 k n0) then show ?case by blast
next
case (WhileHead i b cW k n0)
from WhileHead.prems(1)
have out: "c' = If i b (Seq cW (While i b cW)) (SKIP i)" "s' = s" "frs' = frs"
by auto
have "control_at Π p (While i b cW) k n0 (If i b (Seq cW (While i b cW)) (SKIP i)) (Statement n0)"
by (rule control_at.WhileUnfolded)
then show ?case using out by auto
next
case (WhileUnfolded i b cW k n0)
have srcif: "source_com (If i b (Seq cW (While i b cW)) (SKIP i))" using WhileUnfolded.prems(4)
by simp
show ?case
by (rule control_at_if_step[OF control_at.WhileUnfolded WhileUnfolded.prems(1-3) srcif])
next
case (WhileBody cW n0 r v i b k)
from WhileBody.prems(2) obtain n1 E1 K1 where
cc: "compile Π p cW (Statement n0) (Suc n0) = (n1, Statement (Suc n0), E1, K1)"
and sub: "E1 ⊆ E"
by (rule compile_While_bodyE)
have srcW: "source_com cW" using WhileBody.prems(4) by simp
show ?case
by (rule control_at_seq_step[OF control_at.WhileBody[OF WhileBody.hyps] WhileBody.prems])
(use WhileBody.IH[OF _ cc subset_trans[OF sub WhileBody.prems(3)] srcW] in blast)
next
case (WhileDone i b cW k n0) then show ?case by blast
next
case (CallHead i dst q actuals k n0)
from CallHead.prems(1) obtain x desc sc v where
out: "dst = Some x" "special_table q = Some desc" "classify_special desc actuals = Some sc"
"special_result sc s v" "c' = (SKIP i)" "s' = s(x := v)" "frs' = frs"
by auto
have act: "emitted_action (Call i (Some x) q actuals) = Some (EA_Special sc x)"
using out(2,3) by simp
have mem: "s' ∈ edge_step (EA_Special sc x) s" using out(4,6) by auto
obtain w where "control_at Π p (Call i (Some x) q actuals) k n0 (SKIP i) w"
and "𝒢, g ⊢ (Statement n0, s, stk) →⇩c⇧* (w, s', stk)"
by (rule control_at_base_step[OF control_at.CallHead act
CallHead.prems(2)[unfolded out(1)] CallHead.prems(3) mem]) auto
then show ?case using out(1,5,7) by auto
next
case (CallDone i dst q actuals k n0) then show ?case by blast
next
case (ReturnHead i e k n0) then show ?case by blast
qed
end