Library mips_contrib

Require Import ZArith List.
From mathcomp Require Import ssreflect ssrbool.
Require Import machine_int.
Import MachineInt.
Require Import mips_seplog mips_frame mips_tactics.

Local Open Scope heap_scope.
Import expr_m.
Local Open Scope mips_expr_scope.
Import assert_m.
Local Open Scope mips_assert_scope.
Local Open Scope mips_cmd_scope.
Local Open Scope mips_hoare_scope.

Lemma cell_read e v Q s h : (e |~> v ** TT) s h /\ Q s h ->
 (e |~> v ** (e |~> v -* Q)) s h.
Proof.
move=> [[h1 [h2 [Hdisj [Hunion [Hev _]]]]] HQ].
exists h1, h2; repeat (split; trivial).
move=> h2' [Hdisj2 Hev'] h'' Hunion2.
rewrite Hunion2 -(singl_equal _ _ _ _ _ _ _ Hev Hev') // heap.unionC //.
by rewrite -Hunion.
by apply heap.disj_sym.
Qed.

Various Derived Hoare triples

Lemma hoare_nop' P Q : P ===> Q -> {{ P }} nop {{ Q }}.
Proof. move=> H; apply (hoare_prop_m.hoare_stren Q) => //; by do 2 constructor. Qed.

Lemma hoare_addi' P Q rt rs i : P ===> wp_addi rt rs i Q ->
  {{ P }} addi rt rs i {{ Q }}.
Proof.
move=> H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
Qed.

Lemma hoare_addi R P Q rt rs i c : P ===> wp_addi rt rs i R ->
  {{ R }} c {{ Q }} -> {{ P }} addi rt rs i ; c {{ Q }}.
Proof. move=> H H'; econstructor; eauto; by apply hoare_addi'. Qed.

Lemma hoare_addiu' P Q rt rs i : P ===> wp_addiu rt rs i Q ->
  {{ P }} addiu rt rs i {{ Q }}.
Proof. move=> H; eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done. Qed.

Lemma hoare_addiu R P Q rt rs i c : P ===> wp_addiu rt rs i R ->
  {{ R }} c {{ Q }} -> {{ P }} addiu rt rs i ; c {{ Q }}.
Proof. move=> H H'. econstructor; eauto; by apply hoare_addiu'. Qed.

Local Open Scope machine_int_scope.

Definition FunAndAddiu P i v (iv : immediate) : assert :=
  fun s h => P s h /\ u2Z [i]_s = u2Z ([v]_s `+ sext 16 iv).

Ltac NextAddiu :=
  match goal with
    | |- {{ ?P }} (cmd_cmd0_coercion (addiu ?J ?V ?IV) ; ?C) {{ ?Q }} =>
      let tmp := (eval cbv beta in (FunAndAddiu P J V IV)) in
        apply hoare_addiu with tmp; [unfold FunAndAddiu | idtac]
    | |- WMIPS_Hoare.hoare ?P (cmd_cmd0_coercion (addiu ?J ?V ?IV) ; ?C) ?Q =>
      let tmp := (eval cbv beta in (FunAndAddiu P J V IV)) in
        apply hoare_addiu with tmp; [unfold FunAndAddiu | idtac]
  end.

Local Close Scope machine_int_scope.

Lemma hoare_add' P Q rd rs rt : P ===> wp_add rd rs rt Q ->
  {{ P }} add rd rs rt {{ Q }}.
Proof. move=> H. eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done. Qed.

Lemma hoare_addu' P Q rd rs rt : P ===> wp_addu rd rs rt Q ->
  {{ P }} addu rd rs rt {{ Q }}.
Proof. move=> H. eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done. Qed.

Lemma hoare_addu R P Q rd rs rt c : P ===> wp_addu rd rs rt R ->
  {{ R }} c {{ Q }} -> {{ P }} addu rd rs rt ; c {{ Q }}.
Proof. move=> H H'. econstructor; eauto; by apply hoare_addu'. Qed.

Lemma hoare_and' P Q rd rs rt : P ===> wp_and rd rs rt Q ->
  {{ P }} cmd_and rd rs rt {{ Q }}.
Proof. move=> H. eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done. Qed.

Lemma hoare_and : forall R P Q rd rs rt c, P ===> wp_and rd rs rt R ->
  {{ R }} c {{ Q }} -> {{ P }} cmd_and rd rs rt ; c {{ Q }}.
Proof.
move=> R P Q rd rs rt c H H'.
econstructor; eauto; apply hoare_and' => //.
Qed.

Lemma hoare_andi' : forall P Q rt rs imm, P ===> wp_andi rt rs imm Q ->
  {{ P }} andi rt rs imm {{ Q }}.
Proof.
move=> P Q rt rs imm H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
Qed.

Lemma hoare_andi : forall R P Q rt rs imm c, P ===> wp_andi rt rs imm R ->
  {{ R }} c {{ Q }} -> {{ P }} andi rt rs imm ; c {{ Q }}.
Proof.
move=> R P Q rt rs imm c H H'.
econstructor; eauto; apply hoare_andi' => //.
Qed.

Lemma hoare_lw' : forall rt (index : immediate) base P Q,
  (P ===> wp_lw rt index base Q) ->
  {{ P }} lw rt index base {{ Q }}.
Proof.
move=> rt idx base P Q H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Definition update_store_lw rt v P : assert := fun s h => P (store.upd rt v s) h.

Lemma hoare_lw_back : forall rt (idx : immediate) base Q,
  {{ fun s h => exists e,
    (var_e base \+ int_e (sext 16 idx) |~> int_e e **
      (var_e base \+ int_e (sext 16 idx) |~> int_e e -*
        (update_store_lw rt e Q))) s h }} lw rt idx base {{ Q }}.
Proof.
move=> rt idx base Q.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
move=> s h [x H].
generalize (assert_m.mp _ _ _ _ H) => Hmp.
move: H => [h1 [h2 [Hdisj [Hunion [ [p [Hp1 Hp2] ] H2] ] ] ] ].
exists p; split => //.
exists ([ int_e x ]e_ s); split => //.
rewrite Hunion; apply heap.get_union_L => //.
by rewrite Hp2 heap.get_sing.
Qed.

Lemma hoare_lw_back'' : forall rt (idx : immediate) base P Q R c,
  P ===> (fun s h => exists e,
    (var_e base \+ int_e (sext 16 idx) |~> int_e e **
      ((var_e base \+ int_e (sext 16 idx) |~> int_e e) -*
        (update_store_lw rt e R))) s h) ->
  {{ R }} c {{ Q }} -> {{ P }} lw rt idx base; c {{ Q }}.
Proof.
move=> rt idex base P Q R c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; eauto.
by apply hoare_lw_back.
Qed.

Lemma hoare_lw_back_alt'' : forall rt (idx : immediate) base P Q R c,
  P ===> (fun s h => exists e,
    (var_e base \+ int_e (sext 16 idx) |~> int_e e ** TT) s h /\
    (update_store_lw rt e R) s h) ->
  {{ R }} c {{ Q }} -> {{ P }} lw rt idx base; c {{ Q }}.
Proof.
move=> rt idx base P Q R c H H'.
apply hoare_lw_back'' with R => //.
move=> s h H''.
move: (H _ _ H'') => [x H2].
exists x; by apply cell_read.
Qed.

Lemma hoare_lwxs' : forall rt idx base P Q, P ===> wp_lwxs rt idx base Q ->
  {{ P }} lwxs rt idx base {{ Q }}.
Proof.
move=> rt idx base P Q H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_lwxs : forall R P Q rt idx base c, P ===> wp_lwxs rt idx base R ->
  {{ R }} c {{ Q }} -> {{ P }} lwxs rt idx base ; c {{ Q }}.
Proof.
move=> R P Q rt idx base c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; eauto.
by do 2 constructor.
Qed.

Definition update_store_lwxs rt v P : assert := fun s h => P (store.upd rt v s) h.

Lemma hoare_lwxs_back : forall rt idx base P,
  {{ fun s h => exists e,
    (var_e base \+ shl2_e (var_e idx) |~> int_e e **
      (var_e base \+ shl2_e (var_e idx) |~> int_e e -*
        (update_store_lwxs rt e P))) s h }} lwxs rt idx base {{ P }}.
Proof.
move=> rt idx base P.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
move=> s h [x H].
generalize (assert_m.mp _ _ _ _ H) => Hmp.
move: H => [h1 [h2 [Hdisj [Hunion [ [p [Hp1 Hp2] ] H2] ] ] ] ].
exists p; split => //.
exists ([ int_e x ]e_ s); split => //.
rewrite Hunion; apply heap.get_union_L => //.
by rewrite Hp2 heap.get_sing.
Qed.

Lemma hoare_lwxs_back' : forall rt idx base P Q,
  P ===> (fun s h => exists e,
    (var_e base \+ shl2_e (var_e idx) |~> int_e e **
      ((var_e base \+ shl2_e (var_e idx) |~> int_e e) -*
        update_store_lwxs rt e Q)) s h) ->
  {{P}} lwxs rt idx base {{ Q }}.
Proof.
move=> rt idx base P Q H.
eapply hoare_prop_m.hoare_stren; eauto.
by apply hoare_lwxs_back.
Qed.

Lemma hoare_lwxs_back'' : forall rt idx base P Q R c,
  P ===> (fun s h => exists e,
    (var_e base \+ shl2_e (var_e idx) |~> int_e e **
      ((var_e base \+ shl2_e (var_e idx) |~> int_e e) -*
        update_store_lwxs rt e R)) s h) ->
  {{ R }} c {{ Q }} -> {{ P }} lwxs rt idx base; c {{ Q }}.
Proof.
move=> rt idx base P Q R c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; eauto.
by apply hoare_lwxs_back.
Qed.

Lemma hoare_lwxs_back_alt': forall rt idx base P Q,
  P ===> (fun s h => exists e,
    (var_e base \+ shl2_e (var_e idx) |~> int_e e ** TT) s h /\
    (update_store_lwxs rt e Q) s h) ->
  {{ P }} lwxs rt idx base {{ Q }}.
Proof.
move=> rt idx base P Q H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
move=> s h H0.
move: (H _ _ H0) => [e [ [h1 [h2 [H1 [H2 [ [x [H6 H7] ] H4] ] ] ] ] H5] ].
exists x; split => //.
exists e; split => //.
rewrite H2.
apply heap.get_union_L => //.
by rewrite H7 heap.get_sing.
Qed.

Lemma hoare_lwxs_back_alt'': forall rt idx base P Q R c,
  P ===> (fun s h => exists e,
    ((var_e base \+ shl2_e (var_e idx) |~> int_e e) ** TT) s h /\
    (update_store_lwxs rt e R) s h) ->
  {{ R }} c {{ Q }} -> {{ P }} lwxs rt idx base; c {{ Q }}.
Proof.
move=> rt idx base P Q R c H H'.
apply while.hoare_seq with R => //.
by apply hoare_lwxs_back_alt'.
Qed.

Lemma hoare_maddu' : forall P Q rs rt, P ===> wp_maddu rs rt Q ->
  {{ P }} maddu rs rt {{ Q }}.
Proof.
move=> P Q rs rt H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
Qed.

Lemma hoare_maddu : forall P Q R rs rt c, P ===> wp_maddu rs rt R ->
  {{ R }} c {{ Q }} -> {{ P }} maddu rs rt ; c {{ Q }}.
Proof.
move=> P Q R rs rt c H H'.
apply while.hoare_seq with R => //.
by apply hoare_maddu'.
Qed.

Lemma hoare_mflhxu' : forall P Q rd, P ===> wp_mflhxu rd Q ->
  {{ P }} mflhxu rd {{ Q }}.
Proof.
move=> P Q rd H.
eapply hoare_prop_m.hoare_stren; eauto.
do 2 constructor.
Qed.

Lemma hoare_mflhxu : forall R P Q rd c, P ===> wp_mflhxu rd R ->
  {{ R }} c {{ Q }} -> {{ P }} mflhxu rd ; c {{ Q }}.
Proof.
move=> R P Q rd c H H'.
eapply while.hoare_seq; eauto.
eapply hoare_mflhxu'; eauto.
Qed.

Lemma hoare_mfhi' : forall P Q rd, P ===> wp_mfhi rd Q ->
  {{ P }} mfhi rd {{ Q }}.
Proof.
move=> P Q rd H.
eapply hoare_prop_m.hoare_stren; eauto.
by do 2 constructor.
Qed.

Lemma hoare_mfhi : forall P Q R rd c, P ===> wp_mfhi rd R ->
  {{ R }} c {{ Q }} -> {{ P }} mfhi rd ; c {{ Q }}.
Proof.
move=> P Q R rd c H H'.
eapply while.hoare_seq; eauto.
eapply hoare_mfhi'; eauto.
Qed.

Lemma hoare_mflo' : forall P Q rd, P ===> wp_mflo rd Q ->
  {{ P }} mflo rd {{ Q }}.
Proof. move=> P Q rd H. eapply hoare_prop_m.hoare_stren; eauto. by do 2 constructor. Qed.

Lemma hoare_mflo : forall P Q R rd c, P ===> wp_mflo rd R ->
  {{ R }} c {{ Q }} -> {{ P }} mflo rd ; c {{ Q }}.
Proof.
move=> P Q R rd c H H'.
eapply while.hoare_seq; eauto.
eapply hoare_mflo'; eauto.
Qed.

Lemma hoare_movn' : forall P Q rd rs rt, P ===> wp_movn rd rs rt Q ->
  {{ P }} movn rd rs rt {{ Q }}.
Proof.
move=> P Q rd rs rt H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_movn : forall P Q R rd rs rt c, P ===> wp_movn rd rs rt R ->
  {{ R }} c {{ Q }} -> {{ P }} movn rd rs rt ; c {{ Q }}.
Proof.
move=> P Q R rd rs rt c0 H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_movz' : forall P Q rd rs rt, P ===> wp_movz rd rs rt Q ->
  {{ P }} movz rd rs rt {{ Q }}.
Proof.
move=> P Q rd rs rt H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_movz : forall P Q R rd rs rt c, P ===> wp_movz rd rs rt R ->
  {{ R }} c {{ Q }} -> {{ P }} movz rd rs rt ; c {{ Q }}.
Proof.
move=> P Q R rd rs rt c0 H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_mthi' : forall P Q rs, P ===> wp_mthi rs Q ->
  {{ P }} mthi rs {{ Q }}.
Proof.
move=> P Q rd H.
eapply hoare_prop_m.hoare_stren; eauto.
do 2 constructor.
Qed.

Lemma hoare_mthi : forall P Q R rs c, P ===> wp_mthi rs R ->
  {{ R }} c {{ Q }} -> {{ P }} mthi rs ; c {{ Q }}.
Proof.
move=> P Q R rs c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_mtlo' : forall P Q rs, P ===> wp_mtlo rs Q ->
  {{ P }} mtlo rs {{ Q }}.
Proof.
move=> P Q rs H.
eapply hoare_prop_m.hoare_stren; eauto.
do 2 constructor.
Qed.

Lemma hoare_mtlo : forall P Q R rs c, P ===> wp_mtlo rs R ->
  {{ R }} c {{ Q }} -> {{ P }} mtlo rs ; c {{ Q }}.
Proof.
move=> P Q R rs c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_msubu' : forall P Q rs rt, P ===> wp_msubu rs rt Q ->
  {{ P }} msubu rs rt {{ Q }}.
Proof.
intros.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_msubu : forall P Q R rs rt c, P ===> wp_msubu rs rt R ->
  {{ R }} c {{ Q }} -> {{ P }} msubu rs rt ; c {{ Q }}.
Proof.
move=> P Q R rs rt c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_multu' : forall P Q rs rt, P ===> wp_multu rs rt Q ->
  {{ P }} multu rs rt {{ Q }}.
Proof.
move=> P Q rs rt H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_multu : forall P Q R rs rt c, P ===> wp_multu rs rt R ->
  {{ R }} c {{ Q }} -> {{ P }} multu rs rt ; c {{ Q }}.
Proof.
move=> P Q R rs rt c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_nor' : forall P Q rd rs rt, P ===> wp_nor rd rs rt Q ->
  {{ P }} nor rd rs rt {{ Q }}.
Proof.
move=> P Q rd rs rt H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_or' : forall P Q rd rs rt, P ===> wp_or rd rs rt Q ->
  {{ P }} cmd_or rd rs rt {{ Q }}.
Proof.
move=> P Q rd rs rt H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_or : forall R P Q rd rs rt c, P ===> wp_or rd rs rt R ->
  {{ R }} c {{ Q }} -> {{ P }} cmd_or rd rs rt ; c {{ Q }}.
Proof.
move=> R P Q rd rs rt c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_sll' : forall P Q rx ry sa, P ===> wp_sll rx ry sa Q ->
  {{ P }} sll rx ry sa {{ Q }}.
Proof.
move=> P Q rx ry sa H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_sll : forall R P Q rd rs sa c, P ===> wp_sll rd rs sa R ->
  {{ R }} c {{ Q }} -> {{ P }} sll rd rs sa ; c {{ Q }}.
Proof.
move=> R P Q rd rs sa c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_sllv' : forall P Q rd rs rt, P ===> wp_sllv rd rs rt Q ->
  {{ P }} sllv rd rs rt {{ Q }}.
Proof.
move=> P Q rd rs rt H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_sllv : forall R P Q rd rs rt c, P ===> wp_sllv rd rs rt R ->
  {{ R }} c {{ Q }} -> {{ P }} sllv rd rs rt ; c {{ Q }}.
Proof.
move=> R P Q rd rs rt c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_sra' : forall P Q rx ry ra, P ===> wp_sra rx ry ra Q ->
  {{ P }} sra rx ry ra {{ Q }}.
Proof.
move=> P Q rd rt sa H.
eapply hoare_prop_m.hoare_stren; by [apply H | do 2 constructor].
Qed.

Lemma hoare_sra : forall R P Q rd rs sa c, P ===> wp_sra rd rs sa R ->
  {{ R }} c {{ Q }} -> {{ P }} sra rd rs sa ; c {{ Q }}.
Proof.
move=> R P Q rd rs sa c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; by [apply H | do 2 constructor].
Qed.

Lemma hoare_srl' : forall P Q rx ry ra, P ===> wp_srl rx ry ra Q ->
  {{ P }} srl rx ry ra {{ Q }}.
Proof.
move=> P Q rd rt sa H.
eapply hoare_prop_m.hoare_stren; by [apply H | do 2 constructor].
Qed.

Lemma hoare_srl : forall R P Q rd rs sa c, P ===> wp_srl rd rs sa R ->
  {{ R }} c {{ Q }} -> {{ P }} srl rd rs sa ; c {{ Q }}.
Proof.
move=> R P Q rd rs sa c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; by [apply H | do 2 constructor].
Qed.

Lemma hoare_srlv' : forall P Q rd rs rt, P ===> wp_srlv rd rs rt Q ->
  {{ P }} srlv rd rs rt {{ Q }}.
Proof.
move=> P Q rd rs rt H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_srlv : forall R P Q rd rs rt c, P ===> wp_srlv rd rs rt R ->
  {{ R }} c {{ Q }} -> {{ P }} srlv rd rs rt ; c {{ Q }}.
Proof.
move=> R P Q rd rs rt c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_sltu' : forall P Q rd rs rt, P ===> wp_sltu rd rs rt Q ->
  {{ P }} sltu rd rs rt {{ Q }}.
Proof.
move=> P Q rd rs rt H.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_sltu : forall R P Q rd rs rt c, P ===> wp_sltu rd rs rt R ->
  {{ R }} c {{ Q }} -> {{ P }} sltu rd rs rt ; c {{ Q }}.
Proof.
move=> R P Q rd rs rt c H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_sw' : forall P Q rt off base, P ===> wp_sw rt off base Q ->
  {{ P }} sw rt off base {{ Q }}.
Proof.
move=> P Q rt off base H.
eapply hoare_prop_m.hoare_stren; eauto.
do 2 constructor.
Qed.

Lemma hoare_sw'' : forall R P Q rt off base c, P ===> wp_sw rt off base R ->
  {{ R }} c {{ Q }} -> {{ P }} sw rt off base ; c {{ Q }}.
Proof.
move=> R P Q rt off base c H H'.
apply while.hoare_seq with R => //.
by apply hoare_sw'.
Qed.

Lemma hoare_sw_global : forall P rt (idx : immediate) base,
  {{ (fun s h => exists e'', (var_e base \+ int_e (sext 16 idx) |~> e'') s h) ** P }}
  sw rt idx base
  {{ (var_e base) \+ int_e (sext 16 idx) |~> var_e rt ** P }}.
Proof.
move=> P rt idx base.
apply frame_rule_R; last 2 first.
  rewrite /inde => s h x v /=; tauto.
  done.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
move=> s h [x [x0 [H1 H2]]].
exists x0; split => //.
split.
- exists ([ x ]e_ s); by rewrite H2 heap.get_sing.
- exists x0; split => //; by rewrite H2 heap.upd_sing.
Qed.

Lemma hoare_sw_back rt (idx : immediate) base Q :
  {{ fun s h => exists e,
    (var_e base \+ int_e (sext 16 idx) |~> e **
      (var_e base \+ int_e (sext 16 idx) |~> var_e rt -* Q)) s h }}
  sw rt idx base {{ Q }}.
Proof.
apply (hoare_prop_m.hoare_stren (wp_sw rt idx base Q)); last by do 2 constructor.
move=> s h [x [h1 [h2 [Hdisj [Hunion [ [p [H1p H1] ] H2] ] ] ] ] ].
exists p; split => //.
split.
- exists ([ x ]e_ s).
  rewrite Hunion.
  apply heap.get_union_L => //.
  by rewrite H1 heap.get_sing.
- apply H2 with (heap.upd p [rt]_s h1).
  + split.
    * by apply heap.disj_sym, heap.disj_upd.
    * exists p; split => //.
      by rewrite H1 heap.upd_sing.
  + rewrite Hunion.
    eapply trans_eq.
    * eapply heap.upd_union_L => //.
      rewrite H1 heap.get_sing; reflexivity.
    * rewrite heap.unionC //.
      by apply heap.disj_upd.
Qed.

Lemma hoare_sw_back' rt (idx : immediate) base P Q :
  P ===> (fun s h => exists e,
    (var_e base \+ int_e (sext 16 idx) |~> e **
      ((var_e base \+ int_e (sext 16 idx) |~> var_e rt) -* Q)) s h) ->
  {{ P }} sw rt idx base {{ Q }}.
Proof.
move=> H.
eapply hoare_prop_m.hoare_stren; eauto.
by apply hoare_sw_back.
Qed.

Lemma hoare_sw_back'' : forall rt (idx : immediate) base P Q R c,
  P ===> (fun s h => exists e,
    (var_e base \+ int_e (sext 16 idx) |~> e **
      (var_e base \+ int_e (sext 16 idx) |~> var_e rt -* R)) s h) ->
  {{ R }} c {{ Q}} -> {{ P }} sw rt idx base ; c {{ Q }}.
Proof.
move=> rt idx base P Q R c H H'.
apply while.hoare_seq with R; last by done.
by apply hoare_sw_back'.
Qed.

Lemma hoare_sw_global_alt : forall P rt (idx : immediate) base,
  {{ (fun s h => exists e, (var_e base \+ int_e (sext 16 idx) |~> e ) s h) ** P }}
  sw rt idx base
  {{ (var_e base \+ int_e (sext 16 idx) |~> var_e rt) ** P }}.
Proof.
move=> P rt idx base.
apply frame_rule_R; last 2 first.
  rewrite /inde => s h x v /=; tauto.
  done.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
move=> s h [x [x0 [H1 H2]] ].
exists x0; split => //.
split.
- exists ([ x ]e_ s); by rewrite H2 heap.get_sing.
- exists x0; split => //; by rewrite H2 heap.upd_sing.
Qed.

Lemma hoare_subu' : forall P Q rd rs rt, P ===> wp_subu rd rs rt Q ->
  {{ P }} subu rd rs rt {{ Q }}.
Proof.
intros.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_subu : forall P Q R rd rs rt c, P ===> wp_subu rd rs rt R ->
  {{ R }} c {{ Q }} -> {{ P }} subu rd rs rt ; c {{ Q }}.
Proof.
move=> P Q R rd rs rt c0 H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_xor' : forall P Q rd rs rt, P ===> wp_xor rd rs rt Q ->
  {{ P }} xor rd rs rt {{ Q }}.
Proof.
move=> P Q rd rs rt H.
eapply hoare_prop_m.hoare_stren; last first.
do 2 constructor.
done.
Qed.

Lemma hoare_xor : forall P Q R rd rs rt c, P ===> wp_xor rd rs rt R ->
  {{ R }} c {{ Q }} -> {{ P }} xor rd rs rt ; c {{ Q }}.
Proof.
move=> P Q R rd rs rt c0 H H'.
apply while.hoare_seq with R => //.
eapply hoare_prop_m.hoare_stren; last by do 2 constructor.
done.
Qed.

Lemma hoare_xori' : forall P Q rt rs imm, P ===> wp_xori rt rs imm Q ->
  {{ P }} xori rt rs imm {{ Q }}.
Proof.
move=> P Q rt rs imm H.
eapply hoare_prop_m.hoare_stren; last first.
do 2 constructor.
done.
Qed.

Lemma hoare0_false P : forall (c : cmd0), {{ FF }} c {{ P }}.
Proof.
case.
- apply (hoare_prop_m.hoare_stren P) => //=.
  by do 2 constructor.
- move=> rd rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rt rs i.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rt rs i.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rt rs imm.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rt off base.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rt idx base.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rx ry sa.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd rt sa.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd rt sa.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd rt sa.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rt off base.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rd rs rt.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
- move=> rt rs imm.
  eapply hoare_prop_m.hoare_stren; last by do 2 constructor. done.
Qed.

Lemma hoare_false c P : {{ FF }} c {{ P }}.
Proof. by apply (hoare_prop_m.hoare_false' hoare0_false). Qed.

Lemma extract_exists0 : forall (c : cmd0) (A : Type) (P Q : A -> assert),
  (forall x, {{ P x }} c {{ Q x }}) ->
  {{ fun s h => exists x, P x s h }} c {{ fun s h => exists x, Q x s h }}.
Proof.
case.
- move=> A P Q Hc.
  apply hoare_nop' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a.
  apply H2; by do 2 constructor.
- move=> rd rs rt A P Q Hc.
  apply hoare_add' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H).
  move/exec0_not_None_to_exec_not_None.
  move/exec0_add_not_None => H1 H2.
  split => //.
  exists a; apply H2; by do 2 constructor.
- move=> rt rs imm A P Q Hc.
  apply hoare_addi' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H).
  move/exec0_not_None_to_exec_not_None.
  move/exec0_addi_not_None => H1 H2.
  split => //.
  exists a; apply H2; by do 2 constructor.
- move=> rt rs imm A P Q Hc.
  apply hoare_addiu' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rd rs rt A P Q Hc.
  apply hoare_addu' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rd rs rt A P Q Hc.
  apply hoare_and' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rt rs imm A P Q Hc.
  apply hoare_andi' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rt off base A P Q Hc.
  apply hoare_lw' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H).
  move/exec0_not_None_to_exec_not_None.
  case/exec0_lw_not_None => p [Hp [z' Hz] ] H2.
  exists p; split => //.
  exists z'; split => //.
  exists a; apply H2; by do 2 econstructor; eauto.
- move=> rt idx base A P Q Hc.
  apply hoare_lwxs' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H).
  move/exec0_not_None_to_exec_not_None.
  case/exec0_lwxs_not_None => p [Hp [z' Hz]] H2.
  exists p; split => //.
  exists z'; split => //.
  exists a; apply H2; by do 2 econstructor; eauto.
- move=> rs rt A P Q Hc.
  apply hoare_maddu' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rs A P Q Hc.
  apply hoare_mfhi' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rd A P Q Hc.
  apply hoare_mflhxu' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rd A P Q Hc.
  apply hoare_mflo' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rd rs rt A P Q Hc.
  apply hoare_movn' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  split => Hcondition; exists a; apply H2; by do 2 constructor.
- move=> rd rs rt A P Q Hc.
  apply hoare_movz' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  split => Hcondition; exists a; apply H2; by do 2 constructor.
- move=> rs rt A P Q Hc.
  apply hoare_msubu' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rs A P Q Hc.
  apply hoare_mthi' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rs A P Q Hc.
  apply hoare_mtlo' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rs rt A P Q Hc.
  apply hoare_multu' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rd rs rt A P Q Hc.
  apply hoare_nor' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rd rs rt A P Q Hc.
  apply hoare_or' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rx ry sa A P Q Hc.
  apply hoare_sll' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rd rs rt A P Q Hc.
  apply hoare_sllv' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rd rt rs A P Q Hc.
  apply hoare_sltu' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rd rt sa A P Q Hc.
  apply hoare_sra' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rd rt sa A P Q Hc.
  apply hoare_srl' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rd rt rs A P Q Hc.
  apply hoare_srlv' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rd rs rt A P Q Hc.
  apply hoare_subu' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; do 2 econstructor; eauto.
- move=> rt off base A P Q Hc.
  apply hoare_sw' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H).
  move/exec0_not_None_to_exec_not_None.
  case/exec0_sw_not_None => p [Hp [z' Hz] ] H2.
  exists p; split => //.
  split.
  exists z' => //.
  exists a; apply H2; do 2 econstructor; eauto.
- move=> rd rs rt A P Q Hc.
  apply hoare_xor' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
- move=> rt rs imm A P Q Hc.
  apply hoare_xori' => s h [a H].
  move/hoare_prop_m.soundness: {Hc}(Hc a).
  case/(_ s h H) => H1 H2.
  exists a; apply H2; by do 2 constructor.
Qed.

Lemma pull_out_exists : forall (A : Type) (P : A -> assert) c (Q : assert),
  (forall x, {{ P x }} c {{ Q }}) ->
  {{ fun s h => exists x, P x s h }} c {{ Q }}.
Proof.
move=> A P c Q Hc.
by apply (hoare_prop_m.pull_out_exists' extract_exists0).
Qed.

Lemma pull_out_exists_con (A : Type) (P : A -> assert) P' c Q :
  (forall x, {{ P x ** P' }} c {{ Q }}) ->
  {{ (fun s h => (exists x, P x s h)) ** P' }} c {{ Q }}.
Proof.
move=> H.
apply (hoare_prop_m.hoare_stren (fun s h => (exists x, (P x ** P') s h))).
move=> s h /= [h1 [h2 [Hdisj [Hunion [ [a H1] H2] ] ] ] ].
exists a, h1, h2 => //.
by apply pull_out_exists, H.
Qed.

Lemma pull_out_bang P Q c (A : Prop) :
  (A -> {{ P }} c {{ Q }}) ->
  {{ !(fun s => A) ** P }} c {{ Q }}.
Proof.
move=> H.
case: (Classical_Prop.classic A) => HA.
  apply (hoare_prop_m.hoare_stren P) => //.
  move=> s h /= [h1 [h2 [Hdisj [Hunion [[H1 H2] H3]]]]] //.
  subst h1.
  by rewrite Hunion heap.unioneh.
  apply H => //.
apply (hoare_prop_m.hoare_stren FF).
move=> s h /= [h1 [h2 [Hdisj [Hunion [[H1 H2] H3]]]]] //.
by apply hoare_false.
Qed.

Lemma hoare_con_comm_pre P Q c R : {{ P ** Q }} c {{ R }} -> {{ Q ** P }} c {{ R }}.
Proof. move=> H. apply (hoare_prop_m.hoare_stren (P ** Q)) => //. by apply conC. Qed.

Lemma hoare_con_assoc_pre P Q R c U : {{ P ** Q ** R }} c {{ U }} -> {{ (P ** Q) ** R }} c {{ U }}.
Proof. move=> H. apply (hoare_prop_m.hoare_stren (P ** (Q ** R))) => //. by apply conA. Qed.

Lemma cmd_and_true : forall P rd rs rt, {{ P }} cmd_and rd rs rt {{ TT }}.
Proof.
move=> P rd rs rt0.
eapply while.hoare_conseq.
by apply hoare_prop_m.entails_id.
2: by do 2 constructor.
done.
Qed.

Lemma hoare_frame_rule_and0 : forall (P Q : assert) (c : cmd0),
   hoare0 P c Q ->
   forall P' Q' : store.t -> heap.t -> Prop,
     {{P'}} c {{Q'}} ->
     {{P //\\ P'}} c {{Q //\\ Q'}}.
Proof.
move=> P Q c.
move/(while.hoare_hoare0 store.t heap.t cmd0 expr_b (fun b st => eval_b b (fst st)) hoare0 _ _ _).
move/soundness => H P' Q' H'.
apply hoare_complete.
rewrite /hoare_semantics => s h H0.
split.
  case: H0 => H01 H02.
  move: (proj1 (H s h H01)) => abs.
  contradict abs.
  constructor.
  by apply mips_cmd.semop_prop_m.exec_cmd0_inv.
move=> s' h' exec.
case: H0 => H01 H02.
move: (proj2 (H s h H01) s' h') => abs.
split.
  apply abs.
  constructor.
  by apply mips_cmd.semop_prop_m.exec_cmd0_inv.
move/soundness : H'.
rewrite /hoare_semantics.
case/(_ s h H02) => _.
apply.
done.
Qed.

Lemma exists_conC_hoare A_type P Q R c :
  {{ fun s h => exists A, (P A ** Q) s h }} c {{ R }} ->
  {{ (fun s h => exists A : A_type, P A s h) ** Q }} c {{ R }}.
Proof.
move=> H.
eapply hoare_prop_m.hoare_stren; last by apply H.
move=> s h H' /=.
by apply exists_conC.
Qed.