Library multi_double_u_simu
Require Epsilon.
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_seplog mips_tactics mips_syntax mips_mint.
Import mips_bipl.expr_m.
Require Import simu.
Import simu.simu_m.
Require Import multi_double_u_prg multi_double_u_triple.
Local Open Scope zarith_ext_scope.
Local Open Scope machine_int_scope.
Local Open Scope heap_scope.
Local Open Scope assoc_scope.
Local Open Scope uniq_scope.
Local Open Scope simu_scope.
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_seplog mips_tactics mips_syntax mips_mint.
Import mips_bipl.expr_m.
Require Import simu.
Import simu.simu_m.
Require Import multi_double_u_prg multi_double_u_triple.
Local Open Scope zarith_ext_scope.
Local Open Scope machine_int_scope.
Local Open Scope heap_scope.
Local Open Scope assoc_scope.
Local Open Scope uniq_scope.
Local Open Scope simu_scope.
x <- x * 2, x unsigned
Lemma pfwd_sim_double_u (x : bipl.var.v) (d : assoc.t) (rk rx a0 a1 a2 a3 : reg) :
uniq(rk, rx, a0, a1, a2, a3, r0) ->
disj (mints_regs (assoc.cdom d)) (a0 :: a1 :: a2 :: a3 :: nil) ->
x \notin assoc.dom d -> unsign rk rx \notin assoc.cdom d ->
(x <- var_e x \* nat_e 2)%pseudo_expr%pseudo_cmd
<=p( state_mint (x |=> unsign rk rx \U+ d), fun s st h =>
([ x ]_ s)%pseudo_expr < 2 ^^ ('|u2Z ([ rk ]_st)%asm_expr| * 32 - 1))
multi_double_u rk rx a0 a1 a2 a3.
Proof.
move=> Haux Hd Hd' Hd''.
rewrite /pfwd_sim.
move=> s st h [s_st_h x_k] s' exec_pseudo st' h' exec_mips.
have d_unchanged : forall v r, assoc.get v d = Some r ->
disj (mint_regs r) (mips_frame.modified_regs (multi_double_u rk rx a0 a1 a2 a3)).
move=> v r Hvr; rewrite [mips_frame.modified_regs _]/=; Disj_remove_dup.
apply (disj_incl_LR Hd); last by apply incl_refl_Permutation; PermutProve.
exact/incP/inc_mint_regs/(assoc.get_Some_in_cdom _ v).
set k := '|u2Z ([rk ]_ st)%asm_expr|.
move/multi_double_u_triple : (Haux).
move/(_ '|u2Z ([rk ]_ st)%asm_expr| ([rx ]_ st)%asm_expr
(state_mint_head_unsign_fit _ _ _ _ _ _ _ s_st_h) (Z2ints 32 k ([var_e x ]e_ s)%pseudo_expr)).
rewrite size_Z2ints.
move/(_ Logic.eq_refl) => hoare_triple_double_u.
have [st'' [h'' exec_mips_proj]] : exists st'' h'',
(Some (st, heap.proj h (heap.dom (heap_mint (unsign rk rx) st h)))
-- multi_double_u rk rx a0 a1 a2 a3 ---> Some (st'', h''))%mips_cmd.
exists st', (heap.proj h' (heap.dom (heap_mint (unsign rk rx) st h))).
move/mips_syntax.triple_exec_proj : hoare_triple_double_u; apply => //.
split; first by [].
split; first by rewrite Z_of_nat_Zabs_nat //; apply min_u2Z.
rewrite /heap_cut heap.proj_dom_proj.
apply (state_mint_var_mint _ _ _ _ x (unsign rk rx)) in s_st_h; last by assoc_get_Some.
rewrite /var_mint in s_st_h.
by case: s_st_h => _ [_ ?].
set postcond := (fun s h => exists _, _) in hoare_triple_double_u.
have {hoare_triple_double_u}hoare_triple_post_condition : ( postcond ** assert_m.TT)%asm_assert
st' h'.
move: (mips_frame.frame_rule_R _ _ _ hoare_triple_double_u 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/(_ st h) => Hdouble_u.
lapply Hdouble_u; last first.
exists (heap_mint (unsign rk rx) st h), (h \D\ heap.dom (heap_mint (unsign rk rx) st h)).
split; first by apply heap.disj_difs', seq_ext.inc_refl.
split.
apply heap.union_difsK => //; by apply heap.inclu_proj.
split; last by [].
split; first by [].
split.
rewrite Z_of_nat_Zabs_nat //; by apply min_u2Z.
move: (state_mint_var_mint _ s st h x (unsign rk rx) s_st_h).
rewrite assoc.get_union_sing_eq.
case/(_ refl_equal) => ? ? ?; tauto.
move=> {Hdouble_u} [Hdouble_u Hdouble_u'].
by move: {Hdouble_u'}(Hdouble_u' _ _ exec_mips).
split.
- move=> y ry y_ry.
have [yx | yx] : y \in assoc.dom d \/ y = x.
case/assoc.get_union_Some_inv : y_ry => y_ry.
* by case/assoc.get_sing_inv : y_ry => -> _; right.
* by apply assoc.get_Some_in_dom in y_ry; left.
+ have x_y : y <> x.
move=> ?; subst y; by rewrite yx in Hd'.
move: {s_st_h}(proj1 s_st_h _ _ y_ry) (proj2 s_st_h) => s_st_h1 s_st_h2.
have y_unchanged : ([ y ]_s = [ y ]_s')%pseudo_expr.
Var_unchanged. rewrite /= mem_seq1; exact/negP/eqP.
case: (mips_syntax.exec_deter_proj _ _ _ _ _ exec_mips
(heap.dom (heap_mint (unsign rk rx) st h)) _ _ exec_mips_proj) => H4 [H5 H_h_h'].
have <- : heap_mint ry st h = heap_mint ry st' h'.
apply (heap_mint_state_invariant (heap_mint (unsign rk rx) st h) y s) => //.
move=> rx0 Hrx0; Reg_unchanged.
apply (@disj_not_In _ (mint_regs ry)); last by [].
apply/disj_sym/(d_unchanged y).
by rewrite -y_ry assoc.get_union_sing_neq.
apply s_st_h2 with y x => //.
by rewrite assoc.get_union_sing_eq.
move: s_st_h1; apply var_mint_invariant.
move=> rx0 Hrx0; Reg_unchanged.
apply (@disj_not_In _ (mint_regs ry)); last by [].
apply/disj_sym/(d_unchanged y) => //.
by rewrite -y_ry assoc.get_union_sing_neq.
Var_unchanged; rewrite /= mem_seq1; exact/negP/eqP.
+ subst y.
have ? : ry = unsign rk rx.
rewrite assoc.get_union_sing_eq in y_ry.
by case: y_ry.
subst ry.
set vx := u2Z ([ rx ]_ st)%asm_expr.
set k' := '| u2Z ([ rk ]_ st')%asm_expr |.
set vx' := u2Z ([ rx ]_ st')%asm_expr.
move: (state_mint_var_mint _ s st h x (unsign rk rx) s_st_h).
rewrite assoc.get_union_sing_eq.
case/(_ refl_equal) => X1 X2 X3.
case : hoare_triple_post_condition => h1 [h2 [Hdisj [Hunion [[A' [Hmul2_1 [Hmul2_2 [Hmul2_3 [Hmul2_4 Hmul2_5]]]]] HTT]]]].
have k_k' : k = k' by rewrite /k /k' Hmul2_3 Z_of_nat_Zabs_nat //; apply min_u2Z.
subst k'.
apply mkVarUnsign.
+ by rewrite -k_k' Hmul2_2.
+ split.
- 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.
apply mulZ_ge0 => //; tauto.
- 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 /ZIT.mul mulZC.
case : (ltnP 0 k) => Hk'; last first.
rewrite leqn0 in Hk'. move/eqP in Hk'.
rewrite -/k Hk' ZbetaE mul0n /= in X2.
have {}X2 : ([x]_s = 0)%pseudo_expr by lia.
rewrite X2 mulZ0; by apply Zbeta_gt0.
- rewrite -k_k' ZbetaE (_ : k * 32 = S (k * 32 - 1))%nat; last first.
by rewrite -subSn // ?subn1 // muln_gt0 Hk'.
rewrite ZpowerS; exact/ltZ_pmul2l.
+ apply mapstos_inv_list2heap in Hmul2_4 => //; last first.
by rewrite [eval _ _]/= Hmul2_2 Hmul2_1.
rewrite u2Z_shrl' in Hmul2_4; last by repeat constructor.
rewrite /= Hmul2_2 in Hmul2_4.
rewrite /heap_cut Hunion Hmul2_4.
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 lSum_Z2ints_pos // [ ( [ _ ]e_ _ )%pseudo_expr ]/= in Hmul2_5.
rewrite /ZIT.mul mulZC.
case: (zerop k) => Hk'.
- rewrite -k_k' Hk' Z2ints_0 /= /heap_cut heap.proj_nil.
split; last by [].
move/assert_m.mapstos_inv_addr : X3 => /=.
by rewrite Hmul2_2.
- have Htmp : u2Z ([a2 ]_st')%asm_expr = 0.
have Htmp1 : 2 * ([ x ]_ s)%pseudo_expr < 2 ^^ (k * 32).
rewrite (_ : k * 32 = S (k * 32 - 1))%nat; last first.
move/ltP in Hk'.
by rewrite -subSn // ?subn1 // muln_gt0 Hk'.
rewrite ZpowerS; exact/ltZ_pmul2l.
rewrite -Hmul2_5 in Htmp1.
move: (min_u2Z ([a2]_st')%asm_expr).
case/leZ_eqVlt => Htmp2 //.
rewrite addZC mulnC in Htmp1. move/(poly_Zlt1_inv _ _ _ (min_lSum _ _) (min_u2Z _) (expZ_ge0 _)) : Htmp1 => Htmp1.
rewrite Htmp1 in Htmp2; by move/ltZZ : Htmp2.
rewrite -Hmul2_5.
rewrite Htmp.
rewrite mul0Z addZ0.
rewrite Z_of_nat_Zabs_nat in Hmul2_3.
rewrite Hmul2_3.
rewrite -Z2ints_lSum.
rewrite /heap_cut.
rewrite Hmul2_2.
have <- : heap.dom (list2heap '|vx / 4| A') = iota '|vx / 4| k.
by rewrite dom_list2heap Hmul2_1.
rewrite heap.proj_union_L_dom; last by rewrite -Hmul2_4.
rewrite heap.proj_itself.
apply mapstos_list2heap.
+ rewrite Z_of_nat_Zabs_nat //; last first.
apply Z_div_pos => //; by apply min_u2Z.
rewrite -Zdivide_Zdiv_eq //.
by rewrite -Hmul2_2.
move/assert_m.mapstos_inv_addr : X3.
by apply Zmod_divide.
+ rewrite /vx in X1.
rewrite [eval _ _]/= Hmul2_2; lia.
+ by [].
+ by apply min_u2Z.
- apply (state_mint_part2_one_variable_unsign _ _ _ _ _ _ _ _ _ s_st_h).
+ 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 (unsign rk rx))); last by [].
simpl.
Disj_remove_dup.
by Disj_uniq r0.
* apply (@disj_not_In _ (mint_regs t)); last by [].
Disj_remove_dup.
apply/disj_sym/(disj_incl_LR Hd); last by apply incl_refl_Permutation; PermutProve.
exact/incP/inc_mint_regs.
+ move: (mips_syntax.exec_deter_proj _ _ _ _ _ exec_mips _ _ _ exec_mips_proj); tauto.
+ exact: (mips_syntax.dom_heap_invariant _ _ _ _ _ exec_mips).
Qed.