(* *********************************************************************)
(*                                                                     *)
(*              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.     *)
(*                                                                     *)
(* *********************************************************************)
(** Type expressions for the Compcert C and Clight languages *)
Require Archi.
(** * Syntax of types *)
(** Compcert C types are similar to those of C.  They include numeric types, pointers, arrays, function types, and composite types (struct and union).  Numeric types (integers and floats) fully specify the bit size of the type.  An integer type is a pair of a signed/unsigned flag and a bit size: 8, 16, or 32 bits, or the special [IBool] size standing for the C99 [_Bool] type.  64-bit integers are treated separately. *)
Inductive signedness : Type :=
| Signed: signedness
| Unsigned: signedness.
Inductive intsize : Type :=
| I8: intsize
| I16: intsize
| I32: intsize
| IBool: intsize.
(** Float types come in two sizes: 32 bits (single precision) and 64-bit (double precision). *)
Inductive floatsize : Type :=
| F32: floatsize
| F64: floatsize.
(** Every type carries a set of attributes.  Currently, only two attributes are modeled: [volatile] and [_Alignas(n)] (from ISO C 2011). *)
Record attr : Type := mk_attr {
attr_volatile: bool;
attr_alignas: option N         (**r log2 of required alignment *)
}.
Definition noattr := {| attr_volatile := false; attr_alignas := None |}.
(** The syntax of type expressions.  Some points to note: - Array types [Tarray n] carry the size [n] of the array. Arrays with unknown sizes are represented by pointer types. - Function types [Tfunction targs tres] specify the number and types of the function arguments (list [targs]), and the type of the function result ([tres]).  Variadic functions and old-style unprototyped functions are not supported. *)
Inductive type : Type :=
| Tvoid: type                                    (**r the [void] type *)
| Tint: intsize -> signedness -> attr -> type    (**r integer types *)
| Tlong: signedness -> attr -> type              (**r 64-bit integer types *)
| Tfloat: floatsize -> attr -> type              (**r floating-point types *)
| Tpointer: type -> attr -> type                 (**r pointer types ([*ty]) *)
| Tarray: type -> Z -> attr -> type              (**r array types ([ty[len]]) *)
| Tfunction: typelist -> type -> calling_convention -> type    (**r function types *)
| Tstruct: ident -> attr -> type                 (**r struct types *)
| Tunion: ident -> attr -> type                  (**r union types *)
with typelist : Type :=
| Tnil: typelist
| Tcons: type -> typelist -> typelist.
(** ** Size of a type *)
(** In the ISO C standard, size is defined only for complete types.  However, it is convenient that [sizeof] is a total function.  For [void] and function types, we follow GCC and define their size to be 1.  For undefined structures and unions, the size is arbitrarily taken to be 0. *)
Fixpoint sizeof (env: composite_env) (t: type) : Z :=
match t with
| Tvoid => 1
| Tint I8 _ _ => 1
| Tint I16 _ _ => 2
| Tint I32 _ _ => 4
| Tint IBool _ _ => 1
| Tlong _ _ => 8
| Tfloat F32 _ => 4
| Tfloat F64 _ => 8
| Tpointer _ _ => if Archi.ptr64 then 8 else 4
| Tarray t' n _ => sizeof env t' * Z.max 0 n
| Tfunction _ _ _ => 1
| Tstruct id _ | Tunion id _ =>
match env!id with Some co => co_sizeof co | None => 0 end
end.
(** The size of a type is an integral multiple of its alignment, unless the alignment was artificially increased with the [__Alignas] attribute. *)
Fixpoint naturally_aligned (t: type) : Prop :=
attr_alignas (attr_of_type t) = None /\
match t with
| Tarray t' _ _ => naturally_aligned t'
| _ => True
end.

Lemma sizeof_alignof_compat:
forall env t, naturally_aligned t -> (alignof env t | sizeof env t).