Theory PCFG

Up to index of Isabelle/HOL/Jinja/HRB-Slicing

theory PCFG
imports ProcState
header {* \isaheader{Definition of the CFG} *}

theory PCFG imports ProcState begin

definition Main :: "pname"
where "Main = ''Main''"

datatype label = Label nat | Entry | Exit

subsection{* The CFG for every procedure *}

subsubsection {* Definition of @{text "⊕"} *}

fun label_incr :: "label => nat => label" ("_ ⊕ _" 60)
where "(Label l) ⊕ i = Label (l + i)"
| "Entry ⊕ i = Entry"
| "Exit ⊕ i = Exit"


lemma Exit_label_incr [dest]: "Exit = n ⊕ i ==> n = Exit"
by(cases n,auto)

lemma label_incr_Exit [dest]: "n ⊕ i = Exit ==> n = Exit"
by(cases n,auto)

lemma Entry_label_incr [dest]: "Entry = n ⊕ i ==> n = Entry"
by(cases n,auto)

lemma label_incr_Entry [dest]: "n ⊕ i = Entry ==> n = Entry"
by(cases n,auto)

lemma label_incr_inj:
"n ⊕ c = n' ⊕ c ==> n = n'"
by(cases n)(cases n',auto)+

lemma label_incr_simp:"n ⊕ i = m ⊕ (i + j) ==> n = m ⊕ j"
by(cases n,auto,cases m,auto)

lemma label_incr_simp_rev:"m ⊕ (j + i) = n ⊕ i ==> m ⊕ j = n"
by(cases n,auto,cases m,auto)

lemma label_incr_start_Node_smaller:
"Label l = n ⊕ i ==> n = Label (l - i)"
by(cases n,auto)

lemma label_incr_start_Node_smaller_rev:
"n ⊕ i = Label l ==> n = Label (l - i)"
by(cases n,auto)


lemma label_incr_ge:"Label l = n ⊕ i ==> l ≥ i"
by(cases n) auto

lemma label_incr_0 [dest]:
"[|Label 0 = n ⊕ i; i > 0|] ==> False"
by(cases n) auto

lemma label_incr_0_rev [dest]:
"[|n ⊕ i = Label 0; i > 0|] ==> False"
by(cases n) auto

subsubsection {* The edges of the procedure CFG *}

text {* Control flow information in this language is the node, to which we return
after the calles procedure is finished. *}


datatype p_edge_kind =
IEdge "(vname,val,pname × label,pname) edge_kind"
| CEdge "pname × expr list × vname list"


type_synonym p_edge = "(label × p_edge_kind × label)"

inductive Proc_CFG :: "cmd => label => p_edge_kind => label => bool"
("_ \<turnstile> _ -_->p _")
where

Proc_CFG_Entry_Exit:
"prog \<turnstile> Entry -IEdge (λs. False)\<surd>->p Exit"

| Proc_CFG_Entry:
"prog \<turnstile> Entry -IEdge (λs. True)\<surd>->p Label 0"

| Proc_CFG_Skip:
"Skip \<turnstile> Label 0 -IEdge \<Up>id->p Exit"

| Proc_CFG_LAss:
"V:=e \<turnstile> Label 0 -IEdge \<Up>(λcf. update cf V e)->p Label 1"

| Proc_CFG_LAssSkip:
"V:=e \<turnstile> Label 1 -IEdge \<Up>id->p Exit"

| Proc_CFG_SeqFirst:
"[|c1 \<turnstile> n -et->p n'; n' ≠ Exit|] ==> c1;;c2 \<turnstile> n -et->p n'"

| Proc_CFG_SeqConnect:
"[|c1 \<turnstile> n -et->p Exit; n ≠ Entry|] ==> c1;;c2 \<turnstile> n -et->p Label #:c1"

| Proc_CFG_SeqSecond:
"[|c2 \<turnstile> n -et->p n'; n ≠ Entry|] ==> c1;;c2 \<turnstile> n ⊕ #:c1 -et->p n' ⊕ #:c1"

| Proc_CFG_CondTrue:
"if (b) c1 else c2 \<turnstile> Label 0
-IEdge (λcf. state_check cf b (Some true))\<surd>->p Label 1"


| Proc_CFG_CondFalse:
"if (b) c1 else c2 \<turnstile> Label 0 -IEdge (λcf. state_check cf b (Some false))\<surd>->p
Label (#:c1 + 1)"


| Proc_CFG_CondThen:
"[|c1 \<turnstile> n -et->p n'; n ≠ Entry|] ==> if (b) c1 else c2 \<turnstile> n ⊕ 1 -et->p n' ⊕ 1"

| Proc_CFG_CondElse:
"[|c2 \<turnstile> n -et->p n'; n ≠ Entry|]
==> if (b) c1 else c2 \<turnstile> n ⊕ (#:c1 + 1) -et->p n' ⊕ (#:c1 + 1)"


| Proc_CFG_WhileTrue:
"while (b) c' \<turnstile> Label 0 -IEdge (λcf. state_check cf b (Some true))\<surd>->p Label 2"

| Proc_CFG_WhileFalse:
"while (b) c' \<turnstile> Label 0 -IEdge (λcf. state_check cf b (Some false))\<surd>->p Label 1"

| Proc_CFG_WhileFalseSkip:
"while (b) c' \<turnstile> Label 1 -IEdge \<Up>id->p Exit"

| Proc_CFG_WhileBody:
"[|c' \<turnstile> n -et->p n'; n ≠ Entry; n' ≠ Exit|]
==> while (b) c' \<turnstile> n ⊕ 2 -et->p n' ⊕ 2"


| Proc_CFG_WhileBodyExit:
"[|c' \<turnstile> n -et->p Exit; n ≠ Entry|] ==> while (b) c' \<turnstile> n ⊕ 2 -et->p Label 0"

| Proc_CFG_Call:
"Call p es rets \<turnstile> Label 0 -CEdge (p,es,rets)->p Label 1"

| Proc_CFG_CallSkip:
"Call p es rets \<turnstile> Label 1 -IEdge \<Up>id->p Exit"


subsubsection{* Some lemmas about the procedure CFG *}

lemma Proc_CFG_Exit_no_sourcenode [dest]:
"prog \<turnstile> Exit -et->p n' ==> False"
by(induct prog n"Exit" et n' rule:Proc_CFG.induct,auto)


lemma Proc_CFG_Entry_no_targetnode [dest]:
"prog \<turnstile> n -et->p Entry ==> False"
by(induct prog n et n'"Entry" rule:Proc_CFG.induct,auto)


lemma Proc_CFG_IEdge_intra_kind:
"prog \<turnstile> n -IEdge et->p n' ==> intra_kind et"
by(induct prog n x"IEdge et" n' rule:Proc_CFG.induct,auto simp:intra_kind_def)


lemma [dest]:"prog \<turnstile> n -IEdge (Q:r\<hookrightarrow>pfs)->p n' ==> False"
by(fastforce dest:Proc_CFG_IEdge_intra_kind simp:intra_kind_def)

lemma [dest]:"prog \<turnstile> n -IEdge (Q\<hookleftarrow>pf)->p n' ==> False"
by(fastforce dest:Proc_CFG_IEdge_intra_kind simp:intra_kind_def)


lemma Proc_CFG_sourcelabel_less_num_nodes:
"prog \<turnstile> Label l -et->p n' ==> l < #:prog"
proof(induct prog "Label l" et n' arbitrary:l rule:Proc_CFG.induct)
case (Proc_CFG_SeqFirst c1 et n' c2 l)
thus ?case by simp
next
case (Proc_CFG_SeqConnect c1 et c2 l)
thus ?case by simp
next
case (Proc_CFG_SeqSecond c2 n et n' c1 l)
note n = `n ⊕ #:c1 = Label l`
note IH = `!!l. n = Label l ==> l < #:c2`
from n obtain l' where l':"n = Label l'" by(cases n) auto
from IH[OF this] have "l' < #:c2" .
with n l' show ?case by simp
next
case (Proc_CFG_CondThen c1 n et n' b c2 l)
note n = `n ⊕ 1 = Label l`
note IH = `!!l. n = Label l ==> l < #:c1`
from n obtain l' where l':"n = Label l'" by(cases n) auto
from IH[OF this] have "l' < #:c1" .
with n l' show ?case by simp
next
case (Proc_CFG_CondElse c2 n et n' b c1 l)
note n = `n ⊕ (#:c1 + 1) = Label l`
note IH = `!!l. n = Label l ==> l < #:c2`
from n obtain l' where l':"n = Label l'" by(cases n) auto
from IH[OF this] have "l' < #:c2" .
with n l' show ?case by simp
next
case (Proc_CFG_WhileBody c' n et n' b l)
note n = `n ⊕ 2 = Label l`
note IH = `!!l. n = Label l ==> l < #:c'`
from n obtain l' where l':"n = Label l'" by(cases n) auto
from IH[OF this] have "l' < #:c'" .
with n l' show ?case by simp
next
case (Proc_CFG_WhileBodyExit c' n et b l)
note n = `n ⊕ 2 = Label l`
note IH = `!!l. n = Label l ==> l < #:c'`
from n obtain l' where l':"n = Label l'" by(cases n) auto
from IH[OF this] have "l' < #:c'" .
with n l' show ?case by simp
qed (auto simp:num_inner_nodes_gr_0)


lemma Proc_CFG_targetlabel_less_num_nodes:
"prog \<turnstile> n -et->p Label l ==> l < #:prog"
proof(induct prog n et "Label l" arbitrary:l rule:Proc_CFG.induct)
case (Proc_CFG_SeqFirst c1 n et c2 l)
thus ?case by simp
next
case (Proc_CFG_SeqSecond c2 n et n' c1 l)
note n' = `n' ⊕ #:c1 = Label l`
note IH = `!!l. n' = Label l ==> l < #:c2`
from n' obtain l' where l':"n' = Label l'" by(cases n') auto
from IH[OF this] have "l' < #:c2" .
with n' l' show ?case by simp
next
case (Proc_CFG_CondThen c1 n et n' b c2 l)
note n' = `n' ⊕ 1 = Label l`
note IH = `!!l. n' = Label l ==> l < #:c1`
from n' obtain l' where l':"n' = Label l'" by(cases n') auto
from IH[OF this] have "l' < #:c1" .
with n' l' show ?case by simp
next
case (Proc_CFG_CondElse c2 n et n' b c1 l)
note n' = `n' ⊕ (#:c1 + 1) = Label l`
note IH = `!!l. n' = Label l ==> l < #:c2`
from n' obtain l' where l':"n' = Label l'" by(cases n') auto
from IH[OF this] have "l' < #:c2" .
with n' l' show ?case by simp
next
case (Proc_CFG_WhileBody c' n et n' b l)
note n' = `n' ⊕ 2 = Label l`
note IH = `!!l. n' = Label l ==> l < #:c'`
from n' obtain l' where l':"n' = Label l'" by(cases n') auto
from IH[OF this] have "l' < #:c'" .
with n' l' show ?case by simp
qed (auto simp:num_inner_nodes_gr_0)


lemma Proc_CFG_EntryD:
"prog \<turnstile> Entry -et->p n'
==> (n' = Exit ∧ et = IEdge(λs. False)\<surd>) ∨ (n' = Label 0 ∧ et = IEdge (λs. True)\<surd>)"

by(induct prog n"Entry" et n' rule:Proc_CFG.induct,auto)


lemma Proc_CFG_Exit_edge:
obtains l et where "prog \<turnstile> Label l -IEdge et->p Exit" and "l ≤ #:prog"
proof(atomize_elim)
show "∃l et. prog \<turnstile> Label l -IEdge et->p Exit ∧ l ≤ #:prog"
proof(induct prog)
case Skip
have "Skip \<turnstile> Label 0 -IEdge \<Up>id->p Exit" by(rule Proc_CFG_Skip)
thus ?case by fastforce
next
case (LAss V e)
have "V:=e \<turnstile> Label 1 -IEdge \<Up>id->p Exit" by(rule Proc_CFG_LAssSkip)
thus ?case by fastforce
next
case (Seq c1 c2)
from `∃l et. c2 \<turnstile> Label l -IEdge et->p Exit ∧ l ≤ #:c2`
obtain l et where "c2 \<turnstile> Label l -IEdge et->p Exit" and "l ≤ #:c2" by blast
hence "c1;;c2 \<turnstile> Label l ⊕ #:c1 -IEdge et->p Exit ⊕ #:c1"
by(fastforce intro:Proc_CFG_SeqSecond)
with `l ≤ #:c2` show ?case by fastforce
next
case (Cond b c1 c2)
from `∃l et. c1 \<turnstile> Label l -IEdge et->p Exit ∧ l ≤ #:c1`
obtain l et where "c1 \<turnstile> Label l -IEdge et->p Exit" and "l ≤ #:c1" by blast
hence "if (b) c1 else c2 \<turnstile> Label l ⊕ 1 -IEdge et->p Exit ⊕ 1"
by(fastforce intro:Proc_CFG_CondThen)
with `l ≤ #:c1` show ?case by fastforce
next
case (While b c')
have "while (b) c' \<turnstile> Label 1 -IEdge \<Up>id->p Exit" by(rule Proc_CFG_WhileFalseSkip)
thus ?case by fastforce
next
case (Call p es rets)
have "Call p es rets \<turnstile> Label 1 -IEdge \<Up>id->p Exit" by(rule Proc_CFG_CallSkip)
thus ?case by fastforce
qed
qed


text {* Lots of lemmas for call edges @{text "…"} *}

lemma Proc_CFG_Call_Labels:
"prog \<turnstile> n -CEdge (p,es,rets)->p n' ==> ∃l. n = Label l ∧ n' = Label (Suc l)"
by(induct prog n et"CEdge (p,es,rets)" n' rule:Proc_CFG.induct,auto)


lemma Proc_CFG_Call_target_0:
"prog \<turnstile> n -CEdge (p,es,rets)->p Label 0 ==> n = Entry"
by(induct prog n et"CEdge (p,es,rets)" n'"Label 0" rule:Proc_CFG.induct)
(auto dest:Proc_CFG_Call_Labels)


lemma Proc_CFG_Call_Intra_edge_not_same_source:
"[|prog \<turnstile> n -CEdge (p,es,rets)->p n'; prog \<turnstile> n -IEdge et->p n''|] ==> False"
proof(induct prog n "CEdge (p,es,rets)" n' arbitrary:n'' rule:Proc_CFG.induct)
case (Proc_CFG_SeqFirst c1 n n' c2)
note IH = `!!n''. c1 \<turnstile> n -IEdge et->p n'' ==> False`
from `c1;;c2 \<turnstile> n -IEdge et->p n''` `c1 \<turnstile> n -CEdge (p, es, rets)->p n'`
`n' ≠ Exit`
obtain nx where "c1 \<turnstile> n -IEdge et->p nx"
apply - apply(erule Proc_CFG.cases)
apply(auto intro:Proc_CFG_Entry_Exit Proc_CFG_Entry)
by(case_tac n)(auto dest:Proc_CFG_sourcelabel_less_num_nodes)
then show ?case by (rule IH)
next
case (Proc_CFG_SeqConnect c1 n c2)
from `c1 \<turnstile> n -CEdge (p, es, rets)->p Exit`
show ?case by(fastforce dest:Proc_CFG_Call_Labels)
next
case (Proc_CFG_SeqSecond c2 n n' c1)
note IH = `!!n''. c2 \<turnstile> n -IEdge et->p n'' ==> False`
from `c1;;c2 \<turnstile> n ⊕ #:c1 -IEdge et->p n''` `c2 \<turnstile> n -CEdge (p, es, rets)->p n'`
`n ≠ Entry`
obtain nx where "c2 \<turnstile> n -IEdge et->p nx"
apply - apply(erule Proc_CFG.cases,auto)
apply(cases n) apply(auto dest:Proc_CFG_sourcelabel_less_num_nodes)
apply(cases n) apply(auto dest:Proc_CFG_sourcelabel_less_num_nodes)
by(cases n,auto,case_tac n,auto)
then show ?case by (rule IH)
next
case (Proc_CFG_CondThen c1 n n' b c2)
note IH = `!!n''. c1 \<turnstile> n -IEdge et->p n'' ==> False`
from `if (b) c1 else c2 \<turnstile> n ⊕ 1 -IEdge et->p n''` `c1 \<turnstile> n -CEdge (p, es, rets)->p n'`
`n ≠ Entry`
obtain nx where "c1 \<turnstile> n -IEdge et->p nx"
apply - apply(erule Proc_CFG.cases,auto)
apply(cases n) apply auto apply(case_tac n) apply auto
apply(cases n) apply auto
by(case_tac n)(auto dest:Proc_CFG_sourcelabel_less_num_nodes)
then show ?case by (rule IH)
next
case (Proc_CFG_CondElse c2 n n' b c1)
note IH = `!!n''. c2 \<turnstile> n -IEdge et->p n'' ==> False`
from `if (b) c1 else c2 \<turnstile> n ⊕ #:c1 + 1 -IEdge et->p n''` `c2 \<turnstile> n -CEdge (p, es, rets)->p n'`
`n ≠ Entry`
obtain nx where "c2 \<turnstile> n -IEdge et->p nx"
apply - apply(erule Proc_CFG.cases,auto)
apply(cases n) apply auto
apply(case_tac n) apply(auto dest:Proc_CFG_sourcelabel_less_num_nodes)
by(cases n,auto,case_tac n,auto)
then show ?case by (rule IH)
next
case (Proc_CFG_WhileBody c' n n' b)
note IH = `!!n''. c' \<turnstile> n -IEdge et->p n'' ==> False`
from `while (b) c' \<turnstile> n ⊕ 2 -IEdge et->p n''` `c' \<turnstile> n -CEdge (p, es, rets)->p n'`
`n ≠ Entry` `n' ≠ Exit`
obtain nx where "c' \<turnstile> n -IEdge et->p nx"
apply - apply(erule Proc_CFG.cases,auto)
apply(drule label_incr_ge[OF sym]) apply simp
apply(cases n) apply auto apply(case_tac n) apply auto
by(cases n,auto,case_tac n,auto)
then show ?case by (rule IH)
next
case (Proc_CFG_WhileBodyExit c' n b)
from `c' \<turnstile> n -CEdge (p, es, rets)->p Exit`
show ?case by(fastforce dest:Proc_CFG_Call_Labels)
next
case Proc_CFG_Call
from `Call p es rets \<turnstile> Label 0 -IEdge et->p n''`
show ?case by(fastforce elim:Proc_CFG.cases)
qed


lemma Proc_CFG_Call_Intra_edge_not_same_target:
"[|prog \<turnstile> n -CEdge (p,es,rets)->p n'; prog \<turnstile> n'' -IEdge et->p n'|] ==> False"
proof(induct prog n "CEdge (p,es,rets)" n' arbitrary:n'' rule:Proc_CFG.induct)
case (Proc_CFG_SeqFirst c1 n n' c2)
note IH = `!!n''. c1 \<turnstile> n'' -IEdge et->p n' ==> False`
from `c1;;c2 \<turnstile> n'' -IEdge et->p n'` `c1 \<turnstile> n -CEdge (p, es, rets)->p n'`
`n' ≠ Exit`
have "c1 \<turnstile> n'' -IEdge et->p n'"
apply - apply(erule Proc_CFG.cases)
apply(auto intro:Proc_CFG_Entry dest:Proc_CFG_targetlabel_less_num_nodes)
by(case_tac n')(auto dest:Proc_CFG_targetlabel_less_num_nodes)
then show ?case by (rule IH)
next
case (Proc_CFG_SeqConnect c1 n c2)
from `c1 \<turnstile> n -CEdge (p, es, rets)->p Exit`
show ?case by(fastforce dest:Proc_CFG_Call_Labels)
next
case (Proc_CFG_SeqSecond c2 n n' c1)
note IH = `!!n''. c2 \<turnstile> n'' -IEdge et->p n' ==> False`
from `c1;;c2 \<turnstile> n'' -IEdge et->p n' ⊕ #:c1` `c2 \<turnstile> n -CEdge (p, es, rets)->p n'`
`n ≠ Entry`
obtain nx where "c2 \<turnstile> nx -IEdge et->p n'"
apply - apply(erule Proc_CFG.cases,auto)
apply(fastforce intro:Proc_CFG_Entry_Exit)
apply(cases n') apply(auto dest:Proc_CFG_targetlabel_less_num_nodes)
apply(cases n') apply(auto dest:Proc_CFG_Call_target_0)
apply(cases n') apply(auto dest:Proc_CFG_Call_Labels)
by(case_tac n') auto
then show ?case by (rule IH)
next
case (Proc_CFG_CondThen c1 n n' b c2)
note IH = `!!n''. c1 \<turnstile> n'' -IEdge et->p n' ==> False`
from `if (b) c1 else c2 \<turnstile> n'' -IEdge et->p n' ⊕ 1` `c1 \<turnstile> n -CEdge (p, es, rets)->p n'`
`n ≠ Entry`
obtain nx where "c1 \<turnstile> nx -IEdge et->p n'"
apply - apply(erule Proc_CFG.cases,auto)
apply(cases n') apply(auto intro:Proc_CFG_Entry_Exit)
apply(cases n') apply(auto dest:Proc_CFG_Call_target_0)
apply(cases n') apply(auto dest:Proc_CFG_targetlabel_less_num_nodes)
apply(cases n') apply auto apply(case_tac n') apply auto
apply(cases n') apply auto
apply(case_tac n') apply(auto dest:Proc_CFG_targetlabel_less_num_nodes)
by(case_tac n')(auto dest:Proc_CFG_Call_Labels)
then show ?case by (rule IH)
next
case (Proc_CFG_CondElse c2 n n' b c1)
note IH = `!!n''. c2 \<turnstile> n'' -IEdge et->p n' ==> False`
from `if (b) c1 else c2 \<turnstile> n'' -IEdge et->p n' ⊕ #:c1 + 1` `c2 \<turnstile> n -CEdge (p, es, rets)->p n'`
`n ≠ Entry`
obtain nx where "c2 \<turnstile> nx -IEdge et->p n'"
apply - apply(erule Proc_CFG.cases,auto)
apply(cases n') apply(auto intro:Proc_CFG_Entry_Exit)
apply(cases n') apply(auto dest:Proc_CFG_Call_target_0)
apply(cases n') apply(auto dest:Proc_CFG_Call_target_0)
apply(cases n') apply auto
apply(case_tac n') apply(auto dest:Proc_CFG_targetlabel_less_num_nodes)
apply(case_tac n') apply(auto dest:Proc_CFG_Call_Labels)
by(cases n',auto,case_tac n',auto)
then show ?case by (rule IH)
next
case (Proc_CFG_WhileBody c' n n' b)
note IH = `!!n''. c' \<turnstile> n'' -IEdge et->p n' ==> False`
from `while (b) c' \<turnstile> n'' -IEdge et->p n' ⊕ 2` `c' \<turnstile> n -CEdge (p, es, rets)->p n'`
`n ≠ Entry` `n' ≠ Exit`
obtain nx where "c' \<turnstile> nx -IEdge et->p n'"
apply - apply(erule Proc_CFG.cases,auto)
apply(cases n') apply(auto dest:Proc_CFG_Call_target_0)
apply(cases n') apply auto
by(cases n',auto,case_tac n',auto)
then show ?case by (rule IH)
next
case (Proc_CFG_WhileBodyExit c' n b)
from `c' \<turnstile> n -CEdge (p, es, rets)->p Exit`
show ?case by(fastforce dest:Proc_CFG_Call_Labels)
next
case Proc_CFG_Call
from `Call p es rets \<turnstile> n'' -IEdge et->p Label 1`
show ?case by(fastforce elim:Proc_CFG.cases)
qed


lemma Proc_CFG_Call_nodes_eq:
"[|prog \<turnstile> n -CEdge (p,es,rets)->p n'; prog \<turnstile> n -CEdge (p',es',rets')->p n''|]
==> n' = n'' ∧ p = p' ∧ es = es' ∧ rets = rets'"

proof(induct prog n "CEdge (p,es,rets)" n' arbitrary:n'' rule:Proc_CFG.induct)
case (Proc_CFG_SeqFirst c1 n n' c2)
note IH = `!!n''. c1 \<turnstile> n -CEdge (p',es',rets')->p n''
==> n' = n'' ∧ p = p' ∧ es = es' ∧ rets = rets'`

from `c1;; c2 \<turnstile> n -CEdge (p',es',rets')->p n''` `c1 \<turnstile> n -CEdge (p,es,rets)->p n'`
have "c1 \<turnstile> n -CEdge (p',es',rets')->p n''"
apply - apply(erule Proc_CFG.cases,auto)
apply(fastforce dest:Proc_CFG_Call_Labels)
by(case_tac n,(fastforce dest:Proc_CFG_sourcelabel_less_num_nodes)+)
then show ?case by (rule IH)
next
case (Proc_CFG_SeqConnect c1 n c2)
from `c1 \<turnstile> n -CEdge (p,es,rets)->p Exit` have False
by(fastforce dest:Proc_CFG_Call_Labels)
thus ?case by simp
next
case (Proc_CFG_SeqSecond c2 n n' c1)
note IH = `!!n''. c2 \<turnstile> n -CEdge (p',es',rets')->p n''
==> n' = n'' ∧ p = p' ∧ es = es' ∧ rets = rets'`

from `c1;;c2 \<turnstile> n ⊕ #:c1 -CEdge (p',es',rets')->p n''` `n ≠ Entry`
obtain nx where edge:"c2 \<turnstile> n -CEdge (p',es',rets')->p nx" and nx:"nx ⊕ #:c1 = n''"
apply - apply(erule Proc_CFG.cases,auto)
by(cases n,auto dest:Proc_CFG_sourcelabel_less_num_nodes label_incr_inj)+
from edge have "n' = nx ∧ p = p' ∧ es = es' ∧ rets = rets'" by (rule IH)
with nx show ?case by auto
next
case (Proc_CFG_CondThen c1 n n' b c2)
note IH = `!!n''. c1 \<turnstile> n -CEdge (p',es',rets')->p n''
==> n' = n'' ∧ p = p' ∧ es = es' ∧ rets = rets'`

from `if (b) c1 else c2 \<turnstile> n ⊕ 1 -CEdge (p',es',rets')->p n''`
obtain nx where "c1 \<turnstile> n -CEdge (p',es',rets')->p nx ∧ nx ⊕ 1 = n''"
proof(rule Proc_CFG.cases)
fix c2' nx etx nx' bx c1'
assume "if (b) c1 else c2 = if (bx) c1' else c2'"
and "n ⊕ 1 = nx ⊕ #:c1' + 1" and "nx ≠ Entry"
with `c1 \<turnstile> n -CEdge (p,es,rets)->p n'` obtain l where "n = Label l" and "l ≥ #:c1"
by(cases n,auto,cases nx,auto)
with `c1 \<turnstile> n -CEdge (p,es,rets)->p n'` have False
by(fastforce dest:Proc_CFG_sourcelabel_less_num_nodes)
thus ?thesis by simp
qed (auto dest:label_incr_inj)
then obtain nx where edge:"c1 \<turnstile> n -CEdge (p',es',rets')->p nx"
and nx:"nx ⊕ 1 = n''" by blast
from IH[OF edge] nx show ?case by simp
next
case (Proc_CFG_CondElse c2 n n' b c1)
note IH = `!!n''. c2 \<turnstile> n -CEdge (p',es',rets')->p n''
==> n' = n'' ∧ p = p' ∧ es = es' ∧ rets = rets'`

from `if (b) c1 else c2 \<turnstile> n ⊕ #:c1 + 1 -CEdge (p',es',rets')->p n''`
obtain nx where "c2 \<turnstile> n -CEdge (p',es',rets')->p nx ∧ nx ⊕ #:c1 + 1 = n''"
proof(rule Proc_CFG.cases)
fix c1' nx etx nx' bx c2'
assume ifs:"if (b) c1 else c2 = if (bx) c1' else c2'"
and "n ⊕ #:c1 + 1 = nx ⊕ 1" and "nx ≠ Entry"
and edge:"c1' \<turnstile> nx -etx->p nx'"
then obtain l where "nx = Label l" and "l ≥ #:c1"
by(cases n,auto,cases nx,auto)
with edge ifs have False
by(fastforce dest:Proc_CFG_sourcelabel_less_num_nodes)
thus ?thesis by simp
qed (auto dest:label_incr_inj)
then obtain nx where edge:"c2 \<turnstile> n -CEdge (p',es',rets')->p nx"
and nx:"nx ⊕ #:c1 + 1 = n''"
by blast
from IH[OF edge] nx show ?case by simp
next
case (Proc_CFG_WhileBody c' n n' b)
note IH = `!!n''. c' \<turnstile> n -CEdge (p',es',rets')->p n''
==> n' = n'' ∧ p = p' ∧ es = es' ∧ rets = rets'`

from `while (b) c' \<turnstile> n ⊕ 2 -CEdge (p',es',rets')->p n''`
obtain nx where "c' \<turnstile> n -CEdge (p',es',rets')->p nx ∧ nx ⊕ 2 = n''"
by(rule Proc_CFG.cases,auto dest:label_incr_inj Proc_CFG_Call_Labels)
then obtain nx where edge:"c' \<turnstile> n -CEdge (p',es',rets')->p nx"
and nx:"nx ⊕ 2 = n''" by blast
from IH[OF edge] nx show ?case by simp
next
case (Proc_CFG_WhileBodyExit c' n b)
from `c' \<turnstile> n -CEdge (p,es,rets)->p Exit` have False
by(fastforce dest:Proc_CFG_Call_Labels)
thus ?case by simp
next
case Proc_CFG_Call
from `Call p es rets \<turnstile> Label 0 -CEdge (p',es',rets')->p n''`
have "p = p' ∧ es = es' ∧ rets = rets' ∧ n'' = Label 1"
by(auto elim:Proc_CFG.cases)
then show ?case by simp
qed


lemma Proc_CFG_Call_nodes_eq':
"[|prog \<turnstile> n -CEdge (p,es,rets)->p n'; prog \<turnstile> n'' -CEdge (p',es',rets')->p n'|]
==> n = n'' ∧ p = p' ∧ es = es' ∧ rets = rets'"

proof(induct prog n "CEdge (p,es,rets)" n' arbitrary:n'' rule:Proc_CFG.induct)
case (Proc_CFG_SeqFirst c1 n n' c2)
note IH = `!!n''. c1 \<turnstile> n'' -CEdge (p',es',rets')->p n'
==> n = n'' ∧ p = p' ∧ es = es' ∧ rets = rets'`

from `c1;;c2 \<turnstile> n'' -CEdge (p',es',rets')->p n'` `c1 \<turnstile> n -CEdge (p,es,rets)->p n'`
have "c1 \<turnstile> n'' -CEdge (p',es',rets')->p n'"
apply - apply(erule Proc_CFG.cases,auto)
apply(fastforce dest:Proc_CFG_Call_Labels)
by(case_tac n',auto dest:Proc_CFG_targetlabel_less_num_nodes Proc_CFG_Call_Labels)
then show ?case by (rule IH)
next
case (Proc_CFG_SeqConnect c1 n c2)
from `c1 \<turnstile> n -CEdge (p,es,rets)->p Exit` have False
by(fastforce dest:Proc_CFG_Call_Labels)
thus ?case by simp
next
case (Proc_CFG_SeqSecond c2 n n' c1)
note IH = `!!n''. c2 \<turnstile> n'' -CEdge (p',es',rets')->p n'
==> n = n'' ∧ p = p' ∧ es = es' ∧ rets = rets'`

from `c1;;c2 \<turnstile> n'' -CEdge (p',es',rets')->p n' ⊕ #:c1`
obtain nx where edge:"c2 \<turnstile> nx -CEdge (p',es',rets')->p n'" and nx:"nx ⊕ #:c1 = n''"
apply - apply(erule Proc_CFG.cases,auto)
by(cases n',
auto dest:Proc_CFG_targetlabel_less_num_nodes Proc_CFG_Call_Labels
label_incr_inj)
from edge have "n = nx ∧ p = p' ∧ es = es' ∧ rets = rets'" by (rule IH)
with nx show ?case by auto
next
case (Proc_CFG_CondThen c1 n n' b c2)
note IH = `!!n''. c1 \<turnstile> n'' -CEdge (p',es',rets')->p n'
==> n = n'' ∧ p = p' ∧ es = es' ∧ rets = rets'`

from `if (b) c1 else c2 \<turnstile> n'' -CEdge (p',es',rets')->p n' ⊕ 1`
obtain nx where "c1 \<turnstile> nx -CEdge (p',es',rets')->p n' ∧ nx ⊕ 1 = n''"
proof(cases)
case (Proc_CFG_CondElse nx nx')
from `n' ⊕ 1 = nx' ⊕ #:c1 + 1`
`c1 \<turnstile> n -CEdge (p,es,rets)->p n'`
obtain l where "n' = Label l" and "l ≥ #:c1"
by(cases n', auto dest:Proc_CFG_Call_Labels,cases nx',auto)
with `c1 \<turnstile> n -CEdge (p,es,rets)->p n'` have False
by(fastforce dest:Proc_CFG_targetlabel_less_num_nodes)
thus ?thesis by simp
qed (auto dest:label_incr_inj)
then obtain nx where edge:"c1 \<turnstile> nx -CEdge (p',es',rets')->p n'"
and nx:"nx ⊕ 1 = n''"
by blast
from IH[OF edge] nx show ?case by simp
next
case (Proc_CFG_CondElse c2 n n' b c1)
note IH = `!!n''. c2 \<turnstile> n'' -CEdge (p',es',rets')->p n'
==> n = n'' ∧ p = p' ∧ es = es' ∧ rets = rets'`

from `if (b) c1 else c2 \<turnstile> n'' -CEdge (p',es',rets')->p n' ⊕ #:c1 + 1`
obtain nx where "c2 \<turnstile> nx -CEdge (p',es',rets')->p n' ∧ nx ⊕ #:c1 + 1 = n''"
proof(cases)
case (Proc_CFG_CondThen nx nx')
from `n' ⊕ #:c1 + 1 = nx' ⊕ 1`
`c1 \<turnstile> nx -CEdge (p',es',rets')->p nx'`
obtain l where "nx' = Label l" and "l ≥ #:c1"
by(cases n',auto,cases nx',auto dest:Proc_CFG_Call_Labels)
with `c1 \<turnstile> nx -CEdge (p',es',rets')->p nx'`
have False by(fastforce dest:Proc_CFG_targetlabel_less_num_nodes)
thus ?thesis by simp
qed (auto dest:label_incr_inj)
then obtain nx where edge:"c2 \<turnstile> nx -CEdge (p',es',rets')->p n'"
and nx:"nx ⊕ #:c1 + 1 = n''"
by blast
from IH[OF edge] nx show ?case by simp
next
case (Proc_CFG_WhileBody c' n n' b)
note IH = `!!n''. c' \<turnstile> n'' -CEdge (p',es',rets')->p n'
==> n = n'' ∧ p = p' ∧ es = es' ∧ rets = rets'`

from `while (b) c' \<turnstile> n'' -CEdge (p',es',rets')->p n' ⊕ 2`
obtain nx where edge:"c' \<turnstile> nx -CEdge (p',es',rets')->p n'" and nx:"nx ⊕ 2 = n''"
by(rule Proc_CFG.cases,auto dest:label_incr_inj)
from IH[OF edge] nx show ?case by simp
next
case (Proc_CFG_WhileBodyExit c' n b)
from `c' \<turnstile> n -CEdge (p,es,rets)->p Exit`
have False by(fastforce dest:Proc_CFG_Call_Labels)
thus ?case by simp
next
case Proc_CFG_Call
from `Call p es rets \<turnstile> n'' -CEdge (p',es',rets')->p Label 1`
have "p = p' ∧ es = es' ∧ rets = rets' ∧ n'' = Label 0"
by(auto elim:Proc_CFG.cases)
then show ?case by simp
qed


lemma Proc_CFG_Call_targetnode_no_Call_sourcenode:
"[|prog \<turnstile> n -CEdge (p,es,rets)->p n'; prog \<turnstile> n' -CEdge (p',es',rets')->p n''|]
==> False"

proof(induct prog n "CEdge (p,es,rets)" n' arbitrary:n'' rule:Proc_CFG.induct)
case (Proc_CFG_SeqFirst c1 n n' c2)
note IH = `!!n''. c1 \<turnstile> n' -CEdge (p', es', rets')->p n'' ==> False`
from `c1;; c2 \<turnstile> n' -CEdge (p',es',rets')->p n''` `c1 \<turnstile> n -CEdge (p,es,rets)->p n'`
have "c1 \<turnstile> n' -CEdge (p',es',rets')->p n''"
apply - apply(erule Proc_CFG.cases,auto)
apply(fastforce dest:Proc_CFG_Call_Labels)
by(case_tac n)(auto dest:Proc_CFG_targetlabel_less_num_nodes)
then show ?case by (rule IH)
next
case (Proc_CFG_SeqConnect c1 n c2)
from `c1 \<turnstile> n -CEdge (p,es,rets)->p Exit` have False
by(fastforce dest:Proc_CFG_Call_Labels)
thus ?case by simp
next
case (Proc_CFG_SeqSecond c2 n n' c1)
note IH = `!!n''. c2 \<turnstile> n' -CEdge (p', es', rets')->p n'' ==> False`
from `c1;; c2 \<turnstile> n' ⊕ #:c1 -CEdge (p', es', rets')->p n''` `c2 \<turnstile> n -CEdge (p,es,rets)->p n'`
obtain nx where "c2 \<turnstile> n' -CEdge (p',es',rets')->p nx"
apply - apply(erule Proc_CFG.cases,auto)
apply(cases n') apply(auto dest:Proc_CFG_sourcelabel_less_num_nodes)
apply(fastforce dest:Proc_CFG_Call_Labels)
by(cases n',auto,case_tac n,auto)
then show ?case by (rule IH)
next
case (Proc_CFG_CondThen c1 n n' b c2)
note IH = `!!n''. c1 \<turnstile> n' -CEdge (p',es',rets')->p n'' ==> False`
from `if (b) c1 else c2 \<turnstile> n' ⊕ 1 -CEdge (p', es', rets')->p n''` `c1 \<turnstile> n -CEdge (p,es,rets)->p n'`
obtain nx where "c1 \<turnstile> n' -CEdge (p',es',rets')->p nx"
apply - apply(erule Proc_CFG.cases,auto)
apply(cases n') apply auto apply(case_tac n) apply auto
apply(cases n') apply auto
by(case_tac n)(auto dest:Proc_CFG_targetlabel_less_num_nodes)
then show ?case by (rule IH)
next
case (Proc_CFG_CondElse c2 n n' b c1)
note IH = `!!n''. c2 \<turnstile> n' -CEdge (p',es',rets')->p n'' ==> False`
from `if (b) c1 else c2 \<turnstile> n' ⊕ #:c1 + 1 -CEdge (p', es', rets')->p n''`
`c2 \<turnstile> n -CEdge (p,es,rets)->p n'`
obtain nx where "c2 \<turnstile> n' -CEdge (p',es',rets')->p nx"
apply - apply(erule Proc_CFG.cases,auto)
apply(cases n') apply auto
apply(case_tac n) apply(auto dest:Proc_CFG_sourcelabel_less_num_nodes)
by(cases n',auto,case_tac n,auto)
then show ?case by (rule IH)
next
case (Proc_CFG_WhileBody c' n n' b)
note IH = `!!n''. c' \<turnstile> n' -CEdge (p',es',rets')->p n'' ==> False`
from `while (b) c' \<turnstile> n' ⊕ 2 -CEdge (p', es', rets')->p n''` `c' \<turnstile> n -CEdge (p,es,rets)->p n'`
obtain nx where "c' \<turnstile> n' -CEdge (p',es',rets')->p nx"
apply - apply(erule Proc_CFG.cases,auto)
by(cases n',auto,case_tac n,auto)+
then show ?case by (rule IH)
next
case (Proc_CFG_WhileBodyExit c' n b)
from `c' \<turnstile> n -CEdge (p, es, rets)->p Exit`
show ?case by(fastforce dest:Proc_CFG_Call_Labels)
next
case Proc_CFG_Call
from `Call p es rets \<turnstile> Label 1 -CEdge (p', es', rets')->p n''`
show ?case by(fastforce elim:Proc_CFG.cases)
qed


lemma Proc_CFG_Call_follows_id_edge:
"[|prog \<turnstile> n -CEdge (p,es,rets)->p n'; prog \<turnstile> n' -IEdge et->p n''|] ==> et = \<Up>id"
proof(induct prog n "CEdge (p,es,rets)" n' arbitrary:n'' rule:Proc_CFG.induct)
case (Proc_CFG_SeqFirst c1 n n' c2)
note IH = `!!n''. c1 \<turnstile> n' -IEdge et->p n'' ==> et = \<Up>id`
from `c1;;c2 \<turnstile> n' -IEdge et->p n''` `c1 \<turnstile> n -CEdge (p,es,rets)->p n'` `n' ≠ Exit`
obtain nx where "c1 \<turnstile> n' -IEdge et->p nx"
apply - apply(erule Proc_CFG.cases,auto)
by(case_tac n)(auto dest:Proc_CFG_targetlabel_less_num_nodes)
then show ?case by (rule IH)
next
case (Proc_CFG_SeqConnect c1 n c2)
from `c1 \<turnstile> n -CEdge (p, es, rets)->p Exit`
show ?case by(fastforce dest:Proc_CFG_Call_Labels)
next
case (Proc_CFG_SeqSecond c2 n n' c1)
note IH = `!!n''. c2 \<turnstile> n' -IEdge et->p n'' ==> et = \<Up>id`
from `c1;;c2 \<turnstile> n' ⊕ #:c1 -IEdge et->p n''` `c2 \<turnstile> n -CEdge (p,es,rets)->p n'`
obtain nx where "c2 \<turnstile> n' -IEdge et->p nx"
apply - apply(erule Proc_CFG.cases,auto)
apply(cases n') apply(auto dest:Proc_CFG_sourcelabel_less_num_nodes)
apply(cases n') apply(auto dest:Proc_CFG_sourcelabel_less_num_nodes)
by(cases n',auto,case_tac n,auto)
then show ?case by (rule IH)
next
case (Proc_CFG_CondThen c1 n n' b c2)
note IH = `!!n''. c1 \<turnstile> n' -IEdge et->p n'' ==> et = \<Up>id`
from `if (b) c1 else c2 \<turnstile> n' ⊕ 1 -IEdge et->p n''` `c1 \<turnstile> n -CEdge (p,es,rets)->p n'`
`n ≠ Entry`
obtain nx where "c1 \<turnstile> n' -IEdge et->p nx"
apply - apply(erule Proc_CFG.cases,auto)
apply(cases n') apply auto apply(case_tac n) apply auto
apply(cases n') apply auto
by(case_tac n)(auto dest:Proc_CFG_targetlabel_less_num_nodes)
then show ?case by (rule IH)
next
case (Proc_CFG_CondElse c2 n n' b c1)
note IH = `!!n''. c2 \<turnstile> n' -IEdge et->p n'' ==> et = \<Up>id`
from `if (b) c1 else c2 \<turnstile> n' ⊕ #:c1 + 1 -IEdge et->p n''` `c2 \<turnstile> n -CEdge (p,es,rets)->p n'`
obtain nx where "c2 \<turnstile> n' -IEdge et->p nx"
apply - apply(erule Proc_CFG.cases,auto)
apply(cases n') apply auto
apply(case_tac n) apply(auto dest:Proc_CFG_sourcelabel_less_num_nodes)
by(cases n',auto,case_tac n,auto)
then show ?case by (rule IH)
next
case (Proc_CFG_WhileBody c' n n' b)
note IH = `!!n''. c' \<turnstile> n' -IEdge et->p n'' ==> et = \<Up>id`
from `while (b) c' \<turnstile> n' ⊕ 2 -IEdge et->p n''` `c' \<turnstile> n -CEdge (p,es,rets)->p n'`
obtain nx where "c' \<turnstile> n' -IEdge et->p nx"
apply - apply(erule Proc_CFG.cases,auto)
apply(cases n') apply auto
apply(cases n') apply auto apply(case_tac n) apply auto
by(cases n',auto,case_tac n,auto)
then show ?case by (rule IH)
next
case (Proc_CFG_WhileBodyExit c' n et' b)
from `c' \<turnstile> n -CEdge (p, es, rets)->p Exit`
show ?case by(fastforce dest:Proc_CFG_Call_Labels)
next
case Proc_CFG_Call
from `Call p es rets \<turnstile> Label 1 -IEdge et->p n''` show ?case
by(fastforce elim:Proc_CFG.cases)
qed


lemma Proc_CFG_edge_det:
"[|prog \<turnstile> n -et->p n'; prog \<turnstile> n -et'->p n'|] ==> et = et'"
proof(induct rule:Proc_CFG.induct)
case Proc_CFG_Entry_Exit thus ?case by(fastforce dest:Proc_CFG_EntryD)
next
case Proc_CFG_Entry thus ?case by(fastforce dest:Proc_CFG_EntryD)
next
case Proc_CFG_Skip thus ?case by(fastforce elim:Proc_CFG.cases)
next
case Proc_CFG_LAss thus ?case by(fastforce elim:Proc_CFG.cases)
next
case Proc_CFG_LAssSkip thus ?case by(fastforce elim:Proc_CFG.cases)
next
case (Proc_CFG_SeqFirst c1 n et n' c2)
note edge = `c1 \<turnstile> n -et->p n'`
note IH = `c1 \<turnstile> n -et'->p n' ==> et = et'`
from edge `n' ≠ Exit` obtain l where l:"n' = Label l" by (cases n') auto
with edge have "l < #:c1" by(fastforce intro:Proc_CFG_targetlabel_less_num_nodes)
with `c1;;c2 \<turnstile> n -et'->p n'` l have "c1 \<turnstile> n -et'->p n'"
by(fastforce elim:Proc_CFG.cases intro:Proc_CFG.intros dest:label_incr_ge)
from IH[OF this] show ?case .
next
case (Proc_CFG_SeqConnect c1 n et c2)
note edge = `c1 \<turnstile> n -et->p Exit`
note IH = `c1 \<turnstile> n -et'->p Exit ==> et = et'`
from edge `n ≠ Entry` obtain l where l:"n = Label l" by (cases n) auto
with edge have "l < #:c1" by(fastforce intro: Proc_CFG_sourcelabel_less_num_nodes)
with `c1;;c2 \<turnstile> n -et'->p Label #:c1` l have "c1 \<turnstile> n -et'->p Exit"
by(fastforce elim:Proc_CFG.cases
dest:Proc_CFG_targetlabel_less_num_nodes label_incr_ge)
from IH[OF this] show ?case .
next
case (Proc_CFG_SeqSecond c2 n et n' c1)
note edge = `c2 \<turnstile> n -et->p n'`
note IH = `c2 \<turnstile> n -et'->p n' ==> et = et'`
from edge `n ≠ Entry` obtain l where l:"n = Label l" by (cases n) auto
with edge have "l < #:c2" by(fastforce intro:Proc_CFG_sourcelabel_less_num_nodes)
with `c1;;c2 \<turnstile> n ⊕ #:c1 -et'->p n' ⊕ #:c1` l have "c2 \<turnstile> n -et'->p n'"
by -(erule Proc_CFG.cases,
(fastforce dest:Proc_CFG_sourcelabel_less_num_nodes label_incr_ge
dest!:label_incr_inj)+)
from IH[OF this] show ?case .
next
case Proc_CFG_CondTrue thus ?case by(fastforce elim:Proc_CFG.cases)
next
case Proc_CFG_CondFalse thus ?case by(fastforce elim:Proc_CFG.cases)
next
case (Proc_CFG_CondThen c1 n et n' b c2)
note edge = `c1 \<turnstile> n -et->p n'`
note IH = `c1 \<turnstile> n -et'->p n' ==> et = et'`
from edge `n ≠ Entry` obtain l where l:"n = Label l" by (cases n) auto
with edge have "l < #:c1" by(fastforce intro:Proc_CFG_sourcelabel_less_num_nodes)
with `if (b) c1 else c2 \<turnstile> n ⊕ 1 -et'->p n' ⊕ 1` l have "c1 \<turnstile> n -et'->p n'"
by -(erule Proc_CFG.cases,(fastforce dest:label_incr_ge label_incr_inj)+)
from IH[OF this] show ?case .
next
case (Proc_CFG_CondElse c2 n et n' b c1)
note edge = `c2 \<turnstile> n -et->p n'`
note IH = `c2 \<turnstile> n -et'->p n' ==> et = et'`
from edge `n ≠ Entry` obtain l where l:"n = Label l" by (cases n) auto
with edge have "l < #:c2" by(fastforce intro:Proc_CFG_sourcelabel_less_num_nodes)
with `if (b) c1 else c2 \<turnstile> n ⊕ (#:c1 + 1) -et'->p n' ⊕ (#:c1 + 1)` l
have "c2 \<turnstile> n -et'->p n'"
by -(erule Proc_CFG.cases,(fastforce dest:Proc_CFG_sourcelabel_less_num_nodes
label_incr_inj label_incr_ge label_incr_simp_rev)+)
from IH[OF this] show ?case .
next
case Proc_CFG_WhileTrue thus ?case by(fastforce elim:Proc_CFG.cases)
next
case Proc_CFG_WhileFalse thus ?case by(fastforce elim:Proc_CFG.cases)
next
case Proc_CFG_WhileFalseSkip thus ?case by(fastforce elim:Proc_CFG.cases)
next
case (Proc_CFG_WhileBody c' n et n' b)
note edge = `c' \<turnstile> n -et->p n'`
note IH = `c' \<turnstile> n -et'->p n' ==> et = et'`
from edge `n ≠ Entry` obtain l where l:"n = Label l" by (cases n) auto
with edge have less:"l < #:c'"
by(fastforce intro:Proc_CFG_sourcelabel_less_num_nodes)
from edge `n' ≠ Exit` obtain l' where l':"n' = Label l'" by (cases n') auto
with edge have "l' < #:c'" by(fastforce intro:Proc_CFG_targetlabel_less_num_nodes)
with `while (b) c' \<turnstile> n ⊕ 2 -et'->p n' ⊕ 2` l less l' have "c' \<turnstile> n -et'->p n'"
by(fastforce elim:Proc_CFG.cases dest:label_incr_start_Node_smaller)
from IH[OF this] show ?case .
next
case (Proc_CFG_WhileBodyExit c' n et b)
note edge = `c' \<turnstile> n -et->p Exit`
note IH = `c' \<turnstile> n -et'->p Exit ==> et = et'`
from edge `n ≠ Entry` obtain l where l:"n = Label l" by (cases n) auto
with edge have "l < #:c'" by(fastforce intro:Proc_CFG_sourcelabel_less_num_nodes)
with `while (b) c' \<turnstile> n ⊕ 2 -et'->p Label 0` l have "c' \<turnstile> n -et'->p Exit"
by -(erule Proc_CFG.cases,auto dest:label_incr_start_Node_smaller)
from IH[OF this] show ?case .
next
case Proc_CFG_Call thus ?case by(fastforce elim:Proc_CFG.cases)
next
case Proc_CFG_CallSkip thus ?case by(fastforce elim:Proc_CFG.cases)
qed


lemma WCFG_deterministic:
"[|prog \<turnstile> n1 -et1->p n1'; prog \<turnstile> n2 -et2->p n2'; n1 = n2; n1' ≠ n2'|]
==> ∃Q Q'. et1 = IEdge (Q)\<surd> ∧ et2 = IEdge (Q')\<surd>
(∀s. (Q s --> ¬ Q' s) ∧ (Q' s --> ¬ Q s))"

proof(induct arbitrary:n2 n2' rule:Proc_CFG.induct)
case (Proc_CFG_Entry_Exit prog)
from `prog \<turnstile> n2 -et2->p n2'` `Entry = n2` `Exit ≠ n2'`
have "et2 = IEdge (λs. True)\<surd>" by(fastforce dest:Proc_CFG_EntryD)
thus ?case by simp
next
case (Proc_CFG_Entry prog)
from `prog \<turnstile> n2 -et2->p n2'` `Entry = n2` `Label 0 ≠ n2'`
have "et2 = IEdge (λs. False)\<surd>" by(fastforce dest:Proc_CFG_EntryD)
thus ?case by simp
next
case Proc_CFG_Skip
from `Skip \<turnstile> n2 -et2->p n2'` `Label 0 = n2` `Exit ≠ n2'`
have False by(fastforce elim:Proc_CFG.cases)
thus ?case by simp
next
case (Proc_CFG_LAss V e)
from `V:=e \<turnstile> n2 -et2->p n2'` `Label 0 = n2` `Label 1 ≠ n2'`
have False by -(erule Proc_CFG.cases,auto)
thus ?case by simp
next
case (Proc_CFG_LAssSkip V e)
from `V:=e \<turnstile> n2 -et2->p n2'` `Label 1 = n2` `Exit ≠ n2'`
have False by -(erule Proc_CFG.cases,auto)
thus ?case by simp
next
case (Proc_CFG_SeqFirst c1 n et n' c2)
note IH = `!!n2 n2'. [|c1 \<turnstile> n2 -et2->p n2'; n = n2; n' ≠ n2'|]
==> ∃Q Q'. et = IEdge (Q)\<surd> ∧ et2 = IEdge (Q')\<surd>
(∀s. (Q s --> ¬ Q' s) ∧ (Q' s --> ¬ Q s))`

from `c1;;c2 \<turnstile> n2 -et2->p n2'` `c1 \<turnstile> n -et->p n'` `n = n2` `n' ≠ n2'`
have "c1 \<turnstile> n2 -et2->p n2' ∨ (c1 \<turnstile> n2 -et2->p Exit ∧ n2' = Label #:c1)"
apply - apply(erule Proc_CFG.cases)
apply(auto intro:Proc_CFG.intros)
by(case_tac n,auto dest:Proc_CFG_sourcelabel_less_num_nodes)+
thus ?case
proof
assume "c1 \<turnstile> n2 -et2->p n2'"
from IH[OF this `n = n2` `n' ≠ n2'`] show ?case .
next
assume "c1 \<turnstile> n2 -et2->p Exit ∧ n2' = Label #:c1"
hence edge:"c1 \<turnstile> n2 -et2->p Exit" and n2':"n2' = Label #:c1" by simp_all
from IH[OF edge `n = n2` `n' ≠ Exit`] show ?case .
qed
next
case (Proc_CFG_SeqConnect c1 n et c2)
note IH = `!!n2 n2'. [|c1 \<turnstile> n2 -et2->p n2'; n = n2; Exit ≠ n2'|]
==> ∃Q Q'. et = IEdge (Q)\<surd> ∧ et2 = IEdge (Q')\<surd>
(∀s. (Q s --> ¬ Q' s) ∧ (Q' s --> ¬ Q s))`

from `c1;;c2 \<turnstile> n2 -et2->p n2'` `c1 \<turnstile> n -et->p Exit` `n = n2` `n ≠ Entry`
`Label #:c1 ≠ n2'` have "c1 \<turnstile> n2 -et2->p n2' ∧ Exit ≠ n2'"
apply - apply(erule Proc_CFG.cases)
apply(auto intro:Proc_CFG.intros)
by(case_tac n,auto dest:Proc_CFG_sourcelabel_less_num_nodes)+
from IH[OF this[THEN conjunct1] `n = n2` this[THEN conjunct2]]
show ?case .
next
case (Proc_CFG_SeqSecond c2 n et n' c1)
note IH = `!!n2 n2'. [|c2 \<turnstile> n2 -et2->p n2'; n = n2; n' ≠ n2'|]
==> ∃Q Q'. et = IEdge (Q)\<surd> ∧ et2 = IEdge (Q')\<surd>
(∀s. (Q s --> ¬ Q' s) ∧ (Q' s --> ¬ Q s))`

from `c1;;c2 \<turnstile> n2 -et2->p n2'` `c2 \<turnstile> n -et->p n'` `n ⊕ #:c1 = n2`
`n' ⊕ #:c1 ≠ n2'` `n ≠ Entry`
obtain nx where "c2 \<turnstile> n -et2->p nx ∧ nx ⊕ #:c1 = n2'"
apply - apply(erule Proc_CFG.cases)
apply(auto intro:Proc_CFG.intros)
apply(cases n,auto dest:Proc_CFG_sourcelabel_less_num_nodes)
apply(cases n,auto dest:Proc_CFG_sourcelabel_less_num_nodes)
by(fastforce dest:label_incr_inj)
with `n' ⊕ #:c1 ≠ n2'` have edge:"c2 \<turnstile> n -et2->p nx" and neq:"n' ≠ nx"
by auto
from IH[OF edge _ neq] show ?case by simp
next
case (Proc_CFG_CondTrue b c1 c2)
from `if (b) c1 else c2 \<turnstile> n2 -et2->p n2'` `Label 0 = n2` `Label 1 ≠ n2'`
show ?case by -(erule Proc_CFG.cases,auto)
next
case (Proc_CFG_CondFalse b c1 c2)
from `if (b) c1 else c2 \<turnstile> n2 -et2->p n2'` `Label 0 = n2` `Label (#:c1 + 1) ≠ n2'`
show ?case by -(erule Proc_CFG.cases,auto)
next
case (Proc_CFG_CondThen c1 n et n' b c2)
note IH = `!!n2 n2'. [|c1 \<turnstile> n2 -et2->p n2'; n = n2; n' ≠ n2'|]
==> ∃Q Q'. et = IEdge (Q)\<surd> ∧ et2 = IEdge (Q')\<surd>
(∀s. (Q s --> ¬ Q' s) ∧ (Q' s --> ¬ Q s))`

from `if (b) c1 else c2 \<turnstile> n2 -et2->p n2'` `c1 \<turnstile> n -et->p n'` `n ≠ Entry`
`n ⊕ 1 = n2` `n' ⊕ 1 ≠ n2'`
obtain nx where "c1 \<turnstile> n -et2->p nx ∧ n' ≠ nx"
apply - apply(erule Proc_CFG.cases)
apply(auto intro:Proc_CFG.intros simp del:One_nat_def)
apply(drule label_incr_inj) apply(auto simp del:One_nat_def)
apply(drule label_incr_simp_rev[OF sym])
by(case_tac na,auto dest:Proc_CFG_sourcelabel_less_num_nodes)
from IH[OF this[THEN conjunct1] _ this[THEN conjunct2]] show ?case by simp
next
case (Proc_CFG_CondElse c2 n et n' b c1)
note IH = `!!n2 n2'. [|c2 \<turnstile> n2 -et2->p n2'; n = n2; n' ≠ n2'|]
==> ∃Q Q'. et = IEdge (Q)\<surd> ∧ et2 = IEdge (Q')\<surd>
(∀s. (Q s --> ¬ Q' s) ∧ (Q' s --> ¬ Q s))`

from `if (b) c1 else c2 \<turnstile> n2 -et2->p n2'` `c2 \<turnstile> n -et->p n'` `n ≠ Entry`
`n ⊕ #:c1 + 1 = n2` `n' ⊕ #:c1 + 1 ≠ n2'`
obtain nx where "c2 \<turnstile> n -et2->p nx ∧ n' ≠ nx"
apply - apply(erule Proc_CFG.cases)
apply(auto intro:Proc_CFG.intros simp del:One_nat_def)
apply(drule label_incr_simp_rev)
apply(case_tac na,auto,cases n,auto dest:Proc_CFG_sourcelabel_less_num_nodes)
by(fastforce dest:label_incr_inj)
from IH[OF this[THEN conjunct1] _ this[THEN conjunct2]] show ?case by simp
next
case (Proc_CFG_WhileTrue b c')
from `while (b) c' \<turnstile> n2 -et2->p n2'` `Label 0 = n2` `Label 2 ≠ n2'`
show ?case by -(erule Proc_CFG.cases,auto)
next
case (Proc_CFG_WhileFalse b c')
from `while (b) c' \<turnstile> n2 -et2->p n2'` `Label 0 = n2` `Label 1 ≠ n2'`
show ?case by -(erule Proc_CFG.cases,auto)
next
case (Proc_CFG_WhileFalseSkip b c')
from `while (b) c' \<turnstile> n2 -et2->p n2'` `Label 1 = n2` `Exit ≠ n2'`
show ?case by -(erule Proc_CFG.cases,auto dest:label_incr_ge)
next
case (Proc_CFG_WhileBody c' n et n' b)
note IH = `!!n2 n2'. [|c' \<turnstile> n2 -et2->p n2'; n = n2; n' ≠ n2'|]
==> ∃Q Q'. et = IEdge (Q)\<surd> ∧ et2 = IEdge (Q')\<surd>
(∀s. (Q s --> ¬ Q' s) ∧ (Q' s --> ¬ Q s))`

from `while (b) c' \<turnstile> n2 -et2->p n2'` `c' \<turnstile> n -et->p n'` `n ≠ Entry`
`n' ≠ Exit` `n ⊕ 2 = n2` `n' ⊕ 2 ≠ n2'`
obtain nx where "c' \<turnstile> n -et2->p nx ∧ n' ≠ nx"
apply - apply(erule Proc_CFG.cases)
apply(auto intro:Proc_CFG.intros)
apply(fastforce dest:label_incr_ge[OF sym])
apply(fastforce dest:label_incr_inj)
by(fastforce dest:label_incr_inj)
from IH[OF this[THEN conjunct1] _ this[THEN conjunct2]] show ?case by simp
next
case (Proc_CFG_WhileBodyExit c' n et b)
note IH = `!!n2 n2'. [|c' \<turnstile> n2 -et2->p n2'; n = n2; Exit ≠ n2'|]
==> ∃Q Q'. et = IEdge (Q)\<surd> ∧ et2 = IEdge (Q')\<surd>
(∀s. (Q s --> ¬ Q' s) ∧ (Q' s --> ¬ Q s))`

from `while (b) c' \<turnstile> n2 -et2->p n2'` `c' \<turnstile> n -et->p Exit` `n ≠ Entry`
`n ⊕ 2 = n2` `Label 0 ≠ n2'`
obtain nx where "c' \<turnstile> n -et2->p nx ∧ Exit ≠ nx"
apply - apply(erule Proc_CFG.cases)
apply(auto intro:Proc_CFG.intros)
apply(fastforce dest:label_incr_ge[OF sym])
by(fastforce dest:label_incr_inj)
from IH[OF this[THEN conjunct1] _ this[THEN conjunct2]] show ?case by simp
next
case Proc_CFG_Call thus ?case by -(erule Proc_CFG.cases,auto)
next
case Proc_CFG_CallSkip thus ?case by -(erule Proc_CFG.cases,auto)
qed


subsection {* And now: the interprocedural CFG *}

subsubsection {* Statements containing calls *}

text {* A procedure is a tuple composed of its name, its input and output variables
and its method body *}


type_synonym proc = "(pname × vname list × vname list × cmd)"
type_synonym procs = "proc list"


text {* @{text "containsCall"} guarantees that a call to procedure p is in
a certain statement. *}


declare conj_cong[fundef_cong]

function containsCall ::
"procs => cmd => pname list => pname => bool"
where "containsCall procs Skip ps p <-> False"
| "containsCall procs (V:=e) ps p <-> False"
| "containsCall procs (c1;;c2) ps p <->
containsCall procs c1 ps p ∨ containsCall procs c2 ps p"

| "containsCall procs (if (b) c1 else c2) ps p <->
containsCall procs c1 ps p ∨ containsCall procs c2 ps p"

| "containsCall procs (while (b) c) ps p <->
containsCall procs c ps p"

| "containsCall procs (Call q es' rets') ps p <-> p = q ∧ ps = [] ∨
(∃ins outs c ps'. ps = q#ps' ∧ (q,ins,outs,c) ∈ set procs ∧
containsCall procs c ps' p)"

by pat_completeness auto
termination containsCall
by(relation "measures [λ(procs,c,ps,p). length ps,
λ(procs,c,ps,p). size c]"
) auto


lemmas containsCall_induct[case_names Skip LAss Seq Cond While Call] =
containsCall.induct


lemma containsCallcases:
"containsCall procs prog ps p
==> ps = [] ∧ containsCall procs prog ps p ∨
(∃q ins outs c ps'. ps = ps'@[q] ∧ (q,ins,outs,c) ∈ set procs ∧
containsCall procs c [] p ∧ containsCall procs prog ps' q)"

proof(induct procs prog ps p rule:containsCall_induct)
case (Call procs q es' rets' ps p)
note IH = `!!x y z ps'. [|ps = q#ps'; (q,x,y,z) ∈ set procs;
containsCall procs z ps' p|]
==> ps' = [] ∧ containsCall procs z ps' p ∨
(∃qx ins outs c psx. ps' = psx@[qx] ∧ (qx,ins,outs,c) ∈ set procs ∧
containsCall procs c [] p ∧
containsCall procs z psx qx)`

from `containsCall procs (Call q es' rets') ps p`
have "p = q ∧ ps = [] ∨
(∃ins outs c ps'. ps = q#ps' ∧ (q,ins,outs,c) ∈ set procs ∧
containsCall procs c ps' p)"
by simp
thus ?case
proof
assume assms:"p = q ∧ ps = []"
hence "containsCall procs (Call q es' rets') ps p" by simp
with assms show ?thesis by simp
next
assume "∃ins outs c ps'. ps = q#ps' ∧ (q,ins,outs,c) ∈ set procs ∧
containsCall procs c ps' p"

then obtain ins outs c ps' where "ps = q#ps'" and "(q,ins,outs,c) ∈ set procs"
and "containsCall procs c ps' p" by blast
from IH[OF this] have "ps' = [] ∧ containsCall procs c ps' p ∨
(∃qx insx outsx cx psx.
ps' = psx @ [qx] ∧ (qx,insx,outsx,cx) ∈ set procs ∧
containsCall procs cx [] p ∧ containsCall procs c psx qx)"
.
thus ?thesis
proof
assume assms:"ps' = [] ∧ containsCall procs c ps' p"
have "containsCall procs (Call q es' rets') [] q" by simp
with assms `ps = q#ps'` `(q,ins,outs,c) ∈ set procs` show ?thesis by fastforce
next
assume "∃qx insx outsx cx psx.
ps' = psx@[qx] ∧ (qx,insx,outsx,cx) ∈ set procs ∧
containsCall procs cx [] p ∧ containsCall procs c psx qx"

then obtain qx insx outsx cx psx
where "ps' = psx@[qx]" and "(qx,insx,outsx,cx) ∈ set procs"
and "containsCall procs cx [] p"
and "containsCall procs c psx qx" by blast
from `(q,ins,outs,c) ∈ set procs` `containsCall procs c psx qx`
have "containsCall procs (Call q es' rets') (q#psx) qx" by fastforce
with `ps' = psx@[qx]` `ps = q#ps'` `(qx,insx,outsx,cx) ∈ set procs`
`containsCall procs cx [] p` show ?thesis by fastforce
qed
qed
qed auto



lemma containsCallE:
"[|containsCall procs prog ps p;
[|ps = []; containsCall procs prog ps p|] ==> P procs prog ps p;
!!q ins outs c es' rets' ps'. [|ps = ps'@[q]; (q,ins,outs,c) ∈ set procs;
containsCall procs c [] p; containsCall procs prog ps' q|]
==> P procs prog ps p|] ==> P procs prog ps p"

by(auto dest:containsCallcases)


lemma containsCall_in_proc:
"[|containsCall procs prog qs q; (q,ins,outs,c) ∈ set procs;
containsCall procs c [] p|]
==> containsCall procs prog (qs@[q]) p"

proof(induct procs prog qs q rule:containsCall_induct)
case (Call procs qx esx retsx ps p')
note IH = `!!x y z psx. [|ps = qx#psx; (qx,x,y,z) ∈ set procs;
containsCall procs z psx p'; (p',ins,outs,c) ∈ set procs;
containsCall procs c [] p|] ==> containsCall procs z (psx@[p']) p`

from `containsCall procs (Call qx esx retsx) ps p'`
have "p' = qx ∧ ps = [] ∨
(∃insx outsx cx psx. ps = qx#psx ∧ (qx,insx,outsx,cx) ∈ set procs ∧
containsCall procs cx psx p')"
by simp
thus ?case
proof
assume assms:"p' = qx ∧ ps = []"
with `(p', ins, outs, c) ∈ set procs` `containsCall procs c [] p`
have "containsCall procs (Call qx esx retsx) [p'] p" by fastforce
with assms show ?thesis by simp
next
assume "∃insx outsx cx psx. ps = qx#psx ∧ (qx,insx,outsx,cx) ∈ set procs ∧
containsCall procs cx psx p'"

then obtain insx outsx cx psx where "ps = qx#psx"
and "(qx,insx,outsx,cx) ∈ set procs"
and "containsCall procs cx psx p'" by blast
from IH[OF this `(p', ins, outs, c) ∈ set procs`
`containsCall procs c [] p`]
have "containsCall procs cx (psx @ [p']) p" .
with `ps = qx#psx` `(qx,insx,outsx,cx) ∈ set procs`
show ?thesis by fastforce
qed
qed auto


lemma containsCall_indirection:
"[|containsCall procs prog qs q; containsCall procs c ps p;
(q,ins,outs,c) ∈ set procs|]
==> containsCall procs prog (qs@q#ps) p"

proof(induct procs prog qs q rule:containsCall_induct)
case (Call procs px esx retsx ps' p')
note IH = `!!x y z psx. [|ps' = px # psx; (px, x, y, z) ∈ set procs;
containsCall procs z psx p'; containsCall procs c ps p;
(p', ins, outs, c) ∈ set procs|]
==> containsCall procs z (psx @ p' # ps) p`

from `containsCall procs (Call px esx retsx) ps' p'`
have "p' = px ∧ ps' = [] ∨
(∃insx outsx cx psx. ps' = px#psx ∧ (px,insx,outsx,cx) ∈ set procs ∧
containsCall procs cx psx p')"
by simp
thus ?case
proof
assume "p' = px ∧ ps' = []"
with `containsCall procs c ps p` `(p', ins, outs, c) ∈ set procs`
show ?thesis by fastforce
next
assume "∃insx outsx cx psx. ps' = px#psx ∧ (px,insx,outsx,cx) ∈ set procs ∧
containsCall procs cx psx p'"

then obtain insx outsx cx psx where "ps' = px#psx"
and "(px,insx,outsx,cx) ∈ set procs"
and "containsCall procs cx psx p'" by blast
from IH[OF this `containsCall procs c ps p`
`(p', ins, outs, c) ∈ set procs`]
have "containsCall procs cx (psx @ p' # ps) p" .
with `ps' = px#psx` `(px,insx,outsx,cx) ∈ set procs`
show ?thesis by fastforce
qed
qed auto


lemma Proc_CFG_Call_containsCall:
"prog \<turnstile> n -CEdge (p,es,rets)->p n' ==> containsCall procs prog [] p"
by(induct prog n et"CEdge (p,es,rets)" n' rule:Proc_CFG.induct,auto)


lemma containsCall_empty_Proc_CFG_Call_edge:
assumes "containsCall procs prog [] p"
obtains l es rets l' where "prog \<turnstile> Label l -CEdge (p,es,rets)->p Label l'"
proof(atomize_elim)
from `containsCall procs prog [] p`
show "∃l es rets l'. prog \<turnstile> Label l -CEdge (p,es,rets)->p Label l'"
proof(induct procs prog ps"[]::pname list" p rule:containsCall_induct)
case Seq thus ?case
by auto(fastforce dest:Proc_CFG_SeqFirst,fastforce dest:Proc_CFG_SeqSecond)
next
case Cond thus ?case
by auto(fastforce dest:Proc_CFG_CondThen,fastforce dest:Proc_CFG_CondElse)
next
case While thus ?case by(fastforce dest:Proc_CFG_WhileBody)
next
case Call thus ?case by(fastforce intro:Proc_CFG_Call)
qed auto
qed


subsubsection{* The edges of the combined CFG *}

type_synonym node = "(pname × label)"
type_synonym edge = "(node × (vname,val,node,pname) edge_kind × node)"

fun get_proc :: "node => pname"
where "get_proc (p,l) = p"


inductive PCFG ::
"cmd => procs => node => (vname,val,node,pname) edge_kind => node => bool"
("_,_ \<turnstile> _ -_-> _" [51,51,0,0,0] 81)
for prog::cmd and procs::procs
where

Main:
"prog \<turnstile> n -IEdge et->p n' ==> prog,procs \<turnstile> (Main,n) -et-> (Main,n')"

| Proc:
"[|(p,ins,outs,c) ∈ set procs; c \<turnstile> n -IEdge et->p n';
containsCall procs prog ps p|]
==> prog,procs \<turnstile> (p,n) -et-> (p,n')"



| MainCall:
"[|prog \<turnstile> Label l -CEdge (p,es,rets)->p n'; (p,ins,outs,c) ∈ set procs|]
==> prog,procs \<turnstile> (Main,Label l)
-(λs. True):(Main,n')\<hookrightarrow>pmap (λe cf. interpret e cf) es-> (p,Entry)"


| ProcCall:
"[|(p,ins,outs,c) ∈ set procs; c \<turnstile> Label l -CEdge (p',es',rets')->p Label l';
(p',ins',outs',c') ∈ set procs; containsCall procs prog ps p|]
==> prog,procs \<turnstile> (p,Label l)
-(λs. True):(p,Label l')\<hookrightarrow>p'map (λe cf. interpret e cf) es'-> (p',Entry)"


| MainReturn:
"[|prog \<turnstile> Label l -CEdge (p,es,rets)->p Label l'; (p,ins,outs,c) ∈ set procs|]
==> prog,procs \<turnstile> (p,Exit) -(λcf. snd cf = (Main,Label l'))\<hookleftarrow>p
(λcf cf'. cf'(rets [:=] map cf outs))-> (Main,Label l')"


| ProcReturn:
"[|(p,ins,outs,c) ∈ set procs; c \<turnstile> Label l -CEdge (p',es',rets')->p Label l';
(p',ins',outs',c') ∈ set procs; containsCall procs prog ps p|]
==> prog,procs \<turnstile> (p',Exit) -(λcf. snd cf = (p,Label l'))\<hookleftarrow>p'
(λcf cf'. cf'(rets' [:=] map cf outs'))-> (p,Label l')"


| MainCallReturn:
"prog \<turnstile> n -CEdge (p,es,rets)->p n'
==> prog,procs \<turnstile> (Main,n) -(λs. False)\<surd>-> (Main,n')"


| ProcCallReturn:
"[|(p,ins,outs,c) ∈ set procs; c \<turnstile> n -CEdge (p',es',rets')->p n';
containsCall procs prog ps p|]
==> prog,procs \<turnstile> (p,n) -(λs. False)\<surd>-> (p,n')"



end