(*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
* Copyright (c) 2022 Apple Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-2-Clause
*)
chapter ‹L2 phase: local variable abstraction with lambdas›
theory L2Defs
imports CorresXF L1Defs L1Peephole L1Valid
begin
type_synonym ('s, 'a, 'e) L2_monad = "('e, 'a, 's) exn_monad"
definition "L2_unknown (ns :: nat list) ≡ select UNIV :: ('s, 'a, 'e) L2_monad"
definition "L2_seq (A :: ('s, 'a, 'e) L2_monad) (B :: 'a → ('s, 'b, 'e) L2_monad) ≡ (A >>= B) :: ('s, 'b, 'e) L2_monad"
definition "L2_modify m ≡modify m :: ('s, unit, 'e) L2_monad"
definition "L2_gets f (names :: nat list) ≡ gets f :: ('s, 'a, 'e) L2_monad"
definition "L2_condition c (A :: ('s, 'a, 'e) L2_monad) (B :: ('s, 'a, 'e) L2_monad) ≡ condition c A B"
definition "L2_catch (A :: ('s, 'a, 'e) L2_monad) (B :: 'e → ('s, 'a, 'ee) L2_monad) ≡ (A <catch> B)"
definition "L2_try (A :: ('s, 'a, 'e + 'a) L2_monad) ≡ try A"
definition "L2_while c (A :: 'a → ('s, 'a, 'e) L2_monad) i (ns :: nat list) ≡ whileLoop c A i :: ('s, 'a, 'e) L2_monad"
definition "L2_throw x (ns :: nat list) ≡ throw x :: ('s, 'a, 'e) L2_monad"
definition "L2_spec r ≡ (state_select r >>= (λ_. select UNIV)) :: ('s, 'a, 'e) L2_monad"
definition "L2_assume r ≡ (assume_result_and_state r) :: ('s, 'a, 'e) L2_monad"
definition "L2_guard c ≡ (guard c) :: ('s, unit, 'e) L2_monad"
definition "L2_guarded P c ≡ L2_seq (L2_guard P) (λ_. c)" ―‹used to guard a function-pointer call›
definition "L2_fail ≡ fail :: ('s, 'a, 'e) L2_monad"
definition "L2_call x emb (ns :: nat list) ≡ map_value (map_exn emb) x :: ('s, 'a, 'e) L2_monad"
abbreviation "L2_skip ≡ L2_gets (λ_. ()) []"
definition "L2_VARS f (names::nat list) ≡ f" ― ‹Auxilliary construct to preserve names,
like in @{const L2_unknown}, @{const L2_gets}, ...›
abbreviation "L2_pre_post P R ≡ L2_guarded (λ_. P) (L2_assume R)"
abbreviation "L2_pre_post_read_write r w Pre Post ≡
L2_guarded (λ_. Pre)
(L2_assume (λs. {(v, s'). ∃t'. (v, t') ∈ Post (r s) ∧ s' = w (λ_. t') s}))"
definition gets_theE :: "('s → 'a option) → ('e, 'a, 's) exn_monad" where
"gets_theE ≡ λx. gets_the x" ― ‹Lifting into exception monad›
(*
* Temporary constructions, used internally but not emitted.
*
* "L2_folded_gets" is like "L2_gets", but the peephole optimiser will
* try to eliminate the call to where it is used, eliminating it where
* possible. It is used for automatically generated "L2_gets" calls
* which the user really doesn't need to know about.
*
* The various "call" defintions are to help generate proofs for the
* different ways of making function calls, which are hard to unify.
*)
definition "L2_folded_gets f names ≡ L2_gets f names :: ('s, 'a, 'e) L2_monad"
definition "L2_voidcall x emb ns ≡ L2_seq (L2_call x emb ns) (λret. L2_skip) :: ('s, unit, 'e) L2_monad"
definition "L2_modifycall x m emb ns ≡ L2_seq (L2_call x emb ns) (λret. L2_modify (m ret)) :: ('s, unit, 'e) L2_monad"
definition "L2_returncall x f emb ns ≡ L2_seq (L2_call x emb ns) (λret. L2_folded_gets (f ret) []) :: ('s, 'a, 'e) L2_monad"
(* Syntax variants to emulate congprocs with simprocs *)
definition "L2_seq_guard P A ≡ L2_seq (L2_guard P) A"
definition "L2_seq_gets c n A ≡ L2_seq (L2_gets (λ_. c) n) A"
definition "L2_seq_unknown ns A ≡ L2_seq (L2_unknown ns) A"
definition "L2_seq_condition c L R X ≡ L2_seq (L2_condition c L R) X"
definition L2_exec_spec_monad::
"('s → 't) → (exit_status, 'a, 't) exn_monad → (exit_status c_exntype, 'a, 's) exn_monad" where
"L2_exec_spec_monad st f ≡
map_value (map_exn Nonlocal) (exec_abstract st f)"
definition "SANITIZE_NAMES prj ns ns' = True"
lemma sanitize_namesI: "SANITIZE_NAMES prj ns ns'"
by (simp add: SANITIZE_NAMES_def)
lemma L2_fail_top: "L2_fail = ⊤"
by (simp add: L2_fail_def top_eq_fail)
definition DYN_CALL :: "prop → prop" where "PROP DYN_CALL (PROP P) ≡ PROP P"
lemma DYN_CALL_I: "PROP P ==> PROP DYN_CALL (PROP P)"
by (simp add: DYN_CALL_def)
lemma DYN_CALL_D: "PROP DYN_CALL (PROP P) ==> PROP P"
by (simp add: DYN_CALL_def)
lemma mono_L2_VARS[monad_mono_intros]: "f ≤ g ==> L2_VARS f ns ≤ L2_VARS g ns"
unfolding L2_VARS_def .
lemma mono_L2_VARS'[monad_mono_intros]: "f p ≤ g p ==> L2_VARS f ns p ≤ L2_VARS g ns p"
unfolding L2_VARS_def .
lemma admissible_runs_to_partial[corres_admissible]: "ccpo.admissible Inf (≥) (λf . f ∙ s ?{Q})"
unfolding runs_to_partial_def_old
apply (rule ccpo.admissibleI)
apply (clarsimp simp add: ccpo.admissible_def chain_def
succeeds_def reaches_def split: prod.splits xval_splits)
subgoal
apply transfer
apply (clarsimp simp add: Inf_post_state_def top_post_state_def image_def vimage_def
split: if_split_asm)
by (metis outcomes.simps(2) post_state.distinct(1))
done
lemma reaches_gets_theE [simp]:
"reaches (gets_theE M) s rv s' ⟷ (∃v'. rv = Result v' ∧ s' = s ∧ M s = Some v')"
by (auto simp add: gets_theE_def)
lemma seucceeds_gets_theE [simp]:
"succeeds (gets_theE M) s = (∃v. M s = Some v)"
apply (auto simp add: gets_theE_def)
done
lemma L2_folded_gets_bind:
"L2_seq (L2_folded_gets (λ_. x) ns) f = f x"
unfolding L2_seq_def L2_folded_gets_def L2_gets_def
apply (rule spec_monad_eqI)
apply (auto simp add: runs_to_iff)
done
lemma L2_call_throw_names: "L2_call x emb ns = (x <catch> (λr. L2_throw (emb r) ns))"
unfolding L2_call_def L2_throw_def
apply (rule spec_monad_eqI)
apply (clarsimp simp add: runs_to_iff)
apply (auto simp add: runs_to_def_old map_exn_def split: xval_splits)
done
(* fixme: we can merge these *)
lemmas L2_remove_scaffolding_1 =
L2_folded_gets_bind [THEN eq_reflection]
L2_returncall_def
L2_modifycall_def
L2_voidcall_def
lemmas L2_remove_scaffolding_2 =
L2_remove_scaffolding_1
L2_folded_gets_def
abbreviation (input) "L2_guarded_while G C B i n ≡ L2_seq (L2_guard (G i))
(λ_. L2_while C (λi. L2_seq (B i) (λr. L2_seq (L2_guard (G r)) (λ_. L2_gets (λ_. r) n))) i n)"
lemmas L2_defs = L2_unknown_def L2_seq_def
L2_modify_def L2_gets_def L2_condition_def L2_catch_def L2_while_def
L2_throw_def L2_spec_def L2_assume_def L2_guard_def L2_fail_def L2_folded_gets_def
L2_voidcall_def L2_modifycall_def L2_returncall_def
L2_try_def
(* Alternate definitions. *)
lemma L2_defs':
"L2_unknown n ≡ unknown"
"L2_seq A' B' ≡ A' >>= B'"
"L2_modify m ≡ modify m"
"L2_gets f n ≡ gets f"
"L2_condition c L R ≡ condition c L R"
"L2_catch A B ≡ (A <catch> B)"
"L2_try A ≡ try A"
"L2_while c' B'' i n ≡ whileLoop c' B'' i"
"L2_throw x n ≡ throw x"
"L2_spec r ≡ (state_select r >>= (λ_. select UNIV))"
"L2_assume r' ≡ (assume_result_and_state r')"
"L2_guard c ≡ guard c"
"L2_fail ≡ fail"
by (auto simp: (*monad_defs*) L2_defs unknown_def )
definition
L2corres :: "('s → 't) → ('s → 'r) → ('s → 'e) → ('s → bool)
→ ('e, 'r, 't) exn_monad → (unit, unit, 's) exn_monad → bool"
where
"L2corres st ret_xf ex_xf P A C
≡ corresXF st (λ_. ret_xf) (λ_. ex_xf) P A C"
lemma admissible_nondet_ord_L2corres [corres_admissible]:
"ccpo.admissible Inf (≥) (λA. L2corres st ret_xf ex_xf P A C)"
unfolding L2corres_def
apply (rule admissible_nondet_ord_corresXF)
done
lemma admissible_nondet_ord_L2corres_mcont:
"mcont Inf (≥) Inf (≥) F ==> ccpo.admissible Inf (≥) (λA. L2corres st ret_xf ex_xf P (F A) C)"
using admissible_nondet_ord_L2corres
apply (rule admissible_subst)
apply assumption
done
lemma L2corres_top [corres_top]: "L2corres st ret_xf ex_xf P ⊤ C"
by (auto simp add: L2corres_def corresXF_def)
lemma L2corres_le_trans [corres_le_trans]:
"L2corres st ret_xf ex_xf P A C ==> A ≤ A' ==> L2corres st ret_xf ex_xf P A' C"
by (auto simp add: L2corres_def corres_le_trans)
(* Wrapper for calling un-translated functions. *)
definition
"L2_call_L1 arg_xf gs ret_xf l1body
= do {
s ← get_state;
t ← select {t. gs t = s ∧ arg_xf t};
run_bind l1body t (λr' t'.
(case r' of
Exception _ → fail
| Result _ → do {set_state (gs t'); return (ret_xf t')} ))
}"
lemma L2corres_L2_call_L1:
"L2corres gs ret_xf ex_xf arg_xf
(L2_call_L1 arg_xf gs ret_xf f) f"
apply (clarsimp simp: L2corres_def corresXF_refines_iff L2_call_L1_def L1_seq_def L1_guard_def
split: xval_splits)
apply (simp add: refines_def_old)
apply (intro conjI impI)
subgoal
by (auto simp add: succeeds_bind succeeds_run_bind succeeds_exec_concrete_iff succeeds_catch)
subgoal
by (auto simp add: succeeds_bind succeeds_run_bind reaches_run_bind
succeeds_exec_concrete_iff succeeds_catch reaches_bind default_option_def Exn_def
rel_XF_def rel_xval.simps Exn_def default_option_def
split: exception_or_result_splits)
(smt (verit, ccfv_threshold) Exn_def Exn_neq_Result exception_or_result_cases
imageI mem_Collect_eq old.unit.exhaust option.exhaust_sel)
done
lemma L2corres_L2_call_simpl:
"l1_f ≡ simpl_f ==>
L2corres gs ret_xf ex_xf arg_xf
(L2_call_L1 arg_xf gs ret_xf simpl_f) l1_f"
by (simp add: L2corres_L2_call_L1)
(* shouldn't be needed
lemma empty_set_exists: "(\<forall>a. a \<noteq> {}) = False"
apply blast
done
*)
lemma L2corres_modify_global:
"[ ∧s. P s ==> M (st s) = st (M' s) ] ==>
L2corres st ret ex P (L2_modify M) (L1_modify M')"
unfolding L2_defs L1_defs
by (auto simp add: L2corres_def corresXF_modify_global)
lemma L2corres_modify_unknown:
"[ ∧s. P s ==> st s = st (M s) ] ==>
L2corres st ret ex P (L2_unknown ns) (L1_modify M)"
apply (clarsimp simp: L2corres_def L2_defs L1_defs)
apply (auto intro: corresXF_select_modify)
done
lemma L2corres_spec_unknown:
"[ ∧s a. st s = st (M (a::('a → ('a::{type}))) s) ] ==>
L2corres st ret ex P (L2_unknown ns) (L1_init M)"
apply (auto simp add: L2corres_def corresXF_def L1_defs L2_defs
reaches_bind reaches_succeeds succeeds_bind)
done
lemma L2corres_modify_gets:
"[ ∧s. P s ==> st s = st (M s); ∧s. P s ==> ret (M s) = f (st s) ] ==>
L2corres st ret ex P (L2_gets (λs. f s) n) (L1_modify M)"
by (simp add: L2corres_def L2_defs L1_defs corresXF_modify_gets)
lemma L2corres_gets_skip:
"L2corres st ret ex P L2_skip L1_skip"
by (simp add: L2corres_def L2_defs L1_defs corresXF_def)
lemma L2corres_guard:
"[ ∧s. P s ==> G' s = G (st s) ] ==>
L2corres st return_xf exception_xf P (L2_guard G) (L1_guard G')"
by (simp add: L2corres_def L2_defs L1_defs corresXF_guard)
lemma L2corres_fail:
"L2corres st return_xf exception_xf P L2_fail X"
by (clarsimp simp add: L2corres_def L1_defs L2_defs corresXF_def)
lemma L2corres_spec:
"[ ∧s s'. ((s, s') ∈ A') = ((st s, st s') ∈ A); surj st ]
==> L2corres st return_xf exception_xf P (L2_spec A) (L1_spec A')"
apply (clarsimp simp: L2corres_def L2_defs L1_spec_def corresXF_def succeeds_bind reaches_bind)
by (metis surjD)
lemma L2corres_assume:
"[ ∧s s'. (((), s') ∈ A' s) = (((), st s') ∈ A (st s)) ]
==> L2corres st return_xf exception_xf P (L2_assume A) (L1_assume A')"
by (clarsimp simp: L2corres_def L2_defs L1_assume_def corresXF_def)
lemma L2corres_seq:
"[ L2corres st return_xf exception_xf P A A';
∧x. L2corres st return_xf' exception_xf (P' x) (B x) B';
{R} A' {λ_ s. P' (return_xf s) s}, {λ_ _. True};
∧s. R s ==> P s ] ==>
L2corres st return_xf' exception_xf R (L2_seq A B) (L1_seq A' B')"
apply (unfold L2corres_def L2_seq_def L1_seq_def validE_def)
apply (rule corresXF_join)
apply assumption
apply assumption
apply simp
apply assumption
done
lemma L2corres_guard_imp:
"[ L2corres st ret_state ex_state Q M M'; pred_imp P Q ] ==>
L2corres st ret_state ex_state P M M'"
by (simp add: L2corres_def pred_imp_def corresXF_guard_imp)
lemma L2corres_guarded'':
assumes bdy: "∧s' s. g' s' ==> s = st s' ==> P s' ==> L2corres st ret ex P (c (dest s)) (c' (dest' s'))"
assumes g_g': "∧s'. P s' ==> g' s' = g (st s')"
assumes dest: "∧s' s. g' s' ==> s = st s' ==> P s' ==> dest' s' = dest (st s')"
shows "L2corres st ret ex P (L2_guarded g (L2_seq (L2_gets dest []) c)) (L1_guarded g' (gets dest' ⤜ c'))"
using assms
by (auto simp add: L2corres_def L2_defs L1_defs L2_guarded_def L1_guarded_def corresXF_def
succeeds_bind reaches_bind split: xval_splits)
lemma L2corres_guarded_impl'':
assumes bdy: "∧s' s. g s ==> s = st s' ==> P s' ==> L2corres st ret ex P (c (dest s)) (c' (dest' s'))"
assumes g_g': "∧s'. P s' ==> g (st s') ==> g' s'"
assumes dest: "∧s' s. g' s' ==> s = st s' ==> P s' ==> dest' s' = dest (st s')"
shows "L2corres st ret ex P (L2_guarded g (L2_seq (L2_gets dest ns) c)) (L1_guarded g' (gets dest' ⤜ c'))"
using assms
by (auto simp add: L2corres_def L2_defs L1_defs L2_guarded_def L1_guarded_def corresXF_def
succeeds_bind reaches_bind split: xval_splits)
lemma L2corres_guarded:
assumes bdy: "∧s' s. g' s' ==> s = st s' ==> P s' ==> L2corres st ret ex P c c'"
assumes g_g': "∧s'. P s' ==> g' s' = g (st s')"
shows "L2corres st ret ex P (L2_guarded g c) (L1_guarded g' c')"
using assms
apply (fastforce simp add: L2corres_def L2_defs L1_defs L2_guarded_def L1_guarded_def corresXF_def
succeeds_bind reaches_bind split: xval_splits)
done
lemma L2corres_guarded_impl:
assumes bdy: "∧s' s. g s ==> s = st s' ==> P s' ==> L2corres st ret ex P c c'"
assumes g_g': "∧s'. P s' ==> g (st s') ==> g' s'"
shows "L2corres st ret ex P (L2_guarded g c) (L1_guarded g' c')"
using assms
apply (fastforce simp add: L2corres_def L2_defs L1_defs L2_guarded_def L1_guarded_def corresXF_def
succeeds_bind reaches_bind split: xval_splits)
done
lemma L2corres_catch:
"[ L2corres st V E P L L';
∧x. L2corres st V E' (P' x) (R x) R';
{Q} L' {λ_ _. True}, {λ_ s. P' (E s) s}; ∧s. Q s ==> P s ] ==>
L2corres st V E' Q (L2_catch L R) (L1_catch L' R')"
apply (clarsimp simp: L2corres_def L2_catch_def L1_catch_def validE_def)
apply (rule corresXF_except)
apply (assumption)
apply (assumption)
apply auto
done
lemma L2corres_throw:
"[ ∧s. P s ==> E s = A ] ==> L2corres st V E P (L2_throw A n) (L1_throw)"
by (clarsimp simp: L2corres_def L2_throw_def L1_throw_def corresXF_throw)
lemma L2corres_conseq:
assumes corres: "L2corres st return_xf exception_xf P C C'"
assumes conseq: "∧s. Q s ==> P s"
shows "L2corres st return_xf exception_xf Q C C'"
apply (rule L2corres_guard_imp [OF corres])
using conseq by (simp add: pred_imp_def)
lemma L2corres_cond:
"[ L2corres st return_xf exception_xf P A A';
L2corres st return_xf exception_xf P' B B';
∧s. R s ==> P s;
∧s. R s ==> P' s;
∧s. R s ==> c' s = c (st s) ] ==>
L2corres st return_xf exception_xf R (L2_condition c A B) (L1_condition c' A' B')"
apply (unfold L2corres_def L2_condition_def L1_condition_def)
apply (rule corresXF_cond)
apply (auto intro: corresXF_guard_imp)
done
lemma L2corres_inject_return:
"[ L2corres st V E P L R; {P'} R {λ_ s. W (V s) = V' s}, { λ_ _. True }; ∧s. P' s ==> P s] ==>
L2corres st V' E P' (L2_seq L (λx. L2_gets (λ_. W x) n)) R"
apply (clarsimp simp: L2corres_def validE_def)
apply (drule corresXF_guard_imp [where P=P'], simp)
apply (unfold L2_seq_def L2_gets_def)
apply (rule corresXF_guard_imp)
apply (erule corresXF_append_gets_abs)
apply simp
apply simp
done
lemma L2corres_inject_return':
"[ L2corres st V E P L R;Gets = (λx. L2_gets (λ_. W x) n);{P'} R {λ_ s. W (V s) = V' s}, { λ_ _. True}; ∧s. P' s ==> P s
] ==>
L2corres st V' E P' (L2_seq L Gets) R"
by (auto intro: L2corres_inject_return)
lemma L2corres_skip:
"L2corres st return_xf exception_xf P L2_skip L1_skip"
by (rule L2corres_gets_skip)
lemma L2corres_while:
assumes body_corres: "∧x. L2corres st ret ex (P' x) (A x) B"
and inv_holds: "{λs. P (ret s) s } B {λ_ s. P (ret s) s }, {λ_ _. True}"
and cond_match: "∧s. P (ret s) s ==> c' s = c (ret s) (st s)"
and pred_imply: "∧s x. P x s ==> P' x s"
and pred_extract: "∧s. P x s ==> ret s = x"
and pred_imply2: "∧s. Q x s ==> P x s"
shows "L2corres st ret ex (Q x) (L2_while c A x n) (L1_while c' B)"
apply (clarsimp simp: L2corres_def L2_while_def L1_while_def)
apply (rule corresXF_guard_imp)
apply (rule corresXF_while [
where P="λr s. P (ret s) s" and C'=c and C="λ_. c'" and A=A and B="λ_. B"
and ret="λr s. ret s" and ex="λr s. ex s" and st=st and y=x and x="()" and P'="λr s. Q x s"])
apply (rule corresXF_guard_imp)
apply (rule body_corres [unfolded L2corres_def])
apply (clarsimp simp: pred_imply)
apply (clarsimp simp: cond_match)
apply (rule inv_holds [unfolded validE_def, rule_format])
apply assumption
apply (metis pred_extract pred_imply2)
apply (metis pred_extract pred_imply2)
apply simp
done
lemma L2corres_returncall:
"[ L2corres st ret' ex' P' Z dest_fn;
∧s. P s ==> P' (scope_setup s);
∧t s. st (return_xf t (scope_teardown s t)) = st t;
∧t s. st (result_exn (scope_teardown s t) t) = st t;
∧s. st (scope_setup s) = st s;
∧t s. st (scope_teardown s t) = st t;
∧t s. P s ==> ret (return_xf t (scope_teardown s t)) = F (ret' t) (st t) ;
∧t s. P s ==> (ex (result_exn (scope_teardown s t) t)) = emb (ex' t) ] ==>
L2corres st ret ex P (L2_returncall Z F emb ns)
(L1_call scope_setup dest_fn scope_teardown result_exn return_xf)"
unfolding L1_call_def L1_seq_def L1_throw_def L2_returncall_def L2_call_def L2corres_def L2_defs
apply (rule corresXF_I)
subgoal
apply (clarsimp simp add: corresXF_def succeeds_bind succeeds_catch reaches_catch
reaches_map_value reaches_bind default_option_def Exn_def split: xval_splits exception_or_result_splits)
by (metis Exn_def Exn_neq_Result[of _ "ret' _"] Result_eq_Result[of "ret' _"]
map_exn_simps(2)[of emb "ret' _"])
subgoal
apply (clarsimp simp add: corresXF_def succeeds_bind succeeds_catch reaches_catch
reaches_map_value reaches_bind default_option_def Exn_def split: xval_splits exception_or_result_splits)
by (metis (mono_tags, opaque_lifting) Exception_eq_Exception Exn_def Exn_neq_Result map_exn_simps(1))
subgoal
apply (auto simp add: corresXF_def succeeds_bind succeeds_catch reaches_catch
reaches_map_value reaches_bind default_option_def Exn_def split: xval_splits exception_or_result_splits)
done
done
lemma L2corres_dest_fn_simp:
assumes dest_fn: "∧s. P s ==> dest_fn = dest_fn'"
assumes corres: "L2corres st ret ex P X
(L1_call scope_setup (measure_call dest_fn') scope_teardown result_exn return_xf)"
shows "L2corres st ret ex P X
(L1_call scope_setup (measure_call dest_fn) scope_teardown result_exn return_xf)"
using corres dest_fn unfolding L2corres_def corresXF_def
by blast
lemma L2corres_l2_propagate_fixed_cong:
"(∧s. P s = P' s) ==> (∧s. P' s ==> A = A') ==> L2corres st ret ex P A C = L2corres st ret ex P' A' C"
unfolding L2corres_def corresXF_def simp_implies_def
by (auto split: sum.splits prod.splits)
lemma L2corres_l2_propagate_fixed_cong':
"P = P' ==> (∧s. P' s ==> A = A') ==> (∧s. P' s ==> C = C') ==> L2corres st ret ex P A C = L2corres st ret ex P' A' C'"
unfolding L2corres_def corresXF_def simp_implies_def
by (auto split: sum.splits prod.splits)
lemma L2corres_l2_propagate_fixed_cong'':
"P = P' ==> (A = A') ==> (C = C') ==> L2corres st ret ex P A C = L2corres st ret ex P' A' C'"
unfolding L2corres_def corresXF_def simp_implies_def
by (auto split: sum.splits prod.splits)
lemma L2corres_modifycall:
"[ L2corres st ret' ex' P' Z dest_fn;
∧s. P s ==> P' (scope_setup s);
∧s r. P r ==> F (ret' s) (st s) = st (return_xf s (scope_teardown r s));
∧s. st (scope_setup s) = st s;
∧t s. st (scope_teardown s t) = st t;
∧t s. st (result_exn (scope_teardown s t) t) = st t;
∧t s. P s ==> ex (result_exn (scope_teardown s t) t) = emb (ex' t)] ==>
L2corres st ret ex P (L2_modifycall Z F emb ns)
(L1_call scope_setup dest_fn scope_teardown result_exn return_xf)"
apply (clarsimp simp: L1_call_def L1_seq_def L1_throw_def L2_call_def L2_defs L2corres_def)
apply (rule corresXF_I)
subgoal
apply (clarsimp simp add: corresXF_def succeeds_bind succeeds_catch reaches_catch
reaches_map_value reaches_bind default_option_def Exn_def split: xval_splits exception_or_result_splits)
by (metis Exn_def Exn_neq_Result[of _ "ret' _"] Result_eq_Result[of "ret' _"]
map_exn_simps(2)[of emb "ret' _"])
subgoal
apply (clarsimp simp add: corresXF_def succeeds_bind succeeds_catch reaches_catch
reaches_map_value reaches_bind default_option_def Exn_def split: xval_splits exception_or_result_splits)
by (metis (mono_tags, opaque_lifting) Exception_eq_Exception Exn_def Exn_neq_Result map_exn_simps(1))
subgoal
apply (auto simp add: corresXF_def succeeds_bind succeeds_catch reaches_catch
reaches_map_value reaches_bind default_option_def Exn_def split: xval_splits exception_or_result_splits)
done
done
lemma L2corres_voidcall:
"[ L2corres st ret' ex' P' Z dest_fn;
∧s. P s ==> P' (scope_setup s);
∧s r. st (return_xf s (scope_teardown r s)) = st s;
∧s. st (scope_setup s) = st s;
∧t s. st (scope_teardown s t) = st t;
∧t s. st (result_exn (scope_teardown s t) t) = st t;
∧t s. P s ==> ex (result_exn (scope_teardown s t) t) = emb (ex' t)] ==>
L2corres st ret ex P (L2_voidcall Z emb ns)
(L1_call scope_setup dest_fn scope_teardown result_exn return_xf)"
apply (unfold L2_voidcall_def)
apply (rule subst[where t = "L2_skip" and s = "L2_modify (λs. s)"])
subgoal
apply (simp add: L2_defs)
apply (rule spec_monad_ext)
apply simp
done
apply (fold L2_modifycall_def L2corres_def)
apply (fastforce elim!: L2corres_modifycall)
done
lemma L2corres_call:
"[ L2corres st ret' ex' P' Z dest_fn;
∧s. P s ==> P' (scope_setup s);
∧s r. st (return_xf s (scope_teardown r s)) = st s;
∧s r. ret (return_xf s (scope_teardown r s)) = ret' s;
∧s. st (scope_setup s) = st s;
∧t s. st (scope_teardown s t) = st t;
∧t s. st (result_exn (scope_teardown s t) t) = st t;
∧t s. P s ==> ex (result_exn (scope_teardown s t) t) = emb (ex' t) ] ==>
L2corres st ret ex P (L2_call Z emb ns)
(L1_call scope_setup dest_fn scope_teardown result_exn return_xf)"
apply (clarsimp simp: L2corres_def L2_call_def L1_call_def L1_seq_def L1_throw_def L2_defs)
apply (rule corresXF_I)
subgoal
apply (clarsimp simp add: corresXF_def succeeds_bind succeeds_catch reaches_catch
reaches_map_value reaches_bind default_option_def Exn_def split: xval_splits exception_or_result_splits)
by (metis map_exn_simps(2)[of emb "ret' _"])
subgoal
apply (clarsimp simp add: corresXF_def succeeds_bind succeeds_catch reaches_catch
reaches_map_value reaches_bind default_option_def Exn_def split: xval_splits exception_or_result_splits)
by (metis (mono_tags, opaque_lifting) Exception_eq_Exception Exn_def Exn_neq_Result map_exn_simps(1))
subgoal
apply (auto simp add: corresXF_def succeeds_bind succeeds_catch reaches_catch
reaches_map_value reaches_bind default_option_def Exn_def split: xval_splits exception_or_result_splits)
done
done
lemma (in L1_functions) L2corres_dyn_call:
"L2corres st ret ex P X
(L1_guarded g (gets dest >>= (λp. L1_call scope_setup (P p) scope_teardown result_exn return_xf))) ==>
L2corres st ret ex P X (L1_dyn_call g scope_setup dest scope_teardown result_exn return_xf)"
by (simp add: L1_dyn_call_def)
lemma L2corres_le_trans':
"L2corres st ret_xf ex_xf P A C' ==> C ≤ C' ==> L2corres st ret_xf ex_xf P A C"
by (auto simp add: L2corres_def corresXF_trans')
lemma L2corres_call_simpl:
assumes L1: "L1corres ct Γ p' (Call p)"
assumes L2: "L2corres st ret ex P X p'"
shows "L2corres st ret ex P X (L1_call_simpl ct Γ p)"
proof -
from L1_call_simpl_le_trans [OF L1] have "L1_call_simpl ct Γ p ≤ p'" .
from L2corres_le_trans' [OF L2 this] show ?thesis .
qed
term list_all2
lemma L2corres_map_of_default:
assumes "list_all2 (λ(p, f) (p', f'). (p = p'∧ L2corres st ret ex P f' (L1_call scope_setup f scope_teardown result_exn result_xf))) ps ps'"
shows "L2corres st ret ex P
(map_of_default (λ_. ⊤) ps' p) (L1_call scope_setup
(map_of_default (λ_. ⊤) ps p) scope_teardown result_exn result_xf)"
using assms proof (induct ps arbitrary: ps')
case Nil
then show ?case by (auto simp add: L2corres_top)
next
case (Cons x1 ps)
then show ?case
apply (cases ps')
apply (auto split: )
done
qed
lemma map_value_Nonlocal_assume_result_and_state:
"map_value (map_exn Nonlocal) (assume_result_and_state r) = assume_result_and_state r"
apply (rule spec_monad_eqI)
apply (auto simp add: runs_to_iff)
done
lemma exec_abstract_id: "exec_abstract id f = f"
apply (rule spec_monad_eqI)
apply (auto simp add: runs_to_iff)
done
lemma L2corres_exec_spec_monad:
assumes x: "lense get_x upd_x"
assumes glbls_upd_x_commute: "∧f s. glbls (upd_x f s) = glbls s"
assumes res[simp]: "∧f s. get_res (upd_res f s) = f (get_res s)"
assumes res_commute: "∧f s. get_res (upd_x f s) = get_res s" "∧f s. glbls (upd_res f s) = glbls s"
assumes f: "∧s. P s ==> refines (f (args s)) g (st (glbls s)) (st (glbls s)) (=)"
shows "L2corres glbls get_res get_x P (L2_exec_spec_monad st g) (L1_exec_spec_monad upd_x (st o glbls) args f upd_res)"
proof -
from x interpret lense_x: lense get_x upd_x .
show ?thesis
proof (clarsimp simp add: L2corres_def corresXF_refines_iff rel_XF_def)
fix s
assume P: "P s"
show "refines (L1_exec_spec_monad upd_x (st ∘ glbls) args f upd_res) (L2_exec_spec_monad st g) s (glbls s)
(λ(r, t) (r', t').
t' = glbls t ∧ rel_xval (λe e'. e' = get_x t) (λv v'. v' = get_res t) r r')"
apply (simp add: L1_exec_spec_monad_def L2_exec_spec_monad_def)
using f [OF P]
apply (auto simp add: refines_def_old succeeds_bind reaches_bind succeeds_bind_handle reaches_bind_handle
L1_seq_def L1_modify_def L1_throw_def default_option_def map_exn_def
reaches_exec_abstract reaches_map_value rel_xval.simps split: xval_splits exception_or_result_splits)
subgoal for r s' r' s1'
apply (cases r')
subgoal
apply (auto simp add: default_option_def Exn_def)
using glbls_upd_x_commute
by (metis Exn_def Exn_neq_Result the_Exn_Exn(2))
subgoal
apply (auto simp add: glbls_upd_x_commute res_commute)
by (metis Exn_neq_Result the_Result_simp)
done
done
qed
qed
lemma L2corres_exec_spec_monad_globals:
assumes x: "lense get_x upd_x"
assumes glbls_upd_x_commute: "∧f s. glbls (upd_x f s) = glbls s"
assumes res[simp]: "∧f s. get_res (upd_res f s) = f (get_res s)"
assumes res_commute: "∧f s. get_res (upd_x f s) = get_res s" "∧f s. glbls (upd_res f s) = glbls s"
assumes f: "∧s. P s ==> refines (f (args s)) g (glbls s) (glbls s) (=)"
shows "L2corres glbls get_res get_x P (L2_exec_spec_monad id g) (L1_exec_spec_monad upd_x (glbls) args f upd_res)"
using x glbls_upd_x_commute res res_commute
apply (rule L2corres_exec_spec_monad [where st=id, simplified])
by (rule f)
lemma lense_global_exn_var: "lense global_exn_var'_' global_exn_var'_'_update"
by (unfold_locales) auto
lemmas L1corres_exec_spec_monad' = L1corres_exec_spec_monad [OF lense_global_exn_var]
lemma globals_global_exn_var_commutes: "globals (global_exn_var'_'_update f s) = globals s"
by simp
lemmas L2corres_exec_spec_monad' =
L2corres_exec_spec_monad [where glbls = globals, OF lense_global_exn_var globals_global_exn_var_commutes]
lemmas L2corres_exec_spec_monad_globals' =
L2corres_exec_spec_monad_globals [where glbls = globals, OF lense_global_exn_var globals_global_exn_var_commutes]
lemma L2_gets_bind: "[ ∧s s'. V s = V s' ] ==> L2_seq (L2_gets V n) f = f (V undefined)"
unfolding L2_defs
apply (rule spec_monad_eqI)
apply (simp add: runs_to_iff)
by (auto simp add: runs_to_def_old) metis+
(* TODO: remove internal var if it is not user-visible *)
lemma L2corres_folded_gets:
"[ ∧a. L2corres st ret ex (P and (λs. a = c (st s))) (X a) Y ] ==>
L2corres st ret ex P (L2_seq (L2_folded_gets c ns) X) Y"
by (fastforce simp add: L2_defs L2corres_def corresXF_def succeeds_bind reaches_bind split: xval_splits)
lemma L2_call_cong [fundef_cong, cong]:
"f = f' ==> L2_call f = L2_call f'"
by simp
lemma L2_call_liftE [simp]:
"L2_call (liftE x) emb ns ≡ liftE x"
by (clarsimp simp add: L2_call_def)
lemma L2_call_fail [simp]: "L2_call fail emb ns = fail"
apply (simp add: L2_call_def)
done
lemma L2_call_L2_gets [simp]: "L2_call (L2_gets x n) emb ns = L2_gets x n"
apply (simp add: L2_defs L2_call_def)
done
(*
* Rules for adjusting case_prod statements after transformations.
*
* c.f. fix_L2_while_loop_splits_conv
*)
lemma L2_split_fixup_1:
"(L2_seq A (λx. case y of (a, b) → B a b x)) =
(case y of (a, b) → L2_seq A (λx. B a b x))"
by (auto simp: split_def)
lemma L2_split_fixup_2:
"(L2_seq (case y of (a, b) → B a b) A) =
(case y of (a, b) → L2_seq (B a b) A)"
by (auto simp: split_def)
lemma L2_split_L2_seq_fixup_both:
"(L2_seq (case y of (a,b) → A a b) (case y of (a, b) → B a b)) =
(case y of (a, b) → L2_seq (A a b) (B a b))"
by (auto simp: split_def)
lemma L2_split_L2_seq_gets_fixup_1:
"(L2_seq_gets (case y of (a,b) → A a b) n (case y of (a, b) → B a b)) =
(case y of (a, b) → L2_seq_gets (A a b) n (B a b))"
by (auto simp: split_def)
(*
lemma L2_split_L2_seq_gets_fixup_1:
"(L2_seq_gets A n (\<lambda>x. case y of (a, b) \<Rightarrow> B a b x)) =
(case y of (a, b) \<Rightarrow> L2_seq_gets A n (\<lambda>x. B a b x))"
by (auto simp: split_def)
lemma L2_split_L2_seq_gets_fixup_2:
"(L2_seq_gets (case y of (a, b) \<Rightarrow> B a b) n A) =
(case y of (a, b) \<Rightarrow> L2_seq_gets (B a b) n A)"
by (auto simp: split_def)
*)
lemma L2_split_fixup_3:
"(case (x, y) of (a, b) → P a b) = P x y"
by (auto simp: split_def)
lemma L2_split_fixup_4:
"case_prod (λa (b :: 'a × 'b). P a ) = case_prod (λa. case_prod (λ(x :: 'a) (y :: 'b). P a ))"
by (auto simp: split_def)
lemma L2_split_fixup_f:
"(f (case y of (a, b) → G a b) =
(case y of (a, b) → f (G a b)))"
by (auto simp: split_def)
lemma L2_split_fixup_g:
"case_prod (λa (b :: 'a × 'b). P a b) = case_prod (λa. case_prod (λ(x :: 'a) (y :: 'b). P a (x, y)))"
by (auto simp: split_def)
lemma liftE_fixup: "(λx. liftE (case x of (a, b) → f a b)) = (λ(a,b). liftE (f a b))"
by (simp add: fun_eq_iff split: prod.splits)
lemma finally_fixup: "(λx. finally (case x of (a, b) → f a b)) = (λ(a,b). finally (f a b))"
by (simp add: fun_eq_iff split: prod.splits)
lemma try_fixup: "(λx. try (case x of (a, b) → f a b)) = (λ(a,b). try (f a b))"
by (simp add: fun_eq_iff split: prod.splits)
lemma L2_gets_const_split_fixup: "L2_gets (λ_. case y of (a, b) → G a b) = (case y of (a, b) → L2_gets (λ_. G a b))"
by (simp add: fun_eq_iff split: prod.splits)
definition STOP :: "'a::{} → 'a"
where "STOP P ≡ P"
lemma STOP_cong: "STOP P ≡ STOP P"
by simp
lemma do_STOP: "P ≡ STOP P"
by (simp add: STOP_def)
definition STOP_UNBIND :: "'a::{} → 'a"
where "STOP_UNBIND P ≡ P"
lemma STOP_UNBIND_cong: "STOP_UNBIND P ≡ STOP_UNBIND P"
by simp
lemma do_STOP_UNBIND: "P ≡ STOP_UNBIND P"
by (simp add: STOP_UNBIND_def)
definition FUSE :: "'a::{} → 'a"
where "FUSE P ≡ P"
lemma FUSE_cong: "FUSE P ≡ FUSE P"
by simp
lemma do_FUSE: "P ≡ FUSE P"
by (simp add: FUSE_def)
lemma FUSE_STOP: "X ≡ X' ==> FUSE X ≡ STOP X'"
by (simp add: FUSE_def STOP_def)
lemma fixup_accumulate:
"(λ(x, a). (case a of (x1, x2) → C x1 x2) x) = (λ(x, x1, x2). C x1 x2 x)"
by (auto simp: split_def)
lemma case_prod_apply_distrib:
"(case x of (a, b) → f a b) n = (case x of (a, b) → f a b n )"
by (auto simp add: split_def)
lemma L2_guard_fixup1: "L2_guard (λs. case y of (a, b) → G a b s) = (case y of (a, b) → L2_guard (G a b))"
by (auto simp: split_def)
lemmas L2_split_fixups_base =
L2_split_fixup_3
L2_split_fixup_4
liftE_fixup
finally_fixup
try_fixup
L2_guard_fixup1
L2_split_fixup_f [where f=L2_guard]
L2_split_fixup_f [where f=L2_gets]
L2_split_fixup_f [where f=L2_modify]
L2_gets_const_split_fixup
L2_split_fixup_g [where P="λa b. L2_gets (P a b) n" for P n]
L2_split_fixup_g [where P="λa b. L2_guard (P a b)" for P]
L2_split_fixup_g [where P="λa b. L2_modify (P a b)" for P]
L2_split_fixup_g [where P="λa b. L2_spec (P a b)" for P]
L2_split_fixup_g [where P="λa b. L2_assume (P a b)" for P]
L2_split_fixup_g [where P="λa b. L2_throw (P a b) n" for P n]
L2_split_fixup_g [where P="λa b. L2_seq (L a b) (R a b)" for L R]
L2_split_fixup_g [where P="λa b. L2_while (C a b) (B a b) (I a b) n" for C B I n]
L2_split_fixup_g [where P="λa b. L2_unknown n" for n]
L2_split_fixup_g [where P="λa b. L2_catch (L a b) (R a b)" for L R]
L2_split_fixup_g [where P="λa b. L2_condition (C a b) (L a b) (R a b)" for C L R]
L2_split_fixup_g [where P="λa b. L2_call (M a b)" for M]
L2_split_fixup_g [where P="λa b. liftE (M a b)" for M]
L2_split_fixup_g [where P="λa b. finally (M a b)" for M]
L2_split_fixup_g [where P="λa b. try (M a b)" for M]
lemmas L2_split_fixups =
L2_split_fixup_1
L2_split_fixup_2
L2_split_fixups_base
lemmas L2_split_fixups' =
L2_split_L2_seq_fixup_both
L2_split_L2_seq_gets_fixup_1
L2_split_fixup_g [where P="λa b. L2_seq_gets (L a b) (R a b)" for L R]
fixup_accumulate
L2_split_fixups_base
L2_split_fixup_f [where f=STOP]
case_prod_apply_distrib
lemmas L2_split_fixups_congs =
prod.case_cong
(* Peephole simplification rules for L2 programs (including HeapLift and WordAbstract). *)
named_theorems L2opt
lemma monotone_nondet_monad_L2_seq_le [partial_function_mono]:
assumes mono_X: "monotone R (≤) X"
assumes mono_Y: "∧r. monotone R (≤) (λf. Y f r)"
shows "monotone R (≤)
(λf. (L2_seq (X f) (Y f)))"
unfolding L2_defs
apply (rule partial_function_mono)
apply (rule mono_X)
apply (rule mono_Y)
done
lemma mono_L2_seq [monad_mono_intros]: "(∧x. f2 x ≤ g2 x) ==> f1 ≤ g1 ==> L2_seq f1 f2 ≤ L2_seq g1 g2"
unfolding L2_defs
by (auto intro: monad_mono_intros)
lemma monotone_nondet_monad_L2_seq_ge [partial_function_mono]:
assumes mono_X: "monotone R (≥) X"
assumes mono_Y: "∧r. monotone R (≥) (λf. Y f r)"
shows "monotone R (≥)
(λf. (L2_seq (X f) (Y f)))"
unfolding L2_defs
apply (rule partial_function_mono)
apply (rule mono_X)
apply (rule mono_Y)
done
lemma monotone_nondet_monad_L2_try_le [partial_function_mono]:
assumes mono_X: "monotone R (≤) X"
shows "monotone R (≤)
(λf. (L2_try (X f)))"
unfolding L2_defs
apply (rule partial_function_mono)
apply (rule mono_X)
done
lemma monotone_nondet_monad_L2_try_ge [partial_function_mono]:
assumes mono_X: "monotone R (≥) X"
shows "monotone R (≥)
(λf. (L2_try (X f)))"
unfolding L2_defs
apply (rule partial_function_mono)
apply (rule mono_X)
done
lemma mono_L2_try[monad_mono_intros]: "f ≤ g ==> L2_try f ≤ L2_try g"
unfolding L2_defs
by (auto intro: monad_mono_intros)
lemma monotone_nondet_monad_L2_catch_le [partial_function_mono]:
assumes mono_X: "monotone R (≤) X"
assumes mono_Y: "∧r. monotone R (≤) (λf. Y f r)"
shows "monotone R (≤)
(λf. (L2_catch (X f) (Y f)))"
unfolding L2_defs
apply (rule partial_function_mono)
apply (rule mono_X)
apply (rule mono_Y)
done
lemma monotone_nondet_monad_L2_catch_ge [partial_function_mono]:
assumes mono_X: "monotone R (≥) X"
assumes mono_Y: "∧r. monotone R (≥) (λf. Y f r)"
shows "monotone R (≥)
(λf. (L2_catch (X f) (Y f)))"
unfolding L2_defs
apply (rule partial_function_mono)
apply (rule mono_X)
apply (rule mono_Y)
done
lemma mono_L2_catch[monad_mono_intros]: "f1 ≤ g1 ==> (∧x. f2 x ≤ g2 x) ==> L2_catch f1 f2 ≤ L2_catch g1 g2"
unfolding L2_defs
by (auto intro: monad_mono_intros)
lemma monotone_nondet_monad_L2_condition_le [partial_function_mono]:
assumes mono_X: "monotone R (≤) X"
assumes mono_Y: "monotone R (≤) Y"
shows "monotone R (≤)
(λf. (L2_condition C (X f) (Y f)))"
unfolding L2_defs
apply (rule partial_function_mono)
apply (rule mono_X)
apply (rule mono_Y)
done
lemma monotone_nondet_monad_L2_condition_ge [partial_function_mono]:
assumes mono_X: "monotone R (≥) X"
assumes mono_Y: "monotone R (≥) Y"
shows "monotone R (≥)
(λf. (L2_condition C (X f) (Y f)))"
unfolding L2_defs
apply (rule partial_function_mono)
apply (rule mono_X)
apply (rule mono_Y)
done
lemma mono_L2_condition[monad_mono_intros]:
"f1 ≤ g1 ==> f2 ≤ g2 ==> L2_condition c f1 f2 ≤ L2_condition c g1 g2"
unfolding L2_defs
by (auto intro: monad_mono_intros)
lemma monotone_nondet_monad_L2_guarded_le [partial_function_mono]:
assumes mono_X[partial_function_mono]: "monotone R (≤) X"
shows "monotone R (≤)
(λf. L2_guarded C (X f))"
unfolding L2_guarded_def
apply (rule partial_function_mono)+
done
lemma monotone_nondet_monad_L2_guarded_ge [partial_function_mono]:
assumes mono_X[partial_function_mono]: "monotone R (≥) X"
shows "monotone R (≥)
(λf. L2_guarded C (X f))"
unfolding L2_guarded_def
apply (rule partial_function_mono)+
done
lemma mono_L2_guarded[monad_mono_intros]: "f ≤ g ==> L2_guarded c f ≤ L2_guarded c g"
unfolding L2_defs L2_guarded_def
apply (intro monad_mono_intros)
apply simp
apply (simp add: le_fun_def)
done
lemma monotone_nondet_monad_L2_while_le [partial_function_mono]:
assumes mono_B: "∧r. monotone R (≤) (λf. B f r)"
shows "monotone R (≤) (λf. L2_while C (B f) I ns)"
unfolding L2_defs
apply (rule partial_function_mono)
apply (rule mono_B)
done
lemma monotone_nondet_monad_L2_while_ge [partial_function_mono]:
assumes mono_B: "∧r. monotone R (≥) (λf. B f r)"
shows "monotone R (≥) (λf. L2_while C (B f) I ns)"
unfolding L2_defs
apply (rule partial_function_mono)
apply (rule mono_B)
done
lemma mono_L2_while [monad_mono_intros]:
"(∧x. b1 x ≤ b2 x) ==> L2_while c b1 i ns ≤ L2_while c b2 i ns"
unfolding L2_defs L2_guarded_def
by (auto intro: monad_mono_intros)
lemma monotone_nondet_monad_map_exn_le [partial_function_mono]:
assumes X[partial_function_mono]: "monotone R (≤) X"
shows "monotone R (≤) (λf. map_value (map_exn emb) (X f))"
unfolding map_exn_def
apply (rule partial_function_mono)+
done
lemma monotone_nondet_monad_map_exn_ge [partial_function_mono]:
assumes X[partial_function_mono]: "monotone R (≥) X"
shows "monotone R (≥) (λf. map_value (map_exn emb) (X f))"
unfolding map_exn_def
apply (rule partial_function_mono)+
done
lemma monotone_nondet_monad_L2_call_le [partial_function_mono]:
assumes X[partial_function_mono]: "monotone R (≤) X"
shows "monotone R (≤)
(λf. L2_call (X f) emb ns)"
unfolding L2_call_def
apply (rule partial_function_mono)+
done
lemma monotone_nondet_monad_L2_call_ge [partial_function_mono]:
assumes X[partial_function_mono]: "monotone R (≥) X"
shows "monotone R (≥)
(λf. L2_call (X f) emb ns)"
unfolding L2_call_def
apply (rule partial_function_mono)+
done
lemma mono_L2_call [monad_mono_intros]: "f ≤ g ==> L2_call f emb ns ≤ L2_call g emb ns"
unfolding L2_call_def
by (auto intro: monad_mono_intros)
section ‹Some Relators›
lemma exists_sum_unit_eq: "(∃l'::unit. Inl x = Inl l' ∧ Inr y = Inr l') = (x=() ∧ y=())"
by auto
lemmas unit_convs = exists_sum_unit_eq
definition "rel_Nonlocal = (λe v. case e of Nonlocal x → v = x | _ → False)"
lemma rel_Nonlocal_conv: "(rel_Nonlocal e v) = (e = Nonlocal v)"
by (cases e) (auto simp add: rel_Nonlocal_def)
lemma fun_of_rel_rel_Nonlocal[fun_of_rel_intros]: "fun_of_rel rel_Nonlocal the_Nonlocal"
by (auto simp add: fun_of_rel_def rel_Nonlocal_def split: c_exntype.splits)
lemma funp_rel_Nonlocal[funp_intros, corres_admissible]: "funp rel_Nonlocal"
using fun_of_rel_rel_Nonlocal
by (auto simp add: funp_def)
lemma rel_sum_rel_Nonlocal_case_InlI: "e = Nonlocal v' ==> rel_sum rel_Nonlocal (=) (case e of Nonlocal v → Inl (Nonlocal v) | _ → Inr x) (Inl v')"
by (simp add: rel_Nonlocal_def)
lemma rel_xval_rel_Nonlocal_case_ExnI: "e = Nonlocal v' ==> rel_xval rel_Nonlocal (=) (case e of Nonlocal v → Exn (Nonlocal v) | _ → Result x) (Exn v')"
by (simp add: rel_Nonlocal_def)
lemma rel_sum_rel_Nonlocal_case_InrI: "is_local e ==> x = v' ==> rel_sum rel_Nonlocal (=) (case e of Nonlocal v → Inl (Nonlocal v) | _ → Inr x) (Inr v')"
apply (cases e)
apply (auto simp add: rel_Nonlocal_def)
done
lemma rel_xval_rel_Nonlocal_case_ResultI: "is_local e ==> x = v' ==> rel_xval rel_Nonlocal (=) (case e of Nonlocal v → Exn (Nonlocal v) | _ → Result x) (Result v')"
apply (cases e)
apply (auto simp add: rel_Nonlocal_def)
done
lemma rel_sum_rel_Nonlocal_map_sumI: "v = (map_sum (λx. x) f (case e of Nonlocal x → Inl x | _ → Inr x)) ==>
rel_sum rel_Nonlocal (=) (map_sum Nonlocal f (case e of Nonlocal x → Inl x | _ → Inr x)) v"
apply simp
apply (cases e)
apply (auto simp add: rel_Nonlocal_def)
done
lemma rel_xval_rel_Nonlocal_map_xvalI: "v = (map_xval (λx. x) f (case e of Nonlocal x → Exn x | _ → Result x)) ==>
rel_xval rel_Nonlocal (=) (map_xval Nonlocal f (case e of Nonlocal x → Exn x | _ → Result x)) v"
apply simp
apply (cases e)
apply (auto simp add: rel_Nonlocal_def)
done
(* FIXME: remove if unused? Probably used in replacement of refines_spec *)
definition "rel_Inr v v' ≡ (v = Inr v')"
lemma fun_of_rel_rel_Inr[fun_of_rel_intros]:
"fun_of_rel rel_Inr (λx. case x of Inr v → v | Inl _ → undefined)"
by (auto simp add: rel_Inr_def fun_of_rel_def)
lemma funp_rel_Inr[funp_intros, corres_admissible]: "funp rel_Inr"
using fun_of_rel_rel_Inr by (auto simp add: funp_def)
lemma rel_InrI: "v = Inr v' ==> rel_Inr v v'"
by (simp add: rel_Inr_def)
lemma rel_Inr_apply: "rel_Inr x y = (x = Inr y)"
by (simp add: rel_Inr_def )
lemma rel_Inr_trivial [simp]: "rel_Inr (Inr v) v"
by (simp add: rel_Inr_def)
definition rel_liftE:: "('e, 'a) xval → 'a val → bool" where "rel_liftE v v' ≡ (v = Result (the_Res v'))"
lemma fun_of_rel_rel_liftE[fun_of_rel_intros]:
"fun_of_rel rel_liftE (λx. case x of Result v → Result v | Exn _ → undefined)"
by (auto simp add: rel_liftE_def fun_of_rel_def)
lemma funp_rel_liftE[funp_intros, corres_admissible]: "funp rel_liftE"
using fun_of_rel_rel_liftE by (auto simp add: funp_def)
lemma rel_liftEI: "v = Result (the_Res v') ==> rel_liftE v v'"
by (simp add: rel_liftE_def)
lemma rel_liftE_apply: "rel_liftE x y = (x = Result (the_Res y))"
by (simp add: rel_liftE_def )
lemma rel_liftE_trivial [simp]: "rel_liftE (Result v) (Result v)"
by (simp add: rel_liftE_def)
lemma rel_liftE_rel_exception_or_result_conv: "rel_liftE = rel_exception_or_result (λNone → λ_. True | Some _ → λ_. False) (=)"
apply (rule ext)+
apply (auto simp add: rel_liftE_def rel_exception_or_result.simps)
done
lemma rel_liftE_Result_Result_iff[simp]: "rel_liftE (Result v) (Result v') ⟷ v = v'"
by (auto simp add: rel_liftE_def)
definition "rel_liftE' v v' ≡ (v = Inr v')"
lemma fun_of_rel_rel_liftE'[fun_of_rel_intros]:
"fun_of_rel rel_liftE' (λx. case x of Inr v → v | Inl _ → undefined)"
by (auto simp add: rel_liftE'_def fun_of_rel_def)
lemma funp_rel_liftE'[funp_intros, corres_admissible]: "funp rel_liftE'"
using fun_of_rel_rel_liftE' by (auto simp add: funp_def)
lemma rel_liftE'I: "v = Inr v' ==> rel_liftE' v v'"
by (simp add: rel_liftE'_def)
lemma rel_liftE'_apply: "rel_liftE' x y = (x = Inr y)"
by (simp add: rel_liftE'_def )
lemma rel_liftE'_trivial [simp]: "rel_liftE' (Inr v) v"
by (simp add: rel_liftE'_def)
lemma rel_liftE'_Inr_iff[simp]: "rel_liftE' (Inr v) v' ⟷ v = v'"
by (auto simp add: rel_liftE'_def)
lemma rel_liftE'_rel_liftE_conv: "rel_liftE' = rel_map to_xval OO rel_liftE OO rel_map the_Res"
apply (rule ext)+
apply (auto simp add: relcompp.simps rel_map_def rel_liftE_def rel_liftE'_def)
done
lemma rel_liftE_rel_liftE'_conv: "rel_liftE = rel_map from_xval OO rel_liftE' OO rel_map Result"
apply (rule ext)+
apply (auto simp add: relcompp.simps rel_map_def rel_liftE_def rel_liftE'_def)
done
lemma rel_liftE'_Inr: "rel_liftE' (Inr x) x"
by (simp)
definition rel_throwE' :: "('a → 'b → bool) → 'a + 'c → 'b → bool" where
"rel_throwE' L a c ⟷ (case a of Inl a' → L a' c | Inr _ → False)"
lemma rel_throwE'_iff: "rel_throwE' L a c ⟷ (∃l. a = Inl l ∧ L l c)"
by (auto simp add: rel_throwE'_def split: sum.splits)
lemma rel_throwE'_Inl:
"L x y ==> rel_throwE' L (Inl x) y"
unfolding rel_throwE'_def
by auto
lemma rel_throwE'_Inl_iff[simp]:
"rel_throwE' L (Inl x) y ⟷ L x y"
unfolding rel_throwE'_def
by auto
lemma not_rel_throwE'_Inr[simp]: "¬rel_throwE' R (Inr d) a"
by (auto simp: rel_throwE'_def)
definition rel_throwE :: "('a → 'b → bool) → ('a, 'c) xval → 'b → bool" where
"rel_throwE L a c ⟷ (case a of Exn a' → L a' c | Result _ → False)"
lemma rel_throwE_iff: "rel_throwE L a c ⟷ (∃e. a = Exn e ∧ L e c)"
by (auto simp add: rel_throwE_def split: xval_splits)
lemma rel_throwE_Exn:
"L x y ==> rel_throwE L (Exn x) y"
unfolding rel_throwE_def
by auto
lemma rel_throwE_Exn_iff[simp]:
"rel_throwE L (Exn x) y ⟷ L x y"
unfolding rel_throwE_def
by auto
lemma not_rel_throwE_Result[simp]: "¬rel_throwE R (Result d) a"
by (auto simp: rel_throwE_def)
lemma case_right_eq: "(case v of Inl l → False | Inr r → P r) = (∃r. P r ∧ v = Inr r)"
by (auto split: sum.splits)
lemma case_left_eq: "(case v of Inr r → False | Inl l → P l) = (∃l. P l ∧ v = Inl l)"
by (auto split: sum.splits)
lemma rel_sum_right: "rel_sum L R (Inr r) v = (∃r'. v = Inr r' ∧ R r r')"
by (auto elim: rel_sum.cases intro: rel_sum.intros split: sum.splits)
lemma rel_sum_left: "rel_sum L R (Inl l) v = (∃l'. v = Inl l' ∧ L l l')"
by (auto elim: rel_sum.cases intro: rel_sum.intros split: sum.splits)
lemma rel_sum_eq_apply: "(rel_sum (=) (=) x y) = (x = y)"
by (cases x) (auto elim: rel_sum.cases intro: rel_sum.intros split: sum.splits)
lemma gen_unit_eq: "x = (y::unit)"
by simp
lemma liftE_L2_while: "L2_while c (λr. liftE (B r)) i n = liftE (whileLoop c B i)"
by (clarsimp simp: L2_while_def liftE_whileLoop)
lemma liftE_L2_while_VARS: "L2_while c (λr. liftE (B r)) i n = liftE (L2_VARS (whileLoop c B i) n)"
by (simp add: liftE_L2_while L2_VARS_def)
lemma rel_XF_True_def: "(rel_XF st ret_xf ex_xf (λ_ _. True)) =
(λ(v, t) (r, s). s = st t ∧
(case v of Exn x → r = Exn (ex_xf x t) | Result x → r = Result (ret_xf x t)))"
apply (rule ext)+
apply (auto simp add: rel_XF_def rel_xval.simps split: xval_splits)
done
lemma refines_corresXF: "(∀t. P t ⟶ refines C A t (st t) (λ(v, t) (r, s). s = st t ∧
(case v of Exn x → r = Exn (ex_xf x t) | Result x → r = Result (ret_xf x t))))
==> corresXF st ret_xf ex_xf P A C"
by (simp add: corresXF_refines_iff rel_XF_True_def)
lemma corresXF_refines: "corresXF st ret_xf ex_xf P A C ==>
(∀t. P t ⟶ refines C A t (st t) (λ(v, t) (r, s). s = st t ∧
(case v of Exn x → r = Exn (ex_xf x t) | Result x → r = Result (ret_xf x t))))"
by (simp add: corresXF_refines_iff rel_XF_True_def)
theorem corresXF_refines_conv:
‹corresXF st ret_xf ex_xf P A C ⟷
(∀t. P t ⟶ refines C A t (st t) (λ(v, t) (r, s). s = st t ∧
(case v of Exn x → r = Exn (ex_xf x t) | Result x → r = Result (ret_xf x t))))›
using corresXF_refines refines_corresXF ..
lemma sim_nondet_to_corresXF: "(∧s. refines f f' s s (=)) ==>
corresXF (λs. s) (λr _. r) (λr _ . r) (λ_. True) f' f"
unfolding refines_def_old corresXF_def
apply (auto split: xval_splits)
done
named_theorems rel_spec_monad_rewrite_simps
locale sim_stack_heap_state =
abstract: stack_heap_state htda htd_upda hmema hmem_upda S +
concrete: stack_heap_state htdc htd_updc hmemc hmem_updc S
for
htda:: "'sa → heap_typ_desc" and
htd_upda:: "(heap_typ_desc → heap_typ_desc) → 'sa → 'sa" and
hmema:: "'sa → heap_mem" and
hmem_upda:: "(heap_mem → heap_mem) → 'sa → 'sa" and
htdc:: "'sc → heap_typ_desc" and
htd_updc:: "(heap_typ_desc → heap_typ_desc) → 'sc → 'sc" and
hmemc:: "'sc → heap_mem" and
hmem_updc:: "(heap_mem → heap_mem) → 'sc → 'sc" and
S::"addr set"
begin
definition rel_stack_free where
"rel_stack_free sc sa ≡ stack_free (htdc sc) ⊆ stack_free (htda sa)"
lemma refines_rel_stack_free_with_fresh_stack_ptr:
assumes s: "rel_stack_free sc sa"
assumes init_eq: "∧sc sa. Ic sc = Ia sa"
assumes f: "∧sc sa p. rel_stack_free sc sa ==>
refines (fc p) (fa p) sc sa
(rel_prod (rel_xval L R) rel_stack_free)"
shows "refines
(concrete.with_fresh_stack_ptr n Ic fc)
(abstract.with_fresh_stack_ptr n Ia fa) sc sa
(rel_prod (rel_xval L R) rel_stack_free)"
apply (simp add: concrete.with_fresh_stack_ptr_def abstract.with_fresh_stack_ptr_def)
apply (rule refines_bind_bind_exn [where Q="(rel_prod (rel_xval (λ_ _. False) (=)) rel_stack_free)"])
apply simp_all
subgoal
apply (clarsimp simp add: refines_def_old rel_xval.simps)
using s init_eq
apply (simp add: rel_stack_free_def)
subgoal for p d vs bs
apply (frule (1) stack_allocs_stack_free_mono)
apply clarsimp
subgoal for d'
apply (rule exI[where x="hmem_upda (fold (λi. heap_update_padding (p +p int i) (vs ! i) (take (size_of TYPE('a)) (drop (i * size_of TYPE('a)) bs))) [0..<length vs]) (htd_upda (λ_. d') sa)"])
apply clarsimp
apply (rule conjI)
apply (rule exI[where x="d'"])
apply clarsimp
apply (rule exI[where x="vs"])
apply clarsimp
apply blast
using stack_free_stack_allocs
apply blast
done
done
done
apply (rule refines_rel_prod_on_exit [where S' = rel_stack_free])
apply (rule f)
apply assumption
apply (simp add: rel_stack_free_def)
apply (metis abstract.htd_hmem_upd abstract.typing.get_upd concrete.htd_hmem_upd
concrete.typing.get_upd stack_free_stack_releases_mono')
subgoal using stack_free_stack_releases_mono' by blast
done
definition rel_stack_free_eq where
"rel_stack_free_eq sc sa ≡ stack_free (htdc sc) = stack_free (htda sa)"
lemma refines_rel_stack_free_eq_with_fresh_stack_ptr:
assumes s: "rel_stack_free_eq sc sa"
assumes init_eq: "∧sc sa. Ic sc = Ia sa"
assumes f: "∧sc sa p. rel_stack_free_eq sc sa ==>
refines (fc p) (fa p) sc sa
(rel_prod (rel_xval L R) rel_stack_free_eq)"
shows "refines
(concrete.with_fresh_stack_ptr n Ic fc)
(abstract.with_fresh_stack_ptr n Ia fa) sc sa
(rel_prod (rel_xval L R) rel_stack_free_eq)"
apply (simp add: concrete.with_fresh_stack_ptr_def abstract.with_fresh_stack_ptr_def)
apply (rule refines_bind_bind_exn [where Q="(rel_prod (rel_xval (λ_ _. False) (=)) rel_stack_free_eq)"])
apply simp_all
subgoal
apply (clarsimp simp add: refines_def_old rel_xval.simps)
using s init_eq
apply (simp add: rel_stack_free_eq_def)
subgoal for p d vs bs
apply (frule (1) stack_allocs_stack_free_eq)
apply clarsimp
subgoal for d'
apply (rule exI[where x="hmem_upda (fold (λi. heap_update_padding (p +p int i) (vs ! i) (take (size_of TYPE('a)) (drop (i * size_of TYPE('a)) bs))) [0..<length vs]) (htd_upda (λ_. d') sa)"])
apply clarsimp
apply (rule conjI)
apply (rule exI[where x="d'"])
apply clarsimp
apply (rule exI[where x="vs"])
apply clarsimp
apply blast
using stack_free_stack_allocs
apply blast
done
done
done
apply (rule refines_rel_prod_on_exit [where S' = rel_stack_free_eq])
apply (rule f)
apply assumption
apply clarsimp
subgoal for v t t' sc sa bs
apply (rule exI[where x=" hmem_upda (heap_update_list (ptr_val v) bs) (htd_upda (stack_releases n v) sa)"])
apply (clarsimp simp add: rel_stack_free_eq_def)
by (metis dual_order.eq_iff stack_free_stack_releases_mono')
subgoal by blast
done
end
locale sim_stack_heap_raw_state =
abstract: stack_heap_raw_state hrsa hrs_upda S +
concrete: stack_heap_raw_state hrsc hrs_updc S
for
hrsa:: "'sa → heap_raw_state" and
hrs_upda:: "(heap_raw_state → heap_raw_state) → 'sa → 'sa" and
hrsc:: "'sc → heap_raw_state" and
hrs_updc:: "(heap_raw_state → heap_raw_state) → 'sc → 'sc" and
S::"addr set"
begin
sublocale sim_stack_heap_state
"λs. hrs_htd (hrsa s)" "λupd. hrs_upda (hrs_htd_update upd)"
"λs. hrs_mem (hrsa s)" "λupd. hrs_upda (hrs_mem_update upd)"
"λs. hrs_htd (hrsc s)" "λupd. hrs_updc (hrs_htd_update upd)"
"λs. hrs_mem (hrsc s)" "λupd. hrs_updc (hrs_mem_update upd)"
S
by unfold_locales
end
named_theorems L2corres_with_fresh_stack_ptr
locale L2 = sim_stack_heap_state htda htd_upda hmema hmem_upda htdc htd_updc hmemc hmem_updc S
for
htda:: "'sa → heap_typ_desc" and
htd_upda:: "(heap_typ_desc → heap_typ_desc) → 'sa → 'sa" and
hmema:: "'sa → heap_mem" and
hmem_upda:: "(heap_mem → heap_mem) → 'sa → 'sa" and
htdc:: "'sc → heap_typ_desc" and
htd_updc:: "(heap_typ_desc → heap_typ_desc) → 'sc → 'sc" and
hmemc:: "'sc → heap_mem" and
hmem_updc:: "(heap_mem → heap_mem) → 'sc → 'sc" and
S::"addr set" +
fixes st:: "'sc → 'sa"
assumes htd_st: "∧s. htda (st s) = htdc s"
assumes htd_upd_st: "∧s f. (htd_upda f (st s)) = st (htd_updc f s)"
assumes hmem_upd_st: "∧s f. (hmem_upda f (st s)) = st (hmem_updc f s)"
begin
lemma rel_stack_free_eq_st: "rel_stack_free_eq s (st s)"
by (simp add: rel_stack_free_eq_def htd_st)
definition rel_L2 where
"rel_L2 ex_xf ret_xf ≡ (λ (rc, sc) (ra, sa).
rel_xval (λ_ a. a = ex_xf sc) (λ_ a. a = ret_xf sc) rc ra ∧
(sa = st sc))"
lemma rel_L2_def':
"(rel_L2 ex_xf ret_xf) = (λ(v, t) (r, s).
s = st t ∧ (case v of Exn x → r = Exn (ex_xf t) | Result x → r = Result (ret_xf t)))"
apply (clarsimp simp add: rel_L2_def fun_eq_iff, intro iffI)
subgoal using rel_xval.cases by fastforce
subgoal by(auto split: xval_splits)
done
lemma refines_rel_L2_on_exit':
assumes f: "refines (fc p) (fa p) sc (st sc) (rel_L2 ex_xf ret_xf)"
assumes ex_xf_htd_indep: "∧f s. ex_xf (htd_updc f s) = ex_xf s"
assumes ret_xf_htd_indep: "∧f s. ret_xf (htd_updc f s) = ret_xf s"
shows "refines
(on_exit (fc p) {(s,t). t = htd_updc (release p) s})
(on_exit (fa p) {(s,t). t = htd_upda (release p) s}) sc (st sc)
(rel_L2 ex_xf ret_xf)"
unfolding on_exit_bind_exception_or_result_conv
apply (rule refines_bind_exception_or_result)
apply (rule refines_mono [OF _ f])
apply (clarsimp)
subgoal for r s q t
apply (rule refines_bind_bind_exn[where
Q="(λ(r', s) (q', t). is_Result r' ∧ is_Result q' ∧ rel_L2 ex_xf ret_xf (r, s) (q, t))"])
subgoal
apply (rule refines_assert_result_and_state)
apply (clarsimp simp add: rel_L2_def, intro conjI)
subgoal
using ex_xf_htd_indep ret_xf_htd_indep
by metis
subgoal
using htd_upd_st by force
by auto
apply (auto simp: is_Result_def)
done
done
lemma refines_rel_L2_on_exit:
assumes f: "refines (fc p) (fa p) sc (st sc) (rel_L2 ex_xf ret_xf)"
assumes ex_xf_htd_indep: "∧g f s. ex_xf (hmem_updc g (htd_updc f s)) = ex_xf s"
assumes ret_xf_htd_indep: "∧g f s. ret_xf (hmem_updc g (htd_updc f s)) = ret_xf s"
assumes nonempty_cleanupa: "cleanupa ≠ {}"
assumes cleanup_htd: "∧s s'. (s, s') ∈ cleanupc ==> ∃g f. s' = (hmem_updc g (htd_updc f s))"
assumes stuck_sim: "∧s. ∄s'. (s, s') ∈ cleanupc ==> ∄t'. (st s, t') ∈ cleanupa"
assumes cleanup_sim: "∧s t. (s, t) ∈ cleanupc ==> (st s, st t) ∈ cleanupa"
shows "refines
(on_exit (fc p) cleanupc)
(on_exit (fa p) cleanupa) sc (st sc)
(rel_L2 ex_xf ret_xf)"
unfolding on_exit_bind_exception_or_result_conv
apply (rule refines_bind_exception_or_result)
apply (rule refines_mono [OF _ f])
apply (clarsimp)
subgoal for r s q t
apply (rule refines_bind_bind_exn [where
Q="λ(r', s) (q', t). is_Result r' ∧ is_Result q' ∧ rel_L2 ex_xf ret_xf (r, s) (q, t)"])
subgoal
apply (rule refines_state_select)
apply (clarsimp simp add: rel_L2_def, intro conjI)
subgoal
using cleanup_htd cleanup_sim
by blast
subgoal
using ex_xf_htd_indep ret_xf_htd_indep cleanup_htd
by metis
subgoal
using stuck_sim by (auto simp: rel_L2_def)
done
apply (auto simp: is_Result_def)
done
done
lemma refines_rel_L2_with_fresh_stack_ptr:
assumes init_eq: "Ic sc = Ia (st sc)"
assumes ex_xf_htd_indep: "∧g f s. ex_xf (hmem_updc g (htd_updc f s)) = ex_xf s"
assumes ret_xf_htd_indep: "∧g f s. ret_xf (hmem_updc g (htd_updc f s)) = ret_xf s"
assumes f: "∧(p::'a::mem_type ptr) d vs bs. (p, d) ∈ stack_allocs n S TYPE('a) (htdc sc) ==> vs ∈ Ic sc ==> length vs = n ==>
length bs = n * size_of TYPE('a) ==>
refines
(fc p)
(fa p)
(hmem_updc (fold (λi. heap_update_padding (p +p int i) (vs ! i) (take (size_of TYPE('a)) (drop (i * size_of TYPE('a)) bs))) [0..<length vs]) ((htd_updc (λ_. d)) sc))
(st (hmem_updc (fold (λi. heap_update_padding (p +p int i) (vs ! i) (take (size_of TYPE('a)) (drop (i * size_of TYPE('a)) bs))) [0..<length vs]) ((htd_updc (λ_. d)) sc)))
(rel_L2 ex_xf ret_xf)"
shows "refines
(concrete.with_fresh_stack_ptr n Ic fc)
(abstract.with_fresh_stack_ptr n Ia fa) sc (st sc)
(rel_L2 ex_xf ret_xf)"
apply (simp add: concrete.with_fresh_stack_ptr_def abstract.with_fresh_stack_ptr_def)
apply (rule refines_bind_bind_exn [where Q="(λ(rc, tc) (ra, ta).
(∃d p vs bs. (p, d) ∈ stack_allocs n S TYPE('a) (htdc sc) ∧ rc = Result p ∧ ra = Result p ∧ vs ∈ Ic sc ∧ length vs = n ∧
length bs = n * size_of TYPE('a) ∧
tc = hmem_updc (fold (λi. heap_update_padding (p +p int i) (vs ! i) (take (size_of TYPE('a)) (drop (i * size_of TYPE('a)) bs))) [0..<length vs]) ((htd_updc (λ_. d)) sc) ∧
ta = st tc))"])
apply simp_all
subgoal
apply (clarsimp simp add: refines_def_old rel_xval.simps)
by (metis (full_types) hmem_upd_st htd_st htd_upd_st init_eq )
subgoal for p
apply clarsimp
apply (rule refines_rel_L2_on_exit )
apply (rule f)
apply simp
apply simp
apply simp
apply simp
apply (rule ex_xf_htd_indep)
apply (rule ret_xf_htd_indep)
apply blast
subgoal by auto
subgoal by auto
subgoal using htd_upd_st hmem_upd_st by auto
done
done
lemma L2corres_refines_rel_L2_conv:
‹L2corres st ret_xf ex_xf P A C ⟷
(∀t. P t ⟶ refines C A t (st t) (rel_L2 ex_xf ret_xf))›
by (simp add: L2corres_def corresXF_refines_conv rel_L2_def')
lemma L2corres_refines_rel_L2:
assumes L2: "L2corres st ret_xf ex_xf P A C"
assumes P: "P sc"
shows ‹refines C A sc (st sc) (rel_L2 ex_xf ret_xf)›
using L2 P by (simp add: L2corres_refines_rel_L2_conv)
lemma L2corres_with_fresh_stack_ptr[L2corres_with_fresh_stack_ptr]:
assumes l2: "∧p. L2corres st ret_xf ex_xf P (l2 p) (l1 p)"
assumes I: "∧s. R s ==> I_l1 s = I_l2 (st s)"
assumes P: "∧s. R s ==> P s"
assumes ex_xf_htd_indep: "∧g f s. ex_xf (hmem_updc g (htd_updc f s)) = ex_xf s"
assumes ret_xf_htd_indep: "∧g f s. ret_xf (hmem_updc g (htd_updc f s)) = ret_xf s"
assumes P_indep: "∧f g s. P (hmem_updc g (htd_updc f s)) = P s"
shows "L2corres st ret_xf ex_xf R
(abstract.with_fresh_stack_ptr n (I_l2) (L2_VARS l2 nm))
(concrete.with_fresh_stack_ptr n I_l1 l1)"
apply (clarsimp simp add: L2_VARS_def L2corres_refines_rel_L2_conv)
apply (rule refines_rel_L2_with_fresh_stack_ptr)
apply (rule I, assumption)
apply (rule ex_xf_htd_indep)
apply (rule ret_xf_htd_indep)
apply (rule L2corres_refines_rel_L2)
apply (rule l2)
apply (simp add: P_indep P)
done
end
hide_const (open) L2
lemma refines_rel_prod_guard_on_exit:
assumes f: "refines fc fa sc sa (rel_prod R S')"
assumes cleanup: "∧sc sa tc. S' sc sa ==> grd sa ==> (sc, tc) ∈ cleanupc ==> ∃ta. (sa, ta) ∈ cleanupa ∧ S tc ta"
assumes emp: "∧sc sa. S' sc sa ==> ∄tc. (sc, tc) ∈ cleanupc ==> ∄ta. (sa, ta) ∈ cleanupa"
shows "refines (on_exit fc cleanupc) (guard_on_exit fa grd cleanupa) sc sa (rel_prod R S)"
unfolding on_exit_def on_exit'_def
apply (rule refines_bind_exception_or_result[OF refines_weaken, OF f])
apply (simp add: bind_assoc)
apply (rule refines_bind_guard_right)
apply (rule refines_bind'[OF refines_state_select])
subgoal using cleanup by auto
subgoal using emp by auto
done
lemma refines_bind_no_throw_strong:
assumes "no_throw (λ_. True) f"
assumes "no_throw (λ_. True) f'"
assumes f: "refines f f' s s' Q"
assumes g: "∧r t r' t'. reaches f s (Result r) t ==> reaches f' s' (Result r') t' ==>
Q (Result r, t) (Result r', t') ==> refines (g r) (g' r') t t' R"
shows "refines (f >>= g) (f' >>= g') s s' R"
apply (rule refines_bind_bind_strong' [OF f])
subgoal using assms
apply (clarsimp simp add: no_throw_def runs_to_partial_def_old)
by (metis the_Exception_simp the_Exception_Result reaches_succeeds)
subgoal using assms
apply (clarsimp simp add: no_throw_def runs_to_partial_def_old)
by (metis the_Exception_simp the_Exception_Result reaches_succeeds)
subgoal using assms
apply (clarsimp simp add: no_throw_def runs_to_partial_def_old)
by (metis the_Exception_simp the_Exception_Result reaches_succeeds)
subgoal using g
by auto
done
lemma refines_bind_no_throw:
assumes "no_throw (λ_. True) f"
assumes "no_throw (λ_. True) f'"
assumes f: "refines f f' s s' Q"
assumes g: "∧r t r' t'.
Q (Result r, t) (Result r', t') ==> refines (g r) (g' r') t t' R"
shows "refines (f >>= g) (f' >>= g') s s' R"
using assms
by (rule refines_bind_no_throw_strong)
lemma no_throw_guard[simp]: "no_throw P (guard G)"
by (auto simp add: no_throw_def runs_to_partial_def_old)
lemma no_throw_assert_result_and_state[simp]: "no_throw P (assert_result_and_state f)"
by (auto simp add: no_throw_def runs_to_partial_def_old)
lemma no_throw_assume_result_and_state[simp]: "no_throw P (assume_result_and_state f)"
by (auto simp add: no_throw_def runs_to_partial_def_old)
lemma refines_guard_same: "refines (guard P) (guard P) s s (λ(r, t) (r', t'). t=s ∧ t'=s)"
by (simp add: refines_def_old)
lemma refines_state_select_same:
"refines (state_select R) (state_select R) s s (λ(r, t) (r', t'). t' = t ∧ (s, t) ∈ R)"
by (simp add: refines_def_old)
lemma refines_assert_result_and_state_same:
"refines (assert_result_and_state R) (assert_result_and_state R) s s
(λ(r, t) (r', t'). ∃v. (v, t) ∈ R s ∧ r = Result v ∧ r' = Result v ∧ t = t')"
by (auto simp add: refines_def_old)
lemma refines_assume_result_and_state_same:
"refines (assume_result_and_state R) (assume_result_and_state R) s s
(λ(r, t) (r', t'). ∃v. (v, t) ∈ R s ∧ r = Result v ∧ r' = Result v ∧ t = t')"
by (auto simp add: refines_def_old)
lemma refines_assume_result_and_state_same':
assumes "R s = R' s"
shows "refines (assume_result_and_state R) (assume_result_and_state R') s s
(λ(r, t) (r', t'). ∃v. (v, t) ∈ R s ∧ r = Result v ∧ r' = Result v ∧ t = t')"
using assms
by (auto simp add: refines_def_old)
lemma refines_rel_xval_guard_on_exit:
assumes f: "refines fc fa s s (rel_prod (rel_xval L R) (=))"
shows "refines
(guard_on_exit fc P cleanup)
(guard_on_exit fa P cleanup) s s
(rel_prod (rel_xval L R) (=))"
unfolding guard_on_exit_bind_exception_or_result_conv
apply (rule refines_bind_exception_or_result')
apply (rule f)
apply clarsimp
apply (rule refines_bind_no_throw_strong [OF _ _ refines_guard_same])
apply simp
apply simp
apply clarsimp
apply (rule refines_bind_no_throw_strong [OF _ _ refines_state_select_same])
apply simp
apply simp
apply clarsimp
done
lemma refines_rel_xval_on_exit:
assumes f: "refines fc fa s s (rel_prod (rel_xval L R) (=))"
shows "refines
(on_exit fc cleanup)
(on_exit fa cleanup) s s
(rel_prod (rel_xval L R) (=))"
unfolding on_exit_bind_exception_or_result_conv
apply (rule refines_bind_exception_or_result')
apply (rule f)
apply clarsimp
apply (rule refines_bind_no_throw_strong [OF _ _ refines_state_select_same])
apply simp
apply simp
apply clarsimp
done
lemma refines_rel_xval_assume_on_exit:
assumes f: "refines fc fa s s (rel_prod (rel_xval L R) (=))"
shows "refines
(assume_on_exit fc P cleanup)
(assume_on_exit fa P cleanup) s s
(rel_prod (rel_xval L R) (=))"
unfolding assume_on_exit_bind_exception_or_result_conv
apply (rule refines_bind_exception_or_result')
apply (rule f)
apply (rule refines_bind_no_throw_strong [OF _ _ ])
apply simp
apply simp
apply clarsimp
apply (rule refines_assume_result_and_state_same)
apply clarsimp
apply (rule refines_bind_no_throw_strong [OF _ _ refines_state_select_same])
apply simp
apply simp
apply clarsimp
done
lemma refines_state_assume_pred:
assumes P: "P t"
assumes ref: "refines f g s t R"
shows "refines f (do {assume_result_and_state (λs. {(x, y). (λ() s'. s' = s ∧ P s) x y}); g }) s t R"
using P ref
by (auto simp add: refines_def_old succeeds_bind reaches_bind)
lemma refines_rel_prod_assume_on_exit:
assumes f: "refines fc fa sc sa (rel_prod R S')"
assumes cleanup: "∧sc sa tc. S' sc sa ==> (sc, tc) ∈ cleanupc ==> ∃ta. (sa, ta) ∈ cleanupa ∧ S tc ta"
assumes emp: "∧sc sa. S' sc sa ==> ∄tc. (sc, tc) ∈ cleanupc ==> ∄ta. (sa, ta) ∈ cleanupa"
assumes conseq: "∧sc sa. S' sc sa ==> P sa"
shows "refines (on_exit fc cleanupc) (assume_on_exit fa P cleanupa) sc sa (rel_prod R S)"
unfolding assume_on_exit_bind_exception_or_result_conv on_exit_bind_exception_or_result_conv
apply (rule refines_bind_exception_or_result')
apply (rule f)
apply (rule refines_state_assume_pred )
subgoal using conseq by auto
subgoal
apply (rule refines_bind_no_throw_strong [where Q = "rel_prod (λ_ _. True) S"])
apply simp
apply simp
apply (rule refines_state_select)
subgoal using cleanup by auto
subgoal using emp by auto
subgoal
apply (rule refines_yield)
apply auto
done
done
done
lemma refines_runs_to_partial_rel_prod_assume_on_exit:
assumes f: "refines fc fa sc sa (rel_prod R S')"
assumes runs_to: "fc ∙ sc ?{λr t. P t}"
assumes cleanup: "∧sc sa tc. S' sc sa ==> (sc, tc) ∈ cleanupc ==> P sc ==> ∃ta. (sa, ta) ∈ cleanupa ∧ S tc ta"
assumes emp: "∧sc sa. S' sc sa ==> P sc ==> ∄tc. (sc, tc) ∈ cleanupc ==> ∄ta. (sa, ta) ∈ cleanupa"
assumes conseq: "∧sc sa. S' sc sa ==> P sc ==> P' sa"
shows "refines (on_exit fc cleanupc) (assume_on_exit fa P' cleanupa) sc sa (rel_prod R S)"
proof -
from refines_runs_to_partial_fuse [OF f runs_to]
have "refines fc fa sc sa (λ(r, t) (r', t'). rel_prod R S' (r, t) (r', t') ∧ P t)" .
moreover have "(λ(r, t) (r', t'). rel_prod R S' (r, t) (r', t') ∧ P t) = rel_prod R (λt t'. S' t t' ∧ P t)"
by (auto simp add: rel_prod_conv)
ultimately have "refines fc fa sc sa (rel_prod R (λt t'. S' t t' ∧ P t))" by simp
then show ?thesis
apply (rule refines_rel_prod_assume_on_exit)
subgoal using cleanup by blast
subgoal using emp by blast
subgoal using conseq by auto
done
qed
locale L2_heap_raw_state = sim_stack_heap_raw_state hrsa hrs_upda hrsc hrs_updc S
for
hrsa:: "'sa → heap_raw_state" and
hrs_upda:: "(heap_raw_state → heap_raw_state) → 'sa → 'sa" and
hrsc:: "'sc → heap_raw_state" and
hrs_updc:: "(heap_raw_state → heap_raw_state) → 'sc → 'sc" and
S::"addr set" +
fixes st:: "'sc → 'sa"
assumes hrs_htd_st: "∧s. hrs_htd (hrsa (st s)) = hrs_htd (hrsc s)"
assumes hrs_upd_st: "∧s f. (hrs_upda f (st s)) = st (hrs_updc f s)"
begin
sublocale L2
"λs. hrs_htd (hrsa s)" "λupd. hrs_upda (hrs_htd_update upd)"
"λs. hrs_mem (hrsa s)" "λupd. hrs_upda (hrs_mem_update upd)"
"λs. hrs_htd (hrsc s)" "λupd. hrs_updc (hrs_htd_update upd)"
"λs. hrs_mem (hrsc s)" "λupd. hrs_updc (hrs_mem_update upd)"
S
apply (unfold_locales)
subgoal using hrs_htd_st by simp
subgoal using hrs_upd_st by simp
subgoal using hrs_upd_st by simp
done
end
locale typ_heap_typing = pointer_lense r w + heap_typing_state heap_typing heap_typing_upd
for
r:: "'t → ('a::xmem_type) ptr → 'a" and
w:: "'a ptr → ('a → 'a) → 't → 't" and
heap_typing :: "'t → heap_typ_desc" and
heap_typing_upd :: "(heap_typ_desc → heap_typ_desc) → 't → 't" and
S:: "addr set"
begin
definition stack_ptr_acquire :: "nat → 'a list → 'a ptr → heap_typ_desc → 't → 't"
where "stack_ptr_acquire n vs p d s =
(fold (λi. w (p +p int i) (λ_. (vs ! i))) [0..<n]) (heap_typing_upd (λ_. d) s)"
definition stack_ptr_release :: "nat → 'a ptr → 't → 't"
where "stack_ptr_release n p s =
(heap_typing_upd (stack_releases n p) o (fold (λi. w (p +p int i) (λ_. c_type_class.zero)) [0..<n])) s"
definition assume_stack_alloc:: "nat → ('t → ('a::xmem_type) list set) → ('e::default, 'a ptr, 't) spec_monad" where
"assume_stack_alloc n init ≡ assume_result_and_state (λs. {(p, t).
∃d vs. (p, d) ∈ stack_allocs n S TYPE('a::xmem_type) (heap_typing s) ∧
vs ∈ init s ∧
length vs = n ∧
(∀i ∈ {0..<n}. r s (p +p int i) = ZERO('a::xmem_type)) ∧
t = stack_ptr_acquire n vs p d s})"
definition guard_with_fresh_stack_ptr :: "nat → ('t → 'a list set) → ('a::xmem_type ptr → ('e::default, 'v, 't) spec_monad) → ('e, 'v, 't) spec_monad" where
"guard_with_fresh_stack_ptr n init c ≡
do {
p ← assume_stack_alloc n init;
guard_on_exit (c p)
(λs. ∀i < n. root_ptr_valid (heap_typing s) (p +p int i))
{(s, t). t = stack_ptr_release n p s}
}"
definition assume_with_fresh_stack_ptr :: "nat → ('t → 'a list set) → ('a::xmem_type ptr → ('e::default,'v, 't) spec_monad) → ('e, 'v, 't) spec_monad" where
"assume_with_fresh_stack_ptr n init c ≡
do {
p ← assume_stack_alloc n init;
assume_on_exit (c p)
(λs. ∀i < n. root_ptr_valid (heap_typing s) (p +p int i))
{(s, t). t = stack_ptr_release n p s}
}"
definition with_fresh_stack_ptr :: "nat → ('t → 'a list set) → ('a::xmem_type ptr → ('e::default,'v, 't) spec_monad) → ('e, 'v, 't) spec_monad" where
"with_fresh_stack_ptr n init c ≡
do {
p ← assume_stack_alloc n init;
on_exit (c p)
{(s, t). t = stack_ptr_release n p s}
}"
lemma monotone_guard_with_fresh_stack_ptr_le[partial_function_mono]:
assumes [partial_function_mono]: "∧p. monotone R (≤) (λf. c f p)"
shows "monotone R (≤) (λf. guard_with_fresh_stack_ptr n I (c f))"
unfolding guard_with_fresh_stack_ptr_def
by (intro partial_function_mono)
lemma monotone_guard_with_fresh_stack_ptr_ge[partial_function_mono]:
assumes [partial_function_mono]: "∧p. monotone R (≥) (λf. c f p)"
shows "monotone R (≥) (λf. guard_with_fresh_stack_ptr n I (c f))"
unfolding guard_with_fresh_stack_ptr_def
by (intro partial_function_mono)
lemma mono_guard_with_fresh_stack_ptr [monad_mono_intros]:
"(∧p. f p ≤ g p) ==> guard_with_fresh_stack_ptr n I f ≤ guard_with_fresh_stack_ptr n I g"
unfolding guard_with_fresh_stack_ptr_def assume_stack_alloc_def on_exit'_def
apply (intro monad_mono_intros gfp.leq_refl le_funI)
by (simp add: le_fun_def)
lemma monotone_assume_with_fresh_stack_ptr_le[partial_function_mono]:
assumes [partial_function_mono]: "∧p. monotone R (≤) (λf. c f p)"
shows "monotone R (≤) (λf. assume_with_fresh_stack_ptr n I (c f))"
unfolding assume_with_fresh_stack_ptr_def
by (intro partial_function_mono)
lemma monotone_assume_with_fresh_stack_ptr_ge[partial_function_mono]:
assumes [partial_function_mono]: "∧p. monotone R (≥) (λf. c f p)"
shows "monotone R (≥) (λf. assume_with_fresh_stack_ptr n I (c f))"
unfolding assume_with_fresh_stack_ptr_def
by (intro partial_function_mono)
lemma mono_assume_with_fresh_stack_ptr [monad_mono_intros]:
"(∧p. f p ≤ g p) ==> assume_with_fresh_stack_ptr n I f ≤ assume_with_fresh_stack_ptr n I g"
unfolding assume_with_fresh_stack_ptr_def assume_stack_alloc_def on_exit'_def
apply (intro monad_mono_intros gfp.leq_refl le_funI)
by (simp add: le_fun_def)
lemma monotone_with_fresh_stack_ptr_le[partial_function_mono]:
assumes [partial_function_mono]: "∧p. monotone R (≤) (λf. c f p)"
shows "monotone R (≤) (λf. with_fresh_stack_ptr n I (c f))"
unfolding with_fresh_stack_ptr_def on_exit_def
by (intro partial_function_mono)
lemma monotone_with_fresh_stack_ptr_ge[partial_function_mono]:
assumes [partial_function_mono]: "∧p. monotone R (≥) (λf. c f p)"
shows "monotone R (≥) (λf. with_fresh_stack_ptr n I (c f))"
unfolding with_fresh_stack_ptr_def on_exit_def
by (intro partial_function_mono)
lemma mono_with_fresh_stack_ptr [monad_mono_intros]:
"(∧p. f p ≤ g p) ==> with_fresh_stack_ptr n I f ≤ with_fresh_stack_ptr n I g"
unfolding with_fresh_stack_ptr_def assume_stack_alloc_def on_exit_def on_exit'_def
apply (intro monad_mono_intros gfp.leq_refl le_funI)
by (simp add: le_fun_def)
lemma refines_rel_xval_guard_with_fresh_stack_ptr:
assumes init_eq: "initc s = inita s"
assumes f: "∧s p. refines (fc p) (fa p) s s (rel_prod (rel_xval L R) (=))"
shows
"refines
(guard_with_fresh_stack_ptr n initc (L2_VARS fc nm))
(guard_with_fresh_stack_ptr n inita (L2_VARS fa nm)) s s
(rel_prod (rel_xval L R) (=))"
unfolding guard_with_fresh_stack_ptr_def L2_VARS_def on_exit'_def assume_stack_alloc_def
apply (rule refines_bind')
apply (subst refines_assume_result_and_state_iff)
apply (subst init_eq)
apply (rule sim_set_refl)
apply clarsimp
apply (rule refines_bind_exception_or_result'[OF f])
apply (rule refines_bind')
apply (rule refines_bind')
apply (rule refines_guard)
apply simp_all
apply (rule refines_assert_result_and_state)
apply simp_all
done
lemma refines_rel_xval_assume_with_fresh_stack_ptr:
assumes init_eq: "initc s = inita s"
assumes f: "∧s p. refines (fc p) (fa p) s s (rel_prod (rel_xval L R) (=))"
shows
"refines
(assume_with_fresh_stack_ptr n initc (L2_VARS fc nm))
(assume_with_fresh_stack_ptr n inita (L2_VARS fa nm)) s s
(rel_prod (rel_xval L R) (=))"
unfolding assume_with_fresh_stack_ptr_def L2_VARS_def on_exit'_def assume_stack_alloc_def
apply (rule refines_bind')
apply (subst refines_assume_result_and_state_iff)
apply (subst init_eq)
apply (rule sim_set_refl)
apply clarsimp
apply (rule refines_bind_exception_or_result'[OF f])
apply (rule refines_bind')
apply (rule refines_bind')
apply (rule refines_assuming)
apply simp_all
apply (rule refines_assert_result_and_state)
apply simp_all
done
lemma refines_rel_xval_with_fresh_stack_ptr:
assumes init_eq: "initc s = inita s"
assumes f: "∧s p. refines (fc p) (fa p) s s (rel_prod (rel_xval L R) (=))"
shows
"refines
(with_fresh_stack_ptr n initc (L2_VARS fc nm))
(with_fresh_stack_ptr n inita (L2_VARS fa nm)) s s
(rel_prod (rel_xval L R) (=))"
unfolding with_fresh_stack_ptr_def L2_VARS_def assume_stack_alloc_def
apply (rule refines_bind_no_throw [where Q = "rel_prod (rel_xval (λ_ _. False) (=)) (=)"])
apply simp
apply simp
subgoal using init_eq by (auto simp add: refines_def_old rel_xval.simps)
subgoal
apply clarsimp
apply (rule refines_rel_xval_on_exit)
apply (rule f)
done
done
(* This is not in pointer_lense, since the lemma depends on the xmem type class *)
lemma write_same_ZERO:
"r s p = ZERO('a) ==> w p (λy. ZERO('a)) s = s"
using write_same by simp
end
lemma refines_rel_prod_eq_on_exit:
assumes f: "refines fc fa s s (rel_prod Q (=))"
shows "refines
(on_exit fc cleanup)
(on_exit fa cleanup) s s
(rel_prod Q (=))"
unfolding on_exit_bind_exception_or_result_conv
apply (rule refines_bind_exception_or_result')
apply (rule f)
apply clarsimp
apply (rule refines_bind_no_throw )
apply simp
apply simp
apply (rule refines_state_select_same)
apply clarsimp
done
context stack_heap_state
begin
lemma refines_rel_prod_with_fresh_stack_ptr:
assumes init_eq: "initc s = inita s"
assumes f: "∧s p. refines (fc p) (fa p) s s (rel_prod Q (=))"
shows
"refines
(with_fresh_stack_ptr n initc (L2_VARS fc nm))
(with_fresh_stack_ptr n inita (L2_VARS fa nm)) s s
(rel_prod Q (=))"
unfolding with_fresh_stack_ptr_def L2_VARS_def
apply (rule refines_bind_no_throw )
apply simp
apply simp
apply (rule refines_assume_result_and_state_same')
apply (simp only: init_eq)
apply clarsimp
apply (rule refines_rel_prod_eq_on_exit)
apply (rule f)
done
end
lemma h_val_coerce_ptr_coerce_packed:
fixes p::"'c::packed_type ptr"
assumes sz_eq: "size_of TYPE('c) = size_of TYPE('a::packed_type)"
shows "h_val h (PTR_COERCE ('c → 'a) p) = COERCE ('c → 'a) (h_val h p)"
by (simp add: h_val_def sz_eq from_bytes_def coerce_def to_bytes_p_def to_bytes_def
packed_type_access_ti access_ti0_def field_access_update_same(1)
size_of_fold sz_eq td_fafu_idem update_ti_t_def)
lemma h_val_field_ptr_coerce_from_bytes_packed:
fixes p::"'c::packed_type ptr"
assumes "field_ti TYPE('a) f = Some t"
assumes "export_uinfo t = export_uinfo (typ_info_t TYPE('b::mem_type))"
assumes [simp]: "size_of TYPE('c) = size_of TYPE('a)"
shows "h_val h (PTR('b) &((PTR_COERCE('c::packed_type → 'a::packed_type) p)→f)) =
from_bytes (access_ti0 t (COERCE ('c → 'a) (h_val h p)))"
apply (simp add:h_val_coerce_ptr_coerce_packed[symmetric])
apply (rule h_val_field_from_bytes' [OF assms(1) assms(2)])
done
lemma packed_type_value_update_ti_explode:
"(v::'a::packed_type) = update_ti (typ_info_t TYPE('a)) (to_bytes_p v) v'"
by (simp add: size_of_def update_ti_s_from_bytes update_ti_update_ti_t)
lemma packed_type_to_bytes_to_bytes_p_conv:
"length bs = size_of TYPE('a::packed_type) ==> to_bytes v bs = to_bytes_p (v::'a)"
apply (simp add: to_bytes_p_def)
by (simp add: packed_type_access_ti to_bytes_def)
lemma packed_type_to_byte_p_coerce:
assumes sz:"size_of TYPE('c::packed_type) = size_of TYPE('a::packed_type)"
shows "to_bytes_p (COERCE('a → 'c) v) = to_bytes_p v"
using sz
apply (simp add: to_bytes_p_def coerce_def)
by (metis (mono_tags, lifting) field_access_update_same(1) field_desc.simps(2) field_desc_def
from_bytes_def len length_replicate size_of_fold td_fafu_idem to_bytes_def
update_ti_t_def wf_fd)
lemma to_bytes_coerce_packed:
"size_of TYPE('a) = size_of TYPE('b) ==> length bs = size_of TYPE('a) ==>
to_bytes (COERCE('a::packed_type→'b::packed_type) v) bs = to_bytes v bs"
by (simp add: coerce_def field_access_update_same(1) from_bytes_def packed_type_access_ti
size_of_def td_fafu_idem to_bytes_def update_ti_t_def)
lemma heap_update_ptr_coerse_packed:
fixes p::"'c::packed_type ptr"
assumes cgrd: "c_guard p"
assumes [simp]: "size_of TYPE('c) = size_of TYPE('a::packed_type )"
shows "heap_update (PTR_COERCE('c → 'a) p) v = heap_update p (COERCE('a →'c) v)"
apply (rule ext)
apply (simp add: heap_update_def packed_type_to_bytes_to_bytes_p_conv packed_type_to_byte_p_coerce)
done
lemma c_guard_ptr_coerceI:
"size_td (typ_info_t TYPE('c)) = size_td (typ_info_t TYPE('a)) ==>
align_td (typ_info_t TYPE('a)) ≤ align_td (typ_info_t TYPE('c)) ==>
c_guard p ==>
c_guard (PTR_COERCE('c::c_type→'a::c_type) p)"
apply (cases p)
using power_le_dvd
by (auto simp add: c_guard_def c_null_guard_def ptr_aligned_def align_of_def size_of_def)
lemma heap_update_field_ptr_coerce_from_bytes_packed:
fixes p::"'c::{xmem_type, packed_type} ptr"
assumes fl: "field_lookup (typ_info_t TYPE('a::{xmem_type, packed_type})) f 0 = Some (t, n)"
assumes match: "export_uinfo t = typ_uinfo_t (TYPE('b::{xmem_type}))"
assumes cgrd: "c_guard (PTR_COERCE('c→ 'a) p)"
assumes sz[simp]: "size_of TYPE('c) = size_of TYPE('a)"
shows "heap_update (PTR('b) &((PTR_COERCE('c→ 'a) p)→f)) v h =
heap_update p (coerce_map (update_ti t (to_bytes_p v)) (h_val h p)) h"
apply (subst heap_update_field_root_conv' [OF fl match cgrd])
apply (simp add: heap_update_def h_val_coerce_ptr_coerce_packed )
apply (subst coerce_coerce_map_cancel_packed[OF sz[symmetric], symmetric])
apply (simp add: coerce_map_def)
apply (subst to_bytes_coerce_packed)
apply (simp_all)
done
named_theorems L2_modify_heap_update_field_root_conv
context heap_state
begin
lemma heap_update_field_root_conv:
fixes p::"'a::xmem_type ptr"
assumes fl: "field_lookup (typ_info_t TYPE('a)) f 0 = Some (adjust_ti (typ_info_t TYPE('b::xmem_type)) fld (fld_update ∘ (λx _. x)), n)"
assumes fg_cons: "fg_cons fld (fld_update ∘ (λx _. x))"
assumes cgrd: "c_guard p"
shows "(hmem_upd (heap_update (PTR('b) &(p→f)) v)) =
(λs. (hmem_upd (heap_update p (fld_update (λ_. v) (h_val (hmem s) p)))) s)"
apply (subst heap_update_field_root_conv_pointless' [OF fl fg_cons cgrd])
apply (rule ext)
by (metis (mono_tags, lifting) heap.upd_cong)
lemma heap_update_field_root_conv':
fixes p::"'a::xmem_type ptr"
assumes fl: "field_lookup (typ_info_t TYPE('a)) f 0 = Some (t, n)"
assumes match: "export_uinfo t = typ_uinfo_t TYPE('b::xmem_type)"
assumes cgrd: "c_guard p"
shows "(hmem_upd (heap_update (PTR('b) &(p→f)) v)) =
(λs. (hmem_upd (heap_update p (update_ti t (to_bytes_p v) (h_val (hmem s) p)))) s)"
using heap_update_field_root_conv' [OF fl match cgrd, of v]
using heap.upd_cong by blast
lemma L2_modify_heap_update_field_root_conv:
fixes p::"'a::xmem_type ptr"
assumes fl: "field_lookup (typ_info_t TYPE('a)) f 0 = Some (adjust_ti (typ_info_t TYPE('b::xmem_type)) fld (fld_update ∘ (λx _. x)), n)"
assumes fg_cons: "fg_cons fld (fld_update ∘ (λx _. x))"
assumes cgrd: "c_guard p"
shows "L2_modify (λs. hmem_upd (heap_update (PTR('b) &(p>→f)) (v s)) s) =
L2_modify (λs. (hmem_upd (heap_update p (fld_update (λ_. v s) (h_val (hmem s) p)))) s)"
by (simp add: heap_update_field_root_conv [OF fl fg_cons cgrd])
lemma L2_modify_heap_update_field_root_conv' [L2_modify_heap_update_field_root_conv]:
fixes p::"'a::xmem_type ptr"
assumes fl: "field_lookup (typ_info_t TYPE('a)) f 0 = Some (t, n)"
assumes match: "export_uinfo t = typ_uinfo_t TYPE('b::xmem_type)"
assumes cgrd: "c_guard p"
shows "L2_modify (λs. hmem_upd (heap_update (PTR('b) &(p>→f)) (v s)) s) =
L2_modify (λs. (hmem_upd (heap_update p (update_ti t (to_bytes_p (v s)) (h_val (hmem s) p)))) s)"
by (simp add: heap_update_field_root_conv' [OF fl match cgrd])
lemma L2_modify_heap_update_ptr_coerce_packed_conv':
fixes p::"'c::packed_type ptr"
assumes cgrd: "c_guard p"
assumes sz: "size_td (typ_info_t TYPE('c)) = size_td (typ_info_t TYPE('a::packed_type))"
shows "L2_modify (λs. hmem_upd (heap_update (PTR_COERCE('c → 'a) p) (COERCE('c → 'a) (v s))) s) =
L2_modify (λs. (hmem_upd (heap_update p (v s))) s)"
using heap_update_ptr_coerse_packed [simplified size_of_def, OF cgrd sz] heap.upd_cong
by (metis assms(2) coerce_cancel_packed size_of_def)
lemma L2_modify_heap_update_ptr_coerce_packed_conv[L2_modify_heap_update_field_root_conv]:
fixes p::"'c::packed_type ptr"
assumes cgrd: "c_guard p"
assumes sz: "size_td (typ_info_t TYPE('c)) = size_td (typ_info_t TYPE('a::packed_type))"
shows "L2_modify (λs. hmem_upd (heap_update (PTR_COERCE('c → 'a) p) (v s)) s) =
L2_modify (λs. (hmem_upd (heap_update p (COERCE('a → 'c) (v s)))) s)"
using heap_update_ptr_coerse_packed [simplified size_of_def, OF cgrd sz] heap.upd_cong
by (metis assms(2) coerce_cancel_packed size_of_def)
lemma L2_modify_heap_update_ptr_coerce_packed_field_root_conv [L2_modify_heap_update_field_root_conv]:
fixes p::"'c::{xmem_type, packed_type} ptr"
assumes fl: "field_lookup (typ_info_t TYPE('a::{xmem_type, packed_type})) f 0 = Some (t, n)"
assumes match: "export_uinfo t = typ_uinfo_t TYPE('b::xmem_type)"
assumes cgrd: "c_guard (PTR_COERCE('c→ 'a) p)"
assumes sz: "size_td (typ_info_t TYPE('c)) = size_td (typ_info_t TYPE('a))"
shows "L2_modify (λs. hmem_upd (heap_update (PTR('b) &((PTR_COERCE('c>→ 'a) p)→f)) (v s)) s) =
L2_modify (λs. (hmem_upd (heap_update p (coerce_map (update_ti t (to_bytes_p (v s))) (h_val (hmem s) p)))) s)"
using heap_update_field_ptr_coerce_from_bytes_packed [simplified size_of_def, OF fl match cgrd sz] heap.upd_cong
by meson
end
lemma L2_try_state_asssumeE_bindE:
"L2_try (assume_result_and_state P >>= f) = assume_result_and_state P >>= (λx. L2_try (f x))"
apply (rule spec_monad_eqI)
apply (auto simp add: runs_to_iff L2_defs)
done
lemma refines_L2_try_L2_seq_nondet:
assumes g [unfolded THIN_def, rule_format]: "PROP THIN (∧v t. refines (L2_try (g v)) (g' v) t t (rel_prod rel_liftE (=)))"
assumes f [unfolded THIN_def]: "PROP THIN (Trueprop (refines f f' s s (rel_prod rel_liftE (=))))"
shows "refines (L2_try (L2_seq f g)) (f' >>= g') s s (rel_prod rel_liftE (=))"
unfolding L2_try_def L2_seq_def try_nested_bind_exception_or_result_conv
using g f
apply (clarsimp simp add: refines_def_old L2_defs succeeds_bind reaches_bind reaches_try succeeds_bind_exception_or_result
rel_liftE_def unnest_exn_def reaches_bind_exception_or_result succeeds_bind_exception_or_result split: xval_splits sum.splits)
apply (intro conjI allI impI)
apply (metis case_xval_simps(2) )
apply clarsimp
subgoal for r s' r'
apply (cases r)
subgoal
apply (cases r')
subgoal
apply (clarsimp simp add: default_option_def Exn_def [symmetric])
by (meson Exn_neq_Result obj_sumE)
subgoal
apply (clarsimp simp add: default_option_def Exn_def [symmetric])
subgoal for s1 y r1
apply (cases r1)
subgoal
apply (clarsimp simp add: default_option_def Exn_def [symmetric])
by (metis Exn_neq_Result Result_eq_Result case_xval_simps(1) old.sum.simps(5) sum_all_ex(2))
subgoal
by (auto simp add: default_option_def Exn_def [symmetric])
done
done
done
subgoal
apply (cases r')
subgoal
apply (clarsimp simp add: default_option_def Exn_def [symmetric])
by (meson Exn_neq_Result sum_all_ex(2))
subgoal
apply (clarsimp simp add: default_option_def Exn_def [symmetric])
subgoal for s1 r1
apply (cases r1)
subgoal
apply (clarsimp simp add: default_option_def Exn_def [symmetric])
by (metis Result_eq_Result case_xval_simps(1) old.sum.simps(6) sum_all_ex(2))
subgoal
by (metis case_xval_simps(2))
done
done
done
done
done
lemma refines_L2_try_pure:
assumes f: "refines f (return f') s s (rel_prod rel_liftE (=))"
shows "refines (L2_try f) (return f') s s (rel_prod rel_liftE (=))"
unfolding L2_defs L2_guarded_def using f
by (fastforce simp add: refines_def_old reaches_try rel_liftE_def)
lemma refines_liftE_conv: "refines f f' s t (rel_prod rel_liftE (=)) ⟷
refines f (liftE f') s t (=)"
unfolding L2_defs L2_guarded_def
by (auto simp add: refines_def_old reaches_liftE rel_liftE_def)
lemma refines_rel_liftE_L2_try_on_exit:
assumes f: "refines fc fa s s (rel_prod rel_liftE (=))"
shows "refines (L2_try (on_exit fc cleanup)) (on_exit fa cleanup) s s (rel_prod rel_liftE (=))"
using f unfolding L2_defs try_def refines_map_value_left_iff
apply (rule refines_rel_prod_eq_on_exit[THEN refines_weaken])
apply (auto simp: rel_liftE_def)
done
lemma map_value_on_exit:
"map_value g (on_exit f cleanup) = on_exit (map_value g f) cleanup"
apply (rule spec_monad_eqI)
apply (auto simp add: runs_to_iff on_exit_def on_exit'_def)
done
lemma L2_try_on_exit: "L2_try (on_exit f cleanup) = on_exit (L2_try f) cleanup"
unfolding L2_try_def try_def
by (simp add: map_value_on_exit)
context stack_heap_state
begin
lemma L2_try_with_fresh_stack_ptr:
"L2_try (with_fresh_stack_ptr n init f) = with_fresh_stack_ptr n init (λp. L2_try (f p))"
by (simp add: with_fresh_stack_ptr_def L2_try_state_asssumeE_bindE L2_try_on_exit)
end
lemma map_value_guard_on_exit:
"map_value g (guard_on_exit f P cleanup) = guard_on_exit (map_value g f) P cleanup"
apply (rule spec_monad_eqI)
apply (auto simp add: runs_to_iff on_exit'_def)
done
lemma L2_try_guard_on_exit:
"L2_try (guard_on_exit f P cleanup) = guard_on_exit (L2_try f) P cleanup"
unfolding L2_try_def try_def
by (simp add: map_value_guard_on_exit)
lemma map_value_assume_on_exit:
"map_value g (assume_on_exit f P cleanup) = assume_on_exit (map_value g f) P cleanup"
apply (rule spec_monad_eqI)
apply (auto simp add: runs_to_iff on_exit'_def)
done
lemma L2_try_assume_on_exit:
"L2_try (assume_on_exit f P cleanup) = assume_on_exit (L2_try f) P cleanup"
unfolding L2_try_def try_def
by (simp add: map_value_assume_on_exit)
context typ_heap_typing
begin
lemma L2_try_guard_with_fresh_stack_ptr:
"L2_try (guard_with_fresh_stack_ptr n init f) = guard_with_fresh_stack_ptr n init (λp. L2_try (f p))"
unfolding guard_with_fresh_stack_ptr_def L2_try_state_asssumeE_bindE assume_stack_alloc_def
L2_try_guard_on_exit ..
lemma L2_try_assume_with_fresh_stack_ptr:
"L2_try (assume_with_fresh_stack_ptr n init f) = assume_with_fresh_stack_ptr n init (λp. L2_try (f p))"
unfolding assume_with_fresh_stack_ptr_def L2_try_state_asssumeE_bindE assume_stack_alloc_def
L2_try_assume_on_exit ..
lemma L2_try_with_fresh_stack_ptr:
"L2_try (with_fresh_stack_ptr n init f) = with_fresh_stack_ptr n init (λp. L2_try (f p))"
by (simp add: with_fresh_stack_ptr_def L2_try_state_asssumeE_bindE assume_stack_alloc_def
L2_try_on_exit)
end
lemma refines_L2_seq:
assumes f: "refines f f' s s' Q"
assumes ll: "∧e e' t t'. Q (Exn e, t) (Exn e', t') ==> R (Exn e, t) (Exn e', t')"
assumes lr: "∧e v' t t'. Q (Exn e, t) (Result v', t') ==> refines (throw e) (g' v') t t' R"
assumes rl: "∧v e' t t'. Q (Result v, t) (Exn e', t') ==> refines (g v) (throw e') t t' R"
assumes rr: "∧v v' t t'. Q (Result v, t) (Result v', t') ==> refines (g v) (g' v') t t' R"
shows "refines (L2_seq f g) (L2_seq f' g') s s' R"
unfolding L2_seq_def using f ll lr rl rr
by (rule refines_bind_bind_exn)
lemma rel_Nonlocal_Nonlocal: "rel_Nonlocal (Nonlocal x) x"
by (simp add: rel_Nonlocal_def)
lemmas rel_sum_Inl = rel_sum.intros(1)
lemmas rel_sum_Inr = rel_sum.intros(2)
lemma rel_sum_eq: "rel_sum (=) (=) x x"
by (auto simp add: rel_sum.simps)
definition (in heap_state)
IO_modify_heap_padding::"'a::mem_type ptr → ('s → 'a) → ('b::default, unit, 's) spec_monad" where
"IO_modify_heap_padding p v =
state_select {(s, t). ∃bs. length bs = size_of (TYPE('a)) ∧ t = hmem_upd (heap_update_padding p (v s) bs) s}"
lemma (in heap_state) liftE_IO_modify_heap_padding: "liftE (IO_modify_heap_padding p v) = (IO_modify_heap_padding p v)"
unfolding IO_modify_heap_padding_def
apply (rule spec_monad_eqI)
apply (auto simp add: runs_to_iff)
done
abbreviation (in heap_state) IO_modify_heap_paddingE::
"'a::mem_type ptr → ('s → 'a) → ('b, unit, 's) exn_monad" where
"IO_modify_heap_paddingE p v ≡ liftE (IO_modify_heap_padding p v)"
lemma (in heap_state) no_fail_IO_modify_padding[simp]: "succeeds (IO_modify_heap_padding p v) s"
unfolding IO_modify_heap_padding_def
apply (simp)
using length_to_bytes_p by blast
lemma (in heap_state) no_fail_IO_modify_paddingE[simp]: "succeeds (IO_modify_heap_paddingE p v) s"
unfolding IO_modify_heap_padding_def
apply (simp)
using length_to_bytes_p by blast
end
¤ Dauer der Verarbeitung: 0.61 Sekunden
(vorverarbeitet am 2026-11-04)
¤
*© Formatika GbR, Deutschland
|
|