(** * 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).Definition divs (x y: int) : int :=
  repr (Z.quot (signed x) (signed y)).Definition mods (x y: int) : int :=
  repr (Z.rem (signed x) (signed y)).Definition divu (x y: int) : int :=
  repr (unsigned x / unsigned y).Definition modu (x y: int) : int :=
  repr ((unsigned x) mod (unsigned y)).(** Bitwise boolean operations. *)

Definition and (x y: int): int := repr (Z.land (unsigned x) (unsigned y)).Definition or (x y: int): int := repr (Z.lor (unsigned x) (unsigned y)).Definition xor (x y: int) : int := repr (Z.lxor (unsigned x) (unsigned y)).Definition not (x: int) : int := xor x mone.(** Shifts and rotates. *)

Definition shl (x y: int): int := repr (Z.shiftl (unsigned x) (unsigned y)).Definition shru (x y: int): int := repr (Z.shiftr (unsigned x) (unsigned y)).Definition shr (x y: int): int := repr (Z.shiftr (signed x) (unsigned y)).Definition rol (x y: int) : int :=
  let n := (unsigned y) mod zwordsize in
  repr (Z.lor (Z.shiftl (unsigned x) n) (Z.shiftr (unsigned x) (zwordsize - n))).Definition ror (x y: int) : int :=
  let n := (unsigned y) mod zwordsize in
  repr (Z.lor (Z.shiftr (unsigned x) n) (Z.shiftl (unsigned x) (zwordsize - n))).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).(** High half of full multiply. *)

Definition mulhu (x y: int): int := repr ((unsigned x * unsigned y) / modulus).Definition mulhs (x y: int): int := repr ((signed x * signed y) / modulus).(** Condition flags *)

Definition negative (x: int): int :=
  if lt x zero then one else zero.Definition add_carry (x y cin: int): int :=
  if zlt (unsigned x + unsigned y + unsigned cin) modulus then zero else one.Definition add_overflow (x y cin: int): int :=
  let s := signed x + signed y + signed cin in
  if zle min_signed s && zle s max_signed then zero else one.Definition sub_borrow (x y bin: int): int :=
  if zlt (unsigned x - unsigned y - unsigned bin) 0 then one else zero.Definition sub_overflow (x y bin: int): int :=
  let s := signed x - signed y - signed bin in
  if zle min_signed s && zle s max_signed then zero else one.(** [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) : int :=
  if lt x zero && negb (eq (and x (sub (shl one y) one)) zero)
  then one else zero.(** Zero and sign extensions *)

Definition Zshiftin (b: bool) (x: Z) : Z :=
  if b then Z.succ_double x else Z.double x.(** In pseudo-code:
<<
    Fixpoint Zzero_ext (n: Z) (x: Z) : Z :=
      if zle n 0 then
        0
      else
        Zshiftin (Z.odd x) (Zzero_ext (Z.pred n) (Z.div2 x)).
    Fixpoint Zsign_ext (n: Z) (x: Z) : Z :=
      if zle n 1 then
        if Z.odd x then -1 else 0
      else
        Zshiftin (Z.odd x) (Zzero_ext (Z.pred n) (Z.div2 x)).
>>
  We encode this [nat]-like recursion using the [Z.iter] iteration
  function, in order to make the [Zzero_ext] and [Zsign_ext]
  functions efficiently executable within Coq.
*)

Definition Zzero_ext (n: Z) (x: Z) : Z :=
  Z.iter n
    (fun rec x => Zshiftin (Z.odd x) (rec (Z.div2 x)))
    (fun x => 0)
    x.Definition Zsign_ext (n: Z) (x: Z) : Z :=
  Z.iter (Z.pred n)
    (fun rec x => Zshiftin (Z.odd x) (rec (Z.div2 x)))
    (fun x => if Z.odd x then -1 else 0)
    x.Definition zero_ext (n: Z) (x: int) : int := repr (Zzero_ext n (unsigned x)).Definition sign_ext (n: Z) (x: int) : int := repr (Zsign_ext n (unsigned x)).(** 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 =>
      if Z.odd x
      then i :: Z_one_bits m (Z.div2 x) (i+1)
      else Z_one_bits m (Z.div2 x) (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.(** x86-style extended division and modulus *)

Definition divmodu2 (nhi nlo: int) (d: int) : option (int * int) :=
  if eq_dec d zero then None else
   (let (q, r) := Z.div_eucl (unsigned nhi * modulus + unsigned nlo) (unsigned d) in
    if zle q max_unsigned then Some(repr q, repr r) else None).Definition divmods2 (nhi nlo: int) (d: int) : option (int * int) :=
  if eq_dec d zero then None else
   (let (q, r) := Z.quotrem (signed nhi * modulus + unsigned nlo) (signed d) in
    if zle min_signed q && zle q max_signed then Some(repr q, repr r) else None).(** * Properties of integers and integer arithmetic *)

(** ** Properties of [modulus], [max_unsigned], etc. *)

Remark half_modulus_power:
  half_modulus = two_p (zwordsize - 1).Remark half_modulus_modulus: modulus = 2 * half_modulus.(** Relative positions, from greatest to smallest:
<<
      max_unsigned
      max_signed
      2*wordsize-1
      wordsize
      0
      min_signed
>>
*)

Remark half_modulus_pos: half_modulus > 0.Remark min_signed_neg: min_signed < 0.Remark max_signed_pos: max_signed >= 0.Remark wordsize_max_unsigned: zwordsize <= max_unsigned.Remark two_wordsize_max_unsigned: 2 * zwordsize - 1 <= max_unsigned.Remark max_signed_unsigned: max_signed < max_unsigned.

(* Specifications: *)
Lemma unsigned_repr_eq: forall x, unsigned (repr x) = Z.modulo x modulus.
Lemma signed_repr_eq: forall x, signed (repr x) = if zlt (Z.modulo x modulus) half_modulus then Z.modulo x modulus else Z.modulo x modulus - modulus.
Lemma unsigned_repr_eq: forall x, unsigned (repr x) = Z.modulo x modulus.
Lemma signed_repr_eq: forall x, signed (repr x) = if zlt (Z.modulo x modulus) half_modulus then Z.modulo x modulus else Z.modulo x modulus - modulus.