Library multi_negate_simu
From mathcomp Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq.
Require Import ssrZ ZArith_ext seq_ext uniq_tac.
Require Import machine_int multi_int encode_decode integral_type.
Import MachineInt.
Require Import mips_bipl mips_tactics mips_syntax mips_mint mips_frame.
Import mips_bipl.expr_m.
Require Import simu.
Import simu.simu_m.
Require Import multi_negate_prg multi_negate_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.
Require Import machine_int multi_int encode_decode integral_type.
Import MachineInt.
Require Import mips_bipl mips_tactics mips_syntax mips_mint mips_frame.
Import mips_bipl.expr_m.
Require Import simu.
Import simu.simu_m.
Require Import multi_negate_prg multi_negate_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, x signed
Lemma pfwd_sim_multi_negate (x : bipl.var.v) d k rx a0 :
uniq(rx, a0, r0) ->
disj (mints_regs (assoc.cdom d)) (a0 :: nil) ->
x \notin assoc.dom d ->
signed k rx \notin assoc.cdom d ->
(x <- .--e (var_e x))%pseudo_expr%pseudo_cmd
<=p( state_mint (x |=> signed k rx \U+ d), fun _ _ _ => 0 < Z_of_nat k < 2 ^^ 31 )
multi_negate rx a0.
Proof.
move=> Hset Hdisj x_d rx_d.
rewrite /pfwd_sim.
move=> s st h [s_st_h k_231] s' exec_pseudo st' h' exec_asm.
move: (proj1 s_st_h x (signed k rx)).
rewrite assoc.get_union_sing_eq.
case/(_ (refl_equal _)) => slen ptr A rx_fit encoding ptr_fit memA.
move: (multi_negate_triple rx a0 slen ptr A Hset) => hoare_triple.
have [st'' [h'' exec_triple_proj]] : exists st'' h'',
(Some (st, heap.proj h (heap.dom (heap_mint (signed k rx) st h))) --
multi_negate rx a0 ---> Some (st'', h''))%asm_cmd.
exists st', (heap.proj h' (heap.dom (heap_mint (signed k rx) st h))).
apply: (mips_syntax.triple_exec_proj _ _ _ hoare_triple) => //.
move: (heap_inclu_heap_mint_signed h st k rx).
move/heap.incluE => ->; exact memA.
set postcond := (_ |--> cplt2 _ :: _ ** _)%asm_assert in hoare_triple.
have {hoare_triple}hoare_triple_postcond : (postcond ** assert_m.TT)%asm_assert st' h'.
move: {hoare_triple}(frame_rule_R _ _ _ hoare_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/(_ st h) => Hhoare_triple.
lapply Hhoare_triple; last first.
exists (heap_mint (signed k rx) st h), (h \D\ heap.dom (heap_mint (signed k rx) st h)).
split; first exact/heap.disj_difs'/inc_refl.
split; last by [].
apply heap.union_difsK; last by [].
exact: heap_inclu_heap_mint_signed.
case=> _.
by move/(_ _ _ exec_asm).
have rx_st_st' : ([rx ]_ st = [rx]_st')%asm_expr.
Reg_unchanged. rewrite [modified_regs _]/=. by Uniq_not_In.
rewrite /state_mint; split.
- move=> z mz.
case/assoc.get_union_Some_inv => [z_is_x | z_in_y_or_d].
+ case/assoc.get_sing_inv : z_is_x => ? ?; subst z mz.
have not_weird_slen : ~ weird slen.
rewrite weirdE2.
case: encoding => H1 -> H3 H4.
move=> abs.
have : sgZ (s2Z slen) = -1.
case: (Zsgn_spec (s2Z slen)).
case=> _ abs'.
rewrite abs' in abs.
lia.
case.
case=> abs'.
by rewrite -abs' /= in abs.
by case.
move=> abs'.
rewrite abs' mulN1Z in abs.
apply Z.opp_inj in abs.
rewrite abs in k_231.
by case: k_231 => _ /ltZZ.
apply mkVarSigned with (cplt2 slen) ptr A => //.
* by rewrite -rx_st_st'.
* 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.
case: encoding => H1 H2 H3 H4.
apply mkSignMagn => //.
rewrite s2Z_cplt2 // H2 Zsgn_Zopp Zsgn_Zmult ZsgnK.
suff : sgZ (Z_of_nat k) = 1 by move=> ->; rewrite mulZ1; ring.
case: k_231 => k_231 _.
by apply Zsgn_pos in k_231.
by rewrite Zsgn_Zopp s2Z_cplt2 // Zsgn_Zopp H3.
rewrite s2Z_cplt2 // Zsgn_Zopp H4; ring.
* case: hoare_triple_postcond => h1 [h2 [h1dh2 [h1Uh2 [Hh1 Hh2]]]].
apply con_heap_mint_signed_cons with h1 => //.
- rewrite h1Uh2.
apply heap.inclu_union_L => //.
by apply heap.inclu_refl.
- by rewrite -rx_st_st'.
- case: encoding => H1 H2 H3 H4.
by rewrite H1.
- by case: encoding.
+ have z_x : z <> x.
move=> ?; subst z.
apply assoc.get_Some_in in z_in_y_or_d.
rewrite -assoc.elts_dom in x_d.
move/negP : x_d; apply.
apply/mapP.
by exists (x, mz).
move: (proj2 s_st_h _ _ z_x mz (signed k rx)).
rewrite assoc.get_union_sing_neq; last by [].
rewrite assoc.get_union_sing_eq.
move/(_ z_in_y_or_d (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_negate rx a0)).
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 mz st h = heap_mint mz st' h'.
apply (heap_mint_state_invariant (heap_mint (signed k rx) st h) z s) => //.
move=> ry Hry; Reg_unchanged.
apply (@disj_not_In _ (mint_regs mz)); last by [].
exact/disj_sym/(Hd_unchanged z).
move: (proj1 s_st_h z mz).
rewrite assoc.get_union_sing_neq; last by [].
exact.
apply var_mint_invariant with s st => //.
* move=> ry ry_my; Reg_unchanged.
apply (@disj_not_In _ (mint_regs mz)); last by [].
exact/disj_sym/(Hd_unchanged z).
* Var_unchanged. rewrite /= mem_seq1; exact/negP/eqP.
* move: (proj1 s_st_h z mz).
rewrite assoc.get_union_sing_neq //; by apply.
- have Hdom : heap.dom (heap_mint (signed k rx) st' h') = heap.dom (heap_mint (signed k rx) st h).
symmetry.
case: hoare_triple_postcond => h1 [h2 [h1_d_h2 [h1_U_h2 [Hh1 Hh2]]]].
rewrite /postcond in Hh1.
apply (dom_heap_mint_sign_state_invariant _ _ _ _ _ _ x s slen (cplt2 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 => //.
by eapply dom_heap_invariant; eauto.
apply (state_mint_part2_one_variable _ _ _ _ _ _ _ _ s_st_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 in 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.
+ exact: (mips_syntax.dom_heap_invariant _ _ _ _ _ exec_asm).
Qed.