(**************************************************************************)
(*                                                                        *)
(*  This file is part of WP plug-in of Frama-C.                           *)
(*                                                                        *)
(*  Copyright (C) 2007-2019                                               *)
(*    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.

(* Why3 goal *)
Lemma lnot_bool : ((Cint.lnot 0%Z) = (-1%Z)%Z) /\
  ((Cint.lnot (-1%Z)%Z) = 0%Z).
Proof.
  split; Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma land_idemp : forall (x:Z), ((Cint.land x x) = x).
Proof.
  intro. Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma land_0 : forall (x:Z), ((Cint.land 0%Z x) = 0%Z).
Proof.
  intro. Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma land_0bis : forall (x:Z), ((Cint.land x 0%Z) = 0%Z).
Proof.
  intro.
  rewrite Zbits.land_commut.
  Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma land_1 : forall (x:Z), ((Cint.land (-1%Z)%Z x) = x).
Proof.
  intro. Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma land_1bis : forall (x:Z), ((Cint.land x (-1%Z)%Z) = x).
Proof.
  intros x.
  rewrite Zbits.land_commut.
  Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma land_bool : ((Cint.land 0%Z 0%Z) = 0%Z) /\ (((Cint.land 0%Z
  1%Z) = 0%Z) /\ (((Cint.land 1%Z 0%Z) = 0%Z) /\ ((Cint.land 1%Z
  1%Z) = 1%Z))).
Proof.
  split;split;split;Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma lor_idemp : forall (x:Z), ((Cint.lor x x) = x).
Proof.
  intro. Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma lor_1 : forall (x:Z), ((Cint.lor (-1%Z)%Z x) = (-1%Z)%Z).
Proof.
  intro. Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma lor_1bis : forall (x:Z), ((Cint.lor x (-1%Z)%Z) = (-1%Z)%Z).
Proof.
  intros x.
  rewrite Zbits.lor_commut.
  Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma lor_0 : forall (x:Z), ((Cint.lor 0%Z x) = x).
Proof.
  intro. Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma lor_0bis : forall (x:Z), ((Cint.lor x 0%Z) = x).
Proof.
  intros x.
  rewrite Zbits.lor_commut.
  Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma lor_bool : ((Cint.lor 0%Z 0%Z) = 0%Z) /\ (((Cint.lor 0%Z 1%Z) = 1%Z) /\
  (((Cint.lor 1%Z 0%Z) = 1%Z) /\ ((Cint.lor 1%Z 1%Z) = 1%Z))).
Proof.
  split;split;split; Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma lxor_nilpotent : forall (x:Z), ((Cint.lxor x x) = 0%Z).
Proof.
  intro. Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma lxor_1 : forall (x:Z), ((Cint.lxor (-1%Z)%Z x) = (Cint.lnot x)).
Proof.
  intro. Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma lxor_1bis : forall (x:Z), ((Cint.lxor x (-1%Z)%Z) = (Cint.lnot x)).
Proof.
  intros x.
  rewrite Zbits.lxor_commut.
  Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma lxor_0 : forall (x:Z), ((Cint.lxor 0%Z x) = x).
Proof.
  intro. Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma lxor_0bis : forall (x:Z), ((Cint.lxor x 0%Z) = x).
Proof.
  intros x.
  rewrite Zbits.lxor_commut.
  Zbits.auto_zbits.
Qed.

(* Why3 goal *)
Lemma lxor_bool : ((Cint.lxor 0%Z 0%Z) = 0%Z) /\ (((Cint.lxor 0%Z
  1%Z) = 1%Z) /\ (((Cint.lxor 1%Z 0%Z) = 1%Z) /\ ((Cint.lxor 1%Z
  1%Z) = 0%Z))).
Proof.
  split; split; split; Zbits.auto_zbits.
Qed.

Require Import Qedlib.
Local Open 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 *)
(** ** Some properties of bit extration *)
(** ** 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.

(** ** Shift operators *)
  
(* Why3 goal *)
Lemma lsl_1_two_power : forall (n:Z), (0%Z <= n)%Z -> ((Cint.lsl 1%Z
  n) = (Cint.two_power_abs n)).
Proof.
  intros n h1.
  unfold Cint.lsl. rewrite Zbits.lsl_pos by auto. 
  unfold Zbits.lsl_def. rewrite Zbits.lsl_arithmetic_shift. 
  unfold Zbits.lsl_arithmetic_def.
  unfold Cint.two_power_abs. ring.
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.

(* Why3 goal *)
Lemma pos_extraction_sup_inv : forall (x:Z) (i:Z), (0%Z <= i)%Z ->
  ((forall (j:Z), (i <= j)%Z -> ~ (Cint.bit_test x j)) -> ((0%Z <= x)%Z /\
  (x < (Cint.lsl 1%Z i))%Z)).
Proof.
  intros x i h1 h2.
  unfold Cint.lsl.
  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.
  apply Zbits.Zbit_unsigned_trail_inv.
  intros k h.
  generalize (h2 (Z.of_nat k)); clear h2; intro h2.
  unfold Cint.bit_test in h2; rewrite Zbits.bit_testb_pos in h2.
  + assert (Zbits.zbit_test_def x (Z.of_nat k) <> true) as h3.
    { apply h2. clear h2. rewrite <- (Zabs2Nat.id k) in h. 
      rewrite <- Zabs2Nat.inj_le in h; auto.
      apply Zle_0_nat. } 
    clear h2.
    unfold Zbits.zbit_test_def in h3. rewrite Zabs2Nat.id in h3. 
    destruct (Bits.Zbit x k).
    * contradiction h3. auto.
    * auto.
  + apply Zle_0_nat.
Qed.

(** * Link between Bit extraction and C type conversions *)
(** ** Unsigned conversions *)
	
(* Why3 goal *)
Lemma to_uint_extraction_sup : forall (n:Z) (x:Z) (i:Z), ((0%Z <= n)%Z /\
  (n <= i)%Z) -> ((Cint.is_uint n x) -> ~ (Cint.bit_test x i)).
Proof.
  intros n x i h1 h2.
  assert (H:(Bits.Zbit x (Z.abs_nat i) = false)).
  { unfold Cint.is_uint in h2.
    apply (Zbits.Zbit_unsigned_trail (Z.abs_nat n) (Z.abs_nat i) x).
    + apply Zabs_nat_le. omega.
    + unfold Cint.two_power_abs in h2.
      trivial. }
  assert (I:(0 <= i)) by omega;
  unfold Cint.bit_test; unfold_bit_testb I; unfold Zbits.zbit_test_def.
  rewrite H; discriminate.
Qed.

(* Why3 goal *)
Lemma to_uint_extraction_inf_bool : forall (n:Z) (x:Z) (i:Z),
  ((0%Z <= i)%Z /\ (i < n)%Z) -> ((Cint.bit_testb (Cint.to_uint n x)
  i) = (Cint.bit_testb x i)).
Proof.
  intros n x i (h1,h2); unfold_bit_testb h1; unfold Zbits.zbit_test_def.
  pose (k:= (Z.abs_nat i)); fold k.
  unfold Cint.to_uint; unfold Cint.to_range.
  simpl.
  replace (x - 0) with x by (auto with zarith).
  unfold Cint.two_power_abs. 
  rewrite Zbits.Zbit_uint_mod_two_power_nat.
  rewrite (leb_correct_conv k (Z.abs_nat n)).
  + trivial.
  + apply Zabs_nat_lt; omega.
Qed.

(* Why3 goal *)
Lemma to_uint_extraction_inf : forall (n:Z) (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < n)%Z) -> ((Cint.bit_test (Cint.to_uint n x) i) <-> (Cint.bit_test x
  i)).
Proof.
  intros n x i (h1,h2);
  unfold Cint.bit_test;
  rewrite to_uint_extraction_inf_bool by auto;
  pose (xb:=Cint.bit_testb x i); fold xb;
  destruct xb; simpl; split; intro G; auto; destruct G; auto.
Qed.

(* Why3 goal *)
Lemma is_uint_ext : forall (n:Z) (x:Z) (y:Z), (0%Z <= n)%Z -> ((Cint.is_uint
  n x) -> ((Cint.is_uint n y) -> ((forall (i:Z), ((0%Z <= i)%Z /\
  (i < n)%Z) -> ((Cint.bit_test x i) <-> (Cint.bit_test y i))) -> (x = y)))).
Proof.
  intros n x y h1 h2 h3 h4.
  assert (forall i: int, (0 <= i)%Z -> (Cint.bit_test x i <-> Cint.bit_test y i)).
  { intros.
    case_lt i n; intro.
    + apply h4; omega.
    + assert (~ Cint.bit_test x i).
      { apply (to_uint_extraction_sup n). omega. auto. }
      assert (~ Cint.bit_test y i).
      { apply (to_uint_extraction_sup n). omega. auto. }
     intuition. }
  clear h1; clear h2; clear h3; clear h4.
  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.

Local Ltac uint_extraction_inf_bool to_uint :=
  intros; rewrite to_uint; 
  apply to_uint_extraction_inf_bool;
  omega.
  
Local Ltac uint_extraction_inf to_uint :=
  intros; rewrite to_uint; 
  apply to_uint_extraction_inf;
  omega.
						 
(** *** 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.
  intros; apply (to_uint_extraction_sup 8); (auto with zarith).
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.
  uint_extraction_inf_bool Cint.to_uint_8.
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.
  uint_extraction_inf Cint.to_uint_8.
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.
  apply (is_uint_ext 8); (auto with zarith).
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.
   intros; apply (to_uint_extraction_sup 16); (auto with zarith).
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.
  uint_extraction_inf_bool Cint.to_uint_16.
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.
  uint_extraction_inf Cint.to_uint_16.
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.
  apply (is_uint_ext 16); (auto with zarith).
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.
  intros; apply (to_uint_extraction_sup 32); (auto with zarith).
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.
  uint_extraction_inf_bool Cint.to_uint_32.
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.
  uint_extraction_inf Cint.to_uint_32.
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.
  apply (is_uint_ext 32); (auto with zarith).
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.
  intros; apply (to_uint_extraction_sup 64); (auto with zarith).
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.
  uint_extraction_inf_bool Cint.to_uint_64.
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.
   uint_extraction_inf Cint.to_uint_64.
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.
  apply (is_uint_ext 64); (auto with zarith).
Qed.

(** ** Signed conversions *)
(* Why3 goal *)
Lemma to_sint_extraction_sup : forall (n:Z) (x:Z) (i:Z), ((0%Z <= n)%Z /\
  (n <= i)%Z) -> ((Cint.is_sint n x) -> ((Cint.bit_test x i) <->
  (x < 0%Z)%Z)).
Proof.
  intros n x i h1.
  unfold Cint.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 n <= Z.abs_nat i)%nat.
  { apply (Zabs_nat_le); omega. }
  rewrite <- Zlt_bool_true_Zlt; 
  apply (Zbits.Zbit_trail (Z.abs_nat n) (Z.abs_nat i) x); auto.
Qed.

(* Why3 goal *)
Lemma to_sint_extraction_inf_bool : forall (n:Z) (x:Z) (i:Z),
  ((0%Z <= i)%Z /\ (i < n)%Z) -> ((Cint.bit_testb (Cint.to_sint n x)
  i) = (Cint.bit_testb x i)).
Proof.
  intros n x i (h1,h2); unfold_bit_testb h1; unfold Zbits.zbit_test_def.
  pose (k:= (Z.abs_nat i)); fold k.
  unfold Cint.to_sint; unfold Cint.to_range.
  rewrite Z.sub_opp_r; rewrite Z.sub_opp_r.
  rewrite Z.add_opp_l.
  replace (Cint.two_power_abs n + Cint.two_power_abs n) with (2 * Cint.two_power_abs n) by (auto with zarith).
  unfold Cint.two_power_abs.
  replace n with ((n-i)+i) by (auto with zarith).
  rewrite Zabs2Nat.inj_add by omega.
  apply Zbits.Zbit_sint_mod_two_power_nat.
Qed.

(* Why3 goal *)
Lemma to_sint_extraction_inf : forall (n:Z) (x:Z) (i:Z), ((0%Z <= i)%Z /\
  (i < n)%Z) -> ((Cint.bit_test (Cint.to_sint n x) i) <-> (Cint.bit_test x
  i)).
Proof.
  intros n x i (h1,h2).
  unfold Cint.bit_test;
  rewrite to_sint_extraction_inf_bool by auto.
  pose (xb:=Cint.bit_testb x i); fold xb;
  destruct xb; simpl; split; intro G; auto; destruct G; auto.
Qed.

(* Why3 goal *)
Lemma is_sint_ext : forall (n:Z) (x:Z) (y:Z), (0%Z <= n)%Z -> ((Cint.is_sint
  n x) -> ((Cint.is_sint n y) -> ((forall (i:Z), ((0%Z <= i)%Z /\
  (i <= n)%Z) -> ((Cint.bit_test x i) <-> (Cint.bit_test y i))) ->
  (x = y)))).
Proof. 
  intros n x y h1 h2 h3 h4.
  assert (forall i: int, (0 <= i)%Z -> (Cint.bit_test x i <-> Cint.bit_test y i)).
  { intros.
    case_leq i n; intro.
    + apply h4; omega.
    + assert (0<=n<=n) by omega.
      specialize ((h4 n) H1).
      generalize ((to_sint_extraction_sup n x n) H1 h2).
      generalize ((to_sint_extraction_sup n y n) H1 h3).
      clear H1; intros.
      rewrite h4 in H2. rewrite H2 in H1. clear H2.
      assert ((Cint.bit_test x i) <-> x < 0).
      { apply (to_sint_extraction_sup n); [omega | auto]. }
      assert ((Cint.bit_test y i) <-> y < 0).
      { apply (to_sint_extraction_sup n); [omega | auto]. }
      rewrite H2.
      rewrite H3.
      auto. }
  clear h1; clear h2; clear h3; clear h4.
  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.

(** 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.

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.

Local Ltac sint_extraction_inf_bool to_sint :=
  intros; rewrite to_sint; 
  apply to_sint_extraction_inf_bool;
  omega.
  
Local Ltac sint_extraction_inf to_sint :=
  intros; rewrite to_sint; 
  apply to_sint_extraction_inf;
  omega.
						 
(** *** Cast to sint8 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.
  intros; apply (to_sint_extraction_sup 7); (auto with zarith).
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.
  sint_extraction_inf_bool Cint.to_sint_8.
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.
  sint_extraction_inf Cint.to_sint_8.
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. apply (is_sint_ext 7) ; (auto with zarith).
Qed.

(** *** Cast to sint16 C type *)
(* 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.
  intros; apply (to_sint_extraction_sup 15); (auto with zarith).
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.
  sint_extraction_inf_bool Cint.to_sint_16.
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.
  sint_extraction_inf Cint.to_sint_16.
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. apply (is_sint_ext 15) ; (auto with zarith).
Qed.

(** *** Cast to uint32 C type *)
(* 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.
  intros; apply (to_sint_extraction_sup 31); (auto with zarith).
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.
  sint_extraction_inf_bool Cint.to_sint_32.
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.
  sint_extraction_inf Cint.to_sint_32.
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. apply (is_sint_ext 31) ; (auto with zarith).
Qed.

(** *** Cast to uint64 C type *)
(* 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.
  intros; apply (to_sint_extraction_sup 63); (auto with zarith).
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.
  sint_extraction_inf_bool Cint.to_sint_64.
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.
  sint_extraction_inf Cint.to_sint_64.
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; apply (is_sint_ext 63); (auto with zarith).
Qed.

(** * Some C-Integer Bits Conversions are distributive *)
(** 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)].

(** ** Unsigned conversions *)
  
(* Why3 goal *)
Lemma to_uint_lor : forall (n:Z) (x:Z) (y:Z), ((Cint.to_uint n (Cint.lor x
  y)) = (Cint.lor (Cint.to_uint n x) (Cint.to_uint n y))).
Proof.
  intros n x y.
  apply Zbits.zbit_test_ext. intro.
  rewrite Zbits.lor_extraction.
  unfold Cint.to_uint; unfold Cint.to_range; Cint.simplify_to_range_unfolding.
  unfold Cint.two_power_abs.
  repeat (rewrite Zbits.uint_mod_two_power_extraction).
  rewrite Zbits.lor_extraction.
  pose (c:=(leb (Z.abs_nat n) (Z.abs_nat n0))); fold c.
  destruct c; auto.
Qed.

(** *** Cast to uint8 C type *)
(* Why3 goal *)
Lemma to_uint8_lor : forall (x:Z) (y:Z), ((Cint.to_uint8 (Cint.lor x
  y)) = (Cint.lor (Cint.to_uint8 x) (Cint.to_uint 8%Z y))).
Proof.
  intros x y; rewrite Cint.to_uint_8; apply to_uint_lor.
Qed.

(** ***  Cast to uint16 C type *)
(* Why3 goal *)
Lemma to_uint16_lor : forall (x:Z) (y:Z), ((Cint.to_uint16 (Cint.lor x
  y)) = (Cint.lor (Cint.to_uint16 x) (Cint.to_uint16 y))).
Proof.
  intros x y; rewrite Cint.to_uint_16; apply to_uint_lor.
Qed.

(** ***  Cast to uint32 C type *)
(* Why3 goal *)
Lemma to_uint32_lor : forall (x:Z) (y:Z), ((Cint.to_uint32 (Cint.lor x
  y)) = (Cint.lor (Cint.to_uint32 x) (Cint.to_uint32 y))).
Proof.
  intros x y; rewrite Cint.to_uint_32; apply to_uint_lor.
Qed.

(** ***  Cast to uint64 C type *)
(* Why3 goal *)
Lemma to_uint64_lor : forall (x:Z) (y:Z), ((Cint.to_uint64 (Cint.lor x
  y)) = (Cint.lor (Cint.to_uint64 x) (Cint.to_uint64 y))).
Proof.
  intros x y; rewrite Cint.to_uint_64; apply to_uint_lor.
Qed.

(* Why3 goal *)
Lemma is_uint_lxor : forall (n:Z) (x:Z) (y:Z), (Cint.is_uint n x) ->
  ((Cint.is_uint n y) -> ((Cint.to_uint n (Cint.lxor x y)) = (Cint.lxor x
  y))).
Proof.
  intro n; is_uint_bitwise xorb (Zabs_nat n). 
Qed.

(** * Some C-Integer Bits Conversions are identity *)
(** ** Unsigned conversions *)
(* Why3 goal *)
Lemma is_uint_lor : forall (n:Z) (x:Z) (y:Z), (Cint.is_uint n x) ->
  ((Cint.is_uint n y) -> ((Cint.to_uint n (Cint.lor x y)) = (Cint.lor x y))).
Proof.
  intro n; is_uint_bitwise orb (Zabs_nat n). 
Qed.

(* Why3 goal *)
Lemma is_uint_land : forall (n:Z) (x:Z) (y:Z), (Cint.is_uint n x) ->
  ((Cint.is_uint n y) -> ((Cint.to_uint n (Cint.land x y)) = (Cint.land x
  y))).
Proof.
  intro n; is_uint_bitwise andb (Zabs_nat n). 
Qed.

(* Why3 goal *)
Lemma is_uint_lsr : forall (n:Z) (x:Z) (y:Z), (0%Z <= y)%Z -> ((Cint.is_uint
  n x) -> ((Cint.to_uint n (Cint.lsr x y)) = (Cint.lsr x y))).
Proof.
  intro n; lsr_in_uint_range (Cint.two_power_abs n).
Qed.

(* Why3 goal *)
Lemma is_uint_lsl1_inf : forall (n:Z) (y:Z), ((0%Z <= y)%Z /\ (y < n)%Z) ->
  ((Cint.to_uint n (Cint.lsl 1%Z y)) = (Cint.lsl 1%Z y)).
Proof.
  intros n 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 (auto with zarith));
  clear Ry.

  assert (Z.abs_nat y < (Z.abs_nat n))%nat as A by
   (apply Zabs_nat_lt; omega);
  clear h1; clear h2;
  pose (M := Z.abs_nat y); fold M; fold M in A.

  unfold Cint.to_uint; unfold Cint.to_range; Cint.simplify_to_range_unfolding.
  rewrite Zmod_small; trivial.
  unfold Cint.two_power_abs; pose (N:=(Z.abs_nat n)); fold N; fold N in A.
  generalize (Bits.two_power_nat_is_positive M); intro Pos.
  generalize (Bits.two_power_nat_increase_strict M N A) ; intro.
  omega.
Qed.

(* Why3 goal *)
Lemma is_uint_lsl1_sup : forall (n:Z) (y:Z), ((0%Z <= n)%Z /\ (n <= y)%Z) ->
  ((Cint.to_uint n (Cint.lsl 1%Z y)) = 0%Z).
Proof.
  intros n 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 (auto with zarith));
  clear Ry.

  assert (Z.abs_nat n <= (Z.abs_nat y))%nat as A by
   (apply Zabs_nat_le; omega);
  clear h1;
  pose (M := Z.abs_nat y); fold M; fold M in A.
  unfold Cint.to_uint; unfold Cint.to_range; Cint.simplify_to_range_unfolding.
  
  rewrite (le_plus_minus (Z.abs_nat n) M A).
  replace (Z.abs_nat n + (M - Z.abs_nat n))%nat with ((M - Z.abs_nat n) + Z.abs_nat n)%nat by (auto with zarith).
  rewrite Bits.two_power_nat_plus.

  apply Z_mod_mult. 
Qed.

(** *** Cast to uint8 C type *)
(* Why3 goal *)
Lemma is_uint8_lxor : forall (x:Z) (y:Z), (Cint.is_uint8 x) ->
  ((Cint.is_uint8 y) -> ((Cint.to_uint8 (Cint.lxor x y)) = (Cint.lxor x y))).
Proof.
  intros; rewrite Cint.to_uint_8; apply is_uint_lxor; trivial.
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.
  intros; rewrite Cint.to_uint_8; apply is_uint_lor; trivial.
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.
  intros; rewrite Cint.to_uint_8; apply is_uint_land; trivial.
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.	
  intros; rewrite Cint.to_uint_8; apply is_uint_lsr; trivial.
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.
  intros; rewrite Cint.to_uint_8; apply is_uint_lsl1_inf; trivial.
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.
  intros; rewrite Cint.to_uint_8; apply is_uint_lsl1_sup; omega.
Qed.

(** ***  Cast to uint16 C type *)
(* Why3 goal *)
Lemma is_uint16_lxor : forall (x:Z) (y:Z), (Cint.is_uint16 x) ->
  ((Cint.is_uint16 y) -> ((Cint.to_uint16 (Cint.lxor x y)) = (Cint.lxor x
  y))).
Proof. 
  intros; rewrite Cint.to_uint_16; apply is_uint_lxor; trivial.
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. 
  intros; rewrite Cint.to_uint_16; apply is_uint_lor; trivial.
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. 
  intros; rewrite Cint.to_uint_16; apply is_uint_land; trivial.
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.
  intros; rewrite Cint.to_uint_16; apply is_uint_lsr; trivial.
Qed.

(* Why3 goal *)
Lemma is_uint16_lsl1_inf : forall (y:Z), ((0%Z <= y)%Z /\ (y < 16%Z)%Z) ->
  ((Cint.to_uint16 (Cint.lsl 1%Z y)) = (Cint.lsl 1%Z y)).
Proof.
  intros; rewrite Cint.to_uint_16. apply is_uint_lsl1_inf; trivial.
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.
  intros; rewrite Cint.to_uint_16; apply is_uint_lsl1_sup; omega.
Qed.

(** *** Cast to uint32 C type *)
(* Why3 goal *)
Lemma is_uint32_lxor : forall (x:Z) (y:Z), (Cint.is_uint32 x) ->
  ((Cint.is_uint32 y) -> ((Cint.to_uint32 (Cint.lxor x y)) = (Cint.lxor x
  y))).
Proof.
  intros; rewrite Cint.to_uint_32; apply is_uint_lxor; trivial.
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.
  intros; rewrite Cint.to_uint_32; apply is_uint_lor; trivial.
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. 
  intros; rewrite Cint.to_uint_32; apply is_uint_land; trivial.
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.
  intros; rewrite Cint.to_uint_32; apply is_uint_lsr; trivial.
Qed.

(* Why3 goal *)
Lemma is_uint32_lsl1_inf : forall (y:Z), ((0%Z <= y)%Z /\ (y < 32%Z)%Z) ->
  ((Cint.to_uint32 (Cint.lsl 1%Z y)) = (Cint.lsl 1%Z y)).
Proof.
  intros; rewrite Cint.to_uint_32; apply is_uint_lsl1_inf; trivial.
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.
  intros; rewrite Cint.to_uint_32; apply is_uint_lsl1_sup; omega.
Qed.

(** *** Cast to uint64 C type *)
(* Why3 goal *)
Lemma is_uint64_lxor : forall (x:Z) (y:Z), (Cint.is_uint64 x) ->
  ((Cint.is_uint64 y) -> ((Cint.to_uint64 (Cint.lxor x y)) = (Cint.lxor x
  y))).
Proof.
  intros; rewrite Cint.to_uint_64; apply is_uint_lxor; trivial.
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.
  intros; rewrite Cint.to_uint_64; apply is_uint_lor; trivial.
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. 
  intros; rewrite Cint.to_uint_64; apply is_uint_land; trivial.
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.
  intros; rewrite Cint.to_uint_64; apply is_uint_lsr; trivial.
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.
  intros; rewrite Cint.to_uint_64; apply is_uint_lsl1_inf; trivial.
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. 
  intros; rewrite Cint.to_uint_64; apply is_uint_lsl1_sup; omega.
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)].

(* Why3 goal *)
Lemma is_sint_lnot : forall (n:Z) (x:Z), (Cint.is_sint n x) ->
  ((Cint.to_sint n (Cint.lnot x)) = (Cint.lnot x)).
Proof.
  intros n; is_sint_lnot (Cint.two_power_abs n).
Qed.

(* Why3 goal *)
Lemma is_sint_lxor : forall (n:Z) (x:Z) (y:Z), (Cint.is_sint n x) ->
  ((Cint.is_sint n y) -> ((Cint.to_sint n (Cint.lxor x y)) = (Cint.lxor x
  y))).
Proof.
  intro n; is_sint_bitwise xorb (Zabs_nat n). 
Qed.

(* Why3 goal *)
Lemma is_sint_lor : forall (n:Z) (x:Z) (y:Z), (Cint.is_sint n x) ->
  ((Cint.is_sint n y) -> ((Cint.to_sint n (Cint.lor x y)) = (Cint.lor x y))).
Proof.
  intro n; is_sint_bitwise orb (Zabs_nat n). 
Qed.

(* Why3 goal *)
Lemma is_sint_land : forall (n:Z) (x:Z) (y:Z), (Cint.is_sint n x) ->
  ((Cint.is_sint n y) -> ((Cint.to_sint n (Cint.land x y)) = (Cint.land x
  y))).
Proof.
  intro n; is_sint_bitwise andb (Zabs_nat n). 
Qed.

(* Why3 goal *)
Lemma is_sint_lsr : forall (n:Z) (x:Z) (y:Z), (0%Z <= y)%Z -> ((Cint.is_sint
  n x) -> ((Cint.to_sint n (Cint.lsr x y)) = (Cint.lsr x y))).
Proof.
  intro n; lsr_in_sint_range (Cint.two_power_abs n).
Qed.

(* Why3 goal *)
Lemma is_sint_lsl1_inf : forall (n:Z) (y:Z), ((0%Z <= y)%Z /\ (y < n)%Z) ->
  ((Cint.to_sint n (Cint.lsl 1%Z y)) = (Cint.lsl 1%Z y)).
Proof.
  intros n y (h1,h2).
  apply Cint.id_sint.
  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 (auto with zarith)).
  unfold Cint.is_sint.
  generalize (Cint.two_power_abs_is_positive y);
  generalize (Cint.two_power_abs_is_positive n);
  unfold Cint.two_power_abs; intros.
  split; [omega|].
  apply Bits.two_power_nat_increase_strict.
  apply Zabs_nat_lt; omega.
Qed.

(* Why3 goal *)
Lemma is_sint_lsl1_sup : forall (n:Z) (y:Z), ((0%Z <= n)%Z /\ (n < y)%Z) ->
  ((Cint.to_sint n (Cint.lsl 1%Z y)) = 0%Z).
Proof.
  intros n 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 (auto with zarith)).
  pose (M := two_power_nat (Z.abs_nat y)); fold M.
  unfold Cint.to_sint; unfold Cint.to_range; Cint.simplify_to_range_unfolding.
  pose (N:=(Cint.two_power_abs n)); fold N.

  rewrite <- (Z.mod_unique_pos (M + N) (N + N)
                               (Cint.two_power_abs (y - (n + 1)))
                                N).
  + auto with zarith.
  + generalize (Cint.two_power_abs_is_positive n); fold N; omega.
  + rewrite Z.add_cancel_r. 
    replace (N + N) with (2 * N) by (auto with zarith); unfold N. 
    rewrite <- Cint.two_power_abs_plus_one by omega.
    rewrite <- Cint.two_power_abs_plus_pos by omega.
    replace (n + 1 + (y - (n + 1))) with y by ring.
    auto.
Qed.

(** *** 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.to_sint8 (Cint.lsl 1%Z y)) = (Cint.lsl 1%Z y)).
Proof.
  intros; rewrite Cint.to_sint_8; apply is_sint_lsl1_inf; omega.
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.
  intros; rewrite Cint.to_sint_8; apply is_sint_lsl1_sup; omega.
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.to_sint16 (Cint.lsl 1%Z y)) = (Cint.lsl 1%Z y)).
Proof.
  intros; rewrite Cint.to_sint_16; apply is_sint_lsl1_inf; omega.
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.
  intros; rewrite Cint.to_sint_16; apply is_sint_lsl1_sup; omega.
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.to_sint32 (Cint.lsl 1%Z y)) = (Cint.lsl 1%Z y)).
Proof.
   intros; rewrite Cint.to_sint_32; apply is_sint_lsl1_inf; omega.
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.
  intros; rewrite Cint.to_sint_32; apply is_sint_lsl1_sup; omega.
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.to_sint64 (Cint.lsl 1%Z y)) = (Cint.lsl 1%Z y)).
Proof.
  intros; rewrite Cint.to_sint_64; apply is_sint_lsl1_inf; omega.
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.
  intros; rewrite Cint.to_sint_64; apply is_sint_lsl1_sup; omega.
Qed.

(** * Range of some bitwise operations *)
(* Why3 goal *)
Lemma uint_land_range : forall (x:Z) (y:Z), (0%Z <= x)%Z ->
  ((0%Z <= (Cint.land x y))%Z /\ ((Cint.land x y) <= x)%Z).
Proof.
  intros x y h1.
  apply Zbits.uint_land_range; trivial.
Qed.

(* Why3 goal *)
Lemma uint_lor_inf : forall (x:Z) (y:Z), ((-1%Z)%Z <= x)%Z ->
  ((0%Z <= y)%Z -> (x <= (Cint.lor x y))%Z).
Proof.
  intros x y h1 h2.
  case_leq 0 x; intro.
  + apply Zbits.uint_lor_inf; trivial.
  + replace x with (-1).
    { rewrite Zbits.lor_1; omega. }
    omega.
Qed.

(* Why3 goal *)
Lemma sint_land_inf : forall (x:Z) (y:Z), (x <= 0%Z)%Z -> ((y < 0%Z)%Z ->
  ((Cint.land x y) <= x)%Z).
Proof.
  intros x y h1 h2.
  cut (-(x+1) <= -((Cint.land x y)+1)).
  { omega. }
  fold (Bits.zlnot x).
  fold (Bits.zlnot (Cint.land x y)).
  repeat (rewrite <- Zbits.lnot_zlnot_equiv).
  rewrite Zbits.lnot_land_de_morgan.
  repeat (rewrite Zbits.lnot_zlnot_equiv).
  apply (uint_lor_inf (Bits.zlnot x)); unfold Bits.zlnot; try omega.
Qed.

(* Why3 goal *)
Lemma sint_lor_range : forall (x:Z) (y:Z), (x < 0%Z)%Z -> ((x <= (Cint.lor x
  y))%Z /\ ((Cint.lor x y) < 0%Z)%Z).
Proof.
  intros x y h1.
  cut (0 <= -((Cint.lor x y)+1) <= -(x+1)).
  { omega. }
  fold (Bits.zlnot x).
  fold (Bits.zlnot (Cint.lor x y)).
  rewrite <- Zbits.lnot_zlnot_equiv.
  rewrite Zbits.lnot_lor_de_morgan.
  rewrite Zbits.lnot_zlnot_equiv.
  apply (uint_land_range (Bits.zlnot x)).
  unfold Bits.zlnot; omega.
Qed.

(* Why3 goal *)
Lemma is_uint_lor_distrib : forall (n:Z) (x:Z) (y:Z), (Cint.is_uint n
  (Cint.lor x y)) <-> ((Cint.is_uint n x) /\ (Cint.is_uint n y)).
Proof.
  intros n x y; split.
  + unfold Cint.is_uint ; intros.
    destruct H.
    rewrite <- Zbits.lor_sign in H.
    destruct H.
    generalize H0; clear H0.
    assert (h1:((-1) <= x)) by omega.
    generalize (uint_lor_inf x y h1 H1).
    rewrite Zbits.lor_commut.
    assert (h2:((-1) <= y)) by omega.
    generalize (uint_lor_inf y x h2 H).
    unfold Cint.lor;
    pose (z:=(Zbits.lor y x)); fold z; intros.
    omega.
  + intro H; destruct H.
    rewrite <- (is_uint_lor n) by trivial.
    apply Cint.is_to_uint.
Qed.

(** * Link between bitwise operators and addition *)
  
(* Why3 goal *)
Lemma lor_addition : forall (x:Z) (y:Z), ((Cint.land x y) = 0%Z) ->
  ((x + y)%Z = (Cint.lor x y)).
Proof.
  intros x y h1.
  apply Zbits.lor_addition; trivial.
Qed.

(* Why3 goal *)
Lemma lxor_addition : forall (x:Z) (y:Z), ((Cint.land x y) = 0%Z) ->
  ((x + y)%Z = (Cint.lxor x y)).
Proof.
  intros x y h1.
  apply Zbits.lxor_addition; trivial.
Qed.

(** * Link between land and cast operator *)
(* Why3 goal *)
Lemma to_uint_land_edge : forall (x:Z) (n:Z), (0%Z <= n)%Z ->
  ((Cint.to_uint n x) = (Cint.land ((Cint.lsl 1%Z n) - 1%Z)%Z x)).
Proof.
  intros x n h1.
  unfold Cint.to_uint; unfold Cint.to_range; Cint.simplify_to_range_unfolding.
  unfold Cint.two_power_abs.
  rewrite Zbits.pos_mod_two_power_nat_land_edge.
  unfold Cint.land; f_equal.
  unfold Cint.lsl; rewrite Zbits.lsl_pos by omega; unfold Zbits.lsl_def. 
  rewrite Zbits.lsl_arithmetic_shift; unfold Zbits.lsl_arithmetic_def.
  auto with zarith.
Qed.

