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_sub_signed_signed_triple

Require Import ssreflect ssrbool eqtype.
Require Import ZArith_ext Lists_ext.
Require Import machine_int nodup multi_int.
Import MachineInt.
Require Import mips_bipl mips_seplog mips_contrib mips_tactics mips_frame.
Import expr_m.
Import assert_m.

Require Import multi_sub_signed_signed_prg.
Require Import pick_sign_triple multi_add_signed_unsigned_triple multi_sub_signed_unsigned_triple.

Local Open Scope zarith_ext_scope.
Local Open Scope nodup_scope.
Local Open Scope mips_hoare_scope.
Local Open Scope mips_expr_scope.
Local Open Scope mips_assert_scope.
Local Open Scope machine_int_scope.

Lemma multi_sub_s_s_triple : forall rk rx ry a0 a1 a2 a3 a4 ret X Y,
  nodup(rk, rx, ry, a0, a1, a2, a3, a4, ret, X, Y, r0) ->
  forall nk vx vy ptr ptrB, nk <> O -> Z_of_nat nk < 2 ^^ 31 ->
    u2Z ptr + 4 * Z_of_nat nk < Zbeta 1 -> u2Z ptrB + 4 * Z_of_nat nk < Zbeta 1 ->
  forall A B, length A = nk -> length B = nk -> forall slen slenB,
    s2Z slen = Zsgn (s2Z slen) * Z_of_nat nk -> s2Z slenB = Zsgn (s2Z slenB) * Z_of_nat nk ->
    Zsgn (s2Z slen) = Zsgn (Zsgn (s2Z slen) * Sum nk A) ->
    Zsgn (s2Z slenB) = Zsgn (Zsgn (s2Z slenB) * Sum nk B) ->
{{ fun s h => [rx]_s = vx /\ [ry]_s = vy /\ u2Z [rk]_s = Z_of_nat nk /\
    ((var_e rx |--> slen :: ptr :: nil ** int_e ptr |--> A) **
      var_e ry |--> slenB :: ptrB :: nil ** int_e ptrB |--> B) s h }}
 multi_sub_s_s rk rx ry a0 a1 a2 a3 a4 ret X Y
 {{ fun s h => exists A', exists slen', length A' = nk /\
   s2Z slen' = Zsgn (s2Z slen') * Z_of_nat nk /\
   Zsgn (s2Z slen') = Zsgn (Zsgn (s2Z slen) * Sum nk A - Zsgn (s2Z slenB) * Sum nk B) /\
   (var_e rx |--> slen' :: ptr :: nil ** int_e ptr |--> A' **
    var_e ry |--> slenB :: ptrB :: nil ** int_e ptrB |--> B) s h /\
   u2Z ([a3]_ s) <= 1 /\
   Zsgn (s2Z slen') * (Sum nk A' + u2Z ([a3]_ s) * Zbeta nk) =
   Zsgn (s2Z slen) * Sum nk A - Zsgn (s2Z slenB) * Sum nk B }}.
Proof.
move=> rk rx ry a0 a1 a2 a3 a4 ret X Y Hregs nk vx vy ptr ptrB Hnk Hnk' Hptr HptrB
  A B len_A len_B slen slenB Hslen HslenB valid_A valid_B.
rewrite /multi_sub_s_s.

lw Y four16 ry

apply hoare_lw_back_alt'' with (fun s h => [rx ]_ s = vx /\ [ry ]_ s = vy /\
  u2Z [rk ]_ s = Z_of_nat nk /\ [Y ]_s = ptrB /\
  (((var_e rx |--> slen :: ptr :: nil ** int_e ptr |--> A) **
    var_e ry |--> slenB :: ptrB :: nil) ** int_e ptrB |--> B) s h).

move=> s h [r_x [r_y [r_k mem]]].
exists ptrB; split.
- rewrite con_assoc_equiv con_com_equiv -mapsto2_mapstos !con_assoc_equiv
    con_com_equiv con_assoc_equiv in mem.
  move: mem. apply monotony => h' //; apply mapsto_ext => //; by rewrite sext_Z2u.
- rewrite /update_store_lw.
  repeat reg_upd; repeat (split => //).
  by Assert_upd.

pick_sign ry a0 a1

apply while.hoare_seq with (fun s h => [rx ]_ s = vx /\ [ry ]_ s = vy /\
  u2Z [rk ]_ s = Z_of_nat nk /\
  [Y ]_s = ptrB /\ [a0]_s = slenB /\ Zsgn (s2Z [a1]_s) = Zsgn (s2Z slenB) /\
  (s2Z [a1]_s = 0 \/ s2Z [a1]_s = 1 \/ s2Z [a1]_s = -1) /\
  (((var_e rx |--> slen :: ptr :: nil ** int_e ptr |--> A) **
    var_e ry |--> slenB :: ptrB :: nil) ** int_e ptrB |--> B) s h).

eapply while.hoare_conseq; last first.

apply (pick_sign_triple _ _ _
  (fun s h => [rx ]_ s = vx /\ u2Z [rk ]_ s = Z_of_nat nk /\ [Y ]_s = ptrB)
  (((var_e rx |--> slen :: ptr :: nil ** int_e ptr |--> A) **
    (add_e (var_e ry) (int_e four32)) |--> ptrB :: nil) ** int_e ptrB |--> B) vy slenB).
by Nodup_nodup r0.
Inde.
apply inde_mapstos => /=; apply nodup_disj; rewrite [List.app _ _]/=; by Nodup_nodup r0.
by Inde.

move=> s h /= [Hrx [Hry [Rk [HY mem]]]].
rewrite !con_assoc_equiv in mem *.
repeat (split=> //).
by assoc_comm mem.

move=> s h /= [Hry [Ha0 [Ha1 [Ha1' [mem [Hrx [Hrk HY]]]]]]].
rewrite !con_assoc_equiv in mem *.
repeat (split=> //).
by assoc_comm mem.

while.ifte (bgez a1)

apply while.hoare_ifte.

ifte_beq a1, r0

apply while.hoare_ifte.

addiu a3 r0 zero16

apply hoare_addiu'.

move=> s h [[[r_x [r_y [r_k [r_Y [r_A0 [r_a1 [a0_a1 mem]]]]]]] _] Ha1].
rewrite /= in Ha1.
move/eqP/u2Z_inj in Ha1.
rewrite store.get_r0 in Ha1.
rewrite Ha1 s2Z_u2Z_pos' in r_a1; last by rewrite u2Z_Z2u.
rewrite u2Z_Z2u //= in r_a1.
rewrite /wp_addiu.
exists A, slen.
repeat reg_upd.
rewrite -r_a1 Zmult_0_l Zminus_0_r.
repeat (split => //).
by Assert_upd.
by rewrite add_com add_0 sext_Z2u // u2Z_Z2u.
by rewrite add_com add_0 sext_Z2u // u2Z_Z2u // Zmult_0_l Zplus_0_r.

multi_sub_s_u rk rx Y a0 a1 a2 a3 a4 ret X

apply (before_frame
  (fun s h => [ry ]_ s = vy /\ Zsgn (s2Z slenB) = 1 /\
  (var_e ry |--> slenB :: ptrB :: nil) s h )
  (fun s h => [rx ]_ s = vx /\ [Y ]_ s = ptrB /\ u2Z [rk ]_ s = Z_of_nat nk /\
  ((var_e rx |--> slen :: ptr :: nil ** int_e ptr |--> A) ** var_e Y |--> B) s h)
  (fun s h => exists A', exists slen', length A' = nk /\
    [rx ]_ s = vx /\ [Y ]_ s = ptrB /\ s2Z slen' = Zsgn (s2Z slen') * Z_of_nat nk /\
   Zsgn (s2Z slen') = Zsgn (Zsgn (s2Z slen) * Sum nk A - Sum nk B) /\
   (var_e rx |--> slen' :: ptr :: nil ** int_e ptr |--> A' ** var_e Y |--> B ) s h /\
   u2Z ([a3]_ s) <= 1 /\
   Zsgn (s2Z slen') * (Sum nk A' + u2Z ([a3]_s) * Zbeta nk) =
   Zsgn (s2Z slen) * Sum nk A - Sum nk B)).

apply frame_rule.
  apply multi_sub_s_u_triple => //.
  by Nodup_nodup r0.
  by Inde_frame.
  move=> ?; by Inde_mult.

move=> s h [[[r_x [r_y [r_k [r_Y [r_A0 [r_a1 [a0_a1 mem]]]]]]] Ha1'] Ha1].
rewrite /= in Ha1'.
move/Zle_boolP in Ha1'.
rewrite /= in Ha1.
move/eqP in Ha1.
rewrite store.get_r0 u2Z_Z2u // in Ha1.
rewrite con_com_equiv -con_assoc_equiv con_com_equiv in mem.
case: mem => h1 [h2 [h1_d_h2 [h1_U_h2 [Hh1 Hh2]]]].
Compose_sepcon h2 h1.
repeat (split=> //).
rewrite con_com_equiv in Hh2.
move: Hh2; apply monotony => // h'; by apply mapstos_ext.
repeat (split => //).
case: a0_a1 => a0_a1.
rewrite (_ : 0 = s2Z (Z2s 32 0)) in a0_a1; last by rewrite s2Z_Z2s.
apply s2Z_inj in a0_a1.
by rewrite a0_a1 u2Z_Z2s_pos in Ha1.
case: a0_a1 => a0_a1.
by rewrite -r_a1 a0_a1.
rewrite a0_a1 in Ha1'; omega.

move=> s h.
case=> h1 [h2 [h1_d_h2 [h1_U_h2 [Hh1 Hh2]]]].
case: Hh1 => [A' [slen' [len_A' [r_x [r_Y [slen'_nk [HZsgn [mem [Ha3 HSum]]]]]]]]].
case: Hh2 => [r_y [Zsgn_slenB Hh2]].
exists A', slen'.
repeat (split => //).
rewrite HZsgn Zsgn_slenB. f_equal. f_equal. ring.
rewrite con_assoc_equiv con_com_equiv con_assoc_equiv.
Compose_sepcon h2 h1; first by done.
rewrite con_com_equiv.
move: mem; apply monotony => // h'; by apply mapstos_ext.
rewrite HSum Zsgn_slenB. f_equal. ring.

multi_add_s_u rk rx Y a0 a1 a2 a3 a4 ret X

apply (before_frame
  (fun s h => [ry ]_ s = vy /\ Zsgn (s2Z slenB) = -1 /\
  (var_e ry |--> slenB :: ptrB :: nil) s h )
  (fun s h => [rx ]_ s = vx /\ [Y ]_ s = ptrB /\ u2Z [rk ]_ s = Z_of_nat nk /\
  ((var_e rx |--> slen :: ptr :: nil ** int_e ptr |--> A) ** var_e Y |--> B) s h)
  (fun s h => exists A', exists slen', length A' = nk /\ [rx ]_ s = vx /\ [Y ]_ s = ptrB /\
    s2Z slen' = Zsgn (s2Z slen') * Z_of_nat nk /\
    Zsgn (s2Z slen') = Zsgn (Zsgn (s2Z slen) * Sum nk A + Sum nk B) /\
    (var_e rx |--> slen' :: ptr :: nil ** int_e ptr |--> A' ** var_e Y |--> B ) s h /\
    u2Z ([a3]_ s) <= 1 /\
    Zsgn (s2Z slen') * (Sum nk A' + u2Z ([a3]_s) * Zbeta nk) =
    Zsgn (s2Z slen) * Sum nk A + Sum nk B)).

apply frame_rule.
  apply multi_add_s_u_triple => //.
  by Nodup_nodup r0.
  by Inde_frame.
  move=> ?; by Inde_mult.

move=> s h [[r_x [r_y [r_k [r_Y [r_A0 [r_a1 [a0_a1 mem]]]]]]] Ha1].
rewrite /= in Ha1.
move/Zle_boolP in Ha1.
case: a0_a1 => a0_a1.
rewrite a0_a1 in Ha1.
by move: (Ha1 (Zle_refl _)).
case: a0_a1 => a0_a1.
rewrite a0_a1 in Ha1.
exfalso; omega.
rewrite con_com_equiv -con_assoc_equiv con_com_equiv in mem.
case: mem => h1 [h2 [h1_d_h2 [h1_U_h2 [Hh1 Hh2]]]].
Compose_sepcon h2 h1.
repeat (split=> //).
rewrite con_com_equiv in Hh2.
move: Hh2; apply monotony => // h'; by apply mapstos_ext.
repeat (split => //).
by rewrite -r_a1 a0_a1.

move=> s h [h1 [h2 [h1_d_h2 [h1_U_h2 [Hh1 Hh2]]]]].
case: Hh1 => [A' [slen' [len_A' [r_x [r_Y [slen'_nk [HZsgn [mem [Ha3 HSum]]]]]]]]].
case: Hh2 => [r_y [Zsgn_slenB Hh2]].
exists A', slen'; repeat (split => //).
rewrite Zsgn_slenB HZsgn; f_equal. ring.

rewrite con_com_equiv -con_assoc_equiv.
Compose_sepcon h1 h2; last by done.
rewrite con_com_equiv.
move: mem; apply monotony => // h'; by apply mapstos_ext.
rewrite Zsgn_slenB HSum; ring.
Qed.