(**************************************************************************)
(*                                                                        *)
(*  This file is part of WP plug-in of Frama-C.                           *)
(*                                                                        *)
(*  Copyright (C) 2007-2015                                               *)
(*    CEA (Commissariat a l'energie atomique et aux energies              *)
(*         alternatives)                                                  *)
(*                                                                        *)
(*  you can redistribute it and/or modify it under the terms of the GNU   *)
(*  Lesser General Public License as published by the Free Software       *)
(*  Foundation, version 2.1.                                              *)
(*                                                                        *)
(*  It is distributed in the hope that it will be useful,                 *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
(*  GNU Lesser General Public License for more details.                   *)
(*                                                                        *)
(*  See the GNU Lesser General Public License version 2.1                 *)
(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
(*                                                                        *)
(**************************************************************************)

(* This file is generated by Why3's Coq-realize driver *)
(* Beware! Only edit allowed sections below    *)
Require Import BuiltIn.
Require BuiltIn.
Require Qed.
Require bool.Bool.
Require int.Int.
Require int.Abs.
Require int.ComputerDivision.
Require real.Real.
Require real.RealInfix.
Require real.FromInt.
Require Cint.

Require Import Qedlib.
Open Local Scope Z_scope.

(** * Bit extraction *)
(** Tacticals *)
Local Ltac omegaContradiction := cut False; [contradiction|omega].

Ltac unfold_bit_testb h := 
  unfold Cint.bit_testb; unfold Zbits.bit_testb; 
  rewrite (Zle_imp_le_bool _ _ h).

(** Some useful properties *)
Remark Zlt_bool_true_Zlt: forall (b:bool) (x y: Z),
  (b = Zlt_bool x y)  <-> ((b = true) <-> x < y).
Proof.
  intros.
  split; case_lt x y; intros; try rewrite H0.
    split; intro G; auto.
    split; intro G; [discriminate G| omega].
    auto.
    destruct b; try auto.
    destruct H0. assert (x < y) by (by (apply H0)).
    omegaContradiction.
Qed.

(** ** Definition of bit_test predicate *)
(* Why3 goal *)
Lemma bit_test_def : forall (x:Z) (k:Z), ((Cint.bit_testb x k) = true) <->
  (Cint.bit_test x k).
Proof. 
  intros x k.
  unfold Cint.bit_test.
  reflexivity.
Qed.

(** * Link between Bit extraction and bitwise operators *)
(** ** Logical operators *)
(* Why3 goal *)
Lemma bit_test_extraction : forall (x:Z) (k:Z), (0%Z <= k)%Z ->
  ((~ ((Cint.land x (Cint.lsl 1%Z k)) = 0%Z)) <-> (Cint.bit_test x k)).
Proof. 
  intros x k h1.
  unfold Cint.land.
  unfold Cint.lsl; unfold Zbits.lsl. 
  rewrite (Zle_imp_le_bool _ _ h1); unfold Zbits.lsl_def.

  unfold Cint.bit_test; unfold Cint.bit_testb;
  unfold_bit_testb h1; unfold Zbits.zbit_test_def.
  pose (i:= (Z.abs_nat k)); fold i.
  split.
  (** 1st impl *)
    intro NEQ.
    apply Bool.not_false_is_true.
    contradict NEQ.
    rewrite Zbits.Zbit_extraction.
    assumption.
  (** 2sd impl *)
    intro EQ.
    contradict EQ.
    rewrite Bool.not_true_iff_false.
    rewrite <- Zbits.Zbit_extraction.
    assumption.
Qed.

(* Why3 goal *)
Lemma bit_test_extraction_eq : forall (x:Z) (k:Z), (0%Z <= k)%Z ->
  (((Cint.land x (Cint.lsl 1%Z k)) = (Cint.lsl 1%Z k)) <-> (Cint.bit_test x
  k)).
Proof.
  intros x k h1.
  unfold Cint.land.
  unfold Cint.lsl; unfold Zbits.lsl. 
  rewrite (Zle_imp_le_bool _ _ h1); unfold Zbits.lsl_def.

  unfold Cint.bit_test; unfold Cint.bit_testb;
  unfold_bit_testb h1; unfold Zbits.zbit_test_def.
  pose (i:= (Z.abs_nat k)); fold i.
  rewrite Zbits.Zbit_extraction_true.
  split; auto.
Qed.

(* Why3 goal *)
Lemma lsl_1_0 : ((Cint.lsl 1%Z 0%Z) = 1%Z).
Proof.
  compute. auto.
Qed.

(* Why3 goal *)
Lemma bit_test_extraction_bis : forall (x:Z), (~ ((Cint.land 1%Z
  x) = 0%Z)) -> (Cint.bit_test x 0%Z).
Proof. 
  intros x.
  rewrite <- lsl_1_0.
  intro.
  apply bit_test_extraction.
    omega.
  rewrite Zbits.land_commut.
  auto.
Qed.

(* Why3 goal *)
Lemma bit_test_extraction_bis_eq : forall (x:Z), (Cint.bit_test x 0%Z) ->
  ((Cint.land 1%Z x) = 1%Z).
Proof.
  intros x h1.
  rewrite <- lsl_1_0.
  rewrite <- Zbits.land_commut.
  apply bit_test_extraction_eq; auto with zarith.
Qed.

(* Why3 goal *)
Lemma lnot_extraction_bool : forall (x:Z) (i:Z), (0%Z <= i)%Z ->
  ((Cint.bit_testb (Cint.lnot x) i) = (Init.Datatypes.negb (Cint.bit_testb x
  i))).
Proof. 
  intros x i h1. unfold_bit_testb h1.
  apply Zbits.lnot_extraction.
Qed.

(* Why3 goal *)
Lemma lnot_extraction : forall (x:Z) (i:Z), (0%Z <= i)%Z -> ((Cint.bit_test
  (Cint.lnot x) i) <-> ~ (Cint.bit_test x i)).
Proof. 
  intros x i h1.
  unfold Cint.bit_test. rewrite lnot_extraction_bool; auto.
  pose (xb:=Cint.bit_testb x i). fold xb.
  destruct xb; simpl; split; intros; auto.
  discriminate H.
Qed.

(* Why3 goal *)
Lemma land_extraction_bool : forall (x:Z) (y:Z) (i:Z), (0%Z <= i)%Z ->
  ((Cint.bit_testb (Cint.land x y)
  i) = (Init.Datatypes.andb (Cint.bit_testb x i) (Cint.bit_testb y i))).
Proof. 
  intros x y i h1. unfold_bit_testb h1.
  apply Zbits.land_extraction.
Qed.

(* Why3 goal *)
Lemma land_extraction : forall (x:Z) (y:Z) (i:Z), (0%Z <= i)%Z ->
  ((Cint.bit_test (Cint.land x y) i) <-> ((Cint.bit_test x i) /\
  (Cint.bit_test y i))).
Proof. 
  intros x y i h1.
  unfold Cint.bit_test. rewrite land_extraction_bool; auto.
  pose (xb:=Cint.bit_testb x i). fold xb.
  pose (yb:=Cint.bit_testb y i). fold yb.
  destruct xb; destruct yb; simpl; split; intros; auto; destruct H; auto.
Qed.

(* Why3 goal *)
Lemma lor_extraction_bool : forall (x:Z) (y:Z) (i:Z), (0%Z <= i)%Z ->
  ((Cint.bit_testb (Cint.lor x y) i) = (Init.Datatypes.orb (Cint.bit_testb x
  i) (Cint.bit_testb y i))).
Proof. 
  intros x y i h1. unfold_bit_testb h1.
  apply Zbits.lor_extraction.
Qed.

(* Why3 goal *)
Lemma lor_extraction : forall (x:Z) (y:Z) (i:Z), (0%Z <= i)%Z ->
  ((Cint.bit_test (Cint.lor x y) i) <-> ((Cint.bit_test x i) \/
  (Cint.bit_test y i))).
Proof. 
  intros x y i h1.
  unfold Cint.bit_test. rewrite lor_extraction_bool; auto.
  pose (xb:=Cint.bit_testb x i). fold xb.
  pose (yb:=Cint.bit_testb y i). fold yb.
  destruct xb; destruct yb; simpl; split; intros; auto; destruct H; auto.
Qed.

(* Why3 goal *)
Lemma lxor_extraction_bool : forall (x:Z) (y:Z) (i:Z), (0%Z <= i)%Z ->
  ((Cint.bit_testb (Cint.lxor x y)
  i) = (Init.Datatypes.xorb (Cint.bit_testb x i) (Cint.bit_testb y i))).
Proof. 
  intros x y i h1. 
  unfold_bit_testb h1.
  apply Zbits.lxor_extraction.
Qed.

(* Why3 goal *)
Lemma lxor_extraction : forall (x:Z) (y:Z) (i:Z), (0%Z <= i)%Z ->
  ((Cint.bit_test (Cint.lxor x y) i) <-> ((Cint.bit_test x i) <->
  ~ (Cint.bit_test y i))).
Proof.
  intros x y i h1.
  unfold Cint.bit_test. rewrite lxor_extraction_bool; auto.
  pose (xb:=Cint.bit_testb x i). fold xb.
  pose (yb:=Cint.bit_testb y i). fold yb.
  destruct xb; destruct yb; simpl; repeat (split; intros; auto).
  discriminate H. 
  destruct H; contradiction H; auto.
  discriminate H0.
  destruct H; apply H0; discriminate.
Qed.

(* Why3 goal *)
Lemma land_1_lsl_1 : forall (a:Z) (x:Z) (n:Z), (0%Z <= n)%Z ->
  ((a < (Cint.lsl 1%Z n))%Z -> (((2%Z * a)%Z + (Cint.land 1%Z
  x))%Z < (Cint.lsl 1%Z (1%Z + n)%Z))%Z).
Proof. 
  intros a x n h1.
  unfold Cint.lsl; unfold Zbits.lsl.
  case_leq 0%Z (1 + n)%Z ; intro.
  case_leq 0%Z (n)%Z ; intro.

  unfold Zbits.lsl_def.
  rewrite Zbits.lsl_arithmetic_shift.
  unfold Zbits.lsl_arithmetic_def.
  rewrite Zabs2Nat.abs_nat_nonneg by auto.
  rewrite Zabs2Nat.abs_nat_nonneg by auto.
  rewrite Z2Nat.inj_add by omega.
  pose (n0:=Z.to_nat n); fold n0.

  replace ((Z.to_nat 1%Z)%nat) with (1%nat) by auto.
  rewrite Bits.two_power_nat_plus.
  replace ((two_power_nat 1)%Z) with (2%Z) by auto with zarith.
  replace ((1 * two_power_nat n0)%Z) with ((two_power_nat n0)%Z) by auto.
  replace ((1 * (2 * two_power_nat n0))%Z) with ((2 * two_power_nat n0)%Z) by ring.

  intro.
  cut((Cint.land 1 x < 2)%Z) ; auto with zarith.

  case_eq ((Cint.land 1 x)%Z) (0%Z); intros.
  rewrite bit_test_extraction_bis_eq; [omega|].
  apply bit_test_extraction_bis. 
  auto. 
Qed.

(** ** Shift operators *)
(* Why3 goal *)
Lemma lsl_extraction_sup_bool : forall (x:Z) (n:Z) (m:Z), (0%Z <= n)%Z ->
  ((0%Z <= m)%Z -> ((n <= m)%Z -> ((Cint.bit_testb (Cint.lsl x n)
  m) = (Cint.bit_testb x (m - n)%Z)))).
Proof.
  intros x n m h1 h2 h3.
  unfold Cint.lsl. unfold Zbits.lsl. 
  unfold_bit_testb h1.
  rewrite (Zle_imp_le_bool _ _ h2).
  rewrite (Zle_imp_le_bool 0 (m - n)) by omega.
  rewrite Zbits.lsl_extraction.
  rewrite (Z.abs_eq n); auto.
  rewrite (Z.abs_eq m); auto.
  case_leq n m.
  intros.
  reflexivity.
Qed.

(* Why3 goal *)
Lemma lsl_extraction_sup : forall (x:Z) (n:Z) (m:Z), (0%Z <= n)%Z ->
  ((0%Z <= m)%Z -> ((n <= m)%Z -> ((Cint.bit_test (Cint.lsl x n) m) <->
  (Cint.bit_test x (m - n)%Z)))).
Proof.
  intros x n m h1 h2 h3.
  unfold Cint.bit_test; rewrite lsl_extraction_sup_bool; auto; reflexivity.
Qed.

(* Why3 goal *)
Lemma lsl_extraction_inf_bool : forall (x:Z) (n:Z) (m:Z), (0%Z <= n)%Z ->
  ((0%Z <= m)%Z -> ((m < n)%Z -> ((Cint.bit_testb (Cint.lsl x n)
  m) = false))).
Proof.
  intros x n m h1 h2 h3.
  unfold Cint.lsl. unfold Zbits.lsl. 
  unfold_bit_testb h1.
  rewrite (Zle_imp_le_bool _ _ h2).
  rewrite Zbits.lsl_extraction.
  rewrite (Z.abs_eq n); auto.
  rewrite (Z.abs_eq m); auto.
  case_leq n m.
  intros.
  reflexivity.
Qed.

(* Why3 goal *)
Lemma lsl_extraction_inf : forall (x:Z) (n:Z) (m:Z), (0%Z <= n)%Z ->
  ((0%Z <= m)%Z -> ((m < n)%Z -> ~ (Cint.bit_test (Cint.lsl x n) m))).
Proof.
  intros x n m h1 h2 h3.
  unfold Cint.bit_test; rewrite lsl_extraction_inf_bool; auto; reflexivity.
Qed.

(* Why3 goal *)
Lemma lsr_extraction_bool : forall (x:Z) (n:Z) (m:Z), (0%Z <= n)%Z ->
  ((0%Z <= m)%Z -> ((Cint.bit_testb (Cint.lsr x n) m) = (Cint.bit_testb x
  (m + n)%Z))).
Proof.
  intros x n m h1 h2.
  unfold Cint.lsr. unfold Zbits.lsr. 
  unfold_bit_testb h1.
  rewrite (Zle_imp_le_bool _ _ h2).
  rewrite Zbits.lsr_extraction.
  rewrite (Z.abs_eq n); auto.
  rewrite (Z.abs_eq m); auto.
  case_leq 0 (m+n).
  intros.
  reflexivity.
Qed.

(* Why3 goal *)
Lemma lsr_extractionl : forall (x:Z) (n:Z) (m:Z), (0%Z <= n)%Z ->
  ((0%Z <= m)%Z -> ((Cint.bit_test (Cint.lsr x n) m) <-> (Cint.bit_test x
  (m + n)%Z))).
Proof.
  intros x n m h1 h2.
  unfold Cint.bit_test; rewrite lsr_extraction_bool; auto; reflexivity.
Qed.

(* Why3 goal *)
Lemma lsl1_extraction_bool : forall (i:Z) (j:Z), (0%Z <= i)%Z ->
  ((0%Z <= j)%Z -> ((Cint.bit_testb (Cint.lsl 1%Z i) j) = (Qed.eqb i j))).
Proof.
  intros i j h1 h2.
  unfold Cint.lsl. unfold Zbits.lsl.  rewrite (Zle_imp_le_bool _ _ h1).
  unfold_bit_testb h2.
  unfold Zbits.lsl_def.

  rewrite Zbits.lsl_arithmetic_shift; unfold Zbits.lsl_arithmetic_def.
  replace (1 * two_power_nat (Z.abs_nat i))
  with (two_power_nat (Z.abs_nat i)) by ring.

  unfold Zbits.zbit_test_def; rewrite Bits.Zbit_power.
  rewrite Zabs2Nat.abs_nat_nonneg; auto. 
  rewrite Zabs2Nat.abs_nat_nonneg; auto. 

  case_eq i j.
  (** i = j *)
    intro EQ; rewrite EQ; rewrite <- beq_nat_refl.  
    symmetry. apply Qed.eqb1 ; auto.
  (** i <> j *)
    intro NEQ.
    assert (Qed.eqb i j = false) as EQB.
    apply Qed.eqb_false. assumption.
    rewrite EQB.
    rewrite -> beq_nat_false_iff.
    contradict NEQ.
    rewrite Z2Nat.inj_iff in NEQ; auto.
Qed.

(* Why3 goal *)
Lemma lsl1_extraction : forall (i:Z) (j:Z), (0%Z <= i)%Z -> ((0%Z <= j)%Z ->
  ((Cint.bit_test (Cint.lsl 1%Z i) j) <-> (i = j))).
Proof.
  intros i j h1 h2.
  unfold Cint.bit_test; rewrite lsl1_extraction_bool; auto. apply Qed.eqb1.
Qed.

(* Why3 goal *)
Lemma pos_extraction_sup : forall (x:Z) (i:Z) (j:Z), (0%Z <= x)%Z ->
  ((0%Z <= i)%Z -> ((x < (Cint.lsl 1%Z i))%Z -> ((i <= j)%Z ->
  ~ (Cint.bit_test x j)))).
Proof.
  intros x i j h1 h2.
  unfold Cint.lsl ; unfold Cint.bit_test.
  rewrite Zbits.lsl_pos; auto.
  unfold Zbits.lsl_def.
  rewrite Zbits.lsl_arithmetic_shift.
  unfold Zbits.lsl_arithmetic_def.
  replace (1 * two_power_nat (Z.abs_nat i)) with (two_power_nat (Z.abs_nat i)) by ring.
  intros.
  rewrite Zbits.bit_testb_pos ; auto.
  assert (HB:(Bits.Zbit x (Z.abs_nat j) = false)).
    (apply (Zbits.Zbit_unsigned_trail  (Z.abs_nat i) (Z.abs_nat j) x); auto).
     apply Zabs_nat_le; omega.      
    unfold Zbits.zbit_test_def.

  rewrite HB; discriminate.
  omega.
Qed.

(** * Link between Bit extraction and C type conversions *)
(** Tacticals *)
Local Ltac naturalize_int_extraction_inf_bool n vn vz :=
  intros x i (h1,h2); unfold_bit_testb h1; unfold Zbits.zbit_test_def;
  assert (Z.abs_nat i < vn)%nat as A by
    (assert (vn = Z.abs_nat vz) as B by (auto with arith);
     rewrite B;
     apply Zabs_nat_lt; omega);
  clear h1; clear h2;
  pose (n:= (Z.abs_nat i)); fold n; fold n in A.
					   
Local Ltac int_extraction_inf int_extraction_inf_bool :=
  intros x i (h1,h2);
  unfold Cint.bit_test;
  rewrite int_extraction_inf_bool by auto;
  pose (xb:=Cint.bit_testb x i); fold xb;
  destruct xb; simpl; split; intro G; auto; destruct G; auto.
				       
(** ** Unsigned conversions *)
(** Tacticals *)
Local Ltac uint_extraction_inf m x to_uint n vz :=
  unfold to_uint; unfold Cint.to_range;
  simpl;
  (replace (x - 0) with x by (auto with zarith));
  (replace vz with (two_power_nat n) by (auto with zarith));
  (replace n with ((n-m)+m)%nat by (auto with zarith));
  rewrite Zbits.Zbit_uint_mod_two_power_nat;
  (rewrite (leb_correct_conv 0 (n - m)); auto);
  apply ArithProp.lt_minus_O_lt;
  auto.
							 
Local Ltac uint_extraction_sup is_uint vn vz :=
  intros x i h1 h2;
  assert (H:(Bits.Zbit x (Z.abs_nat i) = false)) by
    (unfold is_uint in h2;
     (apply (Zbits.Zbit_unsigned_trail vn (Z.abs_nat i) x); auto);
     (replace vn with (Z.abs_nat vz)%nat by (auto with arith));
     apply Zabs_nat_le;
     omega);
  assert (I:(0 <= i)) by omega;
  unfold Cint.bit_test; unfold_bit_testb I; unfold Zbits.zbit_test_def;
  rewrite H; discriminate.
						   
(** *** Cast to uint8 C type *)
(* Why3 goal *)
Lemma to_uint8_extraction_sup : forall (x:Z) (i:Z), (8%Z <= i)%Z ->
  ((Cint.is_uint8 x) -> ~ (Cint.bit_test x i)).
Proof.
  uint_extraction_sup Cint.is_uint8 8%nat 8.
Qed.

(* Why3 goal *)
Lemma to_uint8_extraction_inf_bool : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 8%Z)%Z) -> ((Cint.bit_testb (Cint.to_uint8 x) i) = (Cint.bit_testb x
  i)).
Proof.
  naturalize_int_extraction_inf_bool n 8%nat 8.
  uint_extraction_inf n x Cint.to_uint8 8%nat 256.
Qed.

(* Why3 goal *)
Lemma to_uint8_extraction_inf : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 8%Z)%Z) -> ((Cint.bit_test (Cint.to_uint8 x) i) <-> (Cint.bit_test x
  i)).
Proof.
  int_extraction_inf to_uint8_extraction_inf_bool.
Qed.

(* Why3 goal *)
Lemma is_uint8_ext : forall (x:Z) (y:Z), (Cint.is_uint8 x) -> ((Cint.is_uint8
  y) -> ((forall (i:Z), ((0%Z <= i)%Z /\ (i < 8%Z)%Z) -> ((Cint.bit_test x
  i) <-> (Cint.bit_test y i))) -> (x = y))).
Proof.
  intros x y h1 h2 h3.
  assert (forall i: int, (0 <= i)%Z -> (Cint.bit_test x i <-> Cint.bit_test y i)).
     intros.
     case_leq i 7; intro.
       apply h3; omega.
     assert (~ Cint.bit_test x i).
       apply to_uint8_extraction_sup. omega. auto.
     assert (~ Cint.bit_test y i).
      apply to_uint8_extraction_sup. omega. auto.
     intuition.
    clear h1; clear h2; clear h3.
 
    unfold Cint.bit_test in H.
    unfold Cint.bit_testb in H.
    apply Zbits.bit_testb_ext; intros.
    rewrite <- Zbits.bool2_eq_true.
    apply H; auto.
Qed.

(** *** Cast to uint16 C type *)
(* Why3 goal *)
Lemma to_uint16_extraction_sup : forall (x:Z) (i:Z), (16%Z <= i)%Z ->
  ((Cint.is_uint16 x) -> ~ (Cint.bit_test x i)).
Proof.
  uint_extraction_sup Cint.is_uint16 16%nat 16.
Qed.

(* Why3 goal *)
Lemma to_uint16_extraction_inf_bool : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 16%Z)%Z) -> ((Cint.bit_testb (Cint.to_uint16 x) i) = (Cint.bit_testb x
  i)).
Proof.
  naturalize_int_extraction_inf_bool n 16%nat 16.
  uint_extraction_inf n x Cint.to_uint16 16%nat 65536.
Qed.

(* Why3 goal *)
Lemma to_uint16_extraction_inf : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 16%Z)%Z) -> ((Cint.bit_test (Cint.to_uint16 x) i) <-> (Cint.bit_test x
  i)).
Proof.
  int_extraction_inf to_uint16_extraction_inf_bool.
Qed.

(* Why3 goal *)
Lemma is_uint16_ext : forall (x:Z) (y:Z), (Cint.is_uint16 x) ->
  ((Cint.is_uint16 y) -> ((forall (i:Z), ((0%Z <= i)%Z /\ (i < 16%Z)%Z) ->
  ((Cint.bit_test x i) <-> (Cint.bit_test y i))) -> (x = y))).
Proof.
  intros x y h1 h2 h3.
  assert (forall i: int, (0 <= i)%Z -> (Cint.bit_test x i <-> Cint.bit_test y i)).
     intros.
     case_leq i 15; intro.
       apply h3; omega.
     assert (~ Cint.bit_test x i).
       apply to_uint16_extraction_sup. omega. auto.
     assert (~ Cint.bit_test y i).
      apply to_uint16_extraction_sup. omega. auto.
     intuition.
    clear h1; clear h2; clear h3.
 
    unfold Cint.bit_test in H.
    unfold Cint.bit_testb in H.
    apply Zbits.bit_testb_ext; intros.
    rewrite <- Zbits.bool2_eq_true.
    apply H; auto.
Qed.

(** *** Cast to uint32 C type *)
(* Why3 goal *)
Lemma to_uint32_extraction_sup : forall (x:Z) (i:Z), (32%Z <= i)%Z ->
  ((Cint.is_uint32 x) -> ~ (Cint.bit_test x i)).
Proof.
  uint_extraction_sup Cint.is_uint32 32%nat 32.
Qed.

(* Why3 goal *)
Lemma to_uint32_extraction_inf_bool : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 32%Z)%Z) -> ((Cint.bit_testb (Cint.to_uint32 x) i) = (Cint.bit_testb x
  i)).
Proof.
  naturalize_int_extraction_inf_bool n 32%nat 32.
  uint_extraction_inf n x Cint.to_uint32 32%nat 4294967296.
Qed.

(* Why3 goal *)
Lemma to_uint32_extraction_inf : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 32%Z)%Z) -> ((Cint.bit_test (Cint.to_uint32 x) i) <-> (Cint.bit_test x
  i)).
Proof.
  int_extraction_inf to_uint32_extraction_inf_bool.
Qed.

(* Why3 goal *)
Lemma is_uint32_ext : forall (x:Z) (y:Z), (Cint.is_uint32 x) ->
  ((Cint.is_uint32 y) -> ((forall (i:Z), ((0%Z <= i)%Z /\ (i < 32%Z)%Z) ->
  ((Cint.bit_test x i) <-> (Cint.bit_test y i))) -> (x = y))).
Proof.
  intros x y h1 h2 h3.
  assert (forall i: int, (0 <= i)%Z -> (Cint.bit_test x i <-> Cint.bit_test y i)).
     intros.
     case_leq i 31; intro.
       apply h3; omega.
     assert (~ Cint.bit_test x i).
       apply to_uint32_extraction_sup. omega. auto.
     assert (~ Cint.bit_test y i).
      apply to_uint32_extraction_sup. omega. auto.
     intuition.
    clear h1; clear h2; clear h3.
 
    unfold Cint.bit_test in H.
    unfold Cint.bit_testb in H.
    apply Zbits.bit_testb_ext; intros.
    rewrite <- Zbits.bool2_eq_true.
    apply H; auto.
Qed.

(** *** Cast to uint64 C type *)
(* Why3 goal *)
Lemma to_uint64_extraction_sup : forall (x:Z) (i:Z), (64%Z <= i)%Z ->
  ((Cint.is_uint64 x) -> ~ (Cint.bit_test x i)).
Proof.
  uint_extraction_sup Cint.is_uint64 64%nat 64.
Qed.

(* Why3 goal *)
Lemma to_uint64_extraction_inf_bool : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 64%Z)%Z) -> ((Cint.bit_testb (Cint.to_uint64 x) i) = (Cint.bit_testb x
  i)).
Proof.
  naturalize_int_extraction_inf_bool n 64%nat 64.
  uint_extraction_inf n x Cint.to_uint64 64%nat 18446744073709551616.
Qed.

(* Why3 goal *)
Lemma to_uint64_extraction_inf : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 64%Z)%Z) -> ((Cint.bit_test (Cint.to_uint64 x) i) <-> (Cint.bit_test x
  i)).
Proof.
  int_extraction_inf to_uint64_extraction_inf_bool.
Qed.

(* Why3 goal *)
Lemma is_uint64_ext : forall (x:Z) (y:Z), (Cint.is_uint64 x) ->
  ((Cint.is_uint64 y) -> ((forall (i:Z), ((0%Z <= i)%Z /\ (i < 64%Z)%Z) ->
  ((Cint.bit_test x i) <-> (Cint.bit_test y i))) -> (x = y))).
Proof.
  intros x y h1 h2 h3.
  assert (forall i: int, (0 <= i)%Z -> (Cint.bit_test x i <-> Cint.bit_test y i)).
     intros.
     case_leq i 63; intro.
       apply h3; omega.
     assert (~ Cint.bit_test x i).
       apply to_uint64_extraction_sup. omega. auto.
     assert (~ Cint.bit_test y i).
      apply to_uint64_extraction_sup. omega. auto.
     intuition.
    clear h1; clear h2; clear h3.
 
    unfold Cint.bit_test in H.
    unfold Cint.bit_testb in H.
    apply Zbits.bit_testb_ext; intros.
    rewrite <- Zbits.bool2_eq_true.
    apply H; auto.
Qed.

(** ** Signed conversions *)
(** Tactical *)
Local Ltac sint_extraction_sup is_sint vn vz :=
  intros x i h1;
  unfold is_sint;
  intro h2;
  assert (H:(0 <= i)) by omega;
  unfold Cint.bit_test; unfold_bit_testb H; unfold Zbits.zbit_test_def;
  assert (Z.abs_nat vz <= Z.abs_nat i)%nat 
  by (assert (vn = Z.abs_nat vz)%nat by (auto with arith);
      apply Zabs_nat_le; omega);
  rewrite <- Zlt_bool_true_Zlt; 
  apply (Zbits.Zbit_trail vn (Z.abs_nat i) x); auto.

(** *** To sint8 C type*)
Local Ltac sint_extraction_inf m x to_sint n vz wz:=
  unfold to_sint; unfold Cint.to_range;
  (replace (vz - wz) with (2 * two_power_nat n) by (auto with zarith));
  (replace (x - wz) with (x + two_power_nat n) by (auto with zarith));
  (replace (wz) with (- two_power_nat n) by (auto with zarith));
  rewrite Z.add_opp_l;
  (replace n with ((n-m)+m)%nat by (auto with zarith));
  rewrite Zbits.Zbit_sint_mod_two_power_nat;
  auto.
  
(** *** To sint16 C type*)
(** *** To sint32 C type *)
(** *** To sint64 C type *)
(** * Some C-Integer Bits Conversions are identity *)
(** Tacticals *)
Local Ltac unfold_hyp h :=
  match goal with 
    | h:(?X1) |- _ => unfold X1 in h
    | h:(?X1 _ ) |- _ => unfold X1 in h
    | h:(?X1 _ _) |- _ => unfold X1 in h
    | h:(?X1 _ _ _) |- _ => unfold X1 in h
    | h:(?X1 _ _ _ _) |- _ => unfold X1 in h
    | _ => idtac
  end.
(** ** Unsigned conversions *)
(** Tacticals *)
Local Ltac is_uint_bitwise f n :=
  intros x y Rx Ry; unfold_hyp Rx; unfold_hyp Ry; apply Cint.id_to_range;
  apply (Zbits.Z_bitwise_in_uint_range f n x y Rx Ry); by compute.  

Local Ltac lsr_in_uint_range n :=
  intros x y Ry Rx; unfold_hyp Rx; apply Cint.id_to_range;
  split;
  [ (apply (Zbits.lsr_lower_bound 0 _ _ Ry); omega)
  | (apply (Zbits.lsr_upper_bound n _ _ Ry); omega)].

Local Ltac naturalize_uint_lsl1_inf n vn vz :=
  intros y (h1,h2);
  (assert (0 <= y) as Ry by omega);
  unfold Cint.lsl; unfold Zbits.lsl; rewrite (Zle_imp_le_bool _ _ Ry);
  unfold Zbits.lsl_def;
  rewrite Zbits.lsl_arithmetic_shift; unfold Zbits.lsl_arithmetic_def;
  (replace (1 * two_power_nat (Z.abs_nat y))
    with (two_power_nat (Z.abs_nat y)) by (ring;forward));
  clear Ry;

  assert ((Z.abs_nat y < vn)%nat) as A by
   ((replace vn with (Z.abs_nat vz) by (auto with arith));
    apply Zabs_nat_lt; omega);
  clear h1; clear h2;
  pose (n := Z.abs_nat y); fold n; fold n in A.
    
Local Ltac uint_lsl1_inf n to_uint vn vnpred bz :=
  unfold to_uint;
  unfold Cint.to_range;
  (replace (0 + (two_power_nat n - 0) mod (bz - 0))
   with ((two_power_nat n) mod bz) by (auto with zarith));
  rewrite Zmod_small ; [auto|];
  split ; 
  [ assert (0 < two_power_nat n) as P by apply Bits.two_power_nat_is_positive;
    pose (i:= two_power_nat n); fold i; fold i in P; 
    omega |];

  (replace bz with (two_power_nat vn) by (compute;forward));
  (replace vn with (vnpred+1)%nat by (compute;forward));
  rewrite Bits.two_power_nat_plus;

  rewrite (le_plus_minus n vnpred) by
    (rewrite (lt_n_Sm_le n vnpred); auto);
  rewrite Bits.two_power_nat_plus;

  (assert (0 < two_power_nat n) as P by 
     apply Bits.two_power_nat_is_positive);
  pose (a:=(two_power_nat n)); fold a; fold a in P;
  (assert (0 < two_power_nat (vnpred - n)) as Q by
     apply Bits.two_power_nat_is_positive);
  pose (b:=(two_power_nat (vnpred - n)%nat)); fold b; fold b in Q;
  (replace (two_power_nat 1%nat) with 2 by (compute;forward));

  (replace a with (a*1) by (auto with zarith));
  (replace (a*1*b*2) with (a*(b*2)) by ring);
  apply (Zmult_gt_0_lt_compat_l 1 (b * 2) a);
  omega.
    
Local Ltac naturalize_uint_lsl1_sup n vn vz :=
  intros y h1;
  assert (0 <= y) as Ry by omega;
  unfold Cint.lsl; unfold Zbits.lsl; rewrite (Zle_imp_le_bool _ _ Ry);
  unfold Zbits.lsl_def;
  rewrite Zbits.lsl_arithmetic_shift; unfold Zbits.lsl_arithmetic_def;
  (replace (1 * two_power_nat (Z.abs_nat y))
    with (two_power_nat (Z.abs_nat y)) by ring);
  clear Ry;
  assert ((vn <= Z.abs_nat y)%nat) as A by
   ((replace vn with (Z.abs_nat vz) by (auto with arith));
    apply Zabs_nat_le; omega);
  clear h1;
  pose (n := Z.abs_nat y); fold n; fold n in A.

Local Ltac uint_lsl1_sup n to_uint vn bz :=
  (rewrite (le_plus_minus vn n) by auto);
  pose (i := (n - vn)%nat); fold i;
  rewrite Bits.two_power_nat_plus;

  unfold to_uint;
  unfold Cint.to_range;
  (replace ((two_power_nat vn) * two_power_nat i - 0)
   with (two_power_nat i * (two_power_nat vn)) by (ring;forward));
  (replace (two_power_nat vn) with bz by (compute;forward));
  (replace (bz - 0) with bz by (compute;forward));
  (replace (0 + (two_power_nat i * bz) mod bz)
   with ((two_power_nat i * bz) mod bz)
   by (auto with zarith));
  apply Z_mod_mult. 

(** *** Cast to uint8 C type *)
(** *** Cast to uint16 C type *)
(** *** Cast to uint32 C type *)
(** *** Cast to uint64 C type *)
(* Why3 goal *)
Lemma to_sint8_extraction_sup : forall (x:Z) (i:Z), (7%Z <= i)%Z ->
  ((Cint.is_sint8 x) -> ((Cint.bit_test x i) <-> (x < 0%Z)%Z)).
Proof.
  sint_extraction_sup Cint.is_sint8 7%nat 7.
Qed.

(* Why3 goal *)
Lemma to_sint8_extraction_inf_bool : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 7%Z)%Z) -> ((Cint.bit_testb (Cint.to_sint8 x) i) = (Cint.bit_testb x
  i)).
Proof.
  naturalize_int_extraction_inf_bool n 7%nat 7.
  sint_extraction_inf n x Cint.to_sint8 7%nat 128 (-128).
Qed.

(* Why3 goal *)
Lemma to_sint8_extraction_inf : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 7%Z)%Z) -> ((Cint.bit_test (Cint.to_sint8 x) i) <-> (Cint.bit_test x
  i)).
Proof.
  int_extraction_inf to_sint8_extraction_inf_bool.
Qed.

(* Why3 goal *)
Lemma is_sint8_ext : forall (x:Z) (y:Z), (Cint.is_sint8 x) -> ((Cint.is_sint8
  y) -> ((forall (i:Z), ((0%Z <= i)%Z /\ (i <= 7%Z)%Z) -> ((Cint.bit_test x
  i) <-> (Cint.bit_test y i))) -> (x = y))).
Proof.
  intros x y h1 h2 h3.
  assert (forall i: int, (0 <= i)%Z -> (Cint.bit_test x i <-> Cint.bit_test y i)).
    intros.
    case_lt i 8; intro.
      apply h3; omega.
    assert (0<=7<=7) by omega.
    specialize ((h3 7) H1); clear H1.
    assert (7<=7) by omega.
    generalize ((to_sint8_extraction_sup x 7) H1 h1).
    generalize ((to_sint8_extraction_sup y 7) H1 h2).
    clear H1; intros.
    rewrite h3 in H2. rewrite H2 in H1. clear H2.
    assert ((Cint.bit_test x i) <-> x < 0).
      apply to_sint8_extraction_sup. omega. auto.
    assert ((Cint.bit_test y i) <-> y < 0).
      apply to_sint8_extraction_sup. omega. auto.
    rewrite H2.
    rewrite H3.
    auto.
    clear h1; clear h2; clear h3.

    unfold Cint.bit_test in H.
    unfold Cint.bit_testb in H.
    apply Zbits.bit_testb_ext; intros.
    rewrite <- Zbits.bool2_eq_true.
    apply H; auto.
Qed.

(* Why3 goal *)
Lemma to_sint16_extraction_sup : forall (x:Z) (i:Z), (15%Z <= i)%Z ->
  ((Cint.is_sint16 x) -> ((Cint.bit_test x i) <-> (x < 0%Z)%Z)).
Proof.
  sint_extraction_sup Cint.is_sint16 15%nat 15.
Qed.

(* Why3 goal *)
Lemma to_sint16_extraction_inf_bool : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 15%Z)%Z) -> ((Cint.bit_testb (Cint.to_sint16 x) i) = (Cint.bit_testb x
  i)).
Proof.
  naturalize_int_extraction_inf_bool n 16%nat 16.
  sint_extraction_inf n x Cint.to_sint16 15%nat 32768 (-32768).
Qed.

(* Why3 goal *)
Lemma to_sint16_extraction_inf : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 15%Z)%Z) -> ((Cint.bit_test (Cint.to_sint16 x) i) <-> (Cint.bit_test x
  i)).
Proof.
  int_extraction_inf to_sint16_extraction_inf_bool.
Qed.

(* Why3 goal *)
Lemma is_sint16_ext : forall (x:Z) (y:Z), (Cint.is_sint16 x) ->
  ((Cint.is_sint16 y) -> ((forall (i:Z), ((0%Z <= i)%Z /\ (i <= 15%Z)%Z) ->
  ((Cint.bit_test x i) <-> (Cint.bit_test y i))) -> (x = y))).
Proof.
  intros x y h1 h2 h3.
  assert (forall i: int, (0 <= i)%Z -> (Cint.bit_test x i <-> Cint.bit_test y i)).
    intros.
    case_lt i 16; intro.
      apply h3; omega.
    assert (0<=15<=15) by omega.
    specialize ((h3 15) H1); clear H1.
    assert (15<=15) by omega.
    generalize ((to_sint16_extraction_sup x 15) H1 h1).
    generalize ((to_sint16_extraction_sup y 15) H1 h2).
    clear H1; intros.
    rewrite h3 in H2. rewrite H2 in H1. clear H2.
    assert ((Cint.bit_test x i) <-> x < 0).
      apply to_sint16_extraction_sup. omega. auto.
    assert ((Cint.bit_test y i) <-> y < 0).
      apply to_sint16_extraction_sup. omega. auto.
    rewrite H2.
    rewrite H3.
    auto.
    clear h1; clear h2; clear h3.

    unfold Cint.bit_test in H.
    unfold Cint.bit_testb in H.
    apply Zbits.bit_testb_ext; intros.
    rewrite <- Zbits.bool2_eq_true.
    apply H; auto.
Qed.

(* Why3 goal *)
Lemma to_sint32_extraction_sup : forall (x:Z) (i:Z), (31%Z <= i)%Z ->
  ((Cint.is_sint32 x) -> ((Cint.bit_test x i) <-> (x < 0%Z)%Z)).
Proof.
  sint_extraction_sup Cint.is_sint32 31%nat 31.
Qed.

(* Why3 goal *)
Lemma to_sint32_extraction_inf_bool : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 31%Z)%Z) -> ((Cint.bit_testb (Cint.to_sint32 x) i) = (Cint.bit_testb x
  i)).
Proof.
  naturalize_int_extraction_inf_bool n 32%nat 32.
  sint_extraction_inf n x Cint.to_sint32 31%nat 2147483648 (-2147483648).
Qed.

(* Why3 goal *)
Lemma to_sint32_extraction_inf : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 31%Z)%Z) -> ((Cint.bit_test (Cint.to_sint32 x) i) <-> (Cint.bit_test x
  i)).
Proof.
  int_extraction_inf to_sint32_extraction_inf_bool.
Qed.

(* Why3 goal *)
Lemma is_sint32_ext : forall (x:Z) (y:Z), (Cint.is_sint32 x) ->
  ((Cint.is_sint32 y) -> ((forall (i:Z), ((0%Z <= i)%Z /\ (i <= 31%Z)%Z) ->
  ((Cint.bit_test x i) <-> (Cint.bit_test y i))) -> (x = y))).
Proof.
  intros x y h1 h2 h3.
  assert (forall i: int, (0 <= i)%Z -> (Cint.bit_test x i <-> Cint.bit_test y i)).
    intros.
    case_lt i 31; intro.
      apply h3; omega.
    assert (0<=31<=31) by omega.
    specialize ((h3 31) H1); clear H1.
    assert (31<=31) by omega.
    generalize ((to_sint32_extraction_sup x 31) H1 h1).
    generalize ((to_sint32_extraction_sup y 31) H1 h2).
    clear H1; intros.
    rewrite h3 in H2. rewrite H2 in H1. clear H2.
    assert ((Cint.bit_test x i) <-> x < 0).
      apply to_sint32_extraction_sup. omega. auto.
    assert ((Cint.bit_test y i) <-> y < 0).
      apply to_sint32_extraction_sup. omega. auto.
    rewrite H2.
    rewrite H3.
    auto.
    clear h1; clear h2; clear h3.

    unfold Cint.bit_test in H.
    unfold Cint.bit_testb in H.
    apply Zbits.bit_testb_ext; intros.
    rewrite <- Zbits.bool2_eq_true.
    apply H; auto.
Qed.

(* Why3 goal *)
Lemma to_sint64_extraction_sup : forall (x:Z) (i:Z), (63%Z <= i)%Z ->
  ((Cint.is_sint64 x) -> ((Cint.bit_test x i) <-> (x < 0%Z)%Z)).
Proof.
  sint_extraction_sup Cint.is_sint64 63%nat 63.
Qed.

(* Why3 goal *)
Lemma to_sint64_extraction_inf_bool : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 63%Z)%Z) -> ((Cint.bit_testb (Cint.to_sint64 x) i) = (Cint.bit_testb x
  i)).
Proof.
  naturalize_int_extraction_inf_bool n 64%nat 64.
  sint_extraction_inf n x Cint.to_sint64 63%nat 9223372036854775808 (-9223372036854775808).
Qed.

(* Why3 goal *)
Lemma to_sint64_extraction_inf : forall (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < 63%Z)%Z) -> ((Cint.bit_test (Cint.to_sint64 x) i) <-> (Cint.bit_test x
  i)).
Proof.
  int_extraction_inf to_sint64_extraction_inf_bool.
Qed.

(* Why3 goal *)
Lemma is_sint64_ext : forall (x:Z) (y:Z), (Cint.is_sint64 x) ->
  ((Cint.is_sint64 y) -> ((forall (i:Z), ((0%Z <= i)%Z /\ (i <= 63%Z)%Z) ->
  ((Cint.bit_test x i) <-> (Cint.bit_test y i))) -> (x = y))).
Proof.
  intros x y h1 h2 h3.
  assert (forall i: int, (0 <= i)%Z -> (Cint.bit_test x i <-> Cint.bit_test y i)).
    intros.
    case_lt i 64; intro.
      apply h3; omega.
    assert (0<=63<=63) by omega.
    specialize ((h3 63) H1); clear H1.
    assert (63<=63) by omega.
    generalize ((to_sint64_extraction_sup x 63) H1 h1).
    generalize ((to_sint64_extraction_sup y 63) H1 h2).
    clear H1; intros.
    rewrite h3 in H2. rewrite H2 in H1. clear H2.
    assert ((Cint.bit_test x i) <-> x < 0).
      apply to_sint64_extraction_sup. omega. auto.
    assert ((Cint.bit_test y i) <-> y < 0).
      apply to_sint64_extraction_sup. omega. auto.
    rewrite H2.
    rewrite H3.
    auto.
    clear h1; clear h2; clear h3.

    unfold Cint.bit_test in H.
    unfold Cint.bit_testb in H.
    apply Zbits.bit_testb_ext; intros.
    rewrite <- Zbits.bool2_eq_true.
    apply H; auto.
Qed.

(* Why3 goal *)
Lemma is_uint8_lor : forall (x:Z) (y:Z), (Cint.is_uint8 x) -> ((Cint.is_uint8
  y) -> ((Cint.to_uint8 (Cint.lor x y)) = (Cint.lor x y))).
Proof. 
  is_uint_bitwise orb 8%nat. 
Qed.

(* Why3 goal *)
Lemma is_uint8_land : forall (x:Z) (y:Z), (Cint.is_uint8 x) ->
  ((Cint.is_uint8 y) -> ((Cint.to_uint8 (Cint.land x y)) = (Cint.land x y))).
Proof.
  is_uint_bitwise andb 8%nat. 
Qed.

(* Why3 goal *)
Lemma is_uint8_lsr : forall (x:Z) (y:Z), (0%Z <= y)%Z -> ((Cint.is_uint8
  x) -> ((Cint.to_uint8 (Cint.lsr x y)) = (Cint.lsr x y))).
Proof.	
  lsr_in_uint_range 256.
Qed.

(* Why3 goal *)
Lemma is_uint8_lsl1_inf : forall (y:Z), ((0%Z <= y)%Z /\ (y < 8%Z)%Z) ->
  ((Cint.to_uint8 (Cint.lsl 1%Z y)) = (Cint.lsl 1%Z y)).
Proof.
  naturalize_uint_lsl1_inf n 8%nat 8. 
  uint_lsl1_inf n Cint.to_uint8 8%nat 7%nat 256.
Qed.

(* Why3 goal *)
Lemma is_uint8_lsl1_sup : forall (y:Z), (8%Z <= y)%Z ->
  ((Cint.to_uint8 (Cint.lsl 1%Z y)) = 0%Z).
Proof.
  naturalize_uint_lsl1_sup n 8%nat 8.
  uint_lsl1_sup n Cint.to_uint8 8%nat 256.
Qed.

(* Why3 goal *)
Lemma is_uint16_lor : forall (x:Z) (y:Z), (Cint.is_uint16 x) ->
  ((Cint.is_uint16 y) -> ((Cint.to_uint16 (Cint.lor x y)) = (Cint.lor x y))).
Proof. 
  is_uint_bitwise orb 16%nat. 
Qed.

(* Why3 goal *)
Lemma is_uint16_land : forall (x:Z) (y:Z), (Cint.is_uint16 x) ->
  ((Cint.is_uint16 y) -> ((Cint.to_uint16 (Cint.land x y)) = (Cint.land x
  y))).
Proof. 
  is_uint_bitwise andb 16%nat. 
Qed.

(* Why3 goal *)
Lemma is_uint16_lsr : forall (x:Z) (y:Z), (0%Z <= y)%Z -> ((Cint.is_uint16
  x) -> ((Cint.to_uint16 (Cint.lsr x y)) = (Cint.lsr x y))).
Proof.
  lsr_in_uint_range 65536.
Qed.

(* Why3 goal *)
Lemma is_uint16_lsl1_inf : forall (y:Z), ((0%Z <= y)%Z /\ (y < 16%Z)%Z) ->
  ((Cint.lsl 1%Z y) = (Cint.to_uint16 (Cint.lsl 1%Z y))).
Proof.
  naturalize_uint_lsl1_inf n 16%nat 16.
  uint_lsl1_inf n Cint.to_uint16 16%nat 15%nat 65536.
Qed.

(* Why3 goal *)
Lemma is_uint16_lsl1_sup : forall (y:Z), (16%Z <= y)%Z ->
  ((Cint.to_uint16 (Cint.lsl 1%Z y)) = 0%Z).
Proof.
  naturalize_uint_lsl1_sup n 16%nat 16.
  uint_lsl1_sup n Cint.to_uint16 16%nat 65536.
Qed.

(* Why3 goal *)
Lemma is_uint32_lor : forall (x:Z) (y:Z), (Cint.is_uint32 x) ->
  ((Cint.is_uint32 y) -> ((Cint.to_uint32 (Cint.lor x y)) = (Cint.lor x y))).
Proof.
  is_uint_bitwise orb 32%nat. 
Qed.

(* Why3 goal *)
Lemma is_uint32_land : forall (x:Z) (y:Z), (Cint.is_uint32 x) ->
  ((Cint.is_uint32 y) -> ((Cint.to_uint32 (Cint.land x y)) = (Cint.land x
  y))).
Proof. 
  is_uint_bitwise andb 32%nat. 
Qed.

(* Why3 goal *)
Lemma is_uint32_lsr : forall (x:Z) (y:Z), (0%Z <= y)%Z -> ((Cint.is_uint32
  x) -> ((Cint.to_uint32 (Cint.lsr x y)) = (Cint.lsr x y))).
Proof.
  lsr_in_uint_range 4294967296.  
Qed.

(* Why3 goal *)
Lemma is_uint32_lsl1_inf : forall (y:Z), ((0%Z <= y)%Z /\ (y < 32%Z)%Z) ->
  ((Cint.lsl 1%Z y) = (Cint.to_uint32 (Cint.lsl 1%Z y))).
Proof.
  naturalize_uint_lsl1_inf n 32%nat 32.
  uint_lsl1_inf n Cint.to_uint32 32%nat 31%nat 4294967296.
Qed.

(* Why3 goal *)
Lemma is_uint32_lsl1_sup : forall (y:Z), (32%Z <= y)%Z ->
  ((Cint.to_uint32 (Cint.lsl 1%Z y)) = 0%Z).
Proof.
  naturalize_uint_lsl1_sup n 32%nat 32 .
  uint_lsl1_sup n Cint.to_uint32 32%nat 4294967296.
Qed.

(* Why3 goal *)
Lemma is_uint64_lor : forall (x:Z) (y:Z), (Cint.is_uint64 x) ->
  ((Cint.is_uint64 y) -> ((Cint.to_uint64 (Cint.lor x y)) = (Cint.lor x y))).
Proof.
  is_uint_bitwise orb 64%nat. 
Qed.

(* Why3 goal *)
Lemma is_uint64_land : forall (x:Z) (y:Z), (Cint.is_uint64 x) ->
  ((Cint.is_uint64 y) -> ((Cint.to_uint64 (Cint.land x y)) = (Cint.land x
  y))).
Proof. 
  is_uint_bitwise andb 64%nat. 
Qed.

(* Why3 goal *)
Lemma is_uint64_lsr : forall (x:Z) (y:Z), (0%Z <= y)%Z -> ((Cint.is_uint64
  x) -> ((Cint.to_uint64 (Cint.lsr x y)) = (Cint.lsr x y))).
Proof.
  lsr_in_uint_range 18446744073709551616.  
Qed.

(* Why3 goal *)
Lemma is_uint64_lsl1_inf : forall (y:Z), ((0%Z <= y)%Z /\ (y < 64%Z)%Z) ->
  ((Cint.to_uint64 (Cint.lsl 1%Z y)) = (Cint.lsl 1%Z y)).
Proof.
  naturalize_uint_lsl1_inf n 64%nat 64.
  uint_lsl1_inf n Cint.to_uint64 64%nat 63%nat 18446744073709551616.
Qed.

(* Why3 goal *)
Lemma is_uint64_lsl1_sup : forall (y:Z), (64%Z <= y)%Z ->
  ((Cint.to_uint64 (Cint.lsl 1%Z y)) = 0%Z).
Proof. 
  naturalize_uint_lsl1_sup n 64%nat 64. 
  uint_lsl1_sup n Cint.to_uint64 64%nat 18446744073709551616.
Qed.

(** ** Signed conversions *)
(** Tacticals *)
Local Ltac is_sint_lnot b :=
  intros x Rx; unfold_hyp Rx; apply Cint.id_to_range;
   apply (Zbits.lnot_in_range (-b) b x Rx); omega.

Local Ltac is_sint_bitwise f n :=
  intros x y Rx Ry; unfold_hyp Rx; unfold_hyp Ry; apply Cint.id_to_range;
  apply (Zbits.Z_bitwise_in_sint_range f n x y Rx Ry); by compute.  

Local Ltac lsr_in_sint_range n :=
  intros x y Ry Rx; unfold_hyp Rx; apply Cint.id_to_range;
  split;
  [ (apply (Zbits.lsr_lower_bound (-n) _ _ Ry); omega)
  | (apply (Zbits.lsr_upper_bound n _ _ Ry); omega)].

Local Ltac naturalize_sint_lsl1_inf n vn vz :=
  intros y (h1,h2);
  unfold Cint.lsl; unfold Zbits.lsl; rewrite (Zle_imp_le_bool _ _ h1);
  unfold Zbits.lsl_def;
  rewrite Zbits.lsl_arithmetic_shift; unfold Zbits.lsl_arithmetic_def;
  (replace (1 * two_power_nat (Z.abs_nat y))
   with (two_power_nat (Z.abs_nat y)) by (ring;forward));
  assert ((Z.abs_nat y < vn)%nat) as A by
   ((replace vn with (Z.abs_nat vz) by (auto with arith));
    apply Zabs_nat_lt; omega);
  clear h1; clear h2;
  pose (n := Z.abs_nat y); fold n; fold n in A.
 					    
Local Ltac sint_lsl1_inf n is_sint vnpred bz :=
  unfold is_sint;
  unfold Cint.to_range;
  assert (0 < two_power_nat n) as P by apply Bits.two_power_nat_is_positive;
  split;
  [ pose (i:= two_power_nat n); fold i; fold i in P; 
    omega |];
  (replace bz with (two_power_nat (vnpred + 1)%nat) by (compute;forward));
  rewrite Bits.two_power_nat_plus;
  (replace (two_power_nat 1%nat) with 2 by (compute;forward));

  (rewrite (le_plus_minus n vnpred) by
      (rewrite (lt_n_Sm_le n vnpred); auto));
  rewrite Bits.two_power_nat_plus;
  pose (a := two_power_nat n); fold a; fold a in P;
  (assert (0 < two_power_nat (vnpred - n)) as Q by
     apply Bits.two_power_nat_is_positive);
  pose (b:=(two_power_nat (vnpred - n)%nat)); fold b; fold b in Q;
  (replace a with (a*1) by (auto with zarith));
  (replace (a*1*b*2) with (a*(b*2)) by ring);
  apply (Zmult_gt_0_lt_compat_l 1 (b * 2) a);
  omega.
						      
Local Ltac naturalize_sint_lsl1_sup n vn vz :=
  intros y h1;
  assert (0 <= y) as Ry by omega;
  unfold Cint.lsl; unfold Zbits.lsl; rewrite (Zle_imp_le_bool _ _ Ry);
  unfold Zbits.lsl_def;
  rewrite Zbits.lsl_arithmetic_shift; unfold Zbits.lsl_arithmetic_def;
  (replace (1 * two_power_nat (Z.abs_nat y))
    with (two_power_nat (Z.abs_nat y)) by (ring;forward));
  clear Ry;

  assert ((vn <= Z.abs_nat y)%nat) as A by
   ((replace vn with (Z.abs_nat vz) by (auto with arith));
    apply Zabs_nat_le; omega);
  clear h1;
  pose (n := Z.abs_nat y); fold n; fold n in A.
					      
Local Ltac sint_lsl1_sup n to_sint vn vnpred az bz :=
  unfold to_sint;
  unfold Cint.to_range;
 
  (replace (bz - az)
   with (two_power_nat vn) by (compute;forward));
  (replace (two_power_nat n - az)
   with (two_power_nat n +bz) by (auto with zarith));
  (replace bz with (two_power_nat vnpred) by (compute;forward));
  (replace az with (- two_power_nat vnpred) by (compute;forward));
  rewrite <- (Z.mod_unique_pos (two_power_nat n + two_power_nat vnpred)
                               (two_power_nat vn) (two_power_nat (n-vn))
                               (two_power_nat vnpred));
  [(compute; auto)
  |(compute ; split; [discriminate | auto])
  |];
  rewrite <- Bits.two_power_nat_plus;
  (replace (vn + (n - vn))%nat with n by (auto with zarith));
  auto.
					     
(** *** Cast to sint8 C type *)
(* Why3 goal *)
Lemma is_sint8_lnot : forall (x:Z), (Cint.is_sint8 x) ->
  ((Cint.to_sint8 (Cint.lnot x)) = (Cint.lnot x)).
Proof. 
  is_sint_lnot 128.
Qed.

(* Why3 goal *)
Lemma is_sint8_lxor : forall (x:Z) (y:Z), (Cint.is_sint8 x) ->
  ((Cint.is_sint8 y) -> ((Cint.to_sint8 (Cint.lxor x y)) = (Cint.lxor x y))).
Proof.
  is_sint_bitwise xorb 7%nat.
Qed.

(* Why3 goal *)
Lemma is_sint8_lor : forall (x:Z) (y:Z), (Cint.is_sint8 x) -> ((Cint.is_sint8
  y) -> ((Cint.to_sint8 (Cint.lor x y)) = (Cint.lor x y))).
Proof.
  is_sint_bitwise orb 7%nat.
Qed.

(* Why3 goal *)
Lemma is_sint8_land : forall (x:Z) (y:Z), (Cint.is_sint8 x) ->
  ((Cint.is_sint8 y) -> ((Cint.to_sint8 (Cint.land x y)) = (Cint.land x y))).
Proof.
  is_sint_bitwise andb 7%nat.
Qed.

(* Why3 goal *)
Lemma is_sint8_lsr : forall (x:Z) (y:Z), (0%Z <= y)%Z -> ((Cint.is_sint8
  x) -> ((Cint.to_sint8 (Cint.lsr x y)) = (Cint.lsr x y))).
Proof.
  lsr_in_sint_range 128.
Qed.

(* Why3 goal *)
Lemma is_sint8_lsl1 : ((Cint.lsl 1%Z 7%Z) = 128%Z).
Proof.
  compute. auto.
Qed.

(* Why3 goal *)
Lemma is_sint8_lsl1_inf : forall (y:Z), ((0%Z <= y)%Z /\ (y < 7%Z)%Z) ->
  (Cint.is_sint8 (Cint.lsl 1%Z y)).
Proof.
  naturalize_sint_lsl1_inf n 7%nat 7.
  sint_lsl1_inf n Cint.is_sint8 6%nat 128.
Qed.

(* Why3 goal *)
Lemma is_sint8_lsl1_sup : forall (y:Z), (8%Z <= y)%Z ->
  ((Cint.to_sint8 (Cint.lsl 1%Z y)) = 0%Z).
Proof.
  naturalize_sint_lsl1_sup n 8%nat 8.
  sint_lsl1_sup n Cint.to_sint8 8%nat 7%nat (-128) 128.
Qed.

(** *** Cast to sint16 C type *)
(* Why3 goal *)
Lemma is_sint16_lnot : forall (x:Z), (Cint.is_sint16 x) ->
  ((Cint.to_sint16 (Cint.lnot x)) = (Cint.lnot x)).
Proof.
  is_sint_lnot 32768.
Qed.

(* Why3 goal *)
Lemma is_sint16_lxor : forall (x:Z) (y:Z), (Cint.is_sint16 x) ->
  ((Cint.is_sint16 y) -> ((Cint.to_sint16 (Cint.lxor x y)) = (Cint.lxor x
  y))).
Proof.
  is_sint_bitwise xorb 15%nat.
Qed.

(* Why3 goal *)
Lemma is_sint16_lor : forall (x:Z) (y:Z), (Cint.is_sint16 x) ->
  ((Cint.is_sint16 y) -> ((Cint.to_sint16 (Cint.lor x y)) = (Cint.lor x y))).
Proof.
  is_sint_bitwise orb 15%nat.
Qed.

(* Why3 goal *)
Lemma is_sint16_land : forall (x:Z) (y:Z), (Cint.is_sint16 x) ->
  ((Cint.is_sint16 y) -> ((Cint.to_sint16 (Cint.land x y)) = (Cint.land x
  y))).
Proof.
  is_sint_bitwise andb 15%nat.
Qed.

(* Why3 goal *)
Lemma is_sint16_lsr : forall (x:Z) (y:Z), (0%Z <= y)%Z -> ((Cint.is_sint16
  x) -> ((Cint.to_sint16 (Cint.lsr x y)) = (Cint.lsr x y))).
Proof.
  lsr_in_sint_range 32768.
Qed.

(* Why3 goal *)
Lemma is_sint16_lsl1 : ((Cint.lsl 1%Z 15%Z) = 32768%Z).
Proof.
  compute. auto.
Qed.

(* Why3 goal *)
Lemma is_sint16_lsl1_inf : forall (y:Z), ((0%Z <= y)%Z /\ (y < 15%Z)%Z) ->
  (Cint.is_sint16 (Cint.lsl 1%Z y)).
Proof.
  naturalize_sint_lsl1_inf n 15%nat 15.
  sint_lsl1_inf n Cint.is_sint16 14%nat 32768.
Qed.

(* Why3 goal *)
Lemma is_sint16_lsl1_sup : forall (y:Z), (16%Z <= y)%Z ->
  ((Cint.to_sint16 (Cint.lsl 1%Z y)) = 0%Z).
Proof.
  naturalize_sint_lsl1_sup n 16%nat 16.
  sint_lsl1_sup n Cint.to_sint16 16%nat 15%nat (-32768) 32768.
Qed.

(** *** Cast to sint32 C type *)
(* Why3 goal *)
Lemma is_sint32_lnot : forall (x:Z), (Cint.is_sint32 x) ->
  ((Cint.to_sint32 (Cint.lnot x)) = (Cint.lnot x)).
Proof.
  is_sint_lnot 2147483648.
Qed.

(* Why3 goal *)
Lemma is_sint32_lxor : forall (x:Z) (y:Z), (Cint.is_sint32 x) ->
  ((Cint.is_sint32 y) -> ((Cint.to_sint32 (Cint.lxor x y)) = (Cint.lxor x
  y))).
Proof.
  is_sint_bitwise xorb 31%nat.
Qed.

(* Why3 goal *)
Lemma is_sint32_lor : forall (x:Z) (y:Z), (Cint.is_sint32 x) ->
  ((Cint.is_sint32 y) -> ((Cint.to_sint32 (Cint.lor x y)) = (Cint.lor x y))).
Proof.
  is_sint_bitwise orb 31%nat.
Qed.

(* Why3 goal *)
Lemma is_sint32_land : forall (x:Z) (y:Z), (Cint.is_sint32 x) ->
  ((Cint.is_sint32 y) -> ((Cint.to_sint32 (Cint.land x y)) = (Cint.land x
  y))).
Proof. 
  is_sint_bitwise andb 31%nat.
Qed.

(* Why3 goal *)
Lemma is_sint32_lsr : forall (x:Z) (y:Z), (0%Z <= y)%Z -> ((Cint.is_sint32
  x) -> ((Cint.to_sint32 (Cint.lsr x y)) = (Cint.lsr x y))).
Proof.
  lsr_in_sint_range 2147483648.
Qed.

(* Why3 goal *)
Lemma is_sint32_lsl1 : ((Cint.lsl 1%Z 31%Z) = 2147483648%Z).
Proof.
  compute. auto.
Qed.

(* Why3 goal *)
Lemma is_sint32_lsl1_inf : forall (y:Z), ((0%Z <= y)%Z /\ (y < 31%Z)%Z) ->
  (Cint.is_sint32 (Cint.lsl 1%Z y)).
Proof.
  naturalize_sint_lsl1_inf n 31%nat 31.
  sint_lsl1_inf n Cint.is_sint32 30%nat 2147483648.
Qed.

(* Why3 goal *)
Lemma is_sint32_lsl1_sup : forall (y:Z), (32%Z <= y)%Z ->
  ((Cint.to_sint32 (Cint.lsl 1%Z y)) = 0%Z).
Proof.
  naturalize_sint_lsl1_sup n 32%nat 32.
  sint_lsl1_sup n Cint.to_sint32 32%nat 31%nat
                (-2147483648) 2147483648.
Qed.

(** *** Cast to sint64 C type *)
(* Why3 goal *)
Lemma is_sint64_lnot : forall (x:Z), (Cint.is_sint64 x) ->
  ((Cint.to_sint64 (Cint.lnot x)) = (Cint.lnot x)).
Proof.
  is_sint_lnot 9223372036854775808. 
Qed.

(* Why3 goal *)
Lemma is_sint64_lxor : forall (x:Z) (y:Z), (Cint.is_sint64 x) ->
  ((Cint.is_sint64 y) -> ((Cint.to_sint64 (Cint.lxor x y)) = (Cint.lxor x
  y))).
Proof. 
  is_sint_bitwise xorb 63%nat.
Qed.

(* Why3 goal *)
Lemma is_sint64_lor : forall (x:Z) (y:Z), (Cint.is_sint64 x) ->
  ((Cint.is_sint64 y) -> ((Cint.to_sint64 (Cint.lor x y)) = (Cint.lor x y))).
Proof.
  is_sint_bitwise orb 63%nat.
Qed.

(* Why3 goal *)
Lemma is_sint64_land : forall (x:Z) (y:Z), (Cint.is_sint64 x) ->
  ((Cint.is_sint64 y) -> ((Cint.to_sint64 (Cint.land x y)) = (Cint.land x
  y))).
Proof. 
  is_sint_bitwise andb 63%nat.
Qed.

(* Why3 goal *)
Lemma is_sint64_lsr : forall (x:Z) (y:Z), (0%Z <= y)%Z -> ((Cint.is_sint64
  x) -> ((Cint.to_sint64 (Cint.lsr x y)) = (Cint.lsr x y))).
Proof.
  lsr_in_sint_range 9223372036854775808.
Qed.

(* Why3 goal *)
Lemma is_sint64_lsl1 : ((Cint.lsl 1%Z 63%Z) = 9223372036854775808%Z).
Proof.
  compute. auto.
Qed.

(* Why3 goal *)
Lemma is_sint64_lsl1_inf : forall (y:Z), ((0%Z <= y)%Z /\ (y < 63%Z)%Z) ->
  (Cint.is_sint64 (Cint.lsl 1%Z y)).
Proof.
  naturalize_sint_lsl1_inf n 63%nat 63.
  sint_lsl1_inf n Cint.is_sint64 62%nat 9223372036854775808.
Qed.

(* Why3 goal *)
Lemma is_sint64_lsl1_sup : forall (y:Z), (64%Z <= y)%Z ->
  ((Cint.to_sint64 (Cint.lsl 1%Z y)) = 0%Z).
Proof.
  naturalize_sint_lsl1_sup n 64%nat 64.
  sint_lsl1_sup n Cint.to_sint64 64%nat 63%nat
                (-9223372036854775808) 9223372036854775808.
Qed.

