Theory Source_Progress
theory Source_Progress
imports Simulation_Preservation
begin
section ‹Reachable source configurations are never stuck›
text ‹
A stuck source configuration would silently cut executions short: every later program point
would be unreachable under \<^const>‹pstep›, so an unreachability verdict could hold for the
wrong reason. Progress rules this out for accepted programs: a reachable configuration
either has finished --- \<^const>‹SKIP› with no caller frame left --- or can take a step.
The shapes that could get stuck are the runtime markers: a bare \<^const>‹Unwind›, and a
\<^const>‹Restore› or \<^term>‹Seq (Unwind j) (Restore i)› with no frame to pop. \<^const>‹csim› already
pairs every \<^const>‹Restore› with its frame and confines \<^const>‹Unwind› to the returning
phase, so it is reused here as the invariant; the only additional fact is that call sites
are well formed.
›
subsection ‹Source commands›
lemma pstep_seq_after_lift:
"𝒢, Π ⊢ (w, s, frs) →⇩p (w', s', frs')
⟹ 𝒢, Π ⊢ (seq_after w afters, s, frs) →⇩p (seq_after w' afters, s', frs')"
by (induction afters arbitrary: w w') auto
text ‹A well-formed source command is \<^const>‹SKIP› or steps, at any frame stack. A
\<^const>‹Return› steps too; whether its \<^const>‹Unwind› can later pop a frame is the
simulation's concern, not this lemma's.›
lemma wf_source_com_progress:
assumes distinct_formals: "⋀p decl. Π p = Some decl ⟹ distinct (formals decl)"
and "wf_source_com Π c"
shows "is_SKIP c ∨ (∃cfg'. 𝒢, Π ⊢ (c, s, frs) →⇩p cfg')"
using assms(2)
proof (induction c)
case (Seq c1 c2)
from Seq.prems have "wf_source_com Π c1" by simp
from Seq.IH(1)[OF this] show ?case
proof
assume "is_SKIP c1"
then obtain j where "c1 = SKIP j" by auto
then show ?thesis by blast
next
assume "∃cfg'. 𝒢, Π ⊢ (c1, s, frs) →⇩p cfg'"
then obtain c1' s' frs' where "𝒢, Π ⊢ (c1, s, frs) →⇩p (c1', s', frs')" by auto
then show ?thesis by blast
qed
next
case (If i b c1 c2)
show ?case by (cases "truthy (⟦b⟧⇩e s)") blast+
next
case (Return i e)
show ?case by (cases e) blast+
next
case (Call i dst p actuals)
show ?case
proof (cases "special_table p")
case None
with Call.prems obtain decl where
decl: "Π p = Some decl" and arity: "length actuals = length (formals decl)"
by (auto split: option.splits)
show ?thesis
using pstep_Call[where Π = Π and p = p, OF decl arity distinct_formals[OF decl]]
by blast
next
case (Some desc)
with Call.prems obtain sc x where
sc: "classify_special desc actuals = Some sc" and dst: "dst = Some x"
by (auto split: option.splits)
obtain v where "special_result sc s v" using special_result_ex by blast
with Some sc show ?thesis unfolding dst by blast
qed
qed auto
lemma control_at_wf_source_com:
"control_at Π p c0 k n r v ⟹ wf_source_com Π c0 ⟹ wf_source_com Π r"
by (induction rule: control_at.induct) auto
subsection ‹The frame-pop phase›
text ‹
A configuration unwinding a finished frame keeps stepping until it is
‹Unwind› (‹unwinding_progress›); a ‹Returning› one then pops its frame.
›
lemma unwinding_progress:
"unwinding u ⟹ (⋀j. u ≠ Unwind j) ⟹ ∃u'. 𝒢, Π ⊢ (u, s, frs) →⇩p (u', s, frs)"
proof (induction u)
case (Seq u1 c2)
then have u1: "unwinding u1" and c2: "¬ is_Restore c2" by simp_all
show ?case
proof (cases "∃j. u1 = Unwind j")
case True
then obtain j where "u1 = Unwind j" by blast
then show ?thesis using c2 by blast
next
case False
then have "u1 ≠ Unwind j" for j by blast
from Seq.IH(1)[OF u1 this] obtain u1' where "𝒢, Π ⊢ (u1, s, frs) →⇩p (u1', s, frs)" ..
then show ?thesis by blast
qed
next
case (Unwind x)
then show ?case by blast
qed simp_all
text ‹The frame a ‹Returning› configuration carries is what lets it pop.›
lemma pop_ready_progress:
assumes "pop_ready w"
shows "∃cfg'. 𝒢, Π ⊢ (w, s, Frame fr dst # frs) →⇩p cfg'"
using assms
proof (cases w rule: pop_ready.cases)
case 1
then show ?thesis by blast
next
case (2 u)
with assms have uw: "unwinding u" by simp
show ?thesis
proof (cases "∃j. u = Unwind j")
case True
then obtain j where "u = Unwind j" by blast
then show ?thesis using 2 by blast
next
case False
then have "u ≠ Unwind j" for j by blast
from unwinding_progress[OF uw this] obtain u' where
"𝒢, Π ⊢ (u, s, Frame fr dst # frs) →⇩p (u', s, Frame fr dst # frs)" ..
then show ?thesis using 2 by blast
qed
qed (use assms in simp_all)
subsection ‹Progress under the simulation relation›
text ‹Only a ‹Base› activation can have finished: ‹Nested› and ‹Returning› both carry a
caller frame and a pending \<^const>‹Restore› that will pop it. No graph fact is used, so
the relation serves here purely as a shape invariant.›
lemma csim_progress_cfg:
assumes "Π, g, ρ ⊢ cfg ≈ dg"
and wf_decls: "⋀p decl. Π p = Some decl ⟹ wf_proc_decl 𝒢 Π decl"
shows "(is_SKIP (fst cfg) ∧ snd (snd cfg) = []) ∨ (∃cfg'. 𝒢, Π ⊢ cfg →⇩p cfg')"
using assms(1)
proof (induction rule: csim.induct)
case (Base p body_p k n c v s)
from Base.hyps(2) obtain decl where decl: "Π p = Some decl" and body_p: "body_p = body decl"
by (rule compiled_at_decl)
have "wf_source_com Π body_p"
using wf_decls[OF decl] body_p by (simp add: wf_proc_decl_def)
from control_at_wf_source_com[OF Base.hyps(1) this]
have "wf_source_com Π c" .
from wf_source_com_progress[OF _ this, of 𝒢 s "[]"] wf_decls
show ?case by (auto simp: wf_proc_decl_def)
next
case (Nested q inner s frs v stk pc body_pc kc nc i afters cont dst args site caller)
let ?F = "[Frame caller dst]"
have "∃w'. 𝒢, Π ⊢ (Seq inner (Restore i), s, frs @ ?F) →⇩p w'"
using Nested.IH
proof
assume "is_SKIP (fst (inner, s, frs)) ∧ snd (snd (inner, s, frs)) = []"
then obtain j where "inner = SKIP j" by auto
then show ?thesis by blast
next
assume "∃cfg'. 𝒢, Π ⊢ (inner, s, frs) →⇩p cfg'"
then obtain i' s' f' where "𝒢, Π ⊢ (inner, s, frs) →⇩p (i', s', f')" by auto
from pstep_frame_extend[OF this, of ?F]
show ?thesis by blast
qed
then obtain w' s' f' where "𝒢, Π ⊢ (Seq inner (Restore i), s, frs @ ?F) →⇩p (w', s', f')"
by auto
from pstep_seq_after_lift[OF this, of afters] show ?case by auto
next
case (Returning w i pc body_pc kc nc afters cont dst p args site callee caller)
from pop_ready_progress[OF Returning.hyps(1), of 𝒢 Π callee caller dst "[]"]
obtain w' s' f' where "𝒢, Π ⊢ (w, callee, [Frame caller dst]) →⇩p (w', s', f')"
by auto
from pstep_seq_after_lift[OF this, of afters] show ?case by auto
qed
theorem csim_progress:
assumes "Π, g, ρ ⊢ (c, s, frs) ≈ dg"
and "⋀p decl. Π p = Some decl ⟹ wf_proc_decl 𝒢 Π decl"
shows "(is_SKIP c ∧ frs = []) ∨ (∃cfg'. 𝒢, Π ⊢ (c, s, frs) →⇩p cfg')"
using csim_progress_cfg[OF assms] by simp
subsection ‹Progress for accepted programs›
text ‹
The premise is source well-formedness alone; no compiled graph is involved. \<^const>‹csim›
still needs some graph with every body embedded, and the complete graph --- every edge
present --- embeds anything, so it stands in for the compiler's output. The finished shape
is exactly \<^term>‹(SKIP, s, [])›: ‹main› contains no \<^const>‹Return›
(\<^const>‹no_return›), so a top-level \<^const>‹Unwind› never arises.
›
theorem source_progress:
assumes wf: "wf_source_program 𝒢 Π"
and run: "𝒢, Π ⊢ (main_body Π, s0, []) →⇩p⇧* (c, s, frs)"
shows "(is_SKIP c ∧ frs = []) ∨ (∃cfg'. 𝒢, Π ⊢ (c, s, frs) →⇩p cfg')"
proof -
define g :: cfg where
"g = ⦇intra = UNIV, calls = UNIV, cfg_entry = FunctionEntry prog_main_name⦈"
have pc: "procs_embedded Π g"
unfolding procs_embedded_def
proof (intro allI impI)
fix p decl assume pd: "Π p = Some decl"
obtain n' en E K where
cb: "compile Π p (body decl) (Statement (0 + csize (body decl))) 0 = (n', en, E, K)"
by (metis prod_cases4)
have "source_com (body decl)" "special_table p = None"
using wf_source_programD(6,7)[OF wf] pd by (auto simp: source_pi_def)
with cb show "∃k n n' en E K. compile Π p (body decl) k n = (n', en, E, K)
∧ E ⊆ intra g ∧ K ⊆ calls g
∧ (FunctionEntry p, EA_Body p, en) ∈ intra g
∧ (k, EA_Ret None p, FunctionResult p) ∈ intra g
∧ k = Statement (n + csize (body decl))
∧ source_com (body decl) ∧ special_table p = None"
by (intro exI[of _ "Statement (0 + csize (body decl))"] exI[of _ "0 :: nat"] exI[of _ n']
exI[of _ en] exI[of _ E] exI[of _ K])
(simp add: g_def)
qed
have main_decl: "Π prog_main_name = Some ⦇formals = [], body = main_body Π⦈"
by (rule wf_source_programD(2)[OF wf])
obtain k n en where
cacc: "compiled_at Π g prog_main_name (body ⦇formals = [], body = main_body Π⦈) k n"
and ctrl: "control_at Π prog_main_name (body ⦇formals = [], body = main_body Π⦈) k n
(body ⦇formals = [], body = main_body Π⦈) en"
by (rule procs_embedded_activation[OF pc main_decl])
have base: "Π, g, prog_main_name ⊢ (main_body Π, s0, []) ≈ (en, s0, [])"
using csim.Base[OF ctrl cacc] by simp
have safe: "return_safe (main_body Π)"
using wf_source_programD(8,4)[OF wf] by (rule return_safe_if_no_return)
from csim_star[OF base pc safe run] obtain dg where "Π, g, prog_main_name ⊢ (c, s, frs) ≈ dg"
by blast
then show ?thesis
by (rule csim_progress) (rule wf_source_programD(5)[OF wf])
qed
end