(** This is the ISO C algebra of arithmetic types, without qualifiers.
    [S] stands for "signed" and [U] for "unsigned".  *)

Inductive int_type : Type :=
  | _Bool
  | Char | SChar | UChar
  | Short | UShort
  | Int | UInt
  | Long | ULong
  | Longlong | ULonglong.(** This is the ISO C algebra of arithmetic types, without qualifiers.
    [S] stands for "signed" and [U] for "unsigned".  *)

Inductive int_type : Type :=
  | _Bool
  | Char | SChar | UChar
  | Short | UShort
  | Int | UInt
  | Long | ULong
  | Longlong | ULonglong.(** This is the ISO C algebra of arithmetic types, without qualifiers.
    [S] stands for "signed" and [U] for "unsigned".  *)

Inductive int_type : Type :=
  | _Bool
  | Char | SChar | UChar
  | Short | UShort
  | Int | UInt
  | Long | ULong
  | Longlong | ULonglong.(** This is the ISO C algebra of arithmetic types, without qualifiers.
    [S] stands for "signed" and [U] for "unsigned".  *)

Inductive int_type : Type :=
  | _Bool
  | Char | SChar | UChar
  | Short | UShort
  | Int | UInt
  | Long | ULong
  | Longlong | ULonglong.(** This is the ISO C algebra of arithmetic types, without qualifiers.
    [S] stands for "signed" and [U] for "unsigned".  *)

Inductive int_type : Type :=
  | _Bool
  | Char | SChar | UChar
  | Short | UShort
  | Int | UInt
  | Long | ULong
  | Longlong | ULonglong.(** This is the ISO C algebra of arithmetic types, without qualifiers.
    [S] stands for "signed" and [U] for "unsigned".  *)

Inductive int_type : Type :=
  | _Bool
  | Char | SChar | UChar
  | Short | UShort
  | Int | UInt
  | Long | ULong
  | Longlong | ULonglong.(** This is the ISO C algebra of arithmetic types, without qualifiers.
    [S] stands for "signed" and [U] for "unsigned".  *)

Inductive int_type : Type :=
  | _Bool
  | Char | SChar | UChar
  | Short | UShort
  | Int | UInt
  | Long | ULong
  | Longlong | ULonglong.(** This is the ISO C algebra of arithmetic types, without qualifiers.
    [S] stands for "signed" and [U] for "unsigned".  *)

Inductive int_type : Type :=
  | _Bool
  | Char | SChar | UChar
  | Short | UShort
  | Int | UInt
  | Long | ULong
  | Longlong | ULonglong.(** This is the ISO C algebra of arithmetic types, without qualifiers.
    [S] stands for "signed" and [U] for "unsigned".  *)

Inductive int_type : Type :=
  | _Bool
  | Char | SChar | UChar
  | Short | UShort
  | Int | UInt
  | Long | ULong
  | Longlong | ULonglong.(** This is the ISO C algebra of arithmetic types, without qualifiers.
    [S] stands for "signed" and [U] for "unsigned".  *)

Inductive int_type : Type :=
  | _Bool
  | Char | SChar | UChar
  | Short | UShort
  | Int | UInt
  | Long | ULong
  | Longlong | ULonglong.(** This is the ISO C algebra of arithmetic types, without qualifiers.
    [S] stands for "signed" and [U] for "unsigned".  *)

Inductive int_type : Type :=
  | _Bool
  | Char | SChar | UChar
  | Short | UShort
  | Int | UInt
  | Long | ULong
  | Longlong | ULonglong.(** This is the ISO C algebra of arithmetic types, without qualifiers.
    [S] stands for "signed" and [U] for "unsigned".  *)

Inductive int_type : Type :=
  | _Bool
  | Char | SChar | UChar
  | Short | UShort
  | Int | UInt
  | Long | ULong
  | Longlong | ULonglong.(** This is the ISO C algebra of arithmetic types, without qualifiers.
    [S] stands for "signed" and [U] for "unsigned".  *)

Inductive int_type : Type :=
  | _Bool
  | Char | SChar | UChar
  | Short | UShort
  | Int | UInt
  | Long | ULong
  | Longlong | ULonglong.Inductive arith_type : Type :=
  | I (it: int_type)
  | Float
  | Double
  | Longdouble.Inductive arith_type : Type :=
  | I (it: int_type)
  | Float
  | Double
  | Longdouble.Inductive arith_type : Type :=
  | I (it: int_type)
  | Float
  | Double
  | Longdouble.Inductive arith_type : Type :=
  | I (it: int_type)
  | Float
  | Double
  | Longdouble.Inductive arith_type : Type :=
  | I (it: int_type)
  | Float
  | Double
  | Longdouble.Definition eq_int_type: forall (x y: int_type), {x=y} + {x<>y}.Definition is_unsigned (t: int_type) : bool :=
  match t with
  | _Bool => true
  | Char => false    (**r as in most of CompCert's target ABIs *)
  | SChar => false
  | UChar => true
  | Short => false
  | UShort => true
  | Int => false
  | UInt => true
  | Long => false
  | ULong => true
  | Longlong => false
  | ULonglong => true
  end.Definition unsigned_type (t: int_type) : int_type :=
  match t with
  | Char => UChar
  | SChar => UChar
  | Short => UShort
  | Int => UInt
  | Long => ULong
  | Longlong => ULonglong
  | _ => t
  end.Definition int_sizeof (t: int_type) : Z :=
  match t with
  | _Bool | Char | SChar | UChar => 1
  | Short | UShort => 2
  | Int | UInt | Long | ULong => 4
  | Longlong | ULonglong => 8
  end.(** 6.3.1.1 para 1: integer conversion rank *)

Definition rank (t: int_type) : Z :=
  match t with
  | _Bool => 1
  | Char | SChar | UChar => 2
  | Short | UShort => 3
  | Int | UInt => 4
  | Long | ULong => 5
  | Longlong | ULonglong => 6
  end.(** 6.3.1.1 para 2: integer promotions, a.k.a. usual unary conversions *)

Definition integer_promotion (t: int_type) : int_type :=
  if zlt (rank t) (rank Int) then Int else t.(** 6.3.1.8: Usual arithmetic conversions, a.k.a. binary conversions.
  This function returns the type to which the two operands must be
  converted. *)

Definition usual_arithmetic_conversion (t1 t2: arith_type) : arith_type :=
  match t1, t2 with
  (* First, if the corresponding real type of either operand is long
     double, the other operand is converted, without change of type domain,
     to a type whose corresponding real type is long double. *)
  | Longdouble, _ | _, Longdouble => Longdouble
  (* Otherwise, if the corresponding real type of either operand is
     double, the other operand is converted, without change of type domain,
     to a type whose corresponding real type is double. *)
  | Double, _ | _, Double => Double
  (* Otherwise, if the corresponding real type of either operand is
     float, the other operand is converted, without change of type domain,
     to a type whose corresponding real type is float. *)
  | Float, _ | _, Float => Float
  (* Otherwise, the integer promotions are performed on both operands. *)
  | I i1, I i2 =>
    let j1 := integer_promotion i1 in
    let j2 := integer_promotion i2 in
    (* Then the following rules are applied to the promoted operands:
       If both operands have the same type, then no further conversion
       is needed. *)
    if eq_int_type j1 j2 then I j1 else
    match is_unsigned j1, is_unsigned j2 with
    (* Otherwise, if both operands have signed integer types or both
       have unsigned integer types, the operand with the type of lesser
       integer conversion rank is converted to the type of the operand with
       greater rank. *)
    | true, true | false, false =>
        if zlt (rank j1) (rank j2) then I j2 else I j1
    | true, false =>
    (* Otherwise, if the operand that has unsigned integer type has
       rank greater or equal to the rank of the type of the other operand,
       then the operand with signed integer type is converted to the type of
       the operand with unsigned integer type. *)
        if zle (rank j2) (rank j1) then I j1 else
    (* Otherwise, if the type of the operand with signed integer type
       can represent all of the values of the type of the operand with
       unsigned integer type, then the operand with unsigned integer type is
       converted to the type of the operand with signed integer type. *)
        if zlt (int_sizeof j1) (int_sizeof j2) then I j2 else
    (* Otherwise, both operands are converted to the unsigned integer type
       corresponding to the type of the operand with signed integer type. *)
        I (unsigned_type j2)
    | false, true =>
    (* Same logic as above, swapping the roles of j1 and j2 *)
        if zle (rank j1) (rank j2) then I j2 else
        if zlt (int_sizeof j2) (int_sizeof j1) then I j1 else
        I (unsigned_type j1)
    end
  end.(** Mapping ISO arithmetic types to CompCert types *)

Definition proj_type (t: arith_type) : type :=
  match t with
  | I _Bool => Tint IBool Unsigned noattr
  | I Char => Tint I8 Unsigned noattr
  | I SChar => Tint I8 Signed noattr
  | I UChar => Tint I8 Unsigned noattr
  | I Short => Tint I16 Signed noattr
  | I UShort => Tint I16 Unsigned noattr
  | I Int => Tint I32 Signed noattr
  | I UInt => Tint I32 Unsigned noattr
  | I Long => Tint I32 Signed noattr
  | I ULong => Tint I32 Unsigned noattr
  | I Longlong => Tlong Signed noattr
  | I ULonglong => Tlong Unsigned noattr
  | Float => Tfloat F32 noattr
  | Double => Tfloat F64 noattr
  | Longdouble => Tfloat F64 noattr
  end.

(* Specifications: *)
Lemma typeconv_integer_promotion: forall i, typeconv (proj_type (I i)) = proj_type (I (integer_promotion i)).
Lemma classify_binarith_arithmetic_conversion: forall t1 t2, binarith_type (classify_binarith (proj_type t1) (proj_type t2)) = proj_type (usual_arithmetic_conversion t1 t2).
Lemma typeconv_integer_promotion: forall i, typeconv (proj_type (I i)) = proj_type (I (integer_promotion i)).
Lemma classify_binarith_arithmetic_conversion: forall t1 t2, binarith_type (classify_binarith (proj_type t1) (proj_type t2)) = proj_type (usual_arithmetic_conversion t1 t2).