From 2ae43be7b9d4118335c9d2cef6e098f9b9f807fe Mon Sep 17 00:00:00 2001 From: xleroy Date: Thu, 9 Feb 2006 14:55:48 +0000 Subject: Initial import of compcert git-svn-id: https://yquem.inria.fr/compcert/svn/compcert/trunk@1 fca1b0fc-160b-0410-b1d3-a4f43f01ea2e --- lib/Integers.v | 2184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2184 insertions(+) create mode 100644 lib/Integers.v (limited to 'lib/Integers.v') diff --git a/lib/Integers.v b/lib/Integers.v new file mode 100644 index 00000000..6b605bd7 --- /dev/null +++ b/lib/Integers.v @@ -0,0 +1,2184 @@ +(** Formalizations of integers modulo $2^32$ #232#. *) + +Require Import Coqlib. +Require Import AST. + +Definition wordsize : nat := 32%nat. +Definition modulus : Z := two_power_nat wordsize. +Definition half_modulus : Z := modulus / 2. + +(** * 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. *) + +Definition in_range (x: Z) := + match x ?= 0 with + | Lt => False + | _ => + match x ?= modulus with + | Lt => True + | _ => False + end + end. + +Record int: Set := mkint { intval: Z; intrange: in_range intval }. + +Module Int. + +Definition max_unsigned : Z := modulus - 1. +Definition max_signed : Z := half_modulus - 1. +Definition min_signed : Z := - half_modulus. + +(** 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. + +Lemma mod_in_range: + forall x, in_range (Zmod x modulus). +Proof. + intro. + generalize (Z_mod_lt x modulus (two_power_nat_pos wordsize)). + intros [A B]. + assert (C: x mod modulus >= 0). omega. + red. red in C. red in B. + rewrite B. destruct (x mod modulus ?= 0); auto. +Qed. + +(** Conversely, [repr] takes a Coq integer and returns the corresponding + machine integer. The argument is treated modulo [modulus]. *) + +Definition repr (x: Z) : int := + mkint (Zmod x modulus) (mod_in_range x). + +Definition zero := repr 0. +Definition one := repr 1. +Definition mone := repr (-1). + +Lemma mkint_eq: + forall x y Px Py, x = y -> mkint x Px = mkint y Py. +Proof. + intros. subst y. + generalize (proof_irrelevance _ 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 cast8signed (x: int) : int := + let y := Zmod (unsigned x) 256 in + if zlt y 128 then repr y else repr (y - 256). +Definition cast8unsigned (x: int) : int := + repr (Zmod (unsigned x) 256). +Definition cast16signed (x: int) : int := + let y := Zmod (unsigned x) 65536 in + if zlt y 32768 then repr y else repr (y - 65536). +Definition cast16unsigned (x: int) : int := + repr (Zmod (unsigned x) 65536). + +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). + +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)). + +(** 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. The values of characteristic functions for [i] greater + than 32 are ignored. *) + +Definition Z_shift_add (b: bool) (x: Z) := + if b then 2 * x + 1 else 2 * x. + +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. + +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) {struct n}: Z := + match n with + | O => 0 + | S m => Z_shift_add (f 0) (Z_of_bits m (fun i => f (i + 1))) + 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))). + +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 + let vy := unsigned y in + repr (Z_of_bits wordsize (fun i => fx (i - vy))). + +Definition shru (x y: int): int := + let fx := bits_of_Z wordsize (unsigned x) in + let vy := unsigned y in + repr (Z_of_bits wordsize (fun i => fx (i + vy))). + +(** Arithmetic right shift is defined as signed division by a power of two. + Two such shifts are defined: [shr] rounds towards minus infinity + (standard behaviour for arithmetic right shift) and + [shrx] rounds towards zero. *) + +Definition shr (x y: int): int := + repr (signed x / two_p (unsigned y)). +Definition shrx (x y: int): int := + divs x (shl one y). + +Definition shr_carry (x y: int) := + sub (shrx x y) (shr x y). + +Definition rol (x y: int) : int := + let fx := bits_of_Z wordsize (unsigned x) in + let vy := unsigned y in + repr (Z_of_bits wordsize + (fun i => fx (Zmod (i - vy) (Z_of_nat wordsize)))). + +Definition rolm (x a m: int): int := and (rol x a) m. + +(** 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. + +(** Recognition of integers that are acceptable as immediate operands + to the [rlwim] PowerPC instruction. These integers are of the form + [000011110000] or [111100001111], that is, a run of one bits + surrounded by zero bits, or conversely. We recognize these integers by + running the following automaton on the bits. The accepting states are + 2, 3, 4, 5, and 6. +<< + 0 1 0 + / \ / \ / \ + \ / \ / \ / + -0--> [1] --1--> [2] --0--> [3] + / + [0] + \ + -1--> [4] --0--> [5] --1--> [6] + / \ / \ / \ + \ / \ / \ / + 1 0 1 +>> +*) + +Inductive rlw_state: Set := + | RLW_S0 : rlw_state + | RLW_S1 : rlw_state + | RLW_S2 : rlw_state + | RLW_S3 : rlw_state + | RLW_S4 : rlw_state + | RLW_S5 : rlw_state + | RLW_S6 : rlw_state + | RLW_Sbad : rlw_state. + +Definition rlw_transition (s: rlw_state) (b: bool) : rlw_state := + match s, b with + | RLW_S0, false => RLW_S1 + | RLW_S0, true => RLW_S4 + | RLW_S1, false => RLW_S1 + | RLW_S1, true => RLW_S2 + | RLW_S2, false => RLW_S3 + | RLW_S2, true => RLW_S2 + | RLW_S3, false => RLW_S3 + | RLW_S3, true => RLW_Sbad + | RLW_S4, false => RLW_S5 + | RLW_S4, true => RLW_S4 + | RLW_S5, false => RLW_S5 + | RLW_S5, true => RLW_S6 + | RLW_S6, false => RLW_Sbad + | RLW_S6, true => RLW_S6 + | RLW_Sbad, _ => RLW_Sbad + end. + +Definition rlw_accepting (s: rlw_state) : bool := + match s with + | RLW_S0 => false + | RLW_S1 => false + | RLW_S2 => true + | RLW_S3 => true + | RLW_S4 => true + | RLW_S5 => true + | RLW_S6 => true + | RLW_Sbad => false + end. + +Fixpoint is_rlw_mask_rec (n: nat) (s: rlw_state) (x: Z) {struct n} : bool := + match n with + | O => + rlw_accepting s + | S m => + let (b, y) := Z_bin_decomp x in + is_rlw_mask_rec m (rlw_transition s b) y + end. + +Definition is_rlw_mask (x: int) : bool := + is_rlw_mask_rec wordsize RLW_S0 (unsigned x). + +(** 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 equality *) + +Theorem one_not_zero: Int.one <> Int.zero. +Proof. + compute. congruence. +Qed. + +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. + +(** ** 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. + +(** We then specialize these definitions to equality modulo + $2^32$ #232#. *) + +Lemma modulus_pos: + modulus > 0. +Proof. + unfold modulus. apply two_power_nat_pos. +Qed. +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_samerepr: forall x y, eqm x y -> repr x = repr y. +Proof. + intros. unfold repr. apply mkint_eq. + apply eqmod_mod_eq. auto with ints. exact H. +Qed. + +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_unsigned_repr: + forall z, eqm z (unsigned (repr z)). +Proof. + unfold eqm, repr, unsigned; intros; simpl. + 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. + intro; red; unfold signed. set (y := unsigned x). + case (zlt y half_modulus); intro. + apply eqmod_refl. red; exists (-1); ring. +Qed. + +Lemma in_range_range: + forall z, in_range z -> 0 <= z < modulus. +Proof. + intros. + assert (z >= 0 /\ z < modulus). + generalize H. unfold in_range, Zge, Zlt. + destruct (z ?= 0). + destruct (z ?= modulus); try contradiction. + intuition congruence. + contradiction. + destruct (z ?= modulus); try contradiction. + intuition congruence. + omega. +Qed. + +Theorem unsigned_range: + forall i, 0 <= unsigned i < modulus. +Proof. + destruct i; simpl. + apply in_range_range. 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. assert (min_signed < 0). compute. auto. + omega. + unfold min_signed, max_signed. change modulus with (2 * half_modulus). + change modulus with (2 * half_modulus) in H. omega. +Qed. + +Theorem repr_unsigned: + forall i, repr (unsigned i) = i. +Proof. + destruct i; simpl. unfold repr. apply mkint_eq. + apply Zmod_small. apply in_range_range; 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_unsigned: ints. + +Theorem unsigned_repr: + forall z, 0 <= z <= max_unsigned -> unsigned (repr z) = z. +Proof. + intros. unfold repr, unsigned; simpl. + 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. case (zle 0 z); intro. + replace (unsigned (repr z)) with z. + rewrite zlt_true. auto. unfold max_signed in H. omega. + symmetry. apply unsigned_repr. + split. auto. apply Zle_trans with max_signed. tauto. + compute; intro; discriminate. + 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. + change modulus with (half_modulus + half_modulus). omega. + symmetry. apply unsigned_repr. + unfold z', max_unsigned. unfold min_signed, max_signed in H. + change modulus with (half_modulus + half_modulus). + omega. + apply eqm_samerepr. unfold z'; red. exists 1. omega. +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, zero. change (unsigned (repr 0)) with 0. + rewrite Zplus_0_r. apply repr_unsigned. +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. + +(** ** 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, zero. compute. apply mkint_eq. auto. +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. change (unsigned zero) with 0. + replace (unsigned x - 0) with (unsigned x). apply repr_unsigned. + omega. +Qed. + +Theorem sub_zero_r: forall x, sub zero x = neg x. +Proof. + intros; unfold sub, neg. change (unsigned zero) with 0. + replace (0 - unsigned x) with (- unsigned x). auto. + omega. +Qed. + +Theorem sub_add_opp: forall x y, sub x y = add x (neg y). +Proof. + intros; unfold sub, add, neg. + replace (unsigned x - unsigned y) + with (unsigned x + (- unsigned y)). + apply eqm_samerepr. auto with ints. omega. +Qed. + +Theorem sub_idem: forall x, sub x x = zero. +Proof. + intros; unfold sub. replace (unsigned x - unsigned x) with 0. + reflexivity. 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. + +(** ** 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. change (unsigned zero) with 0. + unfold zero. decEq. ring. +Qed. + +Theorem mul_one: forall x, mul x one = x. +Proof. + intros; unfold mul. change (unsigned one) with 1. + transitivity (repr (unsigned x)). decEq. ring. + apply repr_unsigned. +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. + +Axiom neg_mul_distr_l: forall x y, neg(mul x y) = mul (neg x) y. +Axiom neg_mul_distr_r: forall x y, neg(mul x y) = mul x (neg y). + +(** ** Properties of binary decompositions *) + +Lemma Z_shift_add_bin_decomp: + forall x, + Z_shift_add (fst (Z_bin_decomp x)) (snd (Z_bin_decomp x)) = x. +Proof. + destruct x; simpl. + auto. + destruct p; reflexivity. + destruct p; try reflexivity. simpl. + assert (forall z, 2 * (z + 1) - 1 = 2 * z + 1). intro; omega. + generalize (H (Zpos p)); simpl. congruence. +Qed. + +Lemma Z_shift_add_inj: + forall b1 x1 b2 x2, + Z_shift_add b1 x1 = Z_shift_add b2 x2 -> b1 = b2 /\ x1 = x2. +Proof. + intros until x2. + unfold Z_shift_add. + destruct b1; destruct b2; intros; + ((split; [reflexivity|omega]) || omegaContradiction). +Qed. + +Lemma Z_of_bits_exten: + forall n f1 f2, + (forall z, 0 <= z < Z_of_nat n -> f1 z = f2 z) -> + Z_of_bits n f1 = Z_of_bits n f2. +Proof. + induction n; intros. + reflexivity. + simpl. rewrite inj_S in H. decEq. apply H. omega. + apply IHn. intros; apply H. omega. +Qed. + +Opaque Zmult. + +Lemma Z_of_bits_of_Z: + forall x, eqm (Z_of_bits wordsize (bits_of_Z wordsize x)) x. +Proof. + assert (forall n x, exists k, + Z_of_bits n (bits_of_Z n x) = k * two_power_nat n + x). + induction n; intros. + rewrite two_power_nat_O. simpl. exists (-x). omega. + rewrite two_power_nat_S. simpl. + caseEq (Z_bin_decomp x). intros b y ZBD. simpl. + replace (Z_of_bits n (fun i => if zeq (i + 1) 0 then b else bits_of_Z n y (i + 1 - 1))) + with (Z_of_bits n (bits_of_Z n y)). + elim (IHn y). intros k1 EQ1. rewrite EQ1. + rewrite <- (Z_shift_add_bin_decomp x). + rewrite ZBD. simpl. + exists k1. + case b; unfold Z_shift_add; 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. + case (zeq x 0); intro. auto. 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. + generalize (Z_shift_add_bin_decomp (2 * x - 1)). + rewrite EQ; simpl. + replace (2 * x - 1) with (Z_shift_add true (x - 1)). + intro. elim (Z_shift_add_inj _ _ _ _ H); intros. + congruence. unfold Z_shift_add. omega. +Qed. + +Lemma bits_of_Z_mone: + forall n x, + 0 <= x < Z_of_nat n -> + bits_of_Z n (two_power_nat n - 1) x = true. +Proof. + induction n; intros. + simpl in H. omegaContradiction. + unfold bits_of_Z; fold bits_of_Z. + rewrite two_power_nat_S. rewrite Z_bin_decomp_2xm1. + rewrite inj_S in H. case (zeq x 0); intro. auto. + apply IHn. omega. +Qed. + +Lemma Z_bin_decomp_shift_add: + forall b x, Z_bin_decomp (Z_shift_add b x) = (b, x). +Proof. + intros. caseEq (Z_bin_decomp (Z_shift_add b x)); intros b' x' EQ. + generalize (Z_shift_add_bin_decomp (Z_shift_add b x)). + rewrite EQ; simpl fst; simpl snd. intro. + elim (Z_shift_add_inj _ _ _ _ H); intros. + congruence. +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) i = f i. +Proof. + induction n; intros; simpl. + simpl in H. omegaContradiction. + rewrite Z_bin_decomp_shift_add. + case (zeq i 0); intro. + congruence. + rewrite IHn. decEq. omega. rewrite inj_S in H. omega. +Qed. + +Lemma Z_of_bits_range: + forall f, 0 <= Z_of_bits wordsize f < modulus. +Proof. + unfold max_unsigned, modulus. + generalize wordsize. induction n; simpl; intros. + rewrite two_power_nat_O. omega. + rewrite two_power_nat_S. generalize (IHn (fun i => f (i + 1))). + set (x := Z_of_bits n (fun i => f (i + 1))). + intro. destruct (f 0); unfold Z_shift_add; omega. +Qed. +Hint Resolve Z_of_bits_range: ints. + +Lemma Z_of_bits_range_2: + forall f, 0 <= Z_of_bits wordsize f <= max_unsigned. +Proof. + intros. unfold max_unsigned. + generalize (Z_of_bits_range f). omega. +Qed. +Hint Resolve Z_of_bits_range_2: ints. + +Lemma bits_of_Z_below: + forall n x i, i < 0 -> bits_of_Z n x i = false. +Proof. + induction n; simpl; intros. + reflexivity. + 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. + reflexivity. + destruct (Z_bin_decomp x). rewrite zeq_false. apply IHn. + rewrite inj_S in H. omega. rewrite inj_S in H. omega. +Qed. + +Opaque Zmult. + +Lemma Z_of_bits_excl: + forall n f g h, + (forall i, 0 <= i < Z_of_nat n -> f i && g i = false) -> + (forall i, 0 <= i < Z_of_nat n -> f i || g i = h i) -> + Z_of_bits n f + Z_of_bits n g = Z_of_bits n h. +Proof. + induction n. + intros; reflexivity. + intros. simpl. rewrite inj_S in H. rewrite inj_S in H0. + rewrite <- (IHn (fun i => f(i+1)) (fun i => g(i+1)) (fun i => h(i+1))). + assert (0 <= 0 < Zsucc(Z_of_nat n)). omega. + unfold Z_shift_add. + rewrite <- H0; auto. + set (F := Z_of_bits n (fun i => f(i + 1))). + set (G := Z_of_bits n (fun i => g(i + 1))). + caseEq (f 0); intros; caseEq (g 0); intros; simpl. + generalize (H 0 H1). rewrite H2; rewrite H3. simpl. intros; discriminate. + omega. omega. omega. + intros; apply H. omega. + intros; apply H0. omega. +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 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. + transitivity (repr (Z_of_bits wordsize (bits_of_Z wordsize (unsigned x)))). + decEq. apply Z_of_bits_exten; intros. auto. + transitivity (repr (unsigned x)). + apply eqm_samerepr. apply Z_of_bits_of_Z. apply repr_unsigned. +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. + unfold and, bitwise_binop, zero; intros. + transitivity (repr (Z_of_bits wordsize (bits_of_Z wordsize 0))). + decEq. apply Z_of_bits_exten. intros. + change (unsigned (repr 0)) with 0. + rewrite bits_of_Z_zero. apply andb_b_false. + auto with ints. +Qed. + +Lemma mone_max_unsigned: + mone = repr max_unsigned. +Proof. + unfold mone. apply eqm_samerepr. exists (-1). + unfold max_unsigned. omega. +Qed. + +Theorem and_mone: forall x, and x mone = x. +Proof. + unfold and, bitwise_binop; intros. + rewrite mone_max_unsigned. unfold max_unsigned, modulus. + transitivity (repr (Z_of_bits wordsize (bits_of_Z wordsize (unsigned x)))). + decEq. apply Z_of_bits_exten. intros. + rewrite unsigned_repr. rewrite bits_of_Z_mone. + apply andb_b_true. omega. compute. intuition congruence. + transitivity (repr (unsigned x)). + apply eqm_samerepr. apply Z_of_bits_of_Z. + apply repr_unsigned. +Qed. + +Theorem and_idem: forall x, and x x = x. +Proof. + assert (forall b, b && b = b). + destruct b; reflexivity. + exact (bitwise_binop_idem andb H). +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. + unfold or, bitwise_binop, zero; intros. + transitivity (repr (Z_of_bits wordsize (bits_of_Z wordsize (unsigned x)))). + decEq. apply Z_of_bits_exten. intros. + change (unsigned (repr 0)) with 0. + rewrite bits_of_Z_zero. apply orb_b_false. + transitivity (repr (unsigned x)); auto with ints. + apply eqm_samerepr. apply Z_of_bits_of_Z. +Qed. + +Theorem or_mone: forall x, or x mone = mone. +Proof. + rewrite mone_max_unsigned. + unfold or, bitwise_binop; intros. + decEq. + transitivity (Z_of_bits wordsize (bits_of_Z wordsize max_unsigned)). + apply Z_of_bits_exten. intros. + change (unsigned (repr max_unsigned)) with max_unsigned. + unfold max_unsigned, modulus. rewrite bits_of_Z_mone; auto. + apply orb_b_true. + apply eqm_small_eq; auto with ints. compute; intuition congruence. +Qed. + +Theorem or_idem: forall x, or x x = x. +Proof. + assert (forall b, b || b = b). + destruct b; reflexivity. + exact (bitwise_binop_idem orb H). +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. + decEq. repeat rewrite unsigned_repr; auto with ints. + apply Z_of_bits_exten; intros. + repeat rewrite bits_of_Z_of_bits; 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. + assert (forall a b c, xorb a (xorb b c) = xorb (xorb a b) c). + symmetry. apply xorb_assoc. + exact (bitwise_binop_assoc xorb H). +Qed. + +Theorem xor_zero: forall x, xor x zero = x. +Proof. + unfold xor, bitwise_binop, zero; intros. + transitivity (repr (Z_of_bits wordsize (bits_of_Z wordsize (unsigned x)))). + decEq. apply Z_of_bits_exten. intros. + change (unsigned (repr 0)) with 0. + rewrite bits_of_Z_zero. apply xorb_false. + transitivity (repr (unsigned x)); auto with ints. + apply eqm_samerepr. apply Z_of_bits_of_Z. +Qed. + +Theorem xor_zero_one: xor zero one = one. +Proof. reflexivity. Qed. + +Theorem xor_one_one: xor one one = zero. +Proof. reflexivity. 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. + decEq. repeat rewrite unsigned_repr; auto with ints. + apply Z_of_bits_exten; intros. + repeat rewrite bits_of_Z_of_bits; 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 shifts and rotates *) + +Lemma Z_of_bits_shift: + forall n f, + exists k, + Z_of_bits n (fun i => f (i - 1)) = + k * two_power_nat n + Z_shift_add (f (-1)) (Z_of_bits n f). +Proof. + induction n; intros. + simpl. rewrite two_power_nat_O. unfold Z_shift_add. + exists (if f (-1) then (-1) else 0). + destruct (f (-1)); omega. + rewrite two_power_nat_S. simpl. + elim (IHn (fun i => f (i + 1))). intros k' EQ. + replace (Z_of_bits n (fun i => f (i - 1 + 1))) + with (Z_of_bits n (fun i => f (i + 1 - 1))) in EQ. + rewrite EQ. + change (-1 + 1) with 0. + exists k'. + unfold Z_shift_add; destruct (f (-1)); destruct (f 0); ring. + apply Z_of_bits_exten; intros. + decEq. omega. +Qed. + +Lemma Z_of_bits_shifts: + forall m f, + 0 <= m -> + (forall i, i < 0 -> f i = false) -> + eqm (Z_of_bits wordsize (fun i => f (i - m))) + (two_p m * Z_of_bits wordsize f). +Proof. + intros. pattern m. apply natlike_ind. + apply eqm_refl2. transitivity (Z_of_bits wordsize f). + apply Z_of_bits_exten; intros. decEq. omega. + simpl two_p. omega. + intros. rewrite two_p_S; auto. + set (f' := fun i => f (i - x)). + apply eqm_trans with (Z_of_bits wordsize (fun i => f' (i - 1))). + apply eqm_refl2. apply Z_of_bits_exten; intros. + unfold f'. decEq. omega. + apply eqm_trans with (Z_shift_add (f' (-1)) (Z_of_bits wordsize f')). + exact (Z_of_bits_shift wordsize f'). + unfold f'. unfold Z_shift_add. rewrite H0. + rewrite <- Zmult_assoc. apply eqm_mult. apply eqm_refl. + apply H2. omega. assumption. +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_shifts. + 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_zero: forall x, shl x zero = x. +Proof. + intros. rewrite shl_mul_two_p. + change (repr (two_p (unsigned zero))) with one. + apply mul_one. +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 shl_rolm: + forall x n, + ltu n (repr (Z_of_nat wordsize)) = true -> + shl x n = rolm x n (shl mone n). +Proof. + intros x n. unfold ltu. + rewrite unsigned_repr. case (zlt (unsigned n) (Z_of_nat wordsize)); intros LT XX. + unfold shl, rolm, rol, and, bitwise_binop. + decEq. apply Z_of_bits_exten; intros. + repeat rewrite unsigned_repr; auto with ints. + repeat rewrite bits_of_Z_of_bits; auto. + case (zlt z (unsigned n)); intro LT2. + assert (z - unsigned n < 0). omega. + rewrite (bits_of_Z_below wordsize (unsigned x) _ H0). + rewrite (bits_of_Z_below wordsize (unsigned mone) _ H0). + symmetry. apply andb_b_false. + assert (z - unsigned n < Z_of_nat wordsize). + generalize (unsigned_range n). omega. + replace (unsigned mone) with (two_power_nat wordsize - 1). + rewrite bits_of_Z_mone. rewrite andb_b_true. decEq. + rewrite Zmod_small. auto. omega. omega. + rewrite mone_max_unsigned. reflexivity. + discriminate. + compute; intuition congruence. +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. + decEq. repeat rewrite unsigned_repr; auto with ints. + apply Z_of_bits_exten; intros. + case (zlt (z - unsigned n) 0); intro. + transitivity false. repeat rewrite bits_of_Z_of_bits; auto. + repeat rewrite bits_of_Z_below; auto. + rewrite bits_of_Z_below; auto. + repeat rewrite bits_of_Z_of_bits; auto. + generalize (unsigned_range n). omega. +Qed. + +Lemma 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 shru_rolm: + forall x n, + ltu n (repr (Z_of_nat wordsize)) = true -> + shru x n = rolm x (sub (repr (Z_of_nat wordsize)) n) (shru mone n). +Proof. + intros x n. unfold ltu. + rewrite unsigned_repr. + case (zlt (unsigned n) (Z_of_nat wordsize)); intros LT XX. + unfold shru, rolm, rol, and, bitwise_binop. + decEq. apply Z_of_bits_exten; intros. + repeat rewrite unsigned_repr; auto with ints. + repeat rewrite bits_of_Z_of_bits; auto. + unfold sub. + change (unsigned (repr (Z_of_nat wordsize))) + with (Z_of_nat wordsize). + rewrite unsigned_repr. + case (zlt (z + unsigned n) (Z_of_nat wordsize)); intro LT2. + replace (unsigned mone) with (two_power_nat wordsize - 1). + rewrite bits_of_Z_mone. rewrite andb_b_true. + decEq. + replace (z - (Z_of_nat wordsize - unsigned n)) + with ((z + unsigned n) + (-1) * Z_of_nat wordsize). + rewrite Z_mod_plus. symmetry. apply Zmod_small. + generalize (unsigned_range n). omega. omega. omega. + generalize (unsigned_range n). omega. + reflexivity. + 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. compute; intuition congruence. + discriminate. + split. omega. compute; intuition congruence. +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. + decEq. repeat rewrite unsigned_repr; auto with ints. + apply Z_of_bits_exten; intros. + case (zlt (z + unsigned n) (Z_of_nat wordsize)); intro. + repeat rewrite bits_of_Z_of_bits; auto. + generalize (unsigned_range n); omega. + transitivity false. repeat rewrite bits_of_Z_of_bits; auto. + repeat rewrite bits_of_Z_above; auto. + rewrite bits_of_Z_above; auto. +Qed. + +Lemma 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 rol_zero: + forall x, + rol x zero = x. +Proof. + intros. unfold rol. transitivity (repr (Z_of_bits wordsize (bits_of_Z wordsize (unsigned x)))). + decEq. + transitivity (repr (unsigned x)). + decEq. apply eqm_small_eq. apply Z_of_bits_of_Z. + auto with ints. auto with ints. auto with ints. +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. + decEq. repeat (rewrite unsigned_repr; auto with ints). + apply Z_of_bits_exten; intros. + repeat rewrite bits_of_Z_of_bits; auto. + apply Z_mod_lt. compute. auto. +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_rol: + forall x n m, + rol (rol x n) m = rol x (modu (add n m) (repr (Z_of_nat wordsize))). +Proof. + intros. unfold rol. decEq. + repeat (rewrite unsigned_repr; auto with ints). + apply Z_of_bits_exten; intros. + repeat rewrite bits_of_Z_of_bits; auto. + decEq. unfold modu, add. + set (W := Z_of_nat wordsize). + set (M := unsigned m); set (N := unsigned n). + assert (W > 0). compute; auto. + assert (forall a, eqmod W a (unsigned (repr a))). + intro. elim (eqm_unsigned_repr a). intros k EQ. + red. exists (k * (modulus / W)). + replace (k * (modulus / W) * W) with (k * modulus). auto. + rewrite <- Zmult_assoc. reflexivity. + apply eqmod_mod_eq. auto. + change (unsigned (repr W)) with W. + apply eqmod_trans with (z - (N + M) mod W). + apply eqmod_trans with ((z - M) - N). + apply eqmod_sub. apply eqmod_sym. apply eqmod_mod. auto. + apply eqmod_refl. + replace (z - M - N) with (z - (N + M)). + apply eqmod_sub. apply eqmod_refl. apply eqmod_mod. auto. + omega. + apply eqmod_sub. apply eqmod_refl. + eapply eqmod_trans; [idtac|apply H1]. + eapply eqmod_trans; [idtac|apply eqmod_mod]. + apply eqmod_sym. eapply eqmod_trans; [idtac|apply eqmod_mod]. + apply eqmod_sym. apply H1. auto. auto. + apply Z_mod_lt. compute; auto. +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, + rolm (rolm x n1 m1) n2 m2 = + rolm x (modu (add n1 n2) (repr (Z_of_nat wordsize))) + (and (rol m1 n2) m2). +Proof. + intros. + unfold rolm. rewrite rol_and. rewrite and_assoc. + rewrite rol_rol. reflexivity. +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 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. + +(** ** Relation between shifts and powers of 2 *) + +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_shift_add_bin_decomp x) in H. + unfold Z_shift_add 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. + generalize (Z_shift_add_bin_decomp x). + generalize (Z_bin_decomp_range x _ H0). + case (Z_bin_decomp x). simpl. intros b y RANGE SHADD. + subst x. unfold Z_shift_add. + destruct b. simpl powerserie. rewrite <- IHn. + rewrite two_p_is_exp. change (two_p 1) with 2. ring. + auto. omega. omega. auto. + rewrite <- IHn. + rewrite two_p_is_exp. change (two_p 1) with 2. ring. + auto. omega. omega. auto. + 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. + assert (Z_of_nat wordsize < max_unsigned). compute. auto. + omega. + intros; discriminate. +Qed. + +Theorem is_power2_range: + forall n logn, + is_power2 n = Some logn -> ltu logn (repr (Z_of_nat wordsize)) = true. +Proof. + intros. unfold ltu. + change (unsigned (repr (Z_of_nat wordsize))) with (Z_of_nat 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. + assert (Z_of_nat wordsize < max_unsigned). compute; auto. + omega. auto with coqlib. + intros; discriminate. +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. + +Lemma Z_of_bits_shift_rev: + forall n f, + (forall i, i >= Z_of_nat n -> f i = false) -> + Z_of_bits n f = Z_shift_add (f 0) (Z_of_bits n (fun i => f(i + 1))). +Proof. + induction n; intros. + simpl. rewrite H. reflexivity. unfold Z_of_nat. omega. + simpl. rewrite (IHn (fun i => f (i + 1))). + reflexivity. + intros. apply H. rewrite inj_S. omega. +Qed. + +Lemma Z_of_bits_shifts_rev: + forall m f, + 0 <= m -> + (forall i, i >= Z_of_nat wordsize -> f i = false) -> + exists k, + Z_of_bits wordsize f = k + two_p m * Z_of_bits wordsize (fun i => f(i + m)) + /\ 0 <= k < two_p m. +Proof. + intros. pattern m. apply natlike_ind. + exists 0. change (two_p 0) with 1. split. + transitivity (Z_of_bits wordsize (fun i => f (i + 0))). + apply Z_of_bits_exten. intros. decEq. omega. + omega. omega. + intros x POSx [k [EQ1 RANGE1]]. + set (f' := fun i => f (i + x)) in *. + assert (forall i, i >= Z_of_nat wordsize -> f' i = false). + intros. unfold f'. apply H0. omega. + generalize (Z_of_bits_shift_rev wordsize f' H1). intro. + rewrite EQ1. rewrite H2. + set (z := Z_of_bits wordsize (fun i => f (i + Zsucc x))). + replace (Z_of_bits wordsize (fun i => f' (i + 1))) with z. + rewrite two_p_S. + case (f' 0); unfold Z_shift_add. + exists (k + two_p x). split. ring. omega. + exists k. split. ring. omega. + auto. + unfold z. apply Z_of_bits_exten; intros. unfold f'. + decEq. omega. + auto. +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). + elim (Z_of_bits_shifts_rev y' (bits_of_Z wordsize x')). + intros k [EQ RANGE]. + replace (Z_of_bits wordsize (bits_of_Z wordsize x')) with x' in EQ. + rewrite Zplus_comm in EQ. rewrite Zmult_comm in EQ. + generalize (Zdiv_unique _ _ _ _ EQ RANGE). intros. + rewrite H. auto. + apply eqm_small_eq. apply eqm_sym. apply Z_of_bits_of_Z. + unfold x'. apply unsigned_range. + auto with ints. + generalize (unsigned_range y). unfold y'. omega. + intros. apply bits_of_Z_above. auto. +Qed. + +Theorem shru_zero: + forall x, shru x zero = x. +Proof. + intros. rewrite shru_div_two_p. change (two_p (unsigned zero)) with 1. + transitivity (repr (unsigned x)). decEq. apply Zdiv_unique with 0. + omega. omega. auto with ints. +Qed. + +Theorem shr_zero: + forall x, shr x zero = x. +Proof. + intros. unfold shr. change (two_p (unsigned zero)) with 1. + replace (signed x / 1) with (signed x). + apply repr_signed. + symmetry. apply Zdiv_unique with 0. omega. omega. +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. + +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 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. + +Theorem shrx_carry: + forall x y, + add (shr x y) (shr_carry x y) = shrx x y. +Proof. + intros. unfold shr_carry. + rewrite sub_add_opp. rewrite add_permut. + rewrite add_neg_zero. apply add_zero. +Qed. + +Lemma add_and: + forall x y z, + and y z = zero -> + or y z = mone -> + add (and x y) (and x z) = x. +Proof. + intros. unfold add. transitivity (repr (unsigned x)); auto with ints. + decEq. unfold and, bitwise_binop. + repeat rewrite unsigned_repr; auto with ints. + transitivity (Z_of_bits wordsize (bits_of_Z wordsize (unsigned x))). + apply Z_of_bits_excl. intros. + assert (forall a b c, a && b && (a && c) = a && (b && c)). + destruct a; destruct b; destruct c; reflexivity. + rewrite H2. + replace (bits_of_Z wordsize (unsigned y) i && + bits_of_Z wordsize (unsigned z) i) + with (bits_of_Z wordsize (unsigned (and y z)) i). + rewrite H. change (unsigned zero) with 0. + rewrite bits_of_Z_zero. apply andb_b_false. + unfold and, bitwise_binop. + rewrite unsigned_repr; auto with ints. rewrite bits_of_Z_of_bits. + reflexivity. auto. + intros. rewrite <- demorgan1. + replace (bits_of_Z wordsize (unsigned y) i || + bits_of_Z wordsize (unsigned z) i) + with (bits_of_Z wordsize (unsigned (or y z)) i). + rewrite H0. change (unsigned mone) with (two_power_nat wordsize - 1). + rewrite bits_of_Z_mone; auto. apply andb_b_true. + unfold or, bitwise_binop. + rewrite unsigned_repr; auto with ints. rewrite bits_of_Z_of_bits; auto. + apply eqm_small_eq; auto with ints. apply Z_of_bits_of_Z. +Qed. + +(** To prove equalities involving modulus and bitwise ``and'', we need to + show complicated integer equalities involving one integer variable + that ranges between 0 and 31. Rather than proving these equalities, + we ask Coq to check them by computing the 32 values of the + left and right-hand sides and checking that they are equal. + This is an instance of proving by reflection. *) + +Section REFLECTION. + +Variables (f g: int -> int). + +Fixpoint check_equal_on_range (n: nat) : bool := + match n with + | O => true + | S n => if eq (f (repr (Z_of_nat n))) (g (repr (Z_of_nat n))) + then check_equal_on_range n + else false + end. + +Lemma check_equal_on_range_correct: + forall n, + check_equal_on_range n = true -> + forall z, 0 <= z < Z_of_nat n -> f (repr z) = g (repr z). +Proof. + induction n. + simpl; intros; omegaContradiction. + simpl check_equal_on_range. + set (fn := f (repr (Z_of_nat n))). + set (gn := g (repr (Z_of_nat n))). + generalize (eq_spec fn gn). + case (eq fn gn); intros. + rewrite inj_S in H1. + assert (0 <= z < Z_of_nat n \/ z = Z_of_nat n). omega. + elim H2; intro. + apply IHn. auto. auto. + subst z; auto. + discriminate. +Qed. + +Lemma equal_on_range: + check_equal_on_range wordsize = true -> + forall n, 0 <= unsigned n < Z_of_nat wordsize -> + f n = g n. +Proof. + intros. replace n with (repr (unsigned n)). + apply check_equal_on_range_correct with wordsize; auto. + apply repr_unsigned. +Qed. + +End REFLECTION. + +(** Here are the three equalities that we prove by reflection. *) + +Remark modu_and_masks_1: + forall logn, 0 <= unsigned logn < Z_of_nat wordsize -> + rol (shru mone logn) logn = shl mone logn. +Proof (equal_on_range + (fun l => rol (shru mone l) l) + (fun l => shl mone l) + (refl_equal true)). +Remark modu_and_masks_2: + forall logn, 0 <= unsigned logn < Z_of_nat wordsize -> + and (shl mone logn) (sub (repr (two_p (unsigned logn))) one) = zero. +Proof (equal_on_range + (fun l => and (shl mone l) + (sub (repr (two_p (unsigned l))) one)) + (fun l => zero) + (refl_equal true)). +Remark modu_and_masks_3: + forall logn, 0 <= unsigned logn < Z_of_nat wordsize -> + or (shl mone logn) (sub (repr (two_p (unsigned logn))) one) = mone. +Proof (equal_on_range + (fun l => or (shl mone l) + (sub (repr (two_p (unsigned l))) one)) + (fun l => mone) + (refl_equal true)). + +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. + assert (n <> zero). + red; intro. subst n. change (unsigned zero) with 0 in H0. + assert (two_p (unsigned logn) > 0). apply two_p_gt_ZERO. omega. + omegaContradiction. + generalize (modu_divu_Euclid x n H2); intro. + assert (forall a b c, add a b = add a c -> b = c). + intros. assert (sub (add a b) a = sub (add a c) a). congruence. + repeat rewrite sub_add_l in H5. repeat rewrite sub_idem in H5. + rewrite add_commut in H5; rewrite add_zero in H5. + rewrite add_commut in H5; rewrite add_zero in H5. + auto. + apply H4 with (mul (divu x n) n). + rewrite <- H3. + rewrite (divu_pow2 x n logn H). + rewrite (mul_pow2 (shru x logn) n logn H). + rewrite shru_rolm. rewrite shl_rolm. rewrite rolm_rolm. + rewrite sub_add_opp. rewrite add_assoc. + replace (add (neg logn) logn) with zero. + rewrite add_zero. + change (modu (repr (Z_of_nat wordsize)) (repr (Z_of_nat wordsize))) + with zero. + rewrite rolm_zero. + symmetry. + replace n with (repr (two_p (unsigned logn))). + rewrite modu_and_masks_1; auto. + rewrite and_idem. + apply add_and. apply modu_and_masks_2; auto. apply modu_and_masks_3; auto. + transitivity (repr (unsigned n)). decEq. auto. auto with ints. + rewrite add_commut. rewrite add_neg_zero. auto. + unfold ltu. apply zlt_true. + change (unsigned (repr (Z_of_nat wordsize))) with (Z_of_nat wordsize). + omega. + unfold ltu. apply zlt_true. + change (unsigned (repr (Z_of_nat wordsize))) with (Z_of_nat wordsize). + omega. +Qed. + +(** ** Properties of integer zero extension and sign extension. *) + +Theorem cast8unsigned_and: + forall x, cast8unsigned x = and x (repr 255). +Proof. + intros; unfold cast8unsigned. + change (repr (unsigned x mod 256)) with (modu x (repr 256)). + change (repr 255) with (sub (repr 256) one). + apply modu_and with (repr 8). reflexivity. +Qed. + +Theorem cast16unsigned_and: + forall x, cast16unsigned x = and x (repr 65535). +Proof. + intros; unfold cast16unsigned. + change (repr (unsigned x mod 65536)) with (modu x (repr 65536)). + change (repr 65535) with (sub (repr 65536) one). + apply modu_and with (repr 16). reflexivity. +Qed. + +Lemma eqmod_256_unsigned_repr: + forall a, eqmod 256 a (unsigned (repr a)). +Proof. + intros. generalize (eqm_unsigned_repr a). unfold eqm, eqmod. + intros [k EQ]. exists (k * (modulus / 256)). + replace (k * (modulus / 256) * 256) + with (k * ((modulus / 256) * 256)). + exact EQ. ring. +Qed. + +Lemma eqmod_65536_unsigned_repr: + forall a, eqmod 65536 a (unsigned (repr a)). +Proof. + intros. generalize (eqm_unsigned_repr a). unfold eqm, eqmod. + intros [k EQ]. exists (k * (modulus / 65536)). + replace (k * (modulus / 65536) * 65536) + with (k * ((modulus / 65536) * 65536)). + exact EQ. ring. +Qed. + +Theorem cast8_signed_unsigned: + forall n, cast8signed (cast8unsigned n) = cast8signed n. +Proof. + intros; unfold cast8signed, cast8unsigned. + set (N := unsigned n). + rewrite unsigned_repr. + replace ((N mod 256) mod 256) with (N mod 256). + auto. + symmetry. apply Zmod_small. apply Z_mod_lt. omega. + assert (0 <= N mod 256 < 256). apply Z_mod_lt. omega. + assert (256 < max_unsigned). compute; auto. + omega. +Qed. + +Theorem cast8_unsigned_signed: + forall n, cast8unsigned (cast8signed n) = cast8unsigned n. +Proof. + intros; unfold cast8signed, cast8unsigned. + set (N := unsigned n mod 256). + assert (0 <= N < 256). unfold N; apply Z_mod_lt. omega. + assert (N mod 256 = N). apply Zmod_small. auto. + assert (256 <= max_unsigned). compute; congruence. + decEq. + case (zlt N 128); intro. + rewrite unsigned_repr. auto. omega. + transitivity (N mod 256); auto. + apply eqmod_mod_eq. omega. + apply eqmod_trans with (N - 256). apply eqmod_sym. apply eqmod_256_unsigned_repr. + assert (eqmod 256 (N - 256) (N - 0)). + apply eqmod_sub. apply eqmod_refl. + red. exists 1; reflexivity. + replace (N - 0) with N in H2. auto. omega. +Qed. + +Theorem cast16_unsigned_signed: + forall n, cast16unsigned (cast16signed n) = cast16unsigned n. +Proof. + intros; unfold cast16signed, cast16unsigned. + set (N := unsigned n mod 65536). + assert (0 <= N < 65536). unfold N; apply Z_mod_lt. omega. + assert (N mod 65536 = N). apply Zmod_small. auto. + assert (65536 <= max_unsigned). compute; congruence. + decEq. + case (zlt N 32768); intro. + rewrite unsigned_repr. auto. omega. + transitivity (N mod 65536); auto. + apply eqmod_mod_eq. omega. + apply eqmod_trans with (N - 65536). apply eqmod_sym. apply eqmod_65536_unsigned_repr. + assert (eqmod 65536 (N - 65536) (N - 0)). + apply eqmod_sub. apply eqmod_refl. + red. exists 1; reflexivity. + replace (N - 0) with N in H2. auto. omega. +Qed. + +Theorem cast8_unsigned_idem: + forall n, cast8unsigned (cast8unsigned n) = cast8unsigned n. +Proof. + intros. repeat rewrite cast8unsigned_and. + rewrite and_assoc. reflexivity. +Qed. + +Theorem cast16_unsigned_idem: + forall n, cast16unsigned (cast16unsigned n) = cast16unsigned n. +Proof. + intros. repeat rewrite cast16unsigned_and. + rewrite and_assoc. reflexivity. +Qed. + +Theorem cast8_signed_idem: + forall n, cast8signed (cast8signed n) = cast8signed n. +Proof. + intros; unfold cast8signed. + set (N := unsigned n mod 256). + assert (256 < max_unsigned). compute; auto. + assert (0 <= N < 256). unfold N. apply Z_mod_lt. omega. + case (zlt N 128); intro. + assert (unsigned (repr N) = N). + apply unsigned_repr. omega. + rewrite H1. + replace (N mod 256) with N. apply zlt_true. auto. + symmetry. apply Zmod_small. auto. + set (M := (unsigned (repr (N - 256)) mod 256)). + assert (M = N). + unfold M, N. apply eqmod_mod_eq. omega. + apply eqmod_trans with (unsigned n mod 256 - 256). + apply eqmod_sym. apply eqmod_256_unsigned_repr. + apply eqmod_trans with (unsigned n - 0). + apply eqmod_sub. + apply eqmod_sym. apply eqmod_mod. omega. + unfold eqmod. exists 1; omega. + apply eqmod_refl2. omega. + rewrite H1. rewrite zlt_false; auto. +Qed. + +Theorem cast16_signed_idem: + forall n, cast16signed (cast16signed n) = cast16signed n. +Proof. + intros; unfold cast16signed. + set (N := unsigned n mod 65536). + assert (65536 < max_unsigned). compute; auto. + assert (0 <= N < 65536). unfold N. apply Z_mod_lt. omega. + case (zlt N 32768); intro. + assert (unsigned (repr N) = N). + apply unsigned_repr. omega. + rewrite H1. + replace (N mod 65536) with N. apply zlt_true. auto. + symmetry. apply Zmod_small. auto. + set (M := (unsigned (repr (N - 65536)) mod 65536)). + assert (M = N). + unfold M, N. apply eqmod_mod_eq. omega. + apply eqmod_trans with (unsigned n mod 65536 - 65536). + apply eqmod_sym. apply eqmod_65536_unsigned_repr. + apply eqmod_trans with (unsigned n - 0). + apply eqmod_sub. + apply eqmod_sym. apply eqmod_mod. omega. + unfold eqmod. exists 1; omega. + apply eqmod_refl2. omega. + rewrite H1. rewrite zlt_false; auto. +Qed. + +Theorem cast8_signed_equal_if_unsigned_equal: + forall x y, + cast8unsigned x = cast8unsigned y -> + cast8signed x = cast8signed y. +Proof. + unfold cast8unsigned, cast8signed; intros until y. + set (x' := unsigned x mod 256). + set (y' := unsigned y mod 256). + intro. + assert (eqm x' y'). + apply eqm_trans with (unsigned (repr x')). apply eqm_unsigned_repr. + rewrite H. apply eqm_sym. apply eqm_unsigned_repr. + assert (forall z, 0 <= z mod 256 < modulus). + intros. + assert (0 <= z mod 256 < 256). apply Z_mod_lt. omega. + assert (256 <= modulus). compute. congruence. + omega. + assert (x' = y'). + apply eqm_small_eq; unfold x', y'; auto. + rewrite H2. auto. +Qed. + +Theorem cast16_signed_equal_if_unsigned_equal: + forall x y, + cast16unsigned x = cast16unsigned y -> + cast16signed x = cast16signed y. +Proof. + unfold cast16unsigned, cast16signed; intros until y. + set (x' := unsigned x mod 65536). + set (y' := unsigned y mod 65536). + intro. + assert (eqm x' y'). + apply eqm_trans with (unsigned (repr x')). apply eqm_unsigned_repr. + rewrite H. apply eqm_sym. apply eqm_unsigned_repr. + assert (forall z, 0 <= z mod 65536 < modulus). + intros. + assert (0 <= z mod 65536 < 65536). apply Z_mod_lt. omega. + assert (65536 <= modulus). compute. congruence. + omega. + assert (x' = y'). + apply eqm_small_eq; unfold x', y'; auto. + rewrite H2. auto. +Qed. + +(** ** Properties of [one_bits] (decomposition in sum of powers of two) *) + +Opaque Z_one_bits. (* Otherwise, next Qed blows up! *) + +Theorem one_bits_range: + forall x i, In i (one_bits x) -> ltu i (repr (Z_of_nat wordsize)) = true. +Proof. + intros. unfold one_bits in H. + elim (list_in_map_inv _ _ _ H). intros i0 [EQ IN]. + subst i. unfold ltu. apply zlt_true. + generalize (Z_one_bits_range _ _ IN). intros. + assert (0 <= Z_of_nat wordsize <= max_unsigned). + compute. intuition congruence. + repeat rewrite unsigned_repr; omega. +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 _ _)). + assert (Z_of_nat wordsize < max_unsigned). compute; auto. 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_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. + simpl. discriminate. +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. + +End Int. -- cgit