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_zero_triple

Require Import ssreflect ssrbool eqtype.
Require Import Arith_ext ZArith_ext Lists_ext.
Require Import machine_int multi_int omegaz.
Import MachineInt.
Require Import mips_seplog mips_tactics mips_contrib mapstos.
Require Import multi_zero_prg.

Local Open Scope heap_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_hoare_scope.
Local Open Scope machine_int_scope.

Section multi_zero.

Variables k z ext Z_ : reg.

Lemma multi_zero_triple : nodup(k, z, ext, Z_, r0) ->
  forall nk Z vz, length Z = nk -> u2Z vz + 4 * Z_of_nat nk < Zbeta 1 ->
  {{ fun s h => [z]_s = vz /\ u2Z [k]_s = Z_of_nat nk /\ (var_e z |--> Z) s h }}
    multi_zero k z ext Z_
  {{ fun s h => [z]_s = vz /\ u2Z [k]_s = Z_of_nat nk /\
   (var_e z |--> rep zero32 nk) s h }}.
Proof.
move=> Hset nk Z vz HlenZ Hnz.
rewrite /multi_zero.

addiu Z z zero16

NextAddiu.
move=> s h [r_z [r_k Hmem]].
rewrite /wp_addiu; repeat reg_upd; repeat (split; trivial).
by Assert_upd.

addiu ext k zero16

NextAddiu.
move=> s h [[r_z [r_k Hmem]] r_ext].
rewrite /wp_addiu; repeat reg_upd; repeat (split; trivial).
by Assert_upd.

while (bne ext r0) (

apply hoare_prop_m.hoare_while_invariant with (fun s h => exists Z, exists next,
  length Z = next /\ u2Z [ext]_s = Z_of_nat next /\ u2Z [k]_s = Z_of_nat nk /\
  (next <= nk)%nat /\ u2Z [Z_]_s = u2Z [z]_s + 4 * Z_of_nat (nk - next) /\
  [z]_s = vz /\ (var_e z |--> rep zero32 (nk - next) ++ Z) s h).

move=> s h [[[r_z [r_k Hmem]] r_Z] r_ext].
exists Z, nk; repeat (split; trivial).
by rewrite r_ext sext_0 add_0.
by rewrite -minus_n_n Zmult_0_r r_Z sext_0 add_0 // Zplus_0_r.
by rewrite -minus_n_n.

move=> {Z HlenZ} s h [[Z [next [len_Z [Hnext [r_k [Hextnk [r_Z [r_z Hmem]]]]]]]] Hext]; rewrite /= in Hext.
repeat (split; trivial).
have {Hext}Hext : next = O.
  move/negPn : Hext; move/Zeq_boolP.
  rewrite Hnext store.get_r0 /zero32 u2Z_Z2u //; by apply Z_of_nat_0.
subst next.
destruct Z; last by done.
by rewrite Hext -minus_n_O -app_nil_end in Hmem.

clear Z HlenZ.

sw r0 zero16 Z ;

apply hoare_prop_m.hoare_stren with (fun s h => exists Z, exists next,
  length Z = next /\ (O < next <= nk)%nat /\ u2Z [ext]_s = Z_of_nat next /\
  u2Z [k]_s = Z_of_nat nk /\ u2Z [Z_]_s = u2Z [z]_s + 4 * Z_of_nat (nk - next) /\
  [z]_s = vz /\ (var_e z |--> rep zero32 (nk - next) ++ Z) s h).

move=> s h [[Z [next [HlenZ [Hnext [r_k [r_Z [Hextnk [r_z Hmem]]]]]]]] Hext]; rewrite /= in Hext.
have {Hext}Hext : (O < next)%nat.
  move/Zeq_boolP : Hext.
  rewrite Hnext store.get_r0 /zero32 u2Z_Z2u // => Hext.
  apply neq_0_lt.
  contradict Hext; by rewrite -Hext.
by exists Z, next; repeat (split; trivial).

apply hoare_sw_back'' with (fun s h => exists Z, exists next,
  length Z = (next - 1)%nat /\ (O < next <= nk)%nat /\ u2Z [ext]_s = Z_of_nat next /\
  u2Z [k]_s = Z_of_nat nk /\ u2Z [Z_]_s = u2Z [z]_s + 4 * Z_of_nat (nk - next) /\
  [z]_s = vz /\ (var_e z |--> rep zero32 (S nk - next) ++ Z) s h).

move=> s h [Z [next [HlenZ [[Hnext1 Hnext2] [r_ext [r_k [r_Z [r_z Hmem]]]]]]]].

destruct Z as [|hd tl].
rewrite -HlenZ /= in Hnext1; move: (lt_irrefl O); contradiction.

have Htmp : [ add_e (var_e Z_) (int_e (sext 16 zero16)) ]e_ s =
            [ add_e (var_e z) (int_e (Z2u 32 (Z_of_nat (4 * (nk - next))))) ]e_ s.
  rewrite [mult]lock /= -lock sext_0 add_0; apply u2Z_inj.
  rewrite u2Z_add_Z_of_nat.
  by rewrite inj_mult.
  rewrite -Zbeta1_Zpower2 inj_mult inj_minus1 // Zmult_minus_distr_l [Zmult]lock /= -lock r_z; move: (min_u2Z vz) => ?; omega.

exists (int_e hd).

rewrite (decompose_equiv _ _ _ _ _ (len_rep _ _)) // !assert_m.con_assoc_equiv assert_m.con_com_equiv !assert_m.con_assoc_equiv in Hmem.
move: Hmem; apply monotony => // ht.
by apply mapsto_ext.
apply currying => h' H'.
exists tl, next; repeat (split; trivial).
by rewrite -HlenZ /= -minus_n_O.
have -> : rep zero32 (S nk - next) = rep zero32 (nk - next) ++ zero32 :: nil by rewrite -rep_last minus_Sn_m.
rewrite app_ass (decompose_equiv _ _ _ _ _ (len_rep _ _)).
assoc_comm H'.
move: H'; apply mapsto_ext => //.
by rewrite /= store.get_r0.

addiu Z Z four16 ;

apply hoare_addiu with (fun s h => exists Z, exists next,
  length Z = (next - 1)%nat /\ (O < next <= nk)%nat /\ u2Z [ext]_s = Z_of_nat next /\
  u2Z [k]_s = Z_of_nat nk /\ u2Z [Z_]_s = u2Z [z]_s + 4 * Z_of_nat (S nk - next) /\
  [z]_s = vz /\ (var_e z |--> rep zero32 (S nk - next) ++ Z) s h).

move=> s h [Z [next [HlenZ [Hnext [r_ext [r_k [r_Z [r_z Hmem]]]]]]]].
rewrite /wp_addiu; repeat reg_upd.
exists Z, next; repeat (split; trivial).
rewrite sext_Z2u // u2Z_add_Z2u //.
- rewrite inj_minus1 in r_Z; last by case : Hnext.
- by omegaz.
rewrite -Zbeta1_Zpower2 r_Z r_z inj_minus1; omega.
by Assert_upd.

addiu ext ext mone16).

apply hoare_addiu'.
move=> s h [Z [next [len_Z [[Hnext1 Hnext2] [r_ext [r_k [r_Z [r_z Hmem]]]]]]]].

rewrite /wp_addiu; exists Z, (next - 1)%nat; repeat reg_upd.
rewrite (_ : nk - (next - 1) = S nk - next)%nat; last first.
  destruct next; by [ inversion Hnext1| rewrite /= -minus_n_O].
repeat (split; trivial).

rewrite sext_Z2s // u2Z_add_Z2s //.
by rewrite inj_minus1 // r_ext.
rewrite r_ext.
destruct next; by [ inversion Hnext1| rewrite Z_S /= -Zplus_assoc Zplus_opp_r Zplus_0_r; apply Zle_0_nat].
by apply le_minus_trans.
by Assert_upd.
Qed.

End multi_zero.