Library multi_halve_s_simu
From mathcomp Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq.
Require Import ssrZ ZArith_ext seq_ext uniq_tac machine_int multi_int.
Require Import encode_decode integral_type.
Import MachineInt.
Require Import mips_bipl mips_tactics mips_syntax mips_mint.
Import mips_bipl.expr_m.
Require Import simu.
Import simu.simu_m.
Require Import multi_halve_s_prg multi_halve_s_triple.
Local Open Scope heap_scope.
Local Open Scope assoc_scope.
Local Open Scope uniq_scope.
Local Open Scope machine_int_scope.
Local Open Scope zarith_ext_scope.
Local Open Scope simu_scope.
Require Import ssrZ ZArith_ext seq_ext uniq_tac machine_int multi_int.
Require Import encode_decode integral_type.
Import MachineInt.
Require Import mips_bipl mips_tactics mips_syntax mips_mint.
Import mips_bipl.expr_m.
Require Import simu.
Import simu.simu_m.
Require Import multi_halve_s_prg multi_halve_s_triple.
Local Open Scope heap_scope.
Local Open Scope assoc_scope.
Local Open Scope uniq_scope.
Local Open Scope machine_int_scope.
Local Open Scope zarith_ext_scope.
Local Open Scope simu_scope.
x <- x / 2, x signed
Lemma pfwd_sim_halve_s (x : bipl.var.v) d k rx a0 a1 a2 a3 a4 a5 :
uniq(rx, a0, a1, a2, a3, a4, a5, r0) ->
disj (mints_regs (assoc.cdom d)) (a0 :: a1 :: a2 :: a3 :: a4 :: a5 :: nil) ->
x \notin assoc.dom d ->
signed k rx \notin assoc.cdom d ->
(x <- var_e x ./e nat_e 2)%pseudo_expr%pseudo_cmd
<=p( state_mint (x |=> signed k rx \U+ d), fun st s h => Z_of_nat k < 2 ^^ 31)
multi_halve_s rx a0 a1 a2 a3 a4 a5.
Proof.
move=> Hnodup Hdisj x_d rx_d.
rewrite /pfwd_sim.
move=> st s h [st_s_h k_231] st' exec_pseudo s' h' exec_asm.
move/state_mint_var_mint : (st_s_h).
move/(_ x (signed k rx)).
rewrite assoc.get_union_sing_eq.
case/(_ (refl_equal _)) => slen ptr A rx_fit A_x ptr_fit memA.
move/multi_halve_s_triple_gen : (Hnodup).
case: A_x => A_nk slen_nk slen_x x_A.
move/(_ k k_231 ([ rx ]_ s)%asm_expr rx_fit _ ptr_fit _ slen_nk _ A_nk).
rewrite x_A in slen_x.
move/(_ slen_x) => Hhoare_triple.
have [s'' [h'' exec_triple_proj]] : exists s'' h'',
(Some (s, heap.proj h (heap.dom (heap_mint (signed k rx) s h))) --
multi_halve_s rx a0 a1 a2 a3 a4 a5 ---> Some (s'', h''))%asm_cmd.
exists s', (heap.proj h' (heap.dom (heap_mint (signed k rx) s h))).
apply: (mips_syntax.triple_exec_proj _ _ _ Hhoare_triple) => //.
split; first by reflexivity.
suff : heap.proj h (heap.dom (heap_mint (signed k rx) s h)) = heap_mint (signed k rx) s h.
by move=> ->.
by apply heap.incluE, heap_inclu_heap_mint_signed.
set postcond := (fun _ _ => exists _, _) in Hhoare_triple.
have {Hhoare_triple}Hoare_triple_post_cond : (postcond ** assert_m.TT)%asm_assert s' h'.
move: (mips_frame.frame_rule_R _ _ _ Hhoare_triple assert_m.TT (assert_m.inde_TT _) (mips_frame.inde_cmd_mult_TT _)).
move/mips_seplog.hoare_prop_m.soundness.
rewrite /while.hoare_semantics.
move/(_ s h) => Hhoare_triple_sem.
lapply Hhoare_triple_sem; last first.
exists (heap_mint (signed k rx) s h), (h \D\ heap.dom (heap_mint (signed k rx) s h)).
split; first by apply heap.disj_difs', seq_ext.inc_refl.
split.
apply heap.union_difsK => //; by apply heap_inclu_heap_mint_signed.
split; last by [].
split; first by reflexivity.
assumption.
move=> {Hhoare_triple_sem}[Hhoare_triple_sem Hhoare_triple_sem'].
by apply Hhoare_triple_sem' in exec_asm.
split.
- have rx_st_st' : ([ rx ]_ s = [ rx ]_ s')%asm_expr.
Reg_unchanged. rewrite [mips_frame.modified_regs _]/=. by Uniq_not_In.
move=> y my.
case/assoc.get_union_Some_inv.
+ case/assoc.get_sing_inv => ? ?; subst y my.
case: Hoare_triple_post_cond => h1 [h2 [h1dh2 [h1Uh2 [Hh1 _]]]].
rewrite /postcond in Hh1.
case: Hh1 => slen' [A' [A'_nk [slen'_nk [slen'_A' [rx_st'_st [Hmem' Hdiv]]]]]].
apply mkVarSigned with slen' ptr A' => //.
* congruence.
* apply mkSignMagn => //.
- move/syntax_m.seplog_m.semop_prop_m.exec_cmd0_inv : exec_pseudo.
case/syntax_m.seplog_m.exec0_assign_inv => _ -> /=.
syntax_m.seplog_m.assert_m.expr_m.Store_upd.
rewrite x_A /ZIT.div -Hdiv -mulZA mulZC Z_div_plus_full_l //.
rewrite Zdiv_small //; last first.
move: (shrl_lt ([a3 ]_ s')%asm_expr 31) => /= ?.
move: (min_u2Z (([a3 ]_ s')%asm_expr `>> 31)) => ?.
lia.
by rewrite addZ0.
- rewrite /ZIT.div.
move/syntax_m.seplog_m.semop_prop_m.exec_cmd0_inv : exec_pseudo.
case/syntax_m.seplog_m.exec0_assign_inv => _ -> /=.
syntax_m.seplog_m.assert_m.expr_m.Store_upd.
rewrite x_A /ZIT.div -Hdiv.
rewrite -mulZA mulZC Z_div_plus_full_l //.
rewrite Zdiv_small //; last first.
move: (shrl_lt ([a3 ]_ s')%asm_expr 31) => /= ?.
move: (min_u2Z (([a3 ]_ s')%asm_expr `>> 31)) => ?.
lia.
by rewrite addZ0.
- apply con_heap_mint_signed_cons with h1 => //.
rewrite h1Uh2.
apply heap.inclu_union_L => //; by apply heap.inclu_refl.
congruence.
by rewrite A'_nk.
+ move=> y_my.
have y_x : y <> x.
move=> ?; subst y.
apply assoc.get_Some_in in y_my.
rewrite -assoc.elts_dom in x_d.
move/negP : x_d; apply.
apply/mapP.
by exists (x, my).
move: (proj2 st_s_h _ _ y_x my (signed k rx)).
rewrite assoc.get_union_sing_neq; last by [].
rewrite assoc.get_union_sing_eq.
move/(_ y_my (refl_equal _)) => heap_mint_disj.
move: (mips_syntax.exec_deter_proj _ _ _ _ _ exec_asm _ _ _ exec_triple_proj) => [st'_st'' [h''_h' h_h']].
have Hd_unchanged : forall v r, assoc.get v d = Some r ->
disj (mint_regs r) (mips_frame.modified_regs (multi_halve_s rx a0 a1 a2 a3 a4 a5)).
move=> v r Hvr; rewrite [mips_frame.modified_regs _]/=; Disj_remove_dup.
apply (disj_incl_LR Hdisj); last by apply incl_refl_Permutation; PermutProve.
exact/incP/inc_mint_regs/(assoc.get_Some_in_cdom _ v).
have <- : heap_mint my s h = heap_mint my s' h'.
apply (heap_mint_state_invariant (heap_mint (signed k rx) s h) y st) => //.
move=> ry Hry; Reg_unchanged.
apply (@disj_not_In _ (mint_regs my)); last by [].
exact/disj_sym/(Hd_unchanged y).
move: (proj1 st_s_h y my).
rewrite assoc.get_union_sing_neq; last by [].
by apply.
apply var_mint_invariant with st s => //.
* move=> ry ry_my; Reg_unchanged.
apply (@disj_not_In _ (mint_regs my)); last by [].
apply/disj_sym/(Hd_unchanged y) => //.
* Var_unchanged. rewrite /= mem_seq1; exact/negP/eqP.
* move: (proj1 st_s_h y my).
rewrite assoc.get_union_sing_neq; last by [].
by apply.
- have Hdom : heap.dom (heap_mint (signed k rx) s' h') = heap.dom (heap_mint (signed k rx) s h).
symmetry.
case: Hoare_triple_post_cond => h1 [h2 [h1_d_h2 [h1_U_h2 [Hh1 Hh2]]]].
case: Hh1 => slen' [A' [A'_nk [slen'_nk [slen'_A' [rx_s'_s [Hh1 Hdiv]]]]]].
apply (dom_heap_mint_sign_state_invariant _ _ _ _ _ _ x st slen slen') => //.
by move/assert_m.mapstos_get1/heap_get_heap_mint_inv : memA.
apply assert_m.mapstos_get1 in Hh1.
rewrite h1_U_h2. by apply heap.get_union_L => //.
apply assert_m.mapstos_get2 in memA.
apply assert_m.mapstos_get2 in Hh1.
rewrite h1_U_h2.
apply heap_get_heap_mint_inv in memA.
rewrite memA.
symmetry.
by apply heap.get_union_L.
apply mkVarSigned with slen ptr A => //.
apply mkSignMagn => //.
congruence.
by eapply dom_heap_invariant; eauto.
- apply (state_mint_part2_one_variable _ _ _ _ _ _ _ _ st_s_h Hdom).
+ move=> t x0 Ht Hx0.
Reg_unchanged. simpl mips_frame.modified_regs.
case/assoc.in_cdom_union_inv : Ht => Ht.
* rewrite assoc.cdom_sing /= seq.mem_seq1 in Ht.
move/eqP : Ht => Ht; subst t.
apply (@disj_not_In _ (mint_regs (signed k rx))); last by [].
Disj_remove_dup.
rewrite /=.
apply uniq_disj.
rewrite [cat _ _]/=.
by Uniq_uniq r0.
* apply (@disj_not_In _ (mint_regs t)); last by [].
Disj_remove_dup.
apply/disj_sym/(disj_incl_LR Hdisj); last by apply incl_refl_Permutation; PermutProve.
exact/incP/inc_mint_regs.
+ move: (mips_syntax.exec_deter_proj _ _ _ _ _ exec_asm _ _ _ exec_triple_proj); tauto.
+ by apply (mips_syntax.dom_heap_invariant _ _ _ _ _ exec_asm).
Qed.