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 multi_div2_triple

Require Import Arith_ext ZArith_ext Lists_ext.
Require Import ssreflect ssrbool.
Require Import machine_int multi_int.
Import MachineInt.
Require Import mips_seplog mips_tactics mips_contrib mapstos.
Require Import multi_div2_prg.

Local Open Scope machine_int_scope.
Local Open Scope heap_scope.
Local Open Scope zarith_ext_scope.
Local Open Scope nodup_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 multi_div2_triple : forall k a i tmp prev next, nodup(k, a, i, tmp, prev, next, r0) ->
forall nk va, u2Z va + 4 * Z_of_nat nk < Zbeta 1 ->
forall A, length A = nk ->
  {{ fun s h => [a]_s = va /\ u2Z [k]_s = Z_of_nat nk /\ (var_e a |--> A) s h }}
  multi_div2 k a i tmp prev next
  {{ fun s h => exists A', length A' = nk /\
     (var_e a |--> A') s h /\ 2 * Sum nk A' + u2Z ([prev]_s [.>>] 31) = Sum nk A }}.
Proof.
move=> k a i tmp prev next Hset nk va Hna A HA; rewrite /multi_div2.

addiu i k zero16;

apply hoare_addiu with (fun s h => [a]_s = va /\ u2Z [k]_s = Z_of_nat nk /\
  u2Z [i]_s = Z_of_nat nk /\ (var_e a |--> A) s h).

move=> s h [Hra [Hri Hmem]].
rewrite /wp_addiu; repeat reg_upd; repeat (split; trivial).
by rewrite sext_0 add_0.
by Assert_upd.

addiu prev r0 zero16;

apply hoare_addiu with (fun s h => [a]_s = va /\ u2Z [k]_s = Z_of_nat nk /\
  u2Z [i]_s = Z_of_nat nk /\ [prev]_s = zero32 /\ (var_e a |--> A) s h).

move=> s h [Hra [Hri [Hrk Hmem]]].
rewrite /wp_addiu; repeat reg_upd; repeat (split; trivial).
by rewrite sext_0 add_0.
by Assert_upd.

while (bne i r0)

apply hoare_prop_m.hoare_while_invariant with (fun s h => exists A', exists ni, length A' = nk /\
  [a ]_ s = va /\ u2Z [k]_s = Z_of_nat nk /\
  u2Z [i ]_ s = Z_of_nat ni /\
  ([prev]_s = zero32 \/ [prev]_s = Z2u 32 (2 ^^ 31)) /\
  (ni <= nk)%nat /\
  (var_e a |--> A') s h /\
  firstn ni A' = firstn ni A /\
  2 * Sum (nk - ni) (skipn ni A') + u2Z ([prev]_s [.>>] 31) = Sum (nk - ni) (skipn ni A)).

move=> s h [Hra [Hrk [Hri [Hrprev Hmem]]]].
exists A, nk; repeat (split; trivial).
by rewrite Hrprev; left.
by rewrite -minus_n_n /= Hrprev shrl_Z2u_0 // u2Z_Z2u.

move=> s h [[A' [ni [HlenA' [Hra [Hrk [Hri [Hprev [Hik [Hmem [Hinv1 Hinv2]]]]]]]]]] Hri'].
rewrite /= in Hri'. move/negPn : Hri'; move/Zeq_boolP => Hri'.
have {Hri'} ? : ni = O.
  apply Z_of_nat_inj; by rewrite -Hri Hri' /= store.get_r0 u2Z_Z2u.
subst ni.
rewrite -minus_n_O ![skipn _ _]//= in Hinv2.
exists A'; by repeat (split; trivial).

addiu i i mone16;

apply hoare_addiu with (fun s h => exists A', exists ni, length A' = nk /\
  [a ]_ s = va /\ u2Z [k]_s = Z_of_nat nk /\
  u2Z [i ]_ s = Z_of_nat ni /\
  ([prev]_s = zero32 \/ [prev]_s = Z2u 32 (2 ^^ 31)) /\
  (ni < nk)%nat /\
  (var_e a |--> A') s h /\
  firstn (S ni) A' = firstn (S ni) A /\
  2 * Sum (nk - S ni) (skipn (S ni) A') + u2Z ([prev ]_ s [.>>] 31) = Sum (nk - S ni) (skipn (S ni) A)).

move=> s h [[A' [ni [HlenA' [Hra [Hrk [Hri [Hprev [Hik [Hmem [Hinv1 Hinv2]]]]]]]]]] Hri'].
rewrite /= store.get_r0 u2Z_Z2u // in Hri'.
move/Zeq_boolP : Hri' => Hri'.
exists A', (ni - 1)%nat.
repeat reg_upd.
rewrite Hri (_ : 0 = Z_of_nat 0) // in Hri'; apply Z_of_nat_inj_neq, not_eq_sym in Hri'.
rewrite minus_Sn_m; last by apply neq_0_lt.
rewrite minus_Sn_1.
repeat (split; trivial).
- rewrite sext_Z2s // u2Z_add_Z2s //; last first.
    rewrite Hri -(Zmult_1_l (-1)) -(Zopp_eq_mult_neg_1 1) (_ : 1 = Z_of_nat 1) //.
    by apply Zle_left, inj_le, neq_0_lt.
  rewrite inj_minus1 //; by [rewrite Hri | apply neq_0_lt].
- rewrite /lt minus_Sn_m //=; by [rewrite -minus_n_O | apply neq_0_lt].
- by Assert_upd.

lwxs tmp i a;

apply hoare_lwxs_back_alt'' with (fun s h => exists A', exists ni, length A' = nk /\
  [a ]_ s = va /\ u2Z [k]_s = Z_of_nat nk /\
  u2Z [i ]_ s = Z_of_nat ni /\
  ([prev]_s = zero32 \/ [prev]_s = Z2u 32 (2 ^^ 31)) /\
  (ni < nk)%nat /\
  (var_e a |--> A') s h /\
  firstn (S ni) A' = firstn (S ni) A /\
  2 * Sum (nk - S ni) (skipn (S ni) A') + u2Z ([prev ]_ s [.>>] 31) = Sum (nk - S ni) (skipn (S ni) A) /\
  [tmp]_s = nth ni A' zero32).

move=> s h [A' [ni [HlenA' [Hra [Hrk [Hri [Hprev [Hik [Hmem [Hinv1 Hinv2]]]]]]]]]].
exists (nth ni A' zero32); split.
- Decompose_32 A' ni A1 A2 HlenA1 HA'; last by rewrite HlenA'.
  rewrite HA' (decompose_equiv _ _ _ _ _ HlenA1) !con_assoc_equiv con_com_equiv !con_assoc_equiv in Hmem.
  move: Hmem; apply monotony => // h'.
  apply mapsto_ext => //.
  by rewrite [mult]lock /= -lock shl_Z2u inj_mult Hri [Zmult]lock /= -lock Zmult_comm.
- rewrite /update_store_lwxs.
  exists A', ni; repeat reg_upd; repeat (split; trivial).
  by Assert_upd.

andi next tmp one16;

apply hoare_andi with (fun s h => exists A', exists ni, length A' = nk /\
  [a ]_ s = va /\ u2Z [k]_s = Z_of_nat nk /\
  u2Z [i ]_ s = Z_of_nat ni /\
  ([prev]_s = zero32 \/ [prev]_s = Z2u 32 (2 ^^ 31)) /\
  (ni < nk)%nat /\
  (var_e a |--> A') s h /\
  firstn (S ni) A' = firstn (S ni) A /\
  2 * Sum (nk - S ni) (skipn (S ni) A') + u2Z ([prev ]_ s [.>>] 31)= Sum (nk - S ni) (skipn (S ni) A) /\
  [tmp]_s = nth ni A' zero32 /\
  [next]_s = (nth ni A' zero32) [.&] one32).

move=> s h [A' [ni [HlenA' [Hra [Hrk [Hri [Hprev [Hik [Hmem [Hinv1 [Hinv2 Htmp]]]]]]]]]]].
exists A', ni; repeat reg_upd; repeat (split; trivial).
by Assert_upd.
by rewrite Htmp zext_Z2u.

srl tmp tmp one5;

apply hoare_srl with (fun s h => exists A', exists ni, length A' = nk /\
  [a ]_ s = va /\ u2Z [k]_s = Z_of_nat nk /\
  u2Z [i ]_ s = Z_of_nat ni /\
  ([prev]_s = zero32 \/ [prev]_s = Z2u 32 (2 ^^ 31)) /\
  (ni < nk)%nat /\
  (var_e a |--> A') s h /\
  firstn (S ni) A' = firstn (S ni) A /\
  2 * Sum (nk - S ni) (skipn (S ni) A') + u2Z ([prev ]_ s [.>>] 31) = Sum (nk - S ni) (skipn (S ni) A) /\
  [tmp]_s = (nth ni A' zero32) [.>>] 1 /\
  [next]_s = (nth ni A' zero32) [.&] one32).

move=> s h [A' [ni [HlenA' [Hra [Hrk [Hri [Hprev [Hik [Hmem [Hinv1 [Hinv2 [Htmp Hnext]]]]]]]]]]]].
exists A', ni; repeat reg_upd; repeat (split; trivial).
by Assert_upd.
by rewrite Htmp u2Z_Z2u.

cmd_or tmp tmp prev;

apply hoare_or with (fun s h => exists A', exists ni, length A' = nk /\
  [a ]_ s = va /\ u2Z [k]_s = Z_of_nat nk /\
  u2Z [i ]_ s = Z_of_nat ni /\
  ([prev]_s = zero32 \/ [prev]_s = Z2u 32 (2 ^^ 31)) /\
  (ni < nk)%nat /\
  (var_e a |--> A') s h /\
  firstn (S ni) A' = firstn (S ni) A /\
  2 * Sum (nk - S ni) (skipn (S ni) A') + u2Z ([prev ]_ s [.>>] 31) = Sum (nk - S ni) (skipn (S ni) A) /\
  [tmp]_s = ((nth ni A' zero32) [.>>] 1) [.|] [prev]_s /\
  [next]_s = (nth ni A' zero32) [.&] one32).

move=> s h [A' [ni [HlenA' [Hra [Hrk [Hri [Hprev [Hik [Hmem [Hinv1 [Hinv2 [Htmp Hnext]]]]]]]]]]]].
exists A', ni; repeat reg_upd; repeat (split; trivial).
by Assert_upd.
by rewrite Htmp.

addiu prev next zero16;

apply hoare_addiu with (fun s h => exists A', exists ni, length A' = nk /\
  [a ]_ s = va /\ u2Z [k]_s = Z_of_nat nk /\
  u2Z [i ]_ s = Z_of_nat ni /\
  ([prev]_s = zero32 \/ [prev]_s = one32) /\
  (ni < nk)%nat /\
  (var_e a |--> A') s h /\
  firstn (S ni) A' = firstn (S ni) A /\
  2 ^^ 33 * Sum (nk - S ni) (skipn (S ni) A') + 2 * u2Z ([tmp]_s) + u2Z ([prev ]_ s) = Sum (nk - ni) (skipn ni A) /\
  [tmp]_s [.%] 31 = ((nth ni A' zero32) [.>>] 1) [.%] 31 /\
  [next]_s = (nth ni A' zero32) [.&] one32).

move=> s h [A' [ni [HlenA' [Hra [Hrk [Hri [Hprev [Hik [Hmem [Hinv1 [Hinv2 [Htmp Hnext]]]]]]]]]]]].
rewrite /wp_addiu; exists A', ni; repeat reg_upd; repeat (split; trivial).
- rewrite sext_0 add_0 Hnext.
  case: (Zeven_odd_dec (u2Z (nth ni A' zero32))).
  + move/int_even_and_1; by left.
  + move/int_odd_and_1; by right.
- by Assert_upd.
- rewrite (skipn_S zero32 A ni); last by rewrite HA.
  rewrite (_ : nk - ni = S (nk - S ni))%nat; last by rewrite minus_Sn_m.
  rewrite Sum_S Hnext Htmp.
  have -> : 2 * u2Z ((nth ni A' zero32[.>>]1) [.|] [prev ]_ s) =
    2 * u2Z (nth ni A' zero32[.>>]1) + 2 * u2Z ([prev ]_ s).
    case: Hprev => Hprev.
    - by rewrite Hprev u2Z_Z2u // Zmult_0_r Zplus_0_r int_or_0 //.
    - rewrite int_or_comm.
      have X_ : (31 <= 32)%nat by repeat constructor.
      rewrite (@or_concat _ _ _ _ X_); last 2 first.
        by move: (shrl_lt (nth ni A' zero32) 1).
        apply u2Z_inj.
        move: (@u2Z_rem'' _ ([prev ]_ s) 30 1).
        rewrite {1}Hprev u2Z_Z2u // => -> //; by rewrite u2Z_Z2u.
      rewrite /cast_le_plus_minus_r2 u2Z_cast u2Z_concat u2Z_shr_shrink' //.
      rewrite Hprev !u2Z_Z2u // rem_Zpower // !u2Z_Z2u //.
      ring_simplify.
      rewrite u2Z_rem' //.
      by move: (shrl_lt (nth ni A' zero32) 1).
  have -> : u2Z (nth ni A zero32) =
    2 * u2Z (nth ni A' zero32[.>>]1) + u2Z (nth ni A' zero32[.&]one32).
    rewrite -(@u2Z_shrl 32 _ 1); last by repeat constructor.
    rewrite [Zpower _ _]/=.
    ring_simplify.
    rewrite (firstn_S zero32 A' ni) // in Hinv1; last by rewrite HlenA'.
    rewrite (firstn_S zero32 A ni) // in Hinv1; last by rewrite HA.
    case/(@app_inj_tail (int 32)): Hinv1 => Hinv' Hinv''.
    by rewrite Hinv'' int_and_rem_1.
  rewrite -Hinv2.
  suff -> : 2 * u2Z ([prev ]_ s) = 2 ^^ 32 * u2Z ([prev ]_ s[.>>]31).
    rewrite Zmult_plus_distr_r Zpower_S sext_0 add_0; ring.
- case: Hprev => Hprev.
  + by rewrite Hprev u2Z_Z2u // Zmult_0_r shrl_Z2u_0 u2Z_Z2u.
  + by rewrite Hprev u2Z_Z2u // shrl_Zpower // -minus_n_n u2Z_Z2u.
- rewrite Htmp.
  case: Hprev => ->.
  + by rewrite int_or_0.
  + by rewrite rem_distr_or rem_Zpower // int_or_0.

sll prev prev thirtyone5;

apply hoare_sll with (fun s h => exists A', exists ni, length A' = nk /\
  [a ]_ s = va /\ u2Z [k]_s = Z_of_nat nk /\
  u2Z [i ]_ s = Z_of_nat ni /\
  ([prev]_s = zero32 \/ [prev]_s = Z2u 32 (2 ^^ 31)) /\
  (ni < nk)%nat /\
  (var_e a |--> A') s h /\
  firstn (S ni) A' = firstn (S ni) A /\
  2 ^^ 33 * Sum (nk - S ni) (skipn (S ni) A') + 2 * u2Z ([tmp]_s) + u2Z ([prev]_ s [.>>] 31) =
  Sum (nk - ni) (skipn ni A) /\
  [tmp]_s [.%] 31 = ((nth ni A' zero32) [.>>] 1) [.%] 31 /\
  [next]_s = (nth ni A' zero32) [.&] one32).

move=> s h [A' [ni [HlenA' [Hra [Hrk [Hri [Hprev [Hik [Hmem [Hinv1 [Hinv2 [Htmp Hnext]]]]]]]]]]]].
exists A', ni; repeat reg_upd; repeat (split; trivial).
- case : Hprev => ->.
  + rewrite shl_zero; by left.
  + rewrite u2Z_Z2u // shl_1; by right.
- by Assert_upd.
- case : Hprev => Hprev.
  + by rewrite Hprev shl_zero shrl_Z2u_0 u2Z_Z2u // -Hinv2 Hprev u2Z_Z2u.
  + rewrite u2Z_Z2u //.
    have X_ : (31 <= 32)%nat by repeat constructor.
    rewrite (_ : Zabs_nat 31 = 31%nat) //.
    by rewrite Hprev (shl_1 X_) shrl_Zpower // -Hinv2 -minus_n_n [2 ^^ 0]/= Hprev.

sll next i two5;

apply hoare_sll with (fun s h => exists A', exists ni, length A' = nk /\
  [a ]_ s = va /\ u2Z [k]_s = Z_of_nat nk /\
  u2Z [i ]_ s = Z_of_nat ni /\
  ([prev]_s = zero32 \/ [prev]_s = Z2u 32 (2^^31)) /\
  (ni < nk)%nat /\
  (var_e a |--> A') s h /\
  firstn (S ni) A' = firstn (S ni) A /\
  2 ^^ 33 * Sum (nk - S ni) (skipn (S ni) A') + 2 * u2Z ([tmp]_s) + u2Z ([prev]_ s [.>>] 31) =
  Sum (nk - ni) (skipn ni A) /\
  [tmp]_s [.%] 31 = (nth ni A' zero32 [.>>] 1) [.%] 31 /\
  u2Z [next]_s = 4 * Z_of_nat ni).

move=> s h [A' [ni [HlenA' [Hra [Hrk [Hri [Hprev [Hik [Hmem [Hinv1 [Hinv2 [Htmp Hnext]]]]]]]]]]]].
exists A', ni; repeat reg_upd; repeat (split; trivial).
by Assert_upd.
rewrite u2Z_Z2u // (_ : Zabs_nat 2 = 2%nat) // (u2Z_shl 2 _ 30) //.
- by rewrite Hri [Zpower _ _]/= Zmult_comm.
- rewrite (_ : Zbeta 1 = 4 * 2 ^^ 30) in Hna; last by rewrite Zbeta1_Zpower2.
  move: (min_u2Z va) => ?; omega.

addu next a next;

apply hoare_addu with (fun s h => exists A', exists ni, length A' = nk /\
  [a ]_ s = va /\ u2Z [k]_s = Z_of_nat nk /\
  u2Z [i ]_ s = Z_of_nat ni /\
  ([prev]_s = zero32 \/ [prev]_s = Z2u 32 (2 ^^ 31)) /\
  (ni < nk)%nat /\
  (var_e a |--> A') s h /\
  firstn (S ni) A' = firstn (S ni) A /\
  2 ^^ 33 * Sum (nk - S ni) (skipn (S ni) A') + 2 * u2Z ([tmp]_s) + u2Z ([prev]_ s [.>>] 31) =
  Sum (nk - ni) (skipn ni A) /\
  [tmp]_s [.%] 31 = (nth ni A' zero32 [.>>] 1) [.%] 31 /\
  u2Z [next]_s = u2Z va + 4 * Z_of_nat ni).

move=> s h [A' [ni [HlenA' [Hra [Hrk [Hri [Hprev [Hik [Hmem [Hinv1 [Hinv2 [Htmp Hnext]]]]]]]]]]]].
exists A', ni; repeat reg_upd; repeat (split; trivial).
- by Assert_upd.
- rewrite u2Z_add.
  + rewrite Hra Hnext; ring.
  + rewrite (_ : Zbeta 1 = 4 * 2 ^^ 30) in Hna; last by rewrite Zbeta1_Zpower2.
    rewrite (_ : 2 ^^ 32 = 4 * 2 ^^ 30) // Hnext Hra; omega.

sw tmp zero16 next

apply hoare_sw_back'.

move=> s h [A' [ni [HlenA' [Hra [Hrk [Hri [Hprev [Hik [Hmem [Hinv1 [Hinv2 [Hrtmp Hrnext]]]]]]]]]]]].

have Htmp : [ add_e (var_e next) (int_e (sext 16 zero16)) ]e_ s =
    [ add_e (var_e a) (int_e (Z2u 32 (Z_of_nat (4 * ni)))) ]e_ s.
  rewrite [mult]lock /= -lock sext_0 // add_0.
  apply u2Z_inj.
  rewrite u2Z_add_Z_of_nat.
  rewrite inj_mult Hra Hrnext //; ring.
  rewrite inj_mult -Zbeta1_Zpower2 Hra; simpl Z_of_nat; omega.

Decompose_32 A' ni A'1 A'2 HlenA1 HA'; last by rewrite HlenA'.
rewrite HA' (decompose_equiv _ _ _ _ _ HlenA1) !con_assoc_equiv con_com_equiv !con_assoc_equiv in Hmem.
exists (int_e (nth ni A' zero32)).
move: Hmem; apply monotony => ht.
by apply mapsto_ext.
apply currying => h' H'; simpl app in H'.
exists (update_list A' ni [tmp]_s), ni.
repeat (split; trivial).
- by apply len_update_list.
- by apply lt_le_weak.
- rewrite HA' update_list_app HlenA1 // -minus_n_n /= (decompose_equiv _ _ _ _ _ HlenA1).
  assoc_comm H'.
  move: H'; by apply mapsto_ext.
- rewrite HA' update_list_app; last by rewrite HlenA1.
  rewrite firstn_app //.
  rewrite (firstn_S zero32 A' ni) // in Hinv1; last by rewrite HlenA'.
  rewrite (firstn_S zero32 A ni) // in Hinv1; last by rewrite HA.
  move/(@app_inj_tail (int 32)): Hinv1 => [Hinv' Hinv''].
  by rewrite -Hinv' HA' firstn_app.
- rewrite -Hinv2.
  f_equal.
  rewrite HA' update_list_app; last by rewrite HlenA1.
  rewrite skipn_app // HlenA1 -minus_n_n [update_list _ _ _]/=.
  have -> : (nk - ni = S (nk - (S ni)))%nat by rewrite minus_Sn_m.
  rewrite Sum_S app_comm_cons -app_ass skipn_app; last first.
    by rewrite app_length /= HlenA1 plus_comm.
  ring_simplify.
  f_equal.
  by rewrite -Zpower_S Zmult_comm.
Qed.