NB: This Coq documentation contains a revised version of the Coq implementation of these papers [1], [2], [3], [4], and is also the support for ongoing research. A partial archive (14/01/2001) is available at here. Drop us a line if you are interested in a complete, up-to-date archive.

Library mips_contrib

Require Import ZArith List.
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 : forall e v Q s h, (e |~> v ** TT) s h /\ Q s h ->
 (e |~> v ** (e |~> v -* Q)) s h.
Proof.
move=> e v Q s h [[h1 [h2 [Hdisj [Hunion [Hev _]]]]] HQ].
exists h1; exists h2; repeat (split; trivial).
move=> h2' [Hdisj2 Hev'] h'' Hunion2.
rewrite Hunion2 -(singl_equal _ _ _ _ _ _ _ Hev Hev') // heap.union_com //.
by rewrite -Hunion.
by apply heap.disj_sym.
Qed.

Various Derived Hoare triples

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

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

Lemma hoare_addi : forall 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=> R P Q x y z c H H'.
econstructor; eauto; apply hoare_addi' => //.
Qed.

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

Lemma hoare_addiu : forall 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=> R P Q rt rs i c H H'.
econstructor; eauto; 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' : forall P Q rd rs rt, P ===> wp_add rd rs rt Q ->
  {{ P }} add 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_addu' : forall P Q rd rs rt, P ===> wp_addu rd rs rt Q ->
  {{ P }} addu 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_addu : forall 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=> R P Q rd rs rt c H H'.
econstructor; eauto; apply hoare_addu' => //.
Qed.

Lemma hoare_and' : forall P Q rd rs rt, P ===> wp_and rd rs rt Q ->
  {{ P }} cmd_and 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_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,
    (add_e (var_e base) (int_e (sext 16 idx)) |~> int_e e **
      (add_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 (eval (int_e x) 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,
    (add_e (var_e base) (int_e (sext 16 idx)) |~> int_e e **
      ((add_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,
    (add_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,
    (add_e (var_e base) (shl2_e (var_e idx)) |~> int_e e **
      (add_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 (eval (int_e x) 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,
    (add_e (var_e base) (shl2_e (var_e idx)) |~> int_e e **
      ((add_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,
    (add_e (var_e base) (shl2_e (var_e idx)) |~> int_e e **
      ((add_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,
    (add_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,
    ((add_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'', (add_e (var_e base) (int_e (sext 16 idx)) |~> e'') s h) ** P }}
  sw rt idx base
  {{ (fun s h => (add_e (var_e base) (int_e (sext 16 idx)) |~> var_e rt) s h) ** P }}.
Proof.
move=> P rt idx base.
apply frame_rule; 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 (eval x s); by rewrite H2 heap.get_sing.
- exists x0; split => //; by rewrite H2 heap.upd_sing.
Qed.

Lemma hoare_sw_back : forall rt (idx : immediate) base Q,
  {{ fun s h => exists e,
    (add_e (var_e base) (int_e (sext 16 idx)) |~> e **
      (add_e (var_e base) (int_e (sext 16 idx)) |~> var_e rt -* Q)) s h }}
  sw rt idx base {{ Q }}.
Proof.
move=> rt idx base Q.
apply hoare_prop_m.hoare_stren with (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 (eval x 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.union_com //.
      by apply heap.disj_upd.
Qed.

Lemma hoare_sw_back' : forall rt (idx : immediate) base P Q,
  P ===> (fun s h => exists e,
    (add_e (var_e base) (int_e (sext 16 idx)) |~> e **
      ((add_e (var_e base) (int_e (sext 16 idx)) |~> var_e rt) -* Q)) s h) ->
  {{ P }} sw rt idx base {{ Q }}.
Proof.
move=> rt idx base P Q 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,
    (add_e (var_e base) (int_e (sext 16 idx)) |~> e **
      ((add_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, (add_e (var_e base) (int_e (sext 16 idx)) |~> e ) s h) ** P }}
  sw rt idx base
  {{ (add_e (var_e base) (int_e (sext 16 idx)) |~> var_e rt) ** P }}.
Proof.
move=> P rt idx base.
apply frame_rule; 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 (eval x 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 : forall (c : cmd0) P, {{ FF }} c {{ P }}.
Proof.
case.
- move=> P.
  apply hoare_prop_m.hoare_stren with P => //=.
  do 2 constructor.
- move=> rd rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rt rs i P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rt rs i P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rt rs imm P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rt off base P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rt idx base P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rx ry sa P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd rt sa P.
  eapply hoare_prop_m.hoare_stren; [done | by do 2 constructor].
- move=> rd rt sa P.
  eapply hoare_prop_m.hoare_stren; [done | by do 2 constructor].
- move=> rd rt sa P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rt off base P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rd rs rt P.
  eapply hoare_prop_m.hoare_stren => //=.
  do 2 constructor.
- move=> rt rs imm P.
  eapply hoare_prop_m.hoare_stren => //=; by do 2 constructor.
Qed.

Lemma hoare_false : forall c P, {{ FF }} c {{ P }}.
Proof. move=> c P; 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 : forall (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=> A P P' c Q H.
apply hoare_prop_m.hoare_stren with (fun s h => (exists x, (P x ** P') s h)).
move=> s h /= [h1 [h2 [Hdisj [Hunion [ [a H1] H2] ] ] ] ].
exists a;exists h1; exists h2 => //.
apply pull_out_exists.
move=> a.
by apply (H a).
Qed.

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

Lemma hoare_con_comm_pre : forall P Q c R, {{ P ** Q }} c {{ R }} -> {{ Q ** P }} c {{ R }}.
Proof.
move=> P Q c R H.
apply hoare_prop_m.hoare_stren with (P ** Q); last by done.
by apply con_com.
Qed.

Lemma hoare_con_assoc_pre : forall P Q R c U, {{ P ** (Q ** R) }} c {{ U }} -> {{ P ** Q ** R }} c {{ U }}.
Proof.
move=> P Q R c U H.
apply hoare_prop_m.hoare_stren with (P ** (Q ** R)); last by done.
by apply con_assoc.
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.