(* *********************************************************************) (* *) (* The Compcert verified compiler *) (* *) (* Xavier Leroy, INRIA Paris-Rocquencourt *) (* *) (* Copyright Institut National de Recherche en Informatique et en *) (* Automatique. All rights reserved. This file is distributed *) (* under the terms of the GNU General Public License as published by *) (* the Free Software Foundation, either version 2 of the License, or *) (* (at your option) any later version. This file is also distributed *) (* under the terms of the INRIA Non-Commercial License Agreement. *) (* *) (* *********************************************************************) (** Formalizations of machine integers modulo $2^N$ #2N#. *) Require Import Axioms. Require Import Coqlib. (** * Comparisons *) Inductive comparison : Type := | Ceq : comparison (**r same *) | Cne : comparison (**r different *) | Clt : comparison (**r less than *) | Cle : comparison (**r less than or equal *) | Cgt : comparison (**r greater than *) | Cge : comparison. (**r greater than or equal *) Definition negate_comparison (c: comparison): comparison := match c with | Ceq => Cne | Cne => Ceq | Clt => Cge | Cle => Cgt | Cgt => Cle | Cge => Clt end. Definition swap_comparison (c: comparison): comparison := match c with | Ceq => Ceq | Cne => Cne | Clt => Cgt | Cle => Cge | Cgt => Clt | Cge => Cle end. (** * Parameterization by the word size, in bits. *) Module Type WORDSIZE. Variable wordsize: nat. Axiom wordsize_not_zero: wordsize <> 0%nat. End WORDSIZE. Module Make(WS: WORDSIZE). Definition wordsize: nat := WS.wordsize. Definition modulus : Z := two_power_nat wordsize. Definition half_modulus : Z := modulus / 2. Definition max_unsigned : Z := modulus - 1. Definition max_signed : Z := half_modulus - 1. Definition min_signed : Z := - half_modulus. Remark wordsize_pos: Z_of_nat wordsize > 0. Proof. unfold wordsize. generalize WS.wordsize_not_zero. omega. Qed. Remark modulus_power: modulus = two_p (Z_of_nat wordsize). Proof. unfold modulus. apply two_power_nat_two_p. Qed. Remark modulus_pos: modulus > 0. Proof. rewrite modulus_power. apply two_p_gt_ZERO. generalize wordsize_pos; omega. Qed. (** * Representation of machine integers *) (** A machine integer (type [int]) is represented as a Coq arbitrary-precision integer (type [Z]) plus a proof that it is in the range 0 (included) to [modulus] (excluded. *) Record int: Type := mkint { intval: Z; intrange: 0 <= intval < modulus }. (** Binary decomposition of integers (type [Z]) *) Definition Z_bin_decomp (x: Z) : bool * Z := match x with | Z0 => (false, 0) | Zpos p => match p with | xI q => (true, Zpos q) | xO q => (false, Zpos q) | xH => (true, 0) end | Zneg p => match p with | xI q => (true, Zneg q - 1) | xO q => (false, Zneg q) | xH => (true, -1) end end. Definition Z_bin_comp (b: bool) (x: Z) : Z := if b then Zdouble_plus_one x else Zdouble x. Lemma Z_bin_comp_eq: forall b x, Z_bin_comp b x = 2 * x + (if b then 1 else 0). Proof. unfold Z_bin_comp; intros. destruct b. apply Zdouble_plus_one_mult. rewrite Zdouble_mult. omega. Qed. Lemma Z_bin_comp_decomp: forall x, Z_bin_comp (fst (Z_bin_decomp x)) (snd (Z_bin_decomp x)) = x. Proof. destruct x; simpl. auto. destruct p; auto. destruct p; auto. simpl. rewrite <- Pplus_one_succ_r. rewrite Pdouble_minus_one_o_succ_eq_xI. auto. Qed. Lemma Z_bin_comp_decomp2: forall x b y, Z_bin_decomp x = (b, y) -> x = Z_bin_comp b y. Proof. intros. rewrite <- (Z_bin_comp_decomp x). rewrite H; auto. Qed. Lemma Z_bin_decomp_comp: forall b x, Z_bin_decomp (Z_bin_comp b x) = (b, x). Proof. intros. destruct b; destruct x; simpl; auto. destruct p; simpl; auto. f_equal. f_equal. rewrite <- Pplus_one_succ_r. apply Psucc_o_double_minus_one_eq_xO. Qed. Lemma Z_bin_comp_inj: forall b1 b2 x1 x2, Z_bin_comp b1 x1 = Z_bin_comp b2 x2 -> (b1, x1) = (b2, x2). Proof. intros. repeat rewrite Z_bin_comp_eq in H. destruct b1; destruct b2. f_equal. omega. omegaContradiction. omegaContradiction. f_equal. omega. Qed. (** Fast normalization modulo [2^n]. *) Fixpoint Z_mod_two_p (x: Z) (n: nat) {struct n} : Z := match n with | O => 0 | S m => let (b, y) := Z_bin_decomp x in Z_bin_comp b (Z_mod_two_p y m) end. Lemma Z_mod_two_p_range: forall n x, 0 <= Z_mod_two_p x n < two_power_nat n. Proof. induction n; simpl; intros. rewrite two_power_nat_O. omega. rewrite two_power_nat_S. destruct (Z_bin_decomp x) as [b y] eqn:?. rewrite Z_bin_comp_eq. generalize (IHn y). destruct b; omega. Qed. Lemma Z_mod_two_p_eq: forall n x, Z_mod_two_p x n = Zmod x (two_power_nat n). Proof. assert (forall n x, exists y, x = y * two_power_nat n + Z_mod_two_p x n). induction n; simpl; intros. rewrite two_power_nat_O. exists x. ring. rewrite two_power_nat_S. destruct (Z_bin_decomp x) as [b y] eqn:?. destruct (IHn y) as [z EQ]. exists z. rewrite (Z_bin_comp_decomp2 _ _ _ Heqp). repeat rewrite Z_bin_comp_eq. rewrite EQ at 1. ring. intros. destruct (H n x) as [y EQ]. symmetry. apply Zmod_unique with y. auto. apply Z_mod_two_p_range. Qed. (** The [unsigned] and [signed] functions return the Coq integer corresponding to the given machine integer, interpreted as unsigned or signed respectively. *) Definition unsigned (n: int) : Z := intval n. Definition signed (n: int) : Z := if zlt (unsigned n) half_modulus then unsigned n else unsigned n - modulus. (** Conversely, [repr] takes a Coq integer and returns the corresponding machine integer. The argument is treated modulo [modulus]. *) Definition repr (x: Z) : int := mkint (Z_mod_two_p x wordsize) (Z_mod_two_p_range wordsize x). Definition zero := repr 0. Definition one := repr 1. Definition mone := repr (-1). Definition iwordsize := repr (Z_of_nat wordsize). Lemma mkint_eq: forall x y Px Py, x = y -> mkint x Px = mkint y Py. Proof. intros. subst y. generalize (proof_irr Px Py); intro. subst Py. reflexivity. Qed. Lemma eq_dec: forall (x y: int), {x = y} + {x <> y}. Proof. intros. destruct x; destruct y. case (zeq intval0 intval1); intro. left. apply mkint_eq. auto. right. red; intro. injection H. exact n. Qed. (** * Arithmetic and logical operations over machine integers *) Definition eq (x y: int) : bool := if zeq (unsigned x) (unsigned y) then true else false. Definition lt (x y: int) : bool := if zlt (signed x) (signed y) then true else false. Definition ltu (x y: int) : bool := if zlt (unsigned x) (unsigned y) then true else false. Definition neg (x: int) : int := repr (- unsigned x). Definition add (x y: int) : int := repr (unsigned x + unsigned y). Definition sub (x y: int) : int := repr (unsigned x - unsigned y). Definition mul (x y: int) : int := repr (unsigned x * unsigned y). (** [Zdiv_round] and [Zmod_round] implement signed division and modulus with round-towards-zero behavior. *) Definition Zdiv_round (x y: Z) : Z := if zlt x 0 then if zlt y 0 then (-x) / (-y) else - ((-x) / y) else if zlt y 0 then -(x / (-y)) else x / y. Definition Zmod_round (x y: Z) : Z := x - (Zdiv_round x y) * y. Definition divs (x y: int) : int := repr (Zdiv_round (signed x) (signed y)). Definition mods (x y: int) : int := repr (Zmod_round (signed x) (signed y)). Definition divu (x y: int) : int := repr (unsigned x / unsigned y). Definition modu (x y: int) : int := repr (Zmod (unsigned x) (unsigned y)). Definition add_carry (x y cin: int): int := if zlt (unsigned x + unsigned y + unsigned cin) modulus then zero else one. (** For bitwise operations, we need to convert between Coq integers [Z] and their bit-level representations. Bit-level representations are represented as characteristic functions, that is, functions [f] of type [nat -> bool] such that [f i] is the value of the [i]-th bit of the number. For [i] less than 0 or greater or equal to [wordsize], the characteristic function is [false]. *) Fixpoint bits_of_Z (n: nat) (x: Z) {struct n}: Z -> bool := match n with | O => (fun i: Z => false) | S m => let (b, y) := Z_bin_decomp x in let f := bits_of_Z m y in (fun i: Z => if zeq i 0 then b else f (i - 1)) end. Fixpoint Z_of_bits (n: nat) (f: Z -> bool) (i: Z) {struct n}: Z := match n with | O => 0 | S m => Z_bin_comp (f i) (Z_of_bits m f (Zsucc i)) end. (** Bitwise logical "and", "or" and "xor" operations. *) Definition bitwise_binop (f: bool -> bool -> bool) (x y: int) := let fx := bits_of_Z wordsize (unsigned x) in let fy := bits_of_Z wordsize (unsigned y) in repr(Z_of_bits wordsize (fun i => f (fx i) (fy i)) 0). Definition and (x y: int): int := bitwise_binop andb x y. Definition or (x y: int): int := bitwise_binop orb x y. Definition xor (x y: int) : int := bitwise_binop xorb x y. Definition not (x: int) : int := xor x mone. (** Shifts and rotates. *) Definition shl (x y: int): int := let fx := bits_of_Z wordsize (unsigned x) in repr (Z_of_bits wordsize fx (- unsigned y)). Definition shru (x y: int): int := let fx := bits_of_Z wordsize (unsigned x) in repr (Z_of_bits wordsize fx (unsigned y)). Definition shr (x y: int): int := let fx := bits_of_Z wordsize (unsigned x) in let sx := fun i => fx (if zlt i (Z_of_nat wordsize) then i else Z_of_nat wordsize - 1) in repr (Z_of_bits wordsize sx (unsigned y)). Definition rol (x y: int) : int := let fx := bits_of_Z wordsize (unsigned x) in let rx := fun i => fx (Zmod i (Z_of_nat wordsize)) in repr (Z_of_bits wordsize rx (-unsigned y)). Definition ror (x y: int) : int := let fx := bits_of_Z wordsize (unsigned x) in let rx := fun i => fx (Zmod i (Z_of_nat wordsize)) in repr (Z_of_bits wordsize rx (unsigned y)). Definition rolm (x a m: int): int := and (rol x a) m. (** Viewed as signed divisions by powers of two, [shrx] rounds towards zero, while [shr] rounds towards minus infinity. *) Definition shrx (x y: int): int := divs x (shl one y). (** [shr_carry x y] is 1 if [x] is negative and at least one 1 bit is shifted away. *) Definition shr_carry (x y: int) := if lt x zero && negb (eq (and x (sub (shl one y) one)) zero) then one else zero. (** Zero and sign extensions *) Definition zero_ext (n: Z) (x: int) : int := let fx := bits_of_Z wordsize (unsigned x) in repr (Z_of_bits wordsize (fun i => if zlt i n then fx i else false) 0). Definition sign_ext (n: Z) (x: int) : int := let fx := bits_of_Z wordsize (unsigned x) in repr (Z_of_bits wordsize (fun i => if zlt i n then fx i else fx (n - 1)) 0). (** Decomposition of a number as a sum of powers of two. *) Fixpoint Z_one_bits (n: nat) (x: Z) (i: Z) {struct n}: list Z := match n with | O => nil | S m => let (b, y) := Z_bin_decomp x in if b then i :: Z_one_bits m y (i+1) else Z_one_bits m y (i+1) end. Definition one_bits (x: int) : list int := List.map repr (Z_one_bits wordsize (unsigned x) 0). (** Recognition of powers of two. *) Definition is_power2 (x: int) : option int := match Z_one_bits wordsize (unsigned x) 0 with | i :: nil => Some (repr i) | _ => None end. (** Comparisons. *) Definition cmp (c: comparison) (x y: int) : bool := match c with | Ceq => eq x y | Cne => negb (eq x y) | Clt => lt x y | Cle => negb (lt y x) | Cgt => lt y x | Cge => negb (lt x y) end. Definition cmpu (c: comparison) (x y: int) : bool := match c with | Ceq => eq x y | Cne => negb (eq x y) | Clt => ltu x y | Cle => negb (ltu y x) | Cgt => ltu y x | Cge => negb (ltu x y) end. Definition is_false (x: int) : Prop := x = zero. Definition is_true (x: int) : Prop := x <> zero. Definition notbool (x: int) : int := if eq x zero then one else zero. (** * Properties of integers and integer arithmetic *) (** ** Properties of [modulus], [max_unsigned], etc. *) Remark half_modulus_power: half_modulus = two_p (Z_of_nat wordsize - 1). Proof. unfold half_modulus. rewrite modulus_power. set (ws1 := Z_of_nat wordsize - 1). replace (Z_of_nat wordsize) with (Zsucc ws1). rewrite two_p_S. rewrite Zmult_comm. apply Z_div_mult. omega. unfold ws1. generalize wordsize_pos; omega. unfold ws1. omega. Qed. Remark half_modulus_modulus: modulus = 2 * half_modulus. Proof. rewrite half_modulus_power. rewrite modulus_power. rewrite <- two_p_S. decEq. omega. generalize wordsize_pos; omega. Qed. (** Relative positions, from greatest to smallest: << max_unsigned max_signed 2*wordsize-1 wordsize 0 min_signed >> *) Remark half_modulus_pos: half_modulus > 0. Proof. rewrite half_modulus_power. apply two_p_gt_ZERO. generalize wordsize_pos; omega. Qed. Remark min_signed_neg: min_signed < 0. Proof. unfold min_signed. generalize half_modulus_pos. omega. Qed. Remark max_signed_pos: max_signed >= 0. Proof. unfold max_signed. generalize half_modulus_pos. omega. Qed. Remark wordsize_max_unsigned: Z_of_nat wordsize <= max_unsigned. Proof. assert (Z_of_nat wordsize < modulus). rewrite modulus_power. apply two_p_strict. generalize wordsize_pos. omega. unfold max_unsigned. omega. Qed. Remark two_wordsize_max_unsigned: 2 * Z_of_nat wordsize - 1 <= max_unsigned. Proof. assert (2 * Z_of_nat wordsize - 1 < modulus). rewrite modulus_power. apply two_p_strict_2. generalize wordsize_pos; omega. unfold max_unsigned; omega. Qed. Remark max_signed_unsigned: max_signed < max_unsigned. Proof. unfold max_signed, max_unsigned. rewrite half_modulus_modulus. generalize half_modulus_pos. omega. Qed. Lemma unsigned_repr_eq: forall x, unsigned (repr x) = Zmod x modulus. Proof. intros. simpl. apply Z_mod_two_p_eq. Qed. Lemma signed_repr_eq: forall x, signed (repr x) = if zlt (Zmod x modulus) half_modulus then Zmod x modulus else Zmod x modulus - modulus. Proof. intros. unfold signed. rewrite unsigned_repr_eq. auto. Qed. (** ** Modulo arithmetic *) (** We define and state properties of equality and arithmetic modulo a positive integer. *) Section EQ_MODULO. Variable modul: Z. Hypothesis modul_pos: modul > 0. Definition eqmod (x y: Z) : Prop := exists k, x = k * modul + y. Lemma eqmod_refl: forall x, eqmod x x. Proof. intros; red. exists 0. omega. Qed. Lemma eqmod_refl2: forall x y, x = y -> eqmod x y. Proof. intros. subst y. apply eqmod_refl. Qed. Lemma eqmod_sym: forall x y, eqmod x y -> eqmod y x. Proof. intros x y [k EQ]; red. exists (-k). subst x. ring. Qed. Lemma eqmod_trans: forall x y z, eqmod x y -> eqmod y z -> eqmod x z. Proof. intros x y z [k1 EQ1] [k2 EQ2]; red. exists (k1 + k2). subst x; subst y. ring. Qed. Lemma eqmod_small_eq: forall x y, eqmod x y -> 0 <= x < modul -> 0 <= y < modul -> x = y. Proof. intros x y [k EQ] I1 I2. generalize (Zdiv_unique _ _ _ _ EQ I2). intro. rewrite (Zdiv_small x modul I1) in H. subst k. omega. Qed. Lemma eqmod_mod_eq: forall x y, eqmod x y -> x mod modul = y mod modul. Proof. intros x y [k EQ]. subst x. rewrite Zplus_comm. apply Z_mod_plus. auto. Qed. Lemma eqmod_mod: forall x, eqmod x (x mod modul). Proof. intros; red. exists (x / modul). rewrite Zmult_comm. apply Z_div_mod_eq. auto. Qed. Lemma eqmod_add: forall a b c d, eqmod a b -> eqmod c d -> eqmod (a + c) (b + d). Proof. intros a b c d [k1 EQ1] [k2 EQ2]; red. subst a; subst c. exists (k1 + k2). ring. Qed. Lemma eqmod_neg: forall x y, eqmod x y -> eqmod (-x) (-y). Proof. intros x y [k EQ]; red. exists (-k). rewrite EQ. ring. Qed. Lemma eqmod_sub: forall a b c d, eqmod a b -> eqmod c d -> eqmod (a - c) (b - d). Proof. intros a b c d [k1 EQ1] [k2 EQ2]; red. subst a; subst c. exists (k1 - k2). ring. Qed. Lemma eqmod_mult: forall a b c d, eqmod a c -> eqmod b d -> eqmod (a * b) (c * d). Proof. intros a b c d [k1 EQ1] [k2 EQ2]; red. subst a; subst b. exists (k1 * k2 * modul + c * k2 + k1 * d). ring. Qed. End EQ_MODULO. Lemma eqmod_divides: forall n m x y, eqmod n x y -> Zdivide m n -> eqmod m x y. Proof. intros. destruct H as [k1 EQ1]. destruct H0 as [k2 EQ2]. exists (k1*k2). rewrite <- Zmult_assoc. rewrite <- EQ2. auto. Qed. (** We then specialize these definitions to equality modulo $2^{wordsize}$ #2wordsize#. *) Hint Resolve modulus_pos: ints. Definition eqm := eqmod modulus. Lemma eqm_refl: forall x, eqm x x. Proof (eqmod_refl modulus). Hint Resolve eqm_refl: ints. Lemma eqm_refl2: forall x y, x = y -> eqm x y. Proof (eqmod_refl2 modulus). Hint Resolve eqm_refl2: ints. Lemma eqm_sym: forall x y, eqm x y -> eqm y x. Proof (eqmod_sym modulus). Hint Resolve eqm_sym: ints. Lemma eqm_trans: forall x y z, eqm x y -> eqm y z -> eqm x z. Proof (eqmod_trans modulus). Hint Resolve eqm_trans: ints. Lemma eqm_small_eq: forall x y, eqm x y -> 0 <= x < modulus -> 0 <= y < modulus -> x = y. Proof (eqmod_small_eq modulus). Hint Resolve eqm_small_eq: ints. Lemma eqm_add: forall a b c d, eqm a b -> eqm c d -> eqm (a + c) (b + d). Proof (eqmod_add modulus). Hint Resolve eqm_add: ints. Lemma eqm_neg: forall x y, eqm x y -> eqm (-x) (-y). Proof (eqmod_neg modulus). Hint Resolve eqm_neg: ints. Lemma eqm_sub: forall a b c d, eqm a b -> eqm c d -> eqm (a - c) (b - d). Proof (eqmod_sub modulus). Hint Resolve eqm_sub: ints. Lemma eqm_mult: forall a b c d, eqm a c -> eqm b d -> eqm (a * b) (c * d). Proof (eqmod_mult modulus). Hint Resolve eqm_mult: ints. (** ** Properties of the coercions between [Z] and [int] *) Lemma eqm_samerepr: forall x y, eqm x y -> repr x = repr y. Proof. intros. unfold repr. apply mkint_eq. repeat rewrite Z_mod_two_p_eq. apply eqmod_mod_eq. auto with ints. exact H. Qed. Lemma eqm_unsigned_repr: forall z, eqm z (unsigned (repr z)). Proof. unfold eqm; intros. rewrite unsigned_repr_eq. apply eqmod_mod. auto with ints. Qed. Hint Resolve eqm_unsigned_repr: ints. Lemma eqm_unsigned_repr_l: forall a b, eqm a b -> eqm (unsigned (repr a)) b. Proof. intros. apply eqm_trans with a. apply eqm_sym. apply eqm_unsigned_repr. auto. Qed. Hint Resolve eqm_unsigned_repr_l: ints. Lemma eqm_unsigned_repr_r: forall a b, eqm a b -> eqm a (unsigned (repr b)). Proof. intros. apply eqm_trans with b. auto. apply eqm_unsigned_repr. Qed. Hint Resolve eqm_unsigned_repr_r: ints. Lemma eqm_signed_unsigned: forall x, eqm (signed x) (unsigned x). Proof. intros; red. unfold signed. set (y := unsigned x). case (zlt y half_modulus); intro. apply eqmod_refl. red; exists (-1); ring. Qed. Theorem unsigned_range: forall i, 0 <= unsigned i < modulus. Proof. destruct i; auto. Qed. Hint Resolve unsigned_range: ints. Theorem unsigned_range_2: forall i, 0 <= unsigned i <= max_unsigned. Proof. intro; unfold max_unsigned. generalize (unsigned_range i). omega. Qed. Hint Resolve unsigned_range_2: ints. Theorem signed_range: forall i, min_signed <= signed i <= max_signed. Proof. intros. unfold signed. generalize (unsigned_range i). set (n := unsigned i). intros. case (zlt n half_modulus); intro. unfold max_signed. generalize min_signed_neg. omega. unfold min_signed, max_signed. rewrite half_modulus_modulus in *. omega. Qed. Theorem repr_unsigned: forall i, repr (unsigned i) = i. Proof. destruct i; simpl. unfold repr. apply mkint_eq. rewrite Z_mod_two_p_eq. apply Zmod_small; auto. Qed. Hint Resolve repr_unsigned: ints. Lemma repr_signed: forall i, repr (signed i) = i. Proof. intros. transitivity (repr (unsigned i)). apply eqm_samerepr. apply eqm_signed_unsigned. auto with ints. Qed. Hint Resolve repr_signed: ints. Opaque repr. Lemma eqm_repr_eq: forall x y, eqm x (unsigned y) -> repr x = y. Proof. intros. rewrite <- (repr_unsigned y). apply eqm_samerepr; auto. Qed. Theorem unsigned_repr: forall z, 0 <= z <= max_unsigned -> unsigned (repr z) = z. Proof. intros. rewrite unsigned_repr_eq. apply Zmod_small. unfold max_unsigned in H. omega. Qed. Hint Resolve unsigned_repr: ints. Theorem signed_repr: forall z, min_signed <= z <= max_signed -> signed (repr z) = z. Proof. intros. unfold signed. destruct (zle 0 z). replace (unsigned (repr z)) with z. rewrite zlt_true. auto. unfold max_signed in H. omega. symmetry. apply unsigned_repr. generalize max_signed_unsigned. omega. pose (z' := z + modulus). replace (repr z) with (repr z'). replace (unsigned (repr z')) with z'. rewrite zlt_false. unfold z'. omega. unfold z'. unfold min_signed in H. rewrite half_modulus_modulus. omega. symmetry. apply unsigned_repr. unfold z', max_unsigned. unfold min_signed, max_signed in H. rewrite half_modulus_modulus. omega. apply eqm_samerepr. unfold z'; red. exists 1. omega. Qed. Theorem signed_eq_unsigned: forall x, unsigned x <= max_signed -> signed x = unsigned x. Proof. intros. unfold signed. destruct (zlt (unsigned x) half_modulus). auto. unfold max_signed in H. omegaContradiction. Qed. Theorem signed_positive: forall x, signed x >= 0 <-> unsigned x <= max_signed. Proof. intros. unfold signed, max_signed. generalize (unsigned_range x) half_modulus_modulus half_modulus_pos; intros. destruct (zlt (unsigned x) half_modulus); omega. Qed. (** ** Properties of zero, one, minus one *) Theorem unsigned_zero: unsigned zero = 0. Proof. unfold zero; rewrite unsigned_repr_eq. apply Zmod_0_l. Qed. Theorem unsigned_one: unsigned one = 1. Proof. unfold one; rewrite unsigned_repr_eq. apply Zmod_small. split. omega. unfold modulus. replace wordsize with (S(pred wordsize)). rewrite two_power_nat_S. generalize (two_power_nat_pos (pred wordsize)). omega. generalize wordsize_pos. omega. Qed. Theorem unsigned_mone: unsigned mone = modulus - 1. Proof. unfold mone; rewrite unsigned_repr_eq. replace (-1) with ((modulus - 1) + (-1) * modulus). rewrite Z_mod_plus_full. apply Zmod_small. generalize modulus_pos. omega. omega. Qed. Theorem signed_zero: signed zero = 0. Proof. unfold signed. rewrite unsigned_zero. apply zlt_true. generalize half_modulus_pos; omega. Qed. Theorem signed_mone: signed mone = -1. Proof. unfold signed. rewrite unsigned_mone. rewrite zlt_false. omega. rewrite half_modulus_modulus. generalize half_modulus_pos. omega. Qed. Theorem one_not_zero: one <> zero. Proof. assert (unsigned one <> unsigned zero). rewrite unsigned_one; rewrite unsigned_zero; congruence. congruence. Qed. Theorem unsigned_repr_wordsize: unsigned iwordsize = Z_of_nat wordsize. Proof. unfold iwordsize; rewrite unsigned_repr_eq. apply Zmod_small. generalize wordsize_pos wordsize_max_unsigned; unfold max_unsigned; omega. Qed. (** ** Properties of equality *) Theorem eq_sym: forall x y, eq x y = eq y x. Proof. intros; unfold eq. case (zeq (unsigned x) (unsigned y)); intro. rewrite e. rewrite zeq_true. auto. rewrite zeq_false. auto. auto. Qed. Theorem eq_spec: forall (x y: int), if eq x y then x = y else x <> y. Proof. intros; unfold eq. case (eq_dec x y); intro. subst y. rewrite zeq_true. auto. rewrite zeq_false. auto. destruct x; destruct y. simpl. red; intro. elim n. apply mkint_eq. auto. Qed. Theorem eq_true: forall x, eq x x = true. Proof. intros. generalize (eq_spec x x); case (eq x x); intros; congruence. Qed. Theorem eq_false: forall x y, x <> y -> eq x y = false. Proof. intros. generalize (eq_spec x y); case (eq x y); intros; congruence. Qed. (** ** Properties of addition *) Theorem add_unsigned: forall x y, add x y = repr (unsigned x + unsigned y). Proof. intros; reflexivity. Qed. Theorem add_signed: forall x y, add x y = repr (signed x + signed y). Proof. intros. rewrite add_unsigned. apply eqm_samerepr. apply eqm_add; apply eqm_sym; apply eqm_signed_unsigned. Qed. Theorem add_commut: forall x y, add x y = add y x. Proof. intros; unfold add. decEq. omega. Qed. Theorem add_zero: forall x, add x zero = x. Proof. intros. unfold add. rewrite unsigned_zero. rewrite Zplus_0_r. apply repr_unsigned. Qed. Theorem add_zero_l: forall x, add zero x = x. Proof. intros. rewrite add_commut. apply add_zero. Qed. Theorem add_assoc: forall x y z, add (add x y) z = add x (add y z). Proof. intros; unfold add. set (x' := unsigned x). set (y' := unsigned y). set (z' := unsigned z). apply eqm_samerepr. apply eqm_trans with ((x' + y') + z'). auto with ints. rewrite <- Zplus_assoc. auto with ints. Qed. Theorem add_permut: forall x y z, add x (add y z) = add y (add x z). Proof. intros. rewrite (add_commut y z). rewrite <- add_assoc. apply add_commut. Qed. Theorem add_neg_zero: forall x, add x (neg x) = zero. Proof. intros; unfold add, neg, zero. apply eqm_samerepr. replace 0 with (unsigned x + (- (unsigned x))). auto with ints. omega. Qed. Theorem unsigned_add_carry: forall x y, unsigned (add x y) = unsigned x + unsigned y - unsigned (add_carry x y zero) * modulus. Proof. intros. unfold add, add_carry. rewrite unsigned_zero. rewrite Zplus_0_r. rewrite unsigned_repr_eq. generalize (unsigned_range x) (unsigned_range y). intros. destruct (zlt (unsigned x + unsigned y) modulus). rewrite unsigned_zero. apply Zmod_unique with 0. omega. omega. rewrite unsigned_one. apply Zmod_unique with 1. omega. omega. Qed. Corollary unsigned_add_either: forall x y, unsigned (add x y) = unsigned x + unsigned y \/ unsigned (add x y) = unsigned x + unsigned y - modulus. Proof. intros. rewrite unsigned_add_carry. unfold add_carry. rewrite unsigned_zero. rewrite Zplus_0_r. destruct (zlt (unsigned x + unsigned y) modulus). rewrite unsigned_zero. left; omega. rewrite unsigned_one. right; omega. Qed. (** ** Properties of negation *) Theorem neg_repr: forall z, neg (repr z) = repr (-z). Proof. intros; unfold neg. apply eqm_samerepr. auto with ints. Qed. Theorem neg_zero: neg zero = zero. Proof. unfold neg. rewrite unsigned_zero. auto. Qed. Theorem neg_involutive: forall x, neg (neg x) = x. Proof. intros; unfold neg. apply eqm_repr_eq. eapply eqm_trans. apply eqm_neg. apply eqm_unsigned_repr_l. apply eqm_refl. apply eqm_refl2. omega. Qed. Theorem neg_add_distr: forall x y, neg(add x y) = add (neg x) (neg y). Proof. intros; unfold neg, add. apply eqm_samerepr. apply eqm_trans with (- (unsigned x + unsigned y)). auto with ints. replace (- (unsigned x + unsigned y)) with ((- unsigned x) + (- unsigned y)). auto with ints. omega. Qed. (** ** Properties of subtraction *) Theorem sub_zero_l: forall x, sub x zero = x. Proof. intros; unfold sub. rewrite unsigned_zero. replace (unsigned x - 0) with (unsigned x) by omega. apply repr_unsigned. Qed. Theorem sub_zero_r: forall x, sub zero x = neg x. Proof. intros; unfold sub, neg. rewrite unsigned_zero. auto. Qed. Theorem sub_add_opp: forall x y, sub x y = add x (neg y). Proof. intros; unfold sub, add, neg. apply eqm_samerepr. apply eqm_add; auto with ints. Qed. Theorem sub_idem: forall x, sub x x = zero. Proof. intros; unfold sub. unfold zero. decEq. omega. Qed. Theorem sub_add_l: forall x y z, sub (add x y) z = add (sub x z) y. Proof. intros. repeat rewrite sub_add_opp. repeat rewrite add_assoc. decEq. apply add_commut. Qed. Theorem sub_add_r: forall x y z, sub x (add y z) = add (sub x z) (neg y). Proof. intros. repeat rewrite sub_add_opp. rewrite neg_add_distr. rewrite add_permut. apply add_commut. Qed. Theorem sub_shifted: forall x y z, sub (add x z) (add y z) = sub x y. Proof. intros. rewrite sub_add_opp. rewrite neg_add_distr. rewrite add_assoc. rewrite (add_commut (neg y) (neg z)). rewrite <- (add_assoc z). rewrite add_neg_zero. rewrite (add_commut zero). rewrite add_zero. symmetry. apply sub_add_opp. Qed. Theorem sub_signed: forall x y, sub x y = repr (signed x - signed y). Proof. intros. unfold sub. apply eqm_samerepr. apply eqm_sub; apply eqm_sym; apply eqm_signed_unsigned. Qed. (** ** Properties of multiplication *) Theorem mul_commut: forall x y, mul x y = mul y x. Proof. intros; unfold mul. decEq. ring. Qed. Theorem mul_zero: forall x, mul x zero = zero. Proof. intros; unfold mul. rewrite unsigned_zero. unfold zero. decEq. ring. Qed. Theorem mul_one: forall x, mul x one = x. Proof. intros; unfold mul. rewrite unsigned_one. transitivity (repr (unsigned x)). decEq. ring. apply repr_unsigned. Qed. Theorem mul_mone: forall x, mul x mone = neg x. Proof. intros; unfold mul, neg. rewrite unsigned_mone. apply eqm_samerepr. replace (-unsigned x) with (0 - unsigned x) by omega. replace (unsigned x * (modulus - 1)) with (unsigned x * modulus - unsigned x) by ring. apply eqm_sub. exists (unsigned x). omega. apply eqm_refl. Qed. Theorem mul_assoc: forall x y z, mul (mul x y) z = mul x (mul y z). Proof. intros; unfold mul. set (x' := unsigned x). set (y' := unsigned y). set (z' := unsigned z). apply eqm_samerepr. apply eqm_trans with ((x' * y') * z'). auto with ints. rewrite <- Zmult_assoc. auto with ints. Qed. Theorem mul_add_distr_l: forall x y z, mul (add x y) z = add (mul x z) (mul y z). Proof. intros; unfold mul, add. apply eqm_samerepr. set (x' := unsigned x). set (y' := unsigned y). set (z' := unsigned z). apply eqm_trans with ((x' + y') * z'). auto with ints. replace ((x' + y') * z') with (x' * z' + y' * z'). auto with ints. ring. Qed. Theorem mul_add_distr_r: forall x y z, mul x (add y z) = add (mul x y) (mul x z). Proof. intros. rewrite mul_commut. rewrite mul_add_distr_l. decEq; apply mul_commut. Qed. Theorem neg_mul_distr_l: forall x y, neg(mul x y) = mul (neg x) y. Proof. intros. unfold mul, neg. set (x' := unsigned x). set (y' := unsigned y). apply eqm_samerepr. apply eqm_trans with (- (x' * y')). auto with ints. replace (- (x' * y')) with ((-x') * y') by ring. auto with ints. Qed. Theorem neg_mul_distr_r: forall x y, neg(mul x y) = mul x (neg y). Proof. intros. rewrite (mul_commut x y). rewrite (mul_commut x (neg y)). apply neg_mul_distr_l. Qed. Theorem mul_signed: forall x y, mul x y = repr (signed x * signed y). Proof. intros; unfold mul. apply eqm_samerepr. apply eqm_mult; apply eqm_sym; apply eqm_signed_unsigned. Qed. (** ** Properties of division and modulus *) Lemma modu_divu_Euclid: forall x y, y <> zero -> x = add (mul (divu x y) y) (modu x y). Proof. intros. unfold add, mul, divu, modu. transitivity (repr (unsigned x)). auto with ints. apply eqm_samerepr. set (x' := unsigned x). set (y' := unsigned y). apply eqm_trans with ((x' / y') * y' + x' mod y'). apply eqm_refl2. rewrite Zmult_comm. apply Z_div_mod_eq. generalize (unsigned_range y); intro. assert (unsigned y <> 0). red; intro. elim H. rewrite <- (repr_unsigned y). unfold zero. congruence. unfold y'. omega. auto with ints. Qed. Theorem modu_divu: forall x y, y <> zero -> modu x y = sub x (mul (divu x y) y). Proof. intros. assert (forall a b c, a = add b c -> c = sub a b). intros. subst a. rewrite sub_add_l. rewrite sub_idem. rewrite add_commut. rewrite add_zero. auto. apply H0. apply modu_divu_Euclid. auto. Qed. Theorem mods_divs: forall x y, mods x y = sub x (mul (divs x y) y). Proof. intros; unfold mods, sub, mul, divs. apply eqm_samerepr. unfold Zmod_round. apply eqm_sub. apply eqm_signed_unsigned. apply eqm_unsigned_repr_r. apply eqm_mult. auto with ints. apply eqm_signed_unsigned. Qed. Theorem divu_one: forall x, divu x one = x. Proof. unfold divu; intros. rewrite unsigned_one. rewrite Zdiv_1_r. apply repr_unsigned. Qed. Theorem modu_one: forall x, modu x one = zero. Proof. intros. rewrite modu_divu. rewrite divu_one. rewrite mul_one. apply sub_idem. apply one_not_zero. Qed. Theorem divs_mone: forall x, divs x mone = neg x. Proof. unfold divs, neg; intros. rewrite signed_mone. replace (Zdiv_round (signed x) (-1)) with (- (signed x)). apply eqm_samerepr. apply eqm_neg. apply eqm_signed_unsigned. unfold Zdiv_round. destruct (zlt (signed x) 0). simpl. rewrite Zdiv_1_r. auto. simpl. rewrite Zdiv_1_r. auto. Qed. Theorem mods_mone: forall x, mods x mone = zero. Proof. intros. rewrite mods_divs. rewrite divs_mone. rewrite <- neg_mul_distr_l. rewrite mul_mone. rewrite neg_involutive. apply sub_idem. Qed. (** ** Properties of binary decompositions *) Lemma Z_of_bits_exten: forall f1 f2 n i1 i2, (forall i, 0 <= i < Z_of_nat n -> f1 (i + i1) = f2 (i + i2)) -> Z_of_bits n f1 i1 = Z_of_bits n f2 i2. Proof. induction n; intros; simpl. auto. rewrite inj_S in H. decEq. apply (H 0). omega. apply IHn. intros. replace (i + Zsucc i1) with (Zsucc i + i1) by omega. replace (i + Zsucc i2) with (Zsucc i + i2) by omega. apply H. omega. Qed. Lemma Z_of_bits_of_Z: forall x, eqm (Z_of_bits wordsize (bits_of_Z wordsize x) 0) x. Proof. assert (forall n x, exists k, Z_of_bits n (bits_of_Z n x) 0 = k * two_power_nat n + x). induction n; intros; simpl. rewrite two_power_nat_O. exists (-x). omega. rewrite two_power_nat_S. destruct (Z_bin_decomp x) as [b y] eqn:?. rewrite zeq_true. destruct (IHn y) as [k EQ]. replace (Z_of_bits n (fun i => if zeq i 0 then b else bits_of_Z n y (i - 1)) 1) with (Z_of_bits n (bits_of_Z n y) 0). rewrite EQ. exists k. rewrite (Z_bin_comp_decomp2 _ _ _ Heqp). repeat rewrite Z_bin_comp_eq. ring. apply Z_of_bits_exten. intros. rewrite zeq_false. decEq. omega. omega. intro. exact (H wordsize x). Qed. Lemma bits_of_Z_zero: forall n x, bits_of_Z n 0 x = false. Proof. induction n; simpl; intros. auto. destruct (zeq x 0); auto. Qed. Remark Z_bin_decomp_2xm1: forall x, Z_bin_decomp (2 * x - 1) = (true, x - 1). Proof. intros. caseEq (Z_bin_decomp (2 * x - 1)). intros b y EQ. apply Z_bin_comp_inj. rewrite <- (Z_bin_comp_decomp2 _ _ _ EQ). rewrite Z_bin_comp_eq. omega. Qed. Lemma bits_of_Z_two_p: forall n x i, x >= 0 -> 0 <= i < Z_of_nat n -> bits_of_Z n (two_p x - 1) i = zlt i x. Proof. induction n; intros. simpl in H0. omegaContradiction. destruct (zeq x 0). subst x. change (two_p 0 - 1) with 0. rewrite bits_of_Z_zero. unfold proj_sumbool; rewrite zlt_false. auto. omega. simpl. replace (two_p x) with (2 * two_p (x - 1)). rewrite Z_bin_decomp_2xm1. destruct (zeq i 0). subst. unfold proj_sumbool. rewrite zlt_true. auto. omega. rewrite inj_S in H0. rewrite IHn. unfold proj_sumbool. destruct (zlt i x). apply zlt_true. omega. apply zlt_false. omega. omega. omega. rewrite <- two_p_S. decEq. omega. omega. Qed. Lemma bits_of_Z_mone: forall x, 0 <= x < Z_of_nat wordsize -> bits_of_Z wordsize (modulus - 1) x = true. Proof. intros. unfold modulus. rewrite two_power_nat_two_p. rewrite bits_of_Z_two_p. unfold proj_sumbool. apply zlt_true; omega. omega. omega. Qed. Lemma Z_of_bits_range: forall f n i, 0 <= Z_of_bits n f i < two_power_nat n. Proof. induction n; simpl; intros. rewrite two_power_nat_O. omega. rewrite two_power_nat_S. generalize (IHn (Zsucc i)). intro. rewrite Z_bin_comp_eq. destruct (f i); omega. Qed. Lemma Z_of_bits_range_1: forall f i, 0 <= Z_of_bits wordsize f i < modulus. Proof. intros. apply Z_of_bits_range. Qed. Hint Resolve Z_of_bits_range_1: ints. Lemma Z_of_bits_range_2: forall f i, 0 <= Z_of_bits wordsize f i <= max_unsigned. Proof. intros. unfold max_unsigned. generalize (Z_of_bits_range_1 f i). omega. Qed. Hint Resolve Z_of_bits_range_2: ints. Lemma bits_of_Z_of_bits_gen: forall n f i j, 0 <= i < Z_of_nat n -> bits_of_Z n (Z_of_bits n f j) i = f (i + j). Proof. induction n; intros; simpl. simpl in H. omegaContradiction. rewrite Z_bin_decomp_comp. destruct (zeq i 0). f_equal. omega. rewrite IHn. f_equal. omega. rewrite inj_S in H. omega. Qed. Lemma bits_of_Z_of_bits: forall n f i, 0 <= i < Z_of_nat n -> bits_of_Z n (Z_of_bits n f 0) i = f i. Proof. intros. rewrite bits_of_Z_of_bits_gen; auto. decEq; omega. Qed. Lemma bits_of_Z_below: forall n x i, i < 0 -> bits_of_Z n x i = false. Proof. induction n; intros; simpl. auto. destruct (Z_bin_decomp x). rewrite zeq_false. apply IHn. omega. omega. Qed. Lemma bits_of_Z_above: forall n x i, i >= Z_of_nat n -> bits_of_Z n x i = false. Proof. induction n; intros; simpl. auto. caseEq (Z_bin_decomp x); intros b x1 EQ. rewrite zeq_false. rewrite IHn. destruct x; simpl in EQ. inv EQ. auto. destruct p; inv EQ; auto. destruct p; inv EQ; auto. rewrite inj_S in H. omega. rewrite inj_S in H. omega. Qed. Lemma bits_of_Z_greater: forall n x i, 0 <= x < two_p i -> bits_of_Z n x i = false. Proof. induction n; intros. auto. destruct (zlt i 0). apply bits_of_Z_below. auto. simpl. destruct (Z_bin_decomp x) as [b x1] eqn:?. destruct (zeq i 0). subst i. simpl in H. assert (x = 0) by omega. subst x. simpl in Heqp. congruence. apply IHn. rewrite (Z_bin_comp_decomp2 _ _ _ Heqp) in H. replace i with (Zsucc (i-1)) in H by omega. rewrite two_p_S in H. rewrite Z_bin_comp_eq in H. destruct b; omega. omega. Qed. Lemma bits_of_Z_of_bits_gen': forall n f i j, bits_of_Z n (Z_of_bits n f j) i = if zlt i 0 then false else if zle (Z_of_nat n) i then false else f (i + j). Proof. intros. destruct (zlt i 0). apply bits_of_Z_below; auto. destruct (zle (Z_of_nat n) i). apply bits_of_Z_above. omega. apply bits_of_Z_of_bits_gen. omega. Qed. Lemma Z_of_bits_excl: forall n f g h j, (forall i, j <= i < j + Z_of_nat n -> f i && g i = false) -> (forall i, j <= i < j + Z_of_nat n -> f i || g i = h i) -> Z_of_bits n f j + Z_of_bits n g j = Z_of_bits n h j. Proof. induction n. intros; reflexivity. intros. simpl. rewrite inj_S in H. rewrite inj_S in H0. rewrite <- (IHn f g h (Zsucc j)). assert (j <= j < j + Zsucc(Z_of_nat n)). omega. repeat rewrite Z_bin_comp_eq. rewrite <- H0; auto. caseEq (f j); intros; caseEq (g j); intros; simpl orb. generalize (H j H1). rewrite H2; rewrite H3. simpl andb; congruence. omega. omega. omega. intros; apply H. omega. intros; apply H0. omega. Qed. Lemma Z_of_bits_compose: forall f m n i, Z_of_bits (m + n) f i = Z_of_bits n f (i + Z_of_nat m) * two_power_nat m + Z_of_bits m f i. Proof. induction m; intros. simpl. repeat rewrite Zplus_0_r. rewrite two_power_nat_O. omega. rewrite inj_S. rewrite two_power_nat_S. simpl Z_of_bits. rewrite IHm. replace (i + Zsucc (Z_of_nat m)) with (Zsucc i + Z_of_nat m) by omega. repeat rewrite Z_bin_comp_eq. ring. Qed. Lemma Z_of_bits_truncate: forall f n i, eqm (Z_of_bits (wordsize + n) f i) (Z_of_bits wordsize f i). Proof. intros. exists (Z_of_bits n f (i + Z_of_nat wordsize)). rewrite Z_of_bits_compose. fold modulus. auto. Qed. Lemma Z_of_bits_false: forall f n i, (forall j, i <= j < i + Z_of_nat n -> f j = false) -> Z_of_bits n f i = 0. Proof. induction n; intros; simpl. auto. rewrite inj_S in H. rewrite H. rewrite IHn. auto. intros; apply H; omega. omega. Qed. Lemma Z_of_bits_complement: forall f n i, Z_of_bits n (fun j => negb (f j)) i = two_power_nat n - 1 - Z_of_bits n f i. Proof. induction n; intros; simpl Z_of_bits. auto. rewrite two_power_nat_S. rewrite IHn. repeat rewrite Z_bin_comp_eq. destruct (f i); simpl negb; ring. Qed. Lemma Z_of_bits_true: forall f n i, (forall j, i <= j < i + Z_of_nat n -> f j = true) -> Z_of_bits n f i = two_power_nat n - 1. Proof. intros. set (z := fun (i: Z) => false). transitivity (Z_of_bits n (fun j => negb (z j)) i). apply Z_of_bits_exten; intros. unfold z. rewrite H. auto. omega. rewrite Z_of_bits_complement. rewrite Z_of_bits_false. omega. unfold z; auto. Qed. (** ** Properties of bitwise and, or, xor *) Lemma bitwise_binop_commut: forall f, (forall a b, f a b = f b a) -> forall x y, bitwise_binop f x y = bitwise_binop f y x. Proof. unfold bitwise_binop; intros. decEq; apply Z_of_bits_exten; intros. auto. Qed. Lemma bitwise_binop_assoc: forall f, (forall a b c, f a (f b c) = f (f a b) c) -> forall x y z, bitwise_binop f (bitwise_binop f x y) z = bitwise_binop f x (bitwise_binop f y z). Proof. unfold bitwise_binop; intros. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. repeat rewrite Zplus_0_r. repeat rewrite bits_of_Z_of_bits; auto. Qed. Lemma bitwise_binop_idem: forall f, (forall a, f a a = a) -> forall x, bitwise_binop f x x = x. Proof. unfold bitwise_binop; intros. apply eqm_repr_eq. eapply eqm_trans. 2: apply Z_of_bits_of_Z. apply eqm_refl2. apply Z_of_bits_exten. auto. Qed. Theorem and_commut: forall x y, and x y = and y x. Proof (bitwise_binop_commut andb andb_comm). Theorem and_assoc: forall x y z, and (and x y) z = and x (and y z). Proof (bitwise_binop_assoc andb andb_assoc). Theorem and_zero: forall x, and x zero = zero. Proof. intros. unfold and, bitwise_binop. apply eqm_samerepr. eapply eqm_trans. 2: apply Z_of_bits_of_Z. apply eqm_refl2. apply Z_of_bits_exten. intros. rewrite unsigned_zero. rewrite bits_of_Z_zero. apply andb_b_false. Qed. Theorem and_mone: forall x, and x mone = x. Proof. intros. unfold and, bitwise_binop. apply eqm_repr_eq. eapply eqm_trans. 2: apply Z_of_bits_of_Z. apply eqm_refl2. apply Z_of_bits_exten; intros. rewrite unsigned_mone. rewrite bits_of_Z_mone. apply andb_b_true. omega. Qed. Theorem and_idem: forall x, and x x = x. Proof. intros. apply (bitwise_binop_idem andb). destruct a; auto. Qed. Theorem or_commut: forall x y, or x y = or y x. Proof (bitwise_binop_commut orb orb_comm). Theorem or_assoc: forall x y z, or (or x y) z = or x (or y z). Proof (bitwise_binop_assoc orb orb_assoc). Theorem or_zero: forall x, or x zero = x. Proof. intros. unfold or, bitwise_binop. apply eqm_repr_eq. eapply eqm_trans. 2: apply Z_of_bits_of_Z. apply eqm_refl2. apply Z_of_bits_exten. intros. rewrite unsigned_zero. rewrite bits_of_Z_zero. apply orb_b_false. Qed. Theorem or_mone: forall x, or x mone = mone. Proof. intros. unfold or, bitwise_binop. apply eqm_repr_eq. eapply eqm_trans. 2: apply Z_of_bits_of_Z. apply eqm_refl2. apply Z_of_bits_exten. intros. rewrite unsigned_mone. rewrite bits_of_Z_mone. apply orb_b_true. omega. Qed. Theorem or_idem: forall x, or x x = x. Proof. intros. apply (bitwise_binop_idem orb). destruct a; auto. Qed. Theorem and_or_distrib: forall x y z, and x (or y z) = or (and x y) (and x z). Proof. intros; unfold and, or, bitwise_binop. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. repeat rewrite bits_of_Z_of_bits; repeat rewrite Zplus_0_r; auto. apply demorgan1. Qed. Theorem xor_commut: forall x y, xor x y = xor y x. Proof (bitwise_binop_commut xorb xorb_comm). Theorem xor_assoc: forall x y z, xor (xor x y) z = xor x (xor y z). Proof. intros. apply (bitwise_binop_assoc xorb). intros. symmetry. apply xorb_assoc. Qed. Theorem xor_zero: forall x, xor x zero = x. Proof. intros. unfold xor, bitwise_binop. apply eqm_repr_eq. eapply eqm_trans. 2: apply Z_of_bits_of_Z. apply eqm_refl2. apply Z_of_bits_exten. intros. rewrite unsigned_zero. rewrite bits_of_Z_zero. apply xorb_false. Qed. Theorem xor_idem: forall x, xor x x = zero. Proof. intros. unfold xor, bitwise_binop. apply eqm_repr_eq. eapply eqm_trans. 2: apply Z_of_bits_of_Z. apply eqm_refl2. apply Z_of_bits_exten. intros. rewrite unsigned_zero. rewrite bits_of_Z_zero. apply xorb_nilpotent. Qed. Theorem xor_zero_one: xor zero one = one. Proof. rewrite xor_commut. apply xor_zero. Qed. Theorem xor_one_one: xor one one = zero. Proof. apply xor_idem. Qed. Theorem and_xor_distrib: forall x y z, and x (xor y z) = xor (and x y) (and x z). Proof. intros; unfold and, xor, bitwise_binop. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. repeat rewrite bits_of_Z_of_bits; repeat rewrite Zplus_0_r; auto. assert (forall a b c, a && (xorb b c) = xorb (a && b) (a && c)). destruct a; destruct b; destruct c; reflexivity. auto. Qed. (** Properties of bitwise complement.*) Theorem not_involutive: forall (x: int), not (not x) = x. Proof. intros. unfold not. rewrite xor_assoc. rewrite xor_idem. apply xor_zero. Qed. Theorem not_zero: not zero = mone. Proof. unfold not. rewrite xor_commut. apply xor_zero. Qed. Theorem not_mone: not mone = zero. Proof. rewrite <- (not_involutive zero). symmetry. decEq. apply not_zero. Qed. Theorem not_or_and_not: forall x y, not (or x y) = and (not x) (not y). Proof. intros; unfold not, xor, and, or, bitwise_binop. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. repeat rewrite bits_of_Z_of_bits; repeat rewrite Zplus_0_r; auto. rewrite unsigned_mone. rewrite bits_of_Z_mone; auto. assert (forall a b, xorb (a || b) true = xorb a true && xorb b true). destruct a; destruct b; reflexivity. auto. Qed. Theorem not_and_or_not: forall x y, not (and x y) = or (not x) (not y). Proof. intros. rewrite <- (not_involutive x) at 1. rewrite <- (not_involutive y) at 1. rewrite <- not_or_and_not. apply not_involutive. Qed. Theorem and_not_self: forall x, and x (not x) = zero. Proof. intros. unfold not. rewrite and_xor_distrib. rewrite and_idem. rewrite and_mone. apply xor_idem. Qed. Theorem or_not_self: forall x, or x (not x) = mone. Proof. intros. rewrite <- (not_involutive x) at 1. rewrite or_commut. rewrite <- not_and_or_not. rewrite and_not_self. apply not_zero. Qed. Theorem xor_not_self: forall x, xor x (not x) = mone. Proof. intros. unfold not. rewrite <- xor_assoc. rewrite xor_idem. apply not_zero. Qed. Theorem not_neg: forall x, not x = add (neg x) mone. Proof. intros. unfold not, xor, bitwise_binop. rewrite unsigned_mone. set (ux := unsigned x). set (bx := bits_of_Z wordsize ux). transitivity (repr (Z_of_bits wordsize (fun i => negb (bx i)) 0)). decEq. apply Z_of_bits_exten. intros. rewrite bits_of_Z_mone; auto. omega. rewrite Z_of_bits_complement. apply eqm_samerepr. rewrite unsigned_mone. fold modulus. replace (modulus - 1 - Z_of_bits wordsize bx 0) with ((- Z_of_bits wordsize bx 0) + (modulus - 1)) by omega. apply eqm_add. unfold neg. apply eqm_unsigned_repr_r. apply eqm_neg. apply Z_of_bits_of_Z. apply eqm_refl. Qed. Theorem neg_not: forall x, neg x = add (not x) one. Proof. intros. rewrite not_neg. rewrite add_assoc. replace (add mone one) with zero. rewrite add_zero. auto. apply eqm_samerepr. rewrite unsigned_mone. rewrite unsigned_one. exists (-1). ring. Qed. (** Connections between [add] and bitwise logical operations. *) Theorem add_is_or: forall x y, and x y = zero -> add x y = or x y. Proof. intros. unfold add, or, bitwise_binop. apply eqm_samerepr. eapply eqm_trans. apply eqm_add. apply eqm_sym. apply Z_of_bits_of_Z. apply eqm_sym. apply Z_of_bits_of_Z. apply eqm_refl2. apply Z_of_bits_excl. intros. replace (bits_of_Z wordsize (unsigned x) i && bits_of_Z wordsize (unsigned y) i) with (bits_of_Z wordsize (unsigned (and x y)) i). rewrite H. rewrite unsigned_zero. rewrite bits_of_Z_zero. auto. unfold and, bitwise_binop. rewrite unsigned_repr; auto with ints. rewrite bits_of_Z_of_bits. reflexivity. auto. auto. Qed. Theorem xor_is_or: forall x y, and x y = zero -> xor x y = or x y. Proof. intros. unfold xor, or, bitwise_binop. decEq. apply Z_of_bits_exten; intros. set (bitx := bits_of_Z wordsize (unsigned x) (i + 0)). set (bity := bits_of_Z wordsize (unsigned y) (i + 0)). assert (bitx && bity = false). replace (bitx && bity) with (bits_of_Z wordsize (unsigned (and x y)) (i + 0)). rewrite H. rewrite unsigned_zero. apply bits_of_Z_zero. unfold and, bitwise_binop. rewrite unsigned_repr; auto with ints. unfold bitx, bity. rewrite bits_of_Z_of_bits. reflexivity. omega. destruct bitx; destruct bity; auto; simpl in H1; congruence. Qed. Theorem add_is_xor: forall x y, and x y = zero -> add x y = xor x y. Proof. intros. rewrite xor_is_or; auto. apply add_is_or; auto. Qed. Theorem add_and: forall x y z, and y z = zero -> add (and x y) (and x z) = and x (or y z). Proof. intros. rewrite add_is_or. rewrite and_or_distrib; auto. rewrite (and_commut x y). rewrite and_assoc. repeat rewrite <- (and_assoc x). rewrite (and_commut (and x x)). rewrite <- and_assoc. rewrite H. rewrite and_commut. apply and_zero. Qed. (** ** Properties of shifts *) Theorem shl_zero: forall x, shl x zero = x. Proof. intros. unfold shl. rewrite unsigned_zero. simpl (-0). transitivity (repr (unsigned x)). apply eqm_samerepr. apply Z_of_bits_of_Z. auto with ints. Qed. Lemma bitwise_binop_shl: forall f x y n, f false false = false -> bitwise_binop f (shl x n) (shl y n) = shl (bitwise_binop f x y) n. Proof. intros. unfold bitwise_binop, shl. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. repeat rewrite Zplus_0_r. destruct (zlt (i + -unsigned n) 0). rewrite bits_of_Z_of_bits_gen; auto. rewrite bits_of_Z_of_bits_gen; auto. repeat rewrite bits_of_Z_below; auto. repeat rewrite bits_of_Z_of_bits_gen; auto. repeat rewrite Zplus_0_r. auto. generalize (unsigned_range n). omega. Qed. Theorem and_shl: forall x y n, and (shl x n) (shl y n) = shl (and x y) n. Proof. unfold and; intros. apply bitwise_binop_shl. reflexivity. Qed. Theorem or_shl: forall x y n, or (shl x n) (shl y n) = shl (or x y) n. Proof. unfold or; intros. apply bitwise_binop_shl. reflexivity. Qed. Theorem xor_shl: forall x y n, xor (shl x n) (shl y n) = shl (xor x y) n. Proof. unfold xor; intros. apply bitwise_binop_shl. reflexivity. Qed. Lemma ltu_inv: forall x y, ltu x y = true -> 0 <= unsigned x < unsigned y. Proof. unfold ltu; intros. destruct (zlt (unsigned x) (unsigned y)). split; auto. generalize (unsigned_range x); omega. discriminate. Qed. Theorem shl_shl: forall x y z, ltu y iwordsize = true -> ltu z iwordsize = true -> ltu (add y z) iwordsize = true -> shl (shl x y) z = shl x (add y z). Proof. intros. unfold shl, add. generalize (ltu_inv _ _ H). generalize (ltu_inv _ _ H0). rewrite unsigned_repr_wordsize. set (x' := unsigned x). set (y' := unsigned y). set (z' := unsigned z). intros. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros n R. rewrite bits_of_Z_of_bits_gen'. destruct (zlt (n + - z') 0). symmetry. apply bits_of_Z_below. omega. destruct (zle (Z_of_nat wordsize) (n + - z')). symmetry. apply bits_of_Z_below. omega. decEq. omega. generalize two_wordsize_max_unsigned; omega. Qed. Theorem shru_zero: forall x, shru x zero = x. Proof. intros. unfold shru. rewrite unsigned_zero. transitivity (repr (unsigned x)). apply eqm_samerepr. apply Z_of_bits_of_Z. auto with ints. Qed. Lemma bitwise_binop_shru: forall f x y n, f false false = false -> bitwise_binop f (shru x n) (shru y n) = shru (bitwise_binop f x y) n. Proof. intros. unfold bitwise_binop, shru. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. repeat rewrite Zplus_0_r. rewrite bits_of_Z_of_bits_gen; auto. rewrite bits_of_Z_of_bits_gen; auto. destruct (zlt (i + unsigned n) (Z_of_nat wordsize)). rewrite bits_of_Z_of_bits. auto. generalize (unsigned_range n); omega. repeat rewrite bits_of_Z_above; auto. Qed. Theorem and_shru: forall x y n, and (shru x n) (shru y n) = shru (and x y) n. Proof. unfold and; intros. apply bitwise_binop_shru. reflexivity. Qed. Theorem or_shru: forall x y n, or (shru x n) (shru y n) = shru (or x y) n. Proof. unfold or; intros. apply bitwise_binop_shru. reflexivity. Qed. Theorem xor_shru: forall x y n, xor (shru x n) (shru y n) = shru (xor x y) n. Proof. unfold xor; intros. apply bitwise_binop_shru. reflexivity. Qed. Theorem shru_shru: forall x y z, ltu y iwordsize = true -> ltu z iwordsize = true -> ltu (add y z) iwordsize = true -> shru (shru x y) z = shru x (add y z). Proof. intros. unfold shru, add. generalize (ltu_inv _ _ H). generalize (ltu_inv _ _ H0). rewrite unsigned_repr_wordsize. set (x' := unsigned x). set (y' := unsigned y). set (z' := unsigned z). intros. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten. intros n R. rewrite bits_of_Z_of_bits_gen'. destruct (zlt (n + z') 0). omegaContradiction. destruct (zle (Z_of_nat wordsize) (n + z')). symmetry. apply bits_of_Z_above. omega. decEq. omega. generalize two_wordsize_max_unsigned; omega. Qed. Theorem shr_zero: forall x, shr x zero = x. Proof. intros. unfold shr. rewrite unsigned_zero. transitivity (repr (unsigned x)). apply eqm_samerepr. eapply eqm_trans. 2: apply Z_of_bits_of_Z. apply eqm_refl2. apply Z_of_bits_exten; intros. rewrite zlt_true. auto. omega. auto with ints. Qed. Lemma bitwise_binop_shr: forall f x y n, bitwise_binop f (shr x n) (shr y n) = shr (bitwise_binop f x y) n. Proof. intros. unfold bitwise_binop, shr. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. repeat rewrite bits_of_Z_of_bits_gen; repeat rewrite Zplus_0_r; auto. generalize (unsigned_range n); intro. destruct (zlt (i + unsigned n) (Z_of_nat wordsize)); omega. Qed. Theorem and_shr: forall x y n, and (shr x n) (shr y n) = shr (and x y) n. Proof. unfold and; intros. apply bitwise_binop_shr. Qed. Theorem or_shr: forall x y n, or (shr x n) (shr y n) = shr (or x y) n. Proof. unfold or; intros. apply bitwise_binop_shr. Qed. Theorem xor_shr: forall x y n, xor (shr x n) (shr y n) = shr (xor x y) n. Proof. unfold xor; intros. apply bitwise_binop_shr. Qed. Theorem shr_shr: forall x y z, ltu y iwordsize = true -> ltu z iwordsize = true -> ltu (add y z) iwordsize = true -> shr (shr x y) z = shr x (add y z). Proof. intros. unfold shr, add. generalize (ltu_inv _ _ H). generalize (ltu_inv _ _ H0). rewrite unsigned_repr_wordsize. set (x' := unsigned x). set (y' := unsigned y). set (z' := unsigned z). intros. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros n R. destruct (zlt (n + z') (Z_of_nat wordsize)). rewrite bits_of_Z_of_bits_gen. rewrite (Zplus_comm y' z'). rewrite Zplus_assoc. auto. omega. rewrite bits_of_Z_of_bits_gen. decEq. symmetry. rewrite zlt_false. destruct (zeq y' 0). rewrite zlt_true; omega. rewrite zlt_false; omega. omega. omega. generalize two_wordsize_max_unsigned; omega. Qed. Remark two_p_m1_range: forall n, 0 <= n <= Z_of_nat wordsize -> 0 <= two_p n - 1 <= max_unsigned. Proof. intros. split. assert (two_p n > 0). apply two_p_gt_ZERO. omega. omega. assert (two_p n <= two_p (Z_of_nat wordsize)). apply two_p_monotone. auto. unfold max_unsigned. unfold modulus. rewrite two_power_nat_two_p. omega. Qed. Theorem shru_shl_and: forall x y, ltu y iwordsize = true -> shru (shl x y) y = and x (repr (two_p (Z_of_nat wordsize - unsigned y) - 1)). Proof. intros. exploit ltu_inv; eauto. rewrite unsigned_repr_wordsize. intros. unfold and, bitwise_binop, shl, shru. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. rewrite Zplus_0_r. rewrite bits_of_Z_two_p. destruct (zlt (i + unsigned y) (Z_of_nat wordsize)). rewrite bits_of_Z_of_bits_gen. unfold proj_sumbool. rewrite zlt_true. rewrite andb_true_r. f_equal. omega. omega. omega. rewrite bits_of_Z_above. unfold proj_sumbool. rewrite zlt_false. rewrite andb_false_r; auto. omega. omega. omega. auto. apply two_p_m1_range. omega. Qed. Theorem and_shr_shru: forall x y z, and (shr x z) (shru y z) = shru (and x y) z. Proof. intros. unfold and, shr, shru, bitwise_binop. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. repeat rewrite Zplus_0_r. rewrite bits_of_Z_of_bits_gen; auto. rewrite bits_of_Z_of_bits_gen; auto. generalize (unsigned_range z); intros. destruct (zlt (i + unsigned z) (Z_of_nat wordsize)). rewrite bits_of_Z_of_bits_gen. repeat rewrite Zplus_0_r. auto. omega. set (b := bits_of_Z wordsize (unsigned x) (Z_of_nat wordsize - 1)). repeat rewrite bits_of_Z_above; auto. apply andb_false_r. Qed. Theorem shr_and_shru_and: forall x y z, shru (shl z y) y = z -> and (shr x y) z = and (shru x y) z. Proof. intros. rewrite <- H. rewrite and_shru. rewrite and_shr_shru. auto. Qed. (** ** Properties of rotations *) Theorem shl_rolm: forall x n, ltu n iwordsize = true -> shl x n = rolm x n (shl mone n). Proof. intros. exploit ltu_inv; eauto. rewrite unsigned_repr_wordsize; intros. unfold shl, rolm, rol, and, bitwise_binop. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. rewrite Zplus_0_r. repeat rewrite bits_of_Z_of_bits_gen; auto. destruct (zlt i (unsigned n)). assert (i + - unsigned n < 0). omega. rewrite (bits_of_Z_below wordsize (unsigned x) _ H2). rewrite (bits_of_Z_below wordsize (unsigned mone) _ H2). symmetry. apply andb_b_false. assert (0 <= i + - unsigned n < Z_of_nat wordsize). generalize (unsigned_range n). omega. rewrite unsigned_mone. rewrite bits_of_Z_mone; auto. rewrite andb_b_true. decEq. rewrite Zmod_small. omega. omega. Qed. Theorem shru_rolm: forall x n, ltu n iwordsize = true -> shru x n = rolm x (sub iwordsize n) (shru mone n). Proof. intros. generalize (ltu_inv _ _ H). rewrite unsigned_repr_wordsize. intro. unfold shru, rolm, rol, and, bitwise_binop. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. rewrite Zplus_0_r. repeat rewrite bits_of_Z_of_bits_gen; auto. unfold sub. rewrite unsigned_repr_wordsize. rewrite unsigned_repr. case (zlt (i + unsigned n) (Z_of_nat wordsize)); intro LT2. rewrite unsigned_mone. rewrite bits_of_Z_mone. rewrite andb_b_true. decEq. replace (i + - (Z_of_nat wordsize - unsigned n)) with ((i + unsigned n) + (-1) * Z_of_nat wordsize) by omega. rewrite Z_mod_plus. symmetry. apply Zmod_small. generalize (unsigned_range n). omega. omega. omega. rewrite (bits_of_Z_above wordsize (unsigned x) _ LT2). rewrite (bits_of_Z_above wordsize (unsigned mone) _ LT2). symmetry. apply andb_b_false. split. omega. apply Zle_trans with (Z_of_nat wordsize). generalize (unsigned_range n); omega. apply wordsize_max_unsigned. Qed. Theorem rol_zero: forall x, rol x zero = x. Proof. intros. transitivity (repr (unsigned x)). unfold rol. apply eqm_samerepr. eapply eqm_trans. 2: apply Z_of_bits_of_Z. apply eqm_refl2. apply Z_of_bits_exten; intros. decEq. rewrite unsigned_zero. replace (i + - 0) with (i + 0) by omega. apply Zmod_small. omega. apply repr_unsigned. Qed. Lemma bitwise_binop_rol: forall f x y n, bitwise_binop f (rol x n) (rol y n) = rol (bitwise_binop f x y) n. Proof. intros. unfold bitwise_binop, rol. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. repeat rewrite bits_of_Z_of_bits_gen. repeat rewrite Zplus_0_r. auto. apply Z_mod_lt. generalize wordsize_pos; omega. omega. omega. Qed. Theorem rol_and: forall x y n, rol (and x y) n = and (rol x n) (rol y n). Proof. intros. symmetry. unfold and. apply bitwise_binop_rol. Qed. Theorem rol_or: forall x y n, rol (or x y) n = or (rol x n) (rol y n). Proof. intros. symmetry. unfold or. apply bitwise_binop_rol. Qed. Theorem rol_xor: forall x y n, rol (xor x y) n = xor (rol x n) (rol y n). Proof. intros. symmetry. unfold xor. apply bitwise_binop_rol. Qed. Theorem rol_rol: forall x n m, Zdivide (Z_of_nat wordsize) modulus -> rol (rol x n) m = rol x (modu (add n m) iwordsize). Proof. intros. unfold rol. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. repeat rewrite bits_of_Z_of_bits; repeat rewrite Zplus_0_r; auto. rewrite bits_of_Z_of_bits_gen. decEq. unfold modu, add. set (W := Z_of_nat wordsize). set (M := unsigned m); set (N := unsigned n). assert (W > 0). unfold W; generalize wordsize_pos; omega. assert (forall a, eqmod W a (unsigned (repr a))). intros. eapply eqmod_divides. apply eqm_unsigned_repr. assumption. apply eqmod_mod_eq. auto. replace (unsigned iwordsize) with W. apply eqmod_trans with (i - (N + M) mod W). apply eqmod_trans with ((i - M) - N). apply eqmod_sub. apply eqmod_sym. apply eqmod_mod. auto. apply eqmod_refl. replace (i - M - N) with (i - (N + M)). apply eqmod_sub. apply eqmod_refl. apply eqmod_mod. auto. omega. apply eqmod_sub. apply eqmod_refl. eapply eqmod_trans; [idtac|apply H2]. eapply eqmod_trans; [idtac|apply eqmod_mod]. apply eqmod_sym. eapply eqmod_trans; [idtac|apply eqmod_mod]. apply eqmod_sym. apply H2. auto. auto. symmetry. unfold W. apply unsigned_repr_wordsize. apply Z_mod_lt. generalize wordsize_pos; omega. Qed. Theorem rolm_zero: forall x m, rolm x zero m = and x m. Proof. intros. unfold rolm. rewrite rol_zero. auto. Qed. Theorem rolm_rolm: forall x n1 m1 n2 m2, Zdivide (Z_of_nat wordsize) modulus -> rolm (rolm x n1 m1) n2 m2 = rolm x (modu (add n1 n2) iwordsize) (and (rol m1 n2) m2). Proof. intros. unfold rolm. rewrite rol_and. rewrite and_assoc. rewrite rol_rol. reflexivity. auto. Qed. Theorem or_rolm: forall x n m1 m2, or (rolm x n m1) (rolm x n m2) = rolm x n (or m1 m2). Proof. intros; unfold rolm. symmetry. apply and_or_distrib. Qed. Theorem ror_rol: forall x y, ltu y iwordsize = true -> ror x y = rol x (sub iwordsize y). Proof. intros. unfold ror, rol, sub. generalize (ltu_inv _ _ H). rewrite unsigned_repr_wordsize. intro. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. decEq. apply eqmod_mod_eq. omega. exists 1. omega. generalize wordsize_pos; generalize wordsize_max_unsigned; omega. Qed. Theorem or_ror: forall x y z, ltu y iwordsize = true -> ltu z iwordsize = true -> add y z = iwordsize -> ror x z = or (shl x y) (shru x z). Proof. intros. generalize (ltu_inv _ _ H). generalize (ltu_inv _ _ H0). rewrite unsigned_repr_wordsize. intros. unfold or, bitwise_binop, shl, shru, ror. set (ux := unsigned x). repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten. intros i iRANGE. rewrite Zplus_0_r. repeat rewrite bits_of_Z_of_bits_gen; auto. assert (y = sub iwordsize z). rewrite <- H1. rewrite add_commut. rewrite sub_add_l. rewrite sub_idem. rewrite add_commut. rewrite add_zero. auto. assert (unsigned y = Z_of_nat wordsize - unsigned z). rewrite H4. unfold sub. rewrite unsigned_repr_wordsize. apply unsigned_repr. generalize wordsize_max_unsigned; omega. destruct (zlt (i + unsigned z) (Z_of_nat wordsize)). rewrite Zmod_small. replace (bits_of_Z wordsize ux (i + - unsigned y)) with false. auto. symmetry. apply bits_of_Z_below. omega. omega. replace (bits_of_Z wordsize ux (i + unsigned z)) with false. rewrite orb_false_r. decEq. replace (i + unsigned z) with (i - unsigned y + 1 * Z_of_nat wordsize) by omega. rewrite Z_mod_plus. apply Zmod_small. omega. generalize wordsize_pos; omega. symmetry. apply bits_of_Z_above. auto. Qed. (** ** Properties of [Z_one_bits] and [is_power2]. *) Fixpoint powerserie (l: list Z): Z := match l with | nil => 0 | x :: xs => two_p x + powerserie xs end. Lemma Z_bin_decomp_range: forall x n, 0 <= x < 2 * n -> 0 <= snd (Z_bin_decomp x) < n. Proof. intros. rewrite <- (Z_bin_comp_decomp x) in H. rewrite Z_bin_comp_eq in H. destruct (fst (Z_bin_decomp x)); omega. Qed. Lemma Z_one_bits_powerserie: forall x, 0 <= x < modulus -> x = powerserie (Z_one_bits wordsize x 0). Proof. assert (forall n x i, 0 <= i -> 0 <= x < two_power_nat n -> x * two_p i = powerserie (Z_one_bits n x i)). induction n; intros. simpl. rewrite two_power_nat_O in H0. assert (x = 0). omega. subst x. omega. rewrite two_power_nat_S in H0. simpl Z_one_bits. destruct (Z_bin_decomp x) as [b y] eqn:?. rewrite (Z_bin_comp_decomp2 _ _ _ Heqp). assert (EQ: y * two_p (i + 1) = powerserie (Z_one_bits n y (i + 1))). apply IHn. omega. replace y with (snd (Z_bin_decomp x)). apply Z_bin_decomp_range; auto. rewrite Heqp; auto. rewrite two_p_is_exp in EQ. change (two_p 1) with 2 in EQ. rewrite Z_bin_comp_eq. destruct b; simpl powerserie; rewrite <- EQ; ring. omega. omega. intros. rewrite <- H. change (two_p 0) with 1. omega. omega. exact H0. Qed. Lemma Z_one_bits_range: forall x i, In i (Z_one_bits wordsize x 0) -> 0 <= i < Z_of_nat wordsize. Proof. assert (forall n x i j, In j (Z_one_bits n x i) -> i <= j < i + Z_of_nat n). induction n; simpl In. intros; elim H. intros x i j. destruct (Z_bin_decomp x). case b. rewrite inj_S. simpl. intros [A|B]. subst j. omega. generalize (IHn _ _ _ B). omega. intros B. rewrite inj_S. generalize (IHn _ _ _ B). omega. intros. generalize (H wordsize x 0 i H0). omega. Qed. Lemma is_power2_rng: forall n logn, is_power2 n = Some logn -> 0 <= unsigned logn < Z_of_nat wordsize. Proof. intros n logn. unfold is_power2. generalize (Z_one_bits_range (unsigned n)). destruct (Z_one_bits wordsize (unsigned n) 0). intros; discriminate. destruct l. intros. injection H0; intro; subst logn; clear H0. assert (0 <= z < Z_of_nat wordsize). apply H. auto with coqlib. rewrite unsigned_repr. auto. generalize wordsize_max_unsigned; omega. intros; discriminate. Qed. Theorem is_power2_range: forall n logn, is_power2 n = Some logn -> ltu logn iwordsize = true. Proof. intros. unfold ltu. rewrite unsigned_repr_wordsize. generalize (is_power2_rng _ _ H). case (zlt (unsigned logn) (Z_of_nat wordsize)); intros. auto. omegaContradiction. Qed. Lemma is_power2_correct: forall n logn, is_power2 n = Some logn -> unsigned n = two_p (unsigned logn). Proof. intros n logn. unfold is_power2. generalize (Z_one_bits_powerserie (unsigned n) (unsigned_range n)). generalize (Z_one_bits_range (unsigned n)). destruct (Z_one_bits wordsize (unsigned n) 0). intros; discriminate. destruct l. intros. simpl in H0. injection H1; intros; subst logn; clear H1. rewrite unsigned_repr. replace (two_p z) with (two_p z + 0). auto. omega. elim (H z); intros. generalize wordsize_max_unsigned; omega. auto with coqlib. intros; discriminate. Qed. Remark two_p_range: forall n, 0 <= n < Z_of_nat wordsize -> 0 <= two_p n <= max_unsigned. Proof. intros. split. assert (two_p n > 0). apply two_p_gt_ZERO. omega. omega. generalize (two_p_monotone_strict _ _ H). rewrite <- two_power_nat_two_p. unfold max_unsigned, modulus. omega. Qed. Remark Z_one_bits_zero: forall n i, Z_one_bits n 0 i = nil. Proof. induction n; intros; simpl; auto. Qed. Remark Z_one_bits_two_p: forall n x i, 0 <= x < Z_of_nat n -> Z_one_bits n (two_p x) i = (i + x) :: nil. Proof. induction n; intros; simpl. simpl in H. omegaContradiction. rewrite inj_S in H. assert (x = 0 \/ 0 < x) by omega. destruct H0. subst x; simpl. decEq. omega. apply Z_one_bits_zero. replace (two_p x) with (Z_bin_comp false (two_p (x-1))). rewrite Z_bin_decomp_comp. replace (i + x) with ((i + 1) + (x - 1)) by omega. apply IHn. omega. rewrite Z_bin_comp_eq. rewrite <- two_p_S. rewrite Zplus_0_r. decEq; omega. omega. Qed. Lemma is_power2_two_p: forall n, 0 <= n < Z_of_nat wordsize -> is_power2 (repr (two_p n)) = Some (repr n). Proof. intros. unfold is_power2. rewrite unsigned_repr. rewrite Z_one_bits_two_p. auto. auto. apply two_p_range. auto. Qed. (** ** Relation between bitwise operations and multiplications / divisions by powers of 2 *) (** Left shifts and multiplications by powers of 2. *) Lemma Z_of_bits_shift_left: forall f m, m >= 0 -> (forall i, i < 0 -> f i = false) -> eqm (Z_of_bits wordsize f (-m)) (two_p m * Z_of_bits wordsize f 0). Proof. intros. set (m' := nat_of_Z m). assert (Z_of_nat m' = m). apply nat_of_Z_eq. auto. generalize (Z_of_bits_compose f m' wordsize (-m)). rewrite H1. replace (-m+m) with 0 by omega. rewrite two_power_nat_two_p. rewrite H1. replace (Z_of_bits m' f (-m)) with 0. intro EQ. eapply eqm_trans. apply eqm_sym. eapply Z_of_bits_truncate with (n := m'). rewrite plus_comm. rewrite EQ. apply eqm_refl2. ring. symmetry. apply Z_of_bits_false. rewrite H1. intros. apply H0. omega. Qed. Lemma shl_mul_two_p: forall x y, shl x y = mul x (repr (two_p (unsigned y))). Proof. intros. unfold shl, mul. apply eqm_samerepr. eapply eqm_trans. apply Z_of_bits_shift_left. generalize (unsigned_range y). omega. intros; apply bits_of_Z_below; auto. rewrite Zmult_comm. apply eqm_mult. apply Z_of_bits_of_Z. apply eqm_unsigned_repr. Qed. Theorem shl_mul: forall x y, shl x y = mul x (shl one y). Proof. intros. assert (shl one y = repr (two_p (unsigned y))). rewrite shl_mul_two_p. rewrite mul_commut. rewrite mul_one. auto. rewrite H. apply shl_mul_two_p. Qed. Theorem mul_pow2: forall x n logn, is_power2 n = Some logn -> mul x n = shl x logn. Proof. intros. generalize (is_power2_correct n logn H); intro. rewrite shl_mul_two_p. rewrite <- H0. rewrite repr_unsigned. auto. Qed. Theorem shifted_or_is_add: forall x y n, 0 <= n < Z_of_nat wordsize -> unsigned y < two_p n -> or (shl x (repr n)) y = repr(unsigned x * two_p n + unsigned y). Proof. intros. rewrite <- add_is_or. rewrite shl_mul_two_p. rewrite unsigned_repr. unfold add. apply eqm_samerepr. unfold mul. auto with ints. generalize wordsize_max_unsigned; omega. unfold and, shl, bitwise_binop. unfold zero. decEq. apply Z_of_bits_false. intros. rewrite unsigned_repr; auto with ints. rewrite bits_of_Z_of_bits_gen. rewrite unsigned_repr. apply andb_false_iff. destruct (zlt j n). left. apply bits_of_Z_below. omega. right. apply bits_of_Z_greater. split. generalize (unsigned_range y); omega. assert (two_p n <= two_p j). apply two_p_monotone. omega. omega. generalize wordsize_max_unsigned; omega. omega. Qed. (** Unsigned right shifts and unsigned divisions by powers of 2. *) Lemma Z_of_bits_shift_right: forall m f, m >= 0 -> (forall i, i >= Z_of_nat wordsize -> f i = false) -> exists k, Z_of_bits wordsize f 0 = k + two_p m * Z_of_bits wordsize f m /\ 0 <= k < two_p m. Proof. intros. set (m' := nat_of_Z m). assert (Z_of_nat m' = m). apply nat_of_Z_eq. auto. generalize (Z_of_bits_compose f m' wordsize 0). rewrite two_power_nat_two_p. rewrite H1. rewrite plus_comm. rewrite Z_of_bits_compose. replace (Z_of_bits m' f (0 + Z_of_nat wordsize)) with 0. repeat rewrite Zplus_0_l. intros EQ. exists (Z_of_bits m' f 0); split. rewrite EQ. ring. rewrite <- H1. rewrite <- two_power_nat_two_p. apply Z_of_bits_range. symmetry. apply Z_of_bits_false. intros. apply H0. omega. Qed. Lemma shru_div_two_p: forall x y, shru x y = repr (unsigned x / two_p (unsigned y)). Proof. intros. unfold shru. set (x' := unsigned x). set (y' := unsigned y). destruct (Z_of_bits_shift_right y' (bits_of_Z wordsize x')) as [k [EQ RANGE]]. generalize (unsigned_range y). unfold y'; omega. intros. rewrite bits_of_Z_above; auto. decEq. symmetry. apply Zdiv_unique with k; auto. transitivity (Z_of_bits wordsize (bits_of_Z wordsize x') 0). apply eqm_small_eq. apply eqm_sym. apply Z_of_bits_of_Z. unfold x'; auto with ints. auto with ints. rewrite EQ. ring. Qed. Theorem divu_pow2: forall x n logn, is_power2 n = Some logn -> divu x n = shru x logn. Proof. intros. generalize (is_power2_correct n logn H). intro. symmetry. unfold divu. rewrite H0. apply shru_div_two_p. Qed. (** Signed right shifts and signed divisions by powers of 2. *) Lemma Z_of_bits_shift_right_neg: forall m f, m >= 0 -> (forall i, i >= Z_of_nat wordsize -> f i = true) -> exists k, Z_of_bits wordsize f 0 - modulus = k + two_p m * (Z_of_bits wordsize f m - modulus) /\ 0 <= k < two_p m. Proof. intros. set (m' := nat_of_Z m). assert (Z_of_nat m' = m). apply nat_of_Z_eq. auto. generalize (Z_of_bits_compose f m' wordsize 0). rewrite two_power_nat_two_p. rewrite H1. rewrite plus_comm. rewrite Z_of_bits_compose. repeat rewrite Zplus_0_l. fold modulus. replace (Z_of_bits m' f (Z_of_nat wordsize)) with (two_p m - 1). intros EQ. exists (Z_of_bits m' f 0); split. replace (Z_of_bits wordsize f 0) with (Z_of_bits wordsize f m * two_p m + Z_of_bits m' f 0 - (two_p m - 1) * modulus) by omega. ring. rewrite <- H1. rewrite <- two_power_nat_two_p. apply Z_of_bits_range. rewrite <- H1. rewrite <- two_power_nat_two_p. symmetry. apply Z_of_bits_true. intros. apply H0. omega. Qed. Lemma sign_bit_of_Z_rec: forall n x, 0 <= x < two_power_nat (S n) -> bits_of_Z (S n) x (Z_of_nat n) = if zlt x (two_power_nat n) then false else true. Proof. induction n; intros. rewrite two_power_nat_S in H. rewrite two_power_nat_O in *. simpl. generalize (Z_bin_comp_decomp x). destruct (Z_bin_decomp x) as [b y]; simpl. intros; subst x. rewrite Z_bin_comp_eq in *. destruct b. rewrite zlt_false. auto. omega. rewrite zlt_true. auto. omega. rewrite inj_S. remember (S n) as sn. simpl. rewrite two_power_nat_S in H. generalize (Z_bin_comp_decomp x). destruct (Z_bin_decomp x) as [b y]; simpl. intros; subst x. rewrite Z_bin_comp_eq in *. rewrite zeq_false. replace (Zsucc (Z_of_nat n) - 1) with (Z_of_nat n). rewrite IHn. subst sn. rewrite two_power_nat_S. destruct (zlt y (two_power_nat n)). rewrite zlt_true. auto. destruct b; omega. rewrite zlt_false. auto. destruct b; omega. destruct b; omega. omega. omega. Qed. Lemma sign_bit_of_Z: forall x, bits_of_Z wordsize (unsigned x) (Z_of_nat wordsize - 1) = if zlt (unsigned x) half_modulus then false else true. Proof. intros. rewrite half_modulus_power. set (w1 := nat_of_Z (Z_of_nat wordsize - 1)). assert (Z_of_nat wordsize - 1 = Z_of_nat w1). unfold w1. rewrite nat_of_Z_eq; auto. generalize wordsize_pos; omega. assert (wordsize = 1 + w1)%nat. apply inj_eq_rev. rewrite inj_plus. simpl (Z_of_nat 1). omega. rewrite H. rewrite <- two_power_nat_two_p. rewrite H0. apply sign_bit_of_Z_rec. simpl in H0; rewrite <- H0. auto with ints. Qed. Lemma shr_div_two_p: forall x y, shr x y = repr (signed x / two_p (unsigned y)). Proof. intros. unfold shr. generalize (sign_bit_of_Z x); intro SIGN. unfold signed. destruct (zlt (unsigned x) half_modulus). (* positive case *) rewrite <- shru_div_two_p. unfold shru. decEq; apply Z_of_bits_exten; intros. destruct (zlt (i + unsigned y) (Z_of_nat wordsize)). auto. rewrite SIGN. symmetry. apply bits_of_Z_above. auto. (* negative case *) set (x' := unsigned x) in *. set (y' := unsigned y) in *. set (f := fun i => bits_of_Z wordsize x' (if zlt i (Z_of_nat wordsize) then i else Z_of_nat wordsize - 1)). destruct (Z_of_bits_shift_right_neg y' f) as [k [EQ RANGE]]. generalize (unsigned_range y). unfold y'; omega. intros. unfold f. rewrite zlt_false; auto. set (A := Z_of_bits wordsize f y') in *. set (B := Z_of_bits wordsize f 0) in *. assert (B = Z_of_bits wordsize (bits_of_Z wordsize x') 0). unfold B. apply Z_of_bits_exten; intros. unfold f. rewrite zlt_true. auto. omega. assert (B = x'). apply eqm_small_eq. rewrite H. apply Z_of_bits_of_Z. unfold B; apply Z_of_bits_range. unfold x'; apply unsigned_range. assert (Q: (x' - modulus) / two_p y' = A - modulus). apply Zdiv_unique with k; auto. rewrite <- H0. rewrite EQ. ring. rewrite Q. apply eqm_samerepr. exists 1; ring. Qed. Theorem divs_pow2: forall x n logn, is_power2 n = Some logn -> divs x n = shrx x logn. Proof. intros. generalize (is_power2_correct _ _ H); intro. unfold shrx. rewrite shl_mul_two_p. rewrite mul_commut. rewrite mul_one. rewrite <- H0. rewrite repr_unsigned. auto. Qed. (** Unsigned modulus over [2^n] is masking with [2^n-1]. *) Lemma Z_of_bits_mod_mask: forall f n, 0 <= n <= Z_of_nat wordsize -> Z_of_bits wordsize (fun i => if zlt i n then f i else false) 0 = (Z_of_bits wordsize f 0) mod (two_p n). Proof. intros. set (f' := fun i => if zlt i n then f i else false). set (n1 := nat_of_Z n). set (m1 := nat_of_Z (Z_of_nat wordsize - n)). assert (Z_of_nat n1 = n). apply nat_of_Z_eq; omega. assert (Z_of_nat m1 = Z_of_nat wordsize - n). apply nat_of_Z_eq; omega. assert (n1 + m1 = wordsize)%nat. apply inj_eq_rev. rewrite inj_plus. omega. generalize (Z_of_bits_compose f n1 m1 0). rewrite H2. rewrite Zplus_0_l. rewrite two_power_nat_two_p. rewrite H0. intros. generalize (Z_of_bits_compose f' n1 m1 0). rewrite H2. rewrite Zplus_0_l. rewrite two_power_nat_two_p. rewrite H0. intros. assert (Z_of_bits n1 f' 0 = Z_of_bits n1 f 0). apply Z_of_bits_exten; intros. unfold f'. apply zlt_true. omega. assert (Z_of_bits m1 f' n = 0). apply Z_of_bits_false; intros. unfold f'. apply zlt_false. omega. assert (Z_of_bits wordsize f' 0 = Z_of_bits n1 f 0). rewrite H4. rewrite H5. rewrite H6. ring. symmetry. apply Zmod_unique with (Z_of_bits m1 f n). omega. rewrite H7. rewrite <- H0. rewrite <- two_power_nat_two_p. apply Z_of_bits_range. Qed. Theorem modu_and: forall x n logn, is_power2 n = Some logn -> modu x n = and x (sub n one). Proof. intros. generalize (is_power2_correct _ _ H); intro. generalize (is_power2_rng _ _ H); intro. unfold modu, and, bitwise_binop. decEq. set (ux := unsigned x). replace ux with (Z_of_bits wordsize (bits_of_Z wordsize ux) 0). rewrite H0. rewrite <- Z_of_bits_mod_mask. apply Z_of_bits_exten; intros. rewrite Zplus_0_r. rewrite bits_of_Z_of_bits; auto. replace (unsigned (sub n one)) with (two_p (unsigned logn) - 1). rewrite bits_of_Z_two_p. unfold proj_sumbool. destruct (zlt i (unsigned logn)). rewrite andb_true_r; auto. rewrite andb_false_r; auto. omega. auto. rewrite <- H0. unfold sub. symmetry. rewrite unsigned_one. apply unsigned_repr. rewrite H0. assert (two_p (unsigned logn) > 0). apply two_p_gt_ZERO. omega. generalize (two_p_range _ H1). omega. omega. apply eqm_small_eq. apply Z_of_bits_of_Z. apply Z_of_bits_range. unfold ux. apply unsigned_range. Qed. (** ** Properties of [shrx] (signed division by a power of 2) *) Lemma Zdiv_round_Zdiv: forall x y, y > 0 -> Zdiv_round x y = if zlt x 0 then (x + y - 1) / y else x / y. Proof. intros. unfold Zdiv_round. destruct (zlt x 0). rewrite zlt_false; try omega. generalize (Z_div_mod_eq (-x) y H). generalize (Z_mod_lt (-x) y H). set (q := (-x) / y). set (r := (-x) mod y). intros. symmetry. apply Zdiv_unique with (y - r - 1). replace x with (- (y * q) - r) by omega. replace (-(y * q)) with ((-q) * y) by ring. omega. omega. apply zlt_false. omega. Qed. Theorem shrx_shr: forall x y, ltu y (repr (Z_of_nat wordsize - 1)) = true -> shrx x y = shr (if lt x zero then add x (sub (shl one y) one) else x) y. Proof. intros. rewrite shr_div_two_p. unfold shrx. unfold divs. exploit ltu_inv; eauto. rewrite unsigned_repr. set (uy := unsigned y). intro RANGE. assert (shl one y = repr (two_p uy)). transitivity (mul one (repr (two_p uy))). symmetry. apply mul_pow2. replace y with (repr uy). apply is_power2_two_p. omega. apply repr_unsigned. rewrite mul_commut. apply mul_one. assert (two_p uy > 0). apply two_p_gt_ZERO. omega. assert (two_p uy < half_modulus). rewrite half_modulus_power. apply two_p_monotone_strict. auto. assert (two_p uy < modulus). rewrite modulus_power. apply two_p_monotone_strict. omega. assert (unsigned (shl one y) = two_p uy). rewrite H0. apply unsigned_repr. unfold max_unsigned. omega. assert (signed (shl one y) = two_p uy). rewrite H0. apply signed_repr. unfold max_signed. generalize min_signed_neg. omega. rewrite H5. rewrite Zdiv_round_Zdiv; auto. unfold lt. rewrite signed_zero. destruct (zlt (signed x) 0); auto. rewrite add_signed. assert (signed (sub (shl one y) one) = two_p uy - 1). unfold sub. rewrite H4. rewrite unsigned_one. apply signed_repr. generalize min_signed_neg. unfold max_signed. omega. rewrite H6. rewrite signed_repr. decEq. decEq. omega. generalize (signed_range x). intros. assert (two_p uy - 1 <= max_signed). unfold max_signed. omega. omega. generalize wordsize_pos wordsize_max_unsigned; omega. Qed. Lemma Zdiv_shift: forall x y, y > 0 -> (x + (y - 1)) / y = x / y + if zeq (Zmod x y) 0 then 0 else 1. Proof. intros. generalize (Z_div_mod_eq x y H). generalize (Z_mod_lt x y H). set (q := x / y). set (r := x mod y). intros. destruct (zeq r 0). apply Zdiv_unique with (y - 1). rewrite H1. rewrite e. ring. omega. apply Zdiv_unique with (r - 1). rewrite H1. ring. omega. Qed. Theorem shrx_carry: forall x y, ltu y (repr (Z_of_nat wordsize - 1)) = true -> shrx x y = add (shr x y) (shr_carry x y). Proof. intros. rewrite shrx_shr; auto. unfold shr_carry. unfold lt. set (sx := signed x). rewrite signed_zero. destruct (zlt sx 0); simpl. 2: rewrite add_zero; auto. set (uy := unsigned y). assert (0 <= uy < Z_of_nat wordsize - 1). exploit ltu_inv; eauto. rewrite unsigned_repr. auto. generalize wordsize_pos wordsize_max_unsigned; omega. assert (shl one y = repr (two_p uy)). rewrite shl_mul_two_p. rewrite mul_commut. apply mul_one. assert (and x (sub (shl one y) one) = modu x (repr (two_p uy))). symmetry. rewrite H1. apply modu_and with (logn := y). rewrite is_power2_two_p. unfold uy. rewrite repr_unsigned. auto. omega. rewrite H2. rewrite H1. repeat rewrite shr_div_two_p. fold sx. fold uy. assert (two_p uy > 0). apply two_p_gt_ZERO. omega. assert (two_p uy < modulus). rewrite modulus_power. apply two_p_monotone_strict. omega. assert (two_p uy < half_modulus). rewrite half_modulus_power. apply two_p_monotone_strict. auto. assert (two_p uy < modulus). rewrite modulus_power. apply two_p_monotone_strict. omega. assert (sub (repr (two_p uy)) one = repr (two_p uy - 1)). unfold sub. apply eqm_samerepr. apply eqm_sub. apply eqm_sym; apply eqm_unsigned_repr. rewrite unsigned_one. apply eqm_refl. rewrite H7. rewrite add_signed. fold sx. rewrite (signed_repr (two_p uy - 1)). rewrite signed_repr. unfold modu. rewrite unsigned_repr. unfold eq. rewrite unsigned_zero. rewrite unsigned_repr. assert (unsigned x mod two_p uy = sx mod two_p uy). apply eqmod_mod_eq; auto. apply eqmod_divides with modulus. fold eqm. unfold sx. apply eqm_sym. apply eqm_signed_unsigned. unfold modulus. rewrite two_power_nat_two_p. exists (two_p (Z_of_nat wordsize - uy)). rewrite <- two_p_is_exp. decEq. omega. omega. omega. rewrite H8. rewrite Zdiv_shift; auto. unfold add. apply eqm_samerepr. apply eqm_add. apply eqm_unsigned_repr. destruct (zeq (sx mod two_p uy) 0); simpl. rewrite unsigned_zero. apply eqm_refl. rewrite unsigned_one. apply eqm_refl. generalize (Z_mod_lt (unsigned x) (two_p uy) H3). unfold max_unsigned. omega. unfold max_unsigned; omega. generalize (signed_range x). fold sx. intros. split. omega. unfold max_signed. omega. generalize min_signed_neg. unfold max_signed. omega. Qed. (** Connections between [shr] and [shru]. *) Lemma shr_shru_positive: forall x y, signed x >= 0 -> shr x y = shru x y. Proof. intros. rewrite shr_div_two_p. rewrite shru_div_two_p. rewrite signed_eq_unsigned. auto. apply signed_positive. auto. Qed. Lemma and_positive: forall x y, signed y >= 0 -> signed (and x y) >= 0. Proof. intros. assert (unsigned y < half_modulus). rewrite signed_positive in H. unfold max_signed in H; omega. generalize (sign_bit_of_Z y). rewrite zlt_true; auto. intros A. generalize (sign_bit_of_Z (and x y)). unfold and at 1. unfold bitwise_binop at 1. set (fx := bits_of_Z wordsize (unsigned x)). set (fy := bits_of_Z wordsize (unsigned y)). rewrite unsigned_repr; auto with ints. rewrite bits_of_Z_of_bits. unfold fy. rewrite A. rewrite andb_false_r. destruct (zlt (unsigned (and x y)) half_modulus); intros. rewrite signed_positive. unfold max_signed; omega. congruence. generalize wordsize_pos; omega. Qed. Theorem shr_and_is_shru_and: forall x y z, lt y zero = false -> shr (and x y) z = shru (and x y) z. Proof. intros. apply shr_shru_positive. apply and_positive. unfold lt in H. rewrite signed_zero in H. destruct (zlt (signed y) 0). congruence. auto. Qed. (** ** Properties of integer zero extension and sign extension. *) Section EXTENSIONS. Variable n: Z. Hypothesis RANGE: 0 < n < Z_of_nat wordsize. Remark two_p_n_pos: two_p n > 0. Proof. apply two_p_gt_ZERO. omega. Qed. Remark two_p_n_range: 0 <= two_p n <= max_unsigned. Proof. apply two_p_range. omega. Qed. Remark two_p_n_range': two_p n <= max_signed + 1. Proof. unfold max_signed. rewrite half_modulus_power. assert (two_p n <= two_p (Z_of_nat wordsize - 1)). apply two_p_monotone. omega. omega. Qed. Remark unsigned_repr_two_p: unsigned (repr (two_p n)) = two_p n. Proof. apply unsigned_repr. apply two_p_n_range. Qed. Remark eqm_eqmod_two_p: forall a b, eqm a b -> eqmod (two_p n) a b. Proof. intros a b [k EQ]. exists (k * two_p (Z_of_nat wordsize - n)). rewrite EQ. decEq. rewrite <- Zmult_assoc. decEq. rewrite <- two_p_is_exp. unfold modulus. rewrite two_power_nat_two_p. decEq. omega. omega. omega. Qed. Theorem zero_ext_and: forall x, zero_ext n x = and x (repr (two_p n - 1)). Proof. intros; unfold zero_ext, and, bitwise_binop. decEq; apply Z_of_bits_exten; intros. rewrite unsigned_repr. rewrite bits_of_Z_two_p. unfold proj_sumbool. destruct (zlt (i+0) n). rewrite andb_true_r; auto. rewrite andb_false_r; auto. omega. omega. generalize two_p_n_range two_p_n_pos; omega. Qed. Theorem zero_ext_mod: forall x, unsigned (zero_ext n x) = Zmod (unsigned x) (two_p n). Proof. intros. replace (unsigned x) with (Z_of_bits wordsize (bits_of_Z wordsize (unsigned x)) 0). unfold zero_ext. rewrite unsigned_repr; auto with ints. apply Z_of_bits_mod_mask. omega. apply eqm_small_eq; auto with ints. apply Z_of_bits_of_Z. Qed. Theorem zero_ext_idem: forall x, zero_ext n (zero_ext n x) = zero_ext n x. Proof. intros. repeat rewrite zero_ext_and. rewrite and_assoc. rewrite and_idem. auto. Qed. Theorem sign_ext_idem: forall x, sign_ext n (sign_ext n x) = sign_ext n x. Proof. intros. unfold sign_ext. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. rewrite Zplus_0_r. repeat rewrite bits_of_Z_of_bits; auto. destruct (zlt i n). auto. destruct (zlt (n - 1) n); auto. omega. Qed. Theorem sign_ext_zero_ext: forall x, sign_ext n (zero_ext n x) = sign_ext n x. Proof. intros. unfold sign_ext, zero_ext. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. rewrite Zplus_0_r. destruct (zlt i n); rewrite bits_of_Z_of_bits; auto. rewrite zlt_true; auto. rewrite zlt_true; auto. omega. omega. Qed. Theorem zero_ext_sign_ext: forall x, zero_ext n (sign_ext n x) = zero_ext n x. Proof. intros. unfold sign_ext, zero_ext. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros. rewrite Zplus_0_r. destruct (zlt i n); auto. rewrite bits_of_Z_of_bits; auto. rewrite zlt_true; auto. Qed. Theorem sign_ext_equal_if_zero_equal: forall x y, zero_ext n x = zero_ext n y -> sign_ext n x = sign_ext n y. Proof. intros. rewrite <- (sign_ext_zero_ext x). rewrite <- (sign_ext_zero_ext y). congruence. Qed. Theorem zero_ext_shru_shl: forall x, let y := repr (Z_of_nat wordsize - n) in zero_ext n x = shru (shl x y) y. Proof. intros. assert (unsigned y = Z_of_nat wordsize - n). unfold y. apply unsigned_repr. generalize wordsize_max_unsigned. omega. rewrite zero_ext_and. symmetry. replace n with (Z_of_nat wordsize - unsigned y). apply shru_shl_and. unfold ltu. apply zlt_true. rewrite H. rewrite unsigned_repr_wordsize. omega. omega. Qed. Theorem sign_ext_shr_shl: forall x, let y := repr (Z_of_nat wordsize - n) in sign_ext n x = shr (shl x y) y. Proof. intros. assert (unsigned y = Z_of_nat wordsize - n). unfold y. apply unsigned_repr. generalize wordsize_max_unsigned. omega. unfold sign_ext, shr, shl. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros; rewrite Zplus_0_r. destruct (zlt i n). rewrite zlt_true. rewrite bits_of_Z_of_bits_gen. decEq. omega. omega. omega. rewrite zlt_false. rewrite bits_of_Z_of_bits_gen. decEq. omega. omega. omega. Qed. (** [zero_ext n x] is the unique integer congruent to [x] modulo [2^n] in the range [0...2^n-1]. *) Lemma zero_ext_range: forall x, 0 <= unsigned (zero_ext n x) < two_p n. Proof. intros. rewrite zero_ext_mod. apply Z_mod_lt. apply two_p_gt_ZERO. omega. Qed. Lemma eqmod_zero_ext: forall x, eqmod (two_p n) (unsigned (zero_ext n x)) (unsigned x). Proof. intros. rewrite zero_ext_mod. apply eqmod_sym. apply eqmod_mod. apply two_p_gt_ZERO. omega. Qed. (** [sign_ext n x] is the unique integer congruent to [x] modulo [2^n] in the range [-2^(n-1)...2^(n-1) - 1]. *) Lemma sign_ext_div: forall x, signed (sign_ext n x) = signed (repr (unsigned x * two_p (Z_of_nat wordsize - n))) / two_p (Z_of_nat wordsize - n). Proof. intros. assert (two_p (Z_of_nat wordsize - n) > 0). apply two_p_gt_ZERO. omega. rewrite sign_ext_shr_shl. rewrite shr_div_two_p. rewrite shl_mul_two_p. unfold mul. repeat rewrite unsigned_repr. rewrite signed_repr. auto. apply Zdiv_interval_2. apply signed_range. generalize min_signed_neg; omega. apply max_signed_pos. auto. generalize wordsize_max_unsigned; omega. assert (two_p (Z_of_nat wordsize - n) < modulus). rewrite modulus_power. apply two_p_monotone_strict. omega. unfold max_unsigned. omega. generalize wordsize_max_unsigned; omega. Qed. Lemma sign_ext_range: forall x, -two_p (n-1) <= signed (sign_ext n x) < two_p (n-1). Proof. intros. assert (two_p (n - 1) > 0). apply two_p_gt_ZERO. omega. rewrite sign_ext_div. apply Zdiv_interval_1. omega. auto. apply two_p_gt_ZERO; omega. rewrite <- Zopp_mult_distr_l. rewrite <- two_p_is_exp. replace (n - 1 + (Z_of_nat wordsize - n)) with (Z_of_nat wordsize - 1) by omega. rewrite <- half_modulus_power. generalize (signed_range (repr (unsigned x * two_p (Z_of_nat wordsize - n)))). unfold min_signed, max_signed. omega. omega. omega. Qed. Lemma eqmod_sign_ext: forall x, eqmod (two_p n) (signed (sign_ext n x)) (unsigned x). Proof. intros. rewrite sign_ext_div. assert (eqm (signed (repr (unsigned x * two_p (Z_of_nat wordsize - n)))) (unsigned x * two_p (Z_of_nat wordsize - n))). eapply eqm_trans. apply eqm_signed_unsigned. apply eqm_sym. apply eqm_unsigned_repr. destruct H as [k EQ]. exists k. rewrite EQ. rewrite Z_div_plus. decEq. replace modulus with (two_p (n + (Z_of_nat wordsize - n))). rewrite two_p_is_exp. rewrite Zmult_assoc. apply Z_div_mult. apply two_p_gt_ZERO; omega. omega. omega. rewrite modulus_power. decEq. omega. apply two_p_gt_ZERO; omega. Qed. Lemma eqmod_sign_ext': forall x, eqmod (two_p n) (unsigned (sign_ext n x)) (unsigned x). Proof. intros. eapply eqmod_trans. apply eqm_eqmod_two_p. auto. apply eqm_sym. apply eqm_signed_unsigned. apply eqmod_sign_ext. Qed. End EXTENSIONS. Theorem zero_ext_widen: forall x n n', 0 < n < Z_of_nat wordsize -> n <= n' < Z_of_nat wordsize -> zero_ext n' (zero_ext n x) = zero_ext n x. Proof. intros. unfold zero_ext. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros; rewrite Zplus_0_r. destruct (zlt i n). rewrite zlt_true. rewrite bits_of_Z_of_bits. apply zlt_true. auto. omega. omega. destruct (zlt i n'); auto. rewrite bits_of_Z_of_bits. apply zlt_false. auto. omega. Qed. Theorem sign_ext_widen: forall x n n', 0 < n < Z_of_nat wordsize -> n <= n' < Z_of_nat wordsize -> sign_ext n' (sign_ext n x) = sign_ext n x. Proof. intros. unfold sign_ext. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros; rewrite Zplus_0_r. destruct (zlt i n). rewrite zlt_true. rewrite bits_of_Z_of_bits. apply zlt_true. auto. omega. omega. destruct (zlt i n'). rewrite bits_of_Z_of_bits. apply zlt_false. auto. omega. rewrite bits_of_Z_of_bits. destruct (zlt (n' - 1) n). assert (n' = n) by omega. congruence. auto. omega. Qed. Theorem sign_zero_ext_widen: forall x n n', 0 < n < Z_of_nat wordsize -> n < n' < Z_of_nat wordsize -> sign_ext n' (zero_ext n x) = zero_ext n x. Proof. intros. unfold sign_ext, zero_ext. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros; rewrite Zplus_0_r. destruct (zlt i n). rewrite zlt_true. rewrite bits_of_Z_of_bits. apply zlt_true. auto. omega. omega. destruct (zlt i n'). rewrite bits_of_Z_of_bits. apply zlt_false. auto. omega. rewrite bits_of_Z_of_bits. apply zlt_false. omega. omega. Qed. Theorem zero_ext_narrow: forall x n n', 0 < n < Z_of_nat wordsize -> n <= n' < Z_of_nat wordsize -> zero_ext n (zero_ext n' x) = zero_ext n x. Proof. intros. unfold zero_ext. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros; rewrite Zplus_0_r. destruct (zlt i n); auto. rewrite bits_of_Z_of_bits; auto. apply zlt_true. omega. Qed. Theorem zero_sign_ext_narrow: forall x n n', 0 < n < Z_of_nat wordsize -> n <= n' < Z_of_nat wordsize -> zero_ext n (sign_ext n' x) = zero_ext n x. Proof. intros. unfold sign_ext, zero_ext. repeat rewrite unsigned_repr; auto with ints. decEq; apply Z_of_bits_exten; intros; rewrite Zplus_0_r. destruct (zlt i n); auto. rewrite bits_of_Z_of_bits; auto. apply zlt_true. omega. Qed. (** ** Properties of [one_bits] (decomposition in sum of powers of two) *) Theorem one_bits_range: forall x i, In i (one_bits x) -> ltu i iwordsize = true. Proof. assert (A: forall p, 0 <= p < Z_of_nat wordsize -> ltu (repr p) iwordsize = true). intros. unfold ltu, iwordsize. apply zlt_true. repeat rewrite unsigned_repr. tauto. generalize wordsize_max_unsigned. omega. generalize wordsize_max_unsigned. omega. intros. unfold one_bits in H. destruct (list_in_map_inv _ _ _ H) as [i0 [EQ IN]]. subst i. apply A. apply Z_one_bits_range with (unsigned x); auto. Qed. Fixpoint int_of_one_bits (l: list int) : int := match l with | nil => zero | a :: b => add (shl one a) (int_of_one_bits b) end. Theorem one_bits_decomp: forall x, x = int_of_one_bits (one_bits x). Proof. intros. transitivity (repr (powerserie (Z_one_bits wordsize (unsigned x) 0))). transitivity (repr (unsigned x)). auto with ints. decEq. apply Z_one_bits_powerserie. auto with ints. unfold one_bits. generalize (Z_one_bits_range (unsigned x)). generalize (Z_one_bits wordsize (unsigned x) 0). induction l. intros; reflexivity. intros; simpl. rewrite <- IHl. unfold add. apply eqm_samerepr. apply eqm_add. rewrite shl_mul_two_p. rewrite mul_commut. rewrite mul_one. apply eqm_unsigned_repr_r. rewrite unsigned_repr. auto with ints. generalize (H a (in_eq _ _)). generalize wordsize_max_unsigned. omega. auto with ints. intros; apply H; auto with coqlib. Qed. (** ** Properties of comparisons *) Theorem negate_cmp: forall c x y, cmp (negate_comparison c) x y = negb (cmp c x y). Proof. intros. destruct c; simpl; try rewrite negb_elim; auto. Qed. Theorem negate_cmpu: forall c x y, cmpu (negate_comparison c) x y = negb (cmpu c x y). Proof. intros. destruct c; simpl; try rewrite negb_elim; auto. Qed. Theorem swap_cmp: forall c x y, cmp (swap_comparison c) x y = cmp c y x. Proof. intros. destruct c; simpl; auto. apply eq_sym. decEq. apply eq_sym. Qed. Theorem swap_cmpu: forall c x y, cmpu (swap_comparison c) x y = cmpu c y x. Proof. intros. destruct c; simpl; auto. apply eq_sym. decEq. apply eq_sym. Qed. Lemma translate_eq: forall x y d, eq (add x d) (add y d) = eq x y. Proof. intros. unfold eq. case (zeq (unsigned x) (unsigned y)); intro. unfold add. rewrite e. apply zeq_true. apply zeq_false. unfold add. red; intro. apply n. apply eqm_small_eq; auto with ints. replace (unsigned x) with ((unsigned x + unsigned d) - unsigned d). replace (unsigned y) with ((unsigned y + unsigned d) - unsigned d). apply eqm_sub. apply eqm_trans with (unsigned (repr (unsigned x + unsigned d))). eauto with ints. apply eqm_trans with (unsigned (repr (unsigned y + unsigned d))). eauto with ints. eauto with ints. eauto with ints. omega. omega. Qed. Lemma translate_ltu: forall x y d, 0 <= unsigned x + unsigned d <= max_unsigned -> 0 <= unsigned y + unsigned d <= max_unsigned -> ltu (add x d) (add y d) = ltu x y. Proof. intros. unfold add. unfold ltu. repeat rewrite unsigned_repr; auto. case (zlt (unsigned x) (unsigned y)); intro. apply zlt_true. omega. apply zlt_false. omega. Qed. Theorem translate_cmpu: forall c x y d, 0 <= unsigned x + unsigned d <= max_unsigned -> 0 <= unsigned y + unsigned d <= max_unsigned -> cmpu c (add x d) (add y d) = cmpu c x y. Proof. intros. unfold cmpu. rewrite translate_eq. repeat rewrite translate_ltu; auto. Qed. Lemma translate_lt: forall x y d, min_signed <= signed x + signed d <= max_signed -> min_signed <= signed y + signed d <= max_signed -> lt (add x d) (add y d) = lt x y. Proof. intros. repeat rewrite add_signed. unfold lt. repeat rewrite signed_repr; auto. case (zlt (signed x) (signed y)); intro. apply zlt_true. omega. apply zlt_false. omega. Qed. Theorem translate_cmp: forall c x y d, min_signed <= signed x + signed d <= max_signed -> min_signed <= signed y + signed d <= max_signed -> cmp c (add x d) (add y d) = cmp c x y. Proof. intros. unfold cmp. rewrite translate_eq. repeat rewrite translate_lt; auto. Qed. Theorem notbool_isfalse_istrue: forall x, is_false x -> is_true (notbool x). Proof. unfold is_false, is_true, notbool; intros; subst x. rewrite eq_true. apply one_not_zero. Qed. Theorem notbool_istrue_isfalse: forall x, is_true x -> is_false (notbool x). Proof. unfold is_false, is_true, notbool; intros. generalize (eq_spec x zero). case (eq x zero); intro. contradiction. auto. Qed. Theorem shru_lt_zero: forall x, shru x (repr (Z_of_nat wordsize - 1)) = if lt x zero then one else zero. Proof. intros. rewrite shru_div_two_p. replace (two_p (unsigned (repr (Z_of_nat wordsize - 1)))) with half_modulus. generalize (unsigned_range x); intro. unfold lt. rewrite signed_zero. unfold signed. destruct (zlt (unsigned x) half_modulus). rewrite zlt_false. replace (unsigned x / half_modulus) with 0. reflexivity. symmetry. apply Zdiv_unique with (unsigned x). ring. omega. omega. rewrite zlt_true. replace (unsigned x / half_modulus) with 1. reflexivity. symmetry. apply Zdiv_unique with (unsigned x - half_modulus). ring. rewrite half_modulus_modulus in H. omega. omega. rewrite unsigned_repr. apply half_modulus_power. generalize wordsize_pos wordsize_max_unsigned; omega. Qed. Theorem ltu_range_test: forall x y, ltu x y = true -> unsigned y <= max_signed -> 0 <= signed x < unsigned y. Proof. intros. unfold ltu in H. destruct (zlt (unsigned x) (unsigned y)); try discriminate. rewrite signed_eq_unsigned. generalize (unsigned_range x). omega. omega. Qed. (** Non-overlapping test *) Definition no_overlap (ofs1: int) (sz1: Z) (ofs2: int) (sz2: Z) : bool := let x1 := unsigned ofs1 in let x2 := unsigned ofs2 in zlt (x1 + sz1) modulus && zlt (x2 + sz2) modulus && (zle (x1 + sz1) x2 || zle (x2 + sz2) x1). Lemma no_overlap_sound: forall ofs1 sz1 ofs2 sz2 base, sz1 > 0 -> sz2 > 0 -> no_overlap ofs1 sz1 ofs2 sz2 = true -> unsigned (add base ofs1) + sz1 <= unsigned (add base ofs2) \/ unsigned (add base ofs2) + sz2 <= unsigned (add base ofs1). Proof. intros. destruct (andb_prop _ _ H1). clear H1. destruct (andb_prop _ _ H2). clear H2. exploit proj_sumbool_true. eexact H1. intro A; clear H1. exploit proj_sumbool_true. eexact H4. intro B; clear H4. assert (unsigned ofs1 + sz1 <= unsigned ofs2 \/ unsigned ofs2 + sz2 <= unsigned ofs1). destruct (orb_prop _ _ H3). left. eapply proj_sumbool_true; eauto. right. eapply proj_sumbool_true; eauto. clear H3. generalize (unsigned_range ofs1) (unsigned_range ofs2). intros P Q. generalize (unsigned_add_either base ofs1) (unsigned_add_either base ofs2). intros [C|C] [D|D]; omega. Qed. End Make. (** * Specialization to integers of size 8, 32, and 64 bits *) Module Wordsize_32. Definition wordsize := 32%nat. Remark wordsize_not_zero: wordsize <> 0%nat. Proof. unfold wordsize; congruence. Qed. End Wordsize_32. Module Int := Make(Wordsize_32). Notation int := Int.int. Remark int_wordsize_divides_modulus: Zdivide (Z_of_nat Int.wordsize) Int.modulus. Proof. exists (two_p (32-5)); reflexivity. Qed. Module Wordsize_8. Definition wordsize := 8%nat. Remark wordsize_not_zero: wordsize <> 0%nat. Proof. unfold wordsize; congruence. Qed. End Wordsize_8. Module Byte := Make(Wordsize_8). Notation byte := Byte.int. Module Wordsize_64. Definition wordsize := 64%nat. Remark wordsize_not_zero: wordsize <> 0%nat. Proof. unfold wordsize; congruence. Qed. End Wordsize_64. Module Int64 := Make(Wordsize_64). Notation int64 := Int64.int.