Library compcert.cfrontend.Cop
Arithmetic and logical operators for the Compcert C and Clight languages
Require Import Coqlib.
Require Import AST.
Require Import Integers.
Require Import Floats.
Require Import Values.
Require Import Memory.
Require Import Ctypes.
Inductive unary_operation : Type :=
| Onotbool : unary_operation
| Onotint : unary_operation
| Oneg : unary_operation
| Oabsfloat : unary_operation.
Inductive binary_operation : Type :=
| Oadd : binary_operation
| Osub : binary_operation
| Omul : binary_operation
| Odiv : binary_operation
| Omod : binary_operation
| Oand : binary_operation
| Oor : binary_operation
| Oxor : binary_operation
| Oshl : binary_operation
| Oshr : binary_operation
| Oeq: binary_operation
| One: binary_operation
| Olt: binary_operation
| Ogt: binary_operation
| Ole: binary_operation
| Oge: binary_operation.
Inductive incr_or_decr : Type := Incr | Decr.
Type classification and semantics of operators.
Casts and truth values
Inductive classify_cast_cases : Type :=
| cast_case_neutral
| cast_case_i2i (sz2:intsize) (si2:signedness)
| cast_case_f2f (sz2:floatsize)
| cast_case_i2f (si1:signedness) (sz2:floatsize)
| cast_case_f2i (sz2:intsize) (si2:signedness)
| cast_case_l2l
| cast_case_i2l (si1: signedness)
| cast_case_l2i (sz2: intsize) (si2: signedness)
| cast_case_l2f (si1: signedness) (sz2: floatsize)
| cast_case_f2l (si2: signedness)
| cast_case_f2bool
| cast_case_l2bool
| cast_case_p2bool
| cast_case_struct (id1: ident) (fld1: fieldlist) (id2: ident) (fld2: fieldlist)
| cast_case_union (id1: ident) (fld1: fieldlist) (id2: ident) (fld2: fieldlist)
| cast_case_void
| cast_case_default.
Definition classify_cast (tfrom tto: type) : classify_cast_cases :=
match tto, tfrom with
| Tint I32 si2 _, (Tint _ _ _ | Tpointer _ _ | Tcomp_ptr _ _ | Tarray _ _ _ | Tfunction _ _ _) => cast_case_neutral
| Tint IBool _ _, Tfloat _ _ => cast_case_f2bool
| Tint IBool _ _, (Tpointer _ _ | Tcomp_ptr _ _ | Tarray _ _ _ | Tfunction _ _ _) => cast_case_p2bool
| Tint sz2 si2 _, Tint sz1 si1 _ => cast_case_i2i sz2 si2
| Tint sz2 si2 _, Tfloat sz1 _ => cast_case_f2i sz2 si2
| Tfloat sz2 _, Tfloat sz1 _ => cast_case_f2f sz2
| Tfloat sz2 _, Tint sz1 si1 _ => cast_case_i2f si1 sz2
| (Tpointer _ _ | Tcomp_ptr _ _), (Tint _ _ _ | Tpointer _ _ | Tcomp_ptr _ _ | Tarray _ _ _ | Tfunction _ _ _) => cast_case_neutral
| Tlong _ _, Tlong _ _ => cast_case_l2l
| Tlong _ _, Tint sz1 si1 _ => cast_case_i2l si1
| Tint IBool _ _, Tlong _ _ => cast_case_l2bool
| Tint sz2 si2 _, Tlong _ _ => cast_case_l2i sz2 si2
| Tlong si2 _, Tfloat sz1 _ => cast_case_f2l si2
| Tfloat sz2 _, Tlong si1 _ => cast_case_l2f si1 sz2
| (Tpointer _ _ | Tcomp_ptr _ _), Tlong _ _ => cast_case_l2i I32 Unsigned
| Tlong si2 _, (Tpointer _ _ | Tcomp_ptr _ _ | Tarray _ _ _ | Tfunction _ _ _) => cast_case_i2l si2
| Tstruct id2 fld2 _, Tstruct id1 fld1 _ => cast_case_struct id1 fld1 id2 fld2
| Tunion id2 fld2 _, Tunion id1 fld1 _ => cast_case_union id1 fld1 id2 fld2
| Tvoid, _ => cast_case_void
| _, _ => cast_case_default
end.
Semantics of casts. sem_cast v1 t1 t2 = Some v2 if value v1,
viewed with static type t1, can be converted to type t2,
resulting in value v2.
Definition cast_int_int (sz: intsize) (sg: signedness) (i: int) : int :=
match sz, sg with
| I8, Signed => Int.sign_ext 8 i
| I8, Unsigned => Int.zero_ext 8 i
| I16, Signed => Int.sign_ext 16 i
| I16, Unsigned => Int.zero_ext 16 i
| I32, _ => i
| IBool, _ => if Int.eq i Int.zero then Int.zero else Int.one
end.
Definition cast_int_float (si: signedness) (sz: floatsize) (i: int) : float :=
match si, sz with
| Signed, F64 => Float.floatofint i
| Unsigned, F64 => Float.floatofintu i
| Signed, F32 => Float.singleofint i
| Unsigned, F32 => Float.singleofintu i
end.
Definition cast_float_int (si : signedness) (f: float) : option int :=
match si with
| Signed => Float.intoffloat f
| Unsigned => Float.intuoffloat f
end.
Definition cast_float_float (sz: floatsize) (f: float) : float :=
match sz with
| F32 => Float.singleoffloat f
| F64 => f
end.
Definition cast_int_long (si: signedness) (i: int) : int64 :=
match si with
| Signed => Int64.repr (Int.signed i)
| Unsigned => Int64.repr (Int.unsigned i)
end.
Definition cast_long_float (si: signedness) (sz: floatsize) (i: int64) : float :=
match si, sz with
| Signed, F64 => Float.floatoflong i
| Unsigned, F64 => Float.floatoflongu i
| Signed, F32 => Float.singleoflong i
| Unsigned, F32 => Float.singleoflongu i
end.
Definition cast_float_long (si : signedness) (f: float) : option int64 :=
match si with
| Signed => Float.longoffloat f
| Unsigned => Float.longuoffloat f
end.
Definition sem_cast (v: val) (t1 t2: type) : option val :=
match classify_cast t1 t2 with
| cast_case_neutral =>
match v with
| Vint _ | Vptr _ _ => Some v
| _ => None
end
| cast_case_i2i sz2 si2 =>
match v with
| Vint i => Some (Vint (cast_int_int sz2 si2 i))
| _ => None
end
| cast_case_f2f sz2 =>
match v with
| Vfloat f => Some (Vfloat (cast_float_float sz2 f))
| _ => None
end
| cast_case_i2f si1 sz2 =>
match v with
| Vint i => Some (Vfloat (cast_int_float si1 sz2 i))
| _ => None
end
| cast_case_f2i sz2 si2 =>
match v with
| Vfloat f =>
match cast_float_int si2 f with
| Some i => Some (Vint (cast_int_int sz2 si2 i))
| None => None
end
| _ => None
end
| cast_case_f2bool =>
match v with
| Vfloat f =>
Some(Vint(if Float.cmp Ceq f Float.zero then Int.zero else Int.one))
| _ => None
end
| cast_case_p2bool =>
match v with
| Vint i => Some (Vint (cast_int_int IBool Signed i))
| Vptr _ _ => Some (Vint Int.one)
| _ => None
end
| cast_case_l2l =>
match v with
| Vlong n => Some (Vlong n)
| _ => None
end
| cast_case_i2l si =>
match v with
| Vint n => Some(Vlong (cast_int_long si n))
| _ => None
end
| cast_case_l2i sz si =>
match v with
| Vlong n => Some(Vint (cast_int_int sz si (Int.repr (Int64.unsigned n))))
| _ => None
end
| cast_case_l2bool =>
match v with
| Vlong n =>
Some(Vint(if Int64.eq n Int64.zero then Int.zero else Int.one))
| _ => None
end
| cast_case_l2f si1 sz2 =>
match v with
| Vlong i => Some (Vfloat (cast_long_float si1 sz2 i))
| _ => None
end
| cast_case_f2l si2 =>
match v with
| Vfloat f =>
match cast_float_long si2 f with
| Some i => Some (Vlong i)
| None => None
end
| _ => None
end
| cast_case_struct id1 fld1 id2 fld2 =>
match v with
| Vptr b ofs =>
if ident_eq id1 id2 && fieldlist_eq fld1 fld2 then Some v else None
| _ => None
end
| cast_case_union id1 fld1 id2 fld2 =>
match v with
| Vptr b ofs =>
if ident_eq id1 id2 && fieldlist_eq fld1 fld2 then Some v else None
| _ => None
end
| cast_case_void =>
Some v
| cast_case_default =>
None
end.
The following describes types that can be interpreted as a boolean:
integers, floats, pointers. It is used for the semantics of
the ! and ? operators, as well as the if, while,
and for statements.
Inductive classify_bool_cases : Type :=
| bool_case_i
| bool_case_f
| bool_case_p
| bool_case_l
| bool_default.
Definition classify_bool (ty: type) : classify_bool_cases :=
match typeconv ty with
| Tint _ _ _ => bool_case_i
| Tpointer _ _ | Tcomp_ptr _ _ => bool_case_p
| Tfloat _ _ => bool_case_f
| Tlong _ _ => bool_case_l
| _ => bool_default
end.
Interpretation of values as truth values.
Non-zero integers, non-zero floats and non-null pointers are
considered as true. The integer zero (which also represents
the null pointer) and the float 0.0 are false.
Definition bool_val (v: val) (t: type) : option bool :=
match classify_bool t with
| bool_case_i =>
match v with
| Vint n => Some (negb (Int.eq n Int.zero))
| _ => None
end
| bool_case_f =>
match v with
| Vfloat f => Some (negb (Float.cmp Ceq f Float.zero))
| _ => None
end
| bool_case_p =>
match v with
| Vint n => Some (negb (Int.eq n Int.zero))
| Vptr b ofs => Some true
| _ => None
end
| bool_case_l =>
match v with
| Vlong n => Some (negb (Int64.eq n Int64.zero))
| _ => None
end
| bool_default => None
end.
Definition sem_notbool (v: val) (ty: type) : option val :=
match classify_bool ty with
| bool_case_i =>
match v with
| Vint n => Some (Val.of_bool (Int.eq n Int.zero))
| _ => None
end
| bool_case_f =>
match v with
| Vfloat f => Some (Val.of_bool (Float.cmp Ceq f Float.zero))
| _ => None
end
| bool_case_p =>
match v with
| Vint n => Some (Val.of_bool (Int.eq n Int.zero))
| Vptr _ _ => Some Vfalse
| _ => None
end
| bool_case_l =>
match v with
| Vlong n => Some (Val.of_bool (Int64.eq n Int64.zero))
| _ => None
end
| bool_default => None
end.
Inductive classify_neg_cases : Type :=
| neg_case_i(s: signedness)
| neg_case_f(sz: floatsize)
| neg_case_l(s: signedness)
| neg_default.
Definition classify_neg (ty: type) : classify_neg_cases :=
match ty with
| Tint I32 Unsigned _ => neg_case_i Unsigned
| Tint _ _ _ => neg_case_i Signed
| Tfloat sz _ => neg_case_f sz
| Tlong si _ => neg_case_l si
| _ => neg_default
end.
Definition sem_neg (v: val) (ty: type) : option val :=
match classify_neg ty with
| neg_case_i sg =>
match v with
| Vint n => Some (Vint (Int.neg n))
| _ => None
end
| neg_case_f sz =>
match v with
| Vfloat f => Some (Vfloat (Float.neg f))
| _ => None
end
| neg_case_l sg =>
match v with
| Vlong n => Some (Vlong (Int64.neg n))
| _ => None
end
| neg_default => None
end.
Definition sem_absfloat (v: val) (ty: type) : option val :=
match classify_neg ty with
| neg_case_i sg =>
match v with
| Vint n => Some (Vfloat (Float.abs (cast_int_float sg F64 n)))
| _ => None
end
| neg_case_f sz =>
match v with
| Vfloat f => Some (Vfloat (Float.abs f))
| _ => None
end
| neg_case_l sg =>
match v with
| Vlong n => Some (Vfloat (Float.abs (cast_long_float sg F64 n)))
| _ => None
end
| neg_default => None
end.
Inductive classify_notint_cases : Type :=
| notint_case_i(s: signedness)
| notint_case_l(s: signedness)
| notint_default.
Definition classify_notint (ty: type) : classify_notint_cases :=
match ty with
| Tint I32 Unsigned _ => notint_case_i Unsigned
| Tint _ _ _ => notint_case_i Signed
| Tlong si _ => notint_case_l si
| _ => notint_default
end.
Definition sem_notint (v: val) (ty: type): option val :=
match classify_notint ty with
| notint_case_i sg =>
match v with
| Vint n => Some (Vint (Int.not n))
| _ => None
end
| notint_case_l sg =>
match v with
| Vlong n => Some (Vlong (Int64.not n))
| _ => None
end
| notint_default => None
end.
Binary operators
- determining the type at which the operation is to be performed (a form of least upper bound of the types of the two arguments);
- casting the two arguments to this common type;
- performing the operation at that type.
Inductive binarith_cases: Type :=
| bin_case_i (s: signedness)
| bin_case_l (s: signedness)
| bin_case_f (sz: floatsize)
| bin_default.
Definition classify_binarith (ty1: type) (ty2: type) : binarith_cases :=
match ty1, ty2 with
| Tint I32 Unsigned _, Tint _ _ _ => bin_case_i Unsigned
| Tint _ _ _, Tint I32 Unsigned _ => bin_case_i Unsigned
| Tint _ _ _, Tint _ _ _ => bin_case_i Signed
| Tlong Signed _, Tlong Signed _ => bin_case_l Signed
| Tlong _ _, Tlong _ _ => bin_case_l Unsigned
| Tlong sg _, Tint _ _ _ => bin_case_l sg
| Tint _ _ _, Tlong sg _ => bin_case_l sg
| Tfloat F32 _, Tfloat F32 _ => bin_case_f F32
| Tfloat _ _, Tfloat _ _ => bin_case_f F64
| Tfloat sz _, (Tint _ _ _ | Tlong _ _) => bin_case_f sz
| (Tint _ _ _ | Tlong _ _), Tfloat sz _ => bin_case_f sz
| _, _ => bin_default
end.
The static type of the result.
Definition binarith_result_type (c: binarith_cases) : option type :=
match c with
| bin_case_i sg => Some(Tint I32 sg noattr)
| bin_case_l sg => Some(Tlong sg noattr)
| bin_case_f sz => Some(Tfloat sz noattr)
| bin_default => None
end.
The type at which the computation is done. Both arguments are
converted to this type before the actual computation.
Definition binarith_type (c: binarith_cases) : type :=
match c with
| bin_case_i sg => Tint I32 sg noattr
| bin_case_l sg => Tlong sg noattr
| bin_case_f sz => Tfloat F64 noattr
| bin_default => Tvoid
end.
Definition sem_binarith
(sem_int: signedness -> int -> int -> option val)
(sem_long: signedness -> int64 -> int64 -> option val)
(sem_float: float -> float -> option val)
(v1: val) (t1: type) (v2: val) (t2: type) : option val :=
let c := classify_binarith t1 t2 in
let t := binarith_type c in
match sem_cast v1 t1 t with
| None => None
| Some v1´ =>
match sem_cast v2 t2 t with
| None => None
| Some v2´ =>
match c with
| bin_case_i sg =>
match v1´, v2´ with
| Vint n1, Vint n2 => sem_int sg n1 n2
| _, _ => None
end
| bin_case_f sz =>
match v1´, v2´ with
| Vfloat n1, Vfloat n2 => sem_float n1 n2
| _, _ => None
end
| bin_case_l sg =>
match v1´, v2´ with
| Vlong n1, Vlong n2 => sem_long sg n1 n2
| _, _ => None
end
| bin_default => None
end end end.
Inductive classify_add_cases : Type :=
| add_case_pi(ty: type)
| add_case_ip(ty: type)
| add_case_pl(ty: type)
| add_case_lp(ty: type)
| add_default.
Definition classify_add (ty1: type) (ty2: type) :=
match typeconv ty1, typeconv ty2 with
| Tpointer ty _, Tint _ _ _ => add_case_pi ty
| Tint _ _ _, Tpointer ty _ => add_case_ip ty
| Tpointer ty _, Tlong _ _ => add_case_pl ty
| Tlong _ _, Tpointer ty _ => add_case_lp ty
| _, _ => add_default
end.
Definition sem_add (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
match classify_add t1 t2 with
| add_case_pi ty =>
match v1,v2 with
| Vptr b1 ofs1, Vint n2 =>
Some (Vptr b1 (Int.add ofs1 (Int.mul (Int.repr (sizeof ty)) n2)))
| _, _ => None
end
| add_case_ip ty =>
match v1,v2 with
| Vint n1, Vptr b2 ofs2 =>
Some (Vptr b2 (Int.add ofs2 (Int.mul (Int.repr (sizeof ty)) n1)))
| _, _ => None
end
| add_case_pl ty =>
match v1,v2 with
| Vptr b1 ofs1, Vlong n2 =>
let n2 := Int.repr (Int64.unsigned n2) in
Some (Vptr b1 (Int.add ofs1 (Int.mul (Int.repr (sizeof ty)) n2)))
| _, _ => None
end
| add_case_lp ty =>
match v1,v2 with
| Vlong n1, Vptr b2 ofs2 =>
let n1 := Int.repr (Int64.unsigned n1) in
Some (Vptr b2 (Int.add ofs2 (Int.mul (Int.repr (sizeof ty)) n1)))
| _, _ => None
end
| add_default =>
sem_binarith
(fun sg n1 n2 => Some(Vint(Int.add n1 n2)))
(fun sg n1 n2 => Some(Vlong(Int64.add n1 n2)))
(fun n1 n2 => Some(Vfloat(Float.add n1 n2)))
v1 t1 v2 t2
end.
Inductive classify_sub_cases : Type :=
| sub_case_pi(ty: type)
| sub_case_pp(ty: type)
| sub_case_pl(ty: type)
| sub_default.
Definition classify_sub (ty1: type) (ty2: type) :=
match typeconv ty1, typeconv ty2 with
| Tpointer ty _, Tint _ _ _ => sub_case_pi ty
| Tpointer ty _ , Tpointer _ _ => sub_case_pp ty
| Tpointer ty _, Tlong _ _ => sub_case_pl ty
| _, _ => sub_default
end.
Definition sem_sub (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
match classify_sub t1 t2 with
| sub_case_pi ty =>
match v1,v2 with
| Vptr b1 ofs1, Vint n2 =>
Some (Vptr b1 (Int.sub ofs1 (Int.mul (Int.repr (sizeof ty)) n2)))
| _, _ => None
end
| sub_case_pl ty =>
match v1,v2 with
| Vptr b1 ofs1, Vlong n2 =>
let n2 := Int.repr (Int64.unsigned n2) in
Some (Vptr b1 (Int.sub ofs1 (Int.mul (Int.repr (sizeof ty)) n2)))
| _, _ => None
end
| sub_case_pp ty =>
match v1,v2 with
| Vptr b1 ofs1, Vptr b2 ofs2 =>
if eq_block b1 b2 then
if Int.eq (Int.repr (sizeof ty)) Int.zero then None
else Some (Vint (Int.divu (Int.sub ofs1 ofs2) (Int.repr (sizeof ty))))
else None
| _, _ => None
end
| sub_default =>
sem_binarith
(fun sg n1 n2 => Some(Vint(Int.sub n1 n2)))
(fun sg n1 n2 => Some(Vlong(Int64.sub n1 n2)))
(fun n1 n2 => Some(Vfloat(Float.sub n1 n2)))
v1 t1 v2 t2
end.
Definition sem_mul (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
sem_binarith
(fun sg n1 n2 => Some(Vint(Int.mul n1 n2)))
(fun sg n1 n2 => Some(Vlong(Int64.mul n1 n2)))
(fun n1 n2 => Some(Vfloat(Float.mul n1 n2)))
v1 t1 v2 t2.
Definition sem_div (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
sem_binarith
(fun sg n1 n2 =>
match sg with
| Signed =>
if Int.eq n2 Int.zero
|| Int.eq n1 (Int.repr Int.min_signed) && Int.eq n2 Int.mone
then None else Some(Vint(Int.divs n1 n2))
| Unsigned =>
if Int.eq n2 Int.zero
then None else Some(Vint(Int.divu n1 n2))
end)
(fun sg n1 n2 =>
match sg with
| Signed =>
if Int64.eq n2 Int64.zero
|| Int64.eq n1 (Int64.repr Int64.min_signed) && Int64.eq n2 Int64.mone
then None else Some(Vlong(Int64.divs n1 n2))
| Unsigned =>
if Int64.eq n2 Int64.zero
then None else Some(Vlong(Int64.divu n1 n2))
end)
(fun n1 n2 => Some(Vfloat(Float.div n1 n2)))
v1 t1 v2 t2.
Definition sem_mod (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
sem_binarith
(fun sg n1 n2 =>
match sg with
| Signed =>
if Int.eq n2 Int.zero
|| Int.eq n1 (Int.repr Int.min_signed) && Int.eq n2 Int.mone
then None else Some(Vint(Int.mods n1 n2))
| Unsigned =>
if Int.eq n2 Int.zero
then None else Some(Vint(Int.modu n1 n2))
end)
(fun sg n1 n2 =>
match sg with
| Signed =>
if Int64.eq n2 Int64.zero
|| Int64.eq n1 (Int64.repr Int64.min_signed) && Int64.eq n2 Int64.mone
then None else Some(Vlong(Int64.mods n1 n2))
| Unsigned =>
if Int64.eq n2 Int64.zero
then None else Some(Vlong(Int64.modu n1 n2))
end)
(fun n1 n2 => None)
v1 t1 v2 t2.
Definition sem_and (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
sem_binarith
(fun sg n1 n2 => Some(Vint(Int.and n1 n2)))
(fun sg n1 n2 => Some(Vlong(Int64.and n1 n2)))
(fun n1 n2 => None)
v1 t1 v2 t2.
Definition sem_or (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
sem_binarith
(fun sg n1 n2 => Some(Vint(Int.or n1 n2)))
(fun sg n1 n2 => Some(Vlong(Int64.or n1 n2)))
(fun n1 n2 => None)
v1 t1 v2 t2.
Definition sem_xor (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
sem_binarith
(fun sg n1 n2 => Some(Vint(Int.xor n1 n2)))
(fun sg n1 n2 => Some(Vlong(Int64.xor n1 n2)))
(fun n1 n2 => None)
v1 t1 v2 t2.
Shifts
Inductive classify_shift_cases : Type:=
| shift_case_ii(s: signedness)
| shift_case_ll(s: signedness)
| shift_case_il(s: signedness)
| shift_case_li(s: signedness)
| shift_default.
Definition classify_shift (ty1: type) (ty2: type) :=
match typeconv ty1, typeconv ty2 with
| Tint I32 Unsigned _, Tint _ _ _ => shift_case_ii Unsigned
| Tint _ _ _, Tint _ _ _ => shift_case_ii Signed
| Tint I32 Unsigned _, Tlong _ _ => shift_case_il Unsigned
| Tint _ _ _, Tlong _ _ => shift_case_il Signed
| Tlong s _, Tint _ _ _ => shift_case_li s
| Tlong s _, Tlong _ _ => shift_case_ll s
| _,_ => shift_default
end.
Definition sem_shift
(sem_int: signedness -> int -> int -> int)
(sem_long: signedness -> int64 -> int64 -> int64)
(v1: val) (t1: type) (v2: val) (t2: type) : option val :=
match classify_shift t1 t2 with
| shift_case_ii sg =>
match v1, v2 with
| Vint n1, Vint n2 =>
if Int.ltu n2 Int.iwordsize
then Some(Vint(sem_int sg n1 n2)) else None
| _, _ => None
end
| shift_case_il sg =>
match v1, v2 with
| Vint n1, Vlong n2 =>
if Int64.ltu n2 (Int64.repr 32)
then Some(Vint(sem_int sg n1 (Int64.loword n2))) else None
| _, _ => None
end
| shift_case_li sg =>
match v1, v2 with
| Vlong n1, Vint n2 =>
if Int.ltu n2 Int64.iwordsize´
then Some(Vlong(sem_long sg n1 (Int64.repr (Int.unsigned n2)))) else None
| _, _ => None
end
| shift_case_ll sg =>
match v1, v2 with
| Vlong n1, Vlong n2 =>
if Int64.ltu n2 Int64.iwordsize
then Some(Vlong(sem_long sg n1 n2)) else None
| _, _ => None
end
| shift_default => None
end.
Definition sem_shl (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
sem_shift
(fun sg n1 n2 => Int.shl n1 n2)
(fun sg n1 n2 => Int64.shl n1 n2)
v1 t1 v2 t2.
Definition sem_shr (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
sem_shift
(fun sg n1 n2 => match sg with Signed => Int.shr n1 n2 | Unsigned => Int.shru n1 n2 end)
(fun sg n1 n2 => match sg with Signed => Int64.shr n1 n2 | Unsigned => Int64.shru n1 n2 end)
v1 t1 v2 t2.
Inductive classify_cmp_cases : Type :=
| cmp_case_pp
| cmp_case_pl
| cmp_case_lp
| cmp_default.
Definition classify_cmp (ty1: type) (ty2: type) :=
match typeconv ty1, typeconv ty2 with
| Tpointer _ _ , Tpointer _ _ => cmp_case_pp
| Tpointer _ _ , Tint _ _ _ => cmp_case_pp
| Tint _ _ _, Tpointer _ _ => cmp_case_pp
| Tpointer _ _ , Tlong _ _ => cmp_case_pl
| Tlong _ _ , Tpointer _ _ => cmp_case_lp
| _, _ => cmp_default
end.
CompCertX:test-compcert-param-memory We create section WITHMEM and associated
contexts to parameterize the proof over the memory model.
Section WITHMEM.
Context `{memory_model: Mem.MemoryModel}.
Definition sem_cmp (c:comparison)
(v1: val) (t1: type) (v2: val) (t2: type)
(m: mem): option val :=
match classify_cmp t1 t2 with
| cmp_case_pp =>
option_map Val.of_bool (Val.cmpu_bool (Mem.valid_pointer m) c v1 v2)
| cmp_case_pl =>
match v2 with
| Vlong n2 =>
let n2 := Int.repr (Int64.unsigned n2) in
option_map Val.of_bool (Val.cmpu_bool (Mem.valid_pointer m) c v1 (Vint n2))
| _ => None
end
| cmp_case_lp =>
match v1 with
| Vlong n1 =>
let n1 := Int.repr (Int64.unsigned n1) in
option_map Val.of_bool (Val.cmpu_bool (Mem.valid_pointer m) c (Vint n1) v2)
| _ => None
end
| cmp_default =>
sem_binarith
(fun sg n1 n2 =>
Some(Val.of_bool(match sg with Signed => Int.cmp c n1 n2 | Unsigned => Int.cmpu c n1 n2 end)))
(fun sg n1 n2 =>
Some(Val.of_bool(match sg with Signed => Int64.cmp c n1 n2 | Unsigned => Int64.cmpu c n1 n2 end)))
(fun n1 n2 =>
Some(Val.of_bool(Float.cmp c n1 n2)))
v1 t1 v2 t2
end.
Context `{memory_model: Mem.MemoryModel}.
Definition sem_cmp (c:comparison)
(v1: val) (t1: type) (v2: val) (t2: type)
(m: mem): option val :=
match classify_cmp t1 t2 with
| cmp_case_pp =>
option_map Val.of_bool (Val.cmpu_bool (Mem.valid_pointer m) c v1 v2)
| cmp_case_pl =>
match v2 with
| Vlong n2 =>
let n2 := Int.repr (Int64.unsigned n2) in
option_map Val.of_bool (Val.cmpu_bool (Mem.valid_pointer m) c v1 (Vint n2))
| _ => None
end
| cmp_case_lp =>
match v1 with
| Vlong n1 =>
let n1 := Int.repr (Int64.unsigned n1) in
option_map Val.of_bool (Val.cmpu_bool (Mem.valid_pointer m) c (Vint n1) v2)
| _ => None
end
| cmp_default =>
sem_binarith
(fun sg n1 n2 =>
Some(Val.of_bool(match sg with Signed => Int.cmp c n1 n2 | Unsigned => Int.cmpu c n1 n2 end)))
(fun sg n1 n2 =>
Some(Val.of_bool(match sg with Signed => Int64.cmp c n1 n2 | Unsigned => Int64.cmpu c n1 n2 end)))
(fun n1 n2 =>
Some(Val.of_bool(Float.cmp c n1 n2)))
v1 t1 v2 t2
end.
Inductive classify_fun_cases : Type:=
| fun_case_f (targs: typelist) (tres: type) (cc: calling_convention)
| fun_default.
Definition classify_fun (ty: type) :=
match ty with
| Tfunction args res cc => fun_case_f args res cc
| Tpointer (Tfunction args res cc) _ => fun_case_f args res cc
| _ => fun_default
end.
Definition sem_unary_operation
(op: unary_operation) (v: val) (ty: type): option val :=
match op with
| Onotbool => sem_notbool v ty
| Onotint => sem_notint v ty
| Oneg => sem_neg v ty
| Oabsfloat => sem_absfloat v ty
end.
Definition sem_binary_operation
(op: binary_operation)
(v1: val) (t1: type) (v2: val) (t2:type)
(m: mem): option val :=
match op with
| Oadd => sem_add v1 t1 v2 t2
| Osub => sem_sub v1 t1 v2 t2
| Omul => sem_mul v1 t1 v2 t2
| Omod => sem_mod v1 t1 v2 t2
| Odiv => sem_div v1 t1 v2 t2
| Oand => sem_and v1 t1 v2 t2
| Oor => sem_or v1 t1 v2 t2
| Oxor => sem_xor v1 t1 v2 t2
| Oshl => sem_shl v1 t1 v2 t2
| Oshr => sem_shr v1 t1 v2 t2
| Oeq => sem_cmp Ceq v1 t1 v2 t2 m
| One => sem_cmp Cne v1 t1 v2 t2 m
| Olt => sem_cmp Clt v1 t1 v2 t2 m
| Ogt => sem_cmp Cgt v1 t1 v2 t2 m
| Ole => sem_cmp Cle v1 t1 v2 t2 m
| Oge => sem_cmp Cge v1 t1 v2 t2 m
end.
Definition sem_incrdecr (id: incr_or_decr) (v: val) (ty: type) :=
match id with
| Incr => sem_add v ty (Vint Int.one) type_int32s
| Decr => sem_sub v ty (Vint Int.one) type_int32s
end.
Definition incrdecr_type (ty: type) :=
match typeconv ty with
| Tpointer ty a => Tpointer ty a
| Tint sz sg a => Tint sz sg noattr
| Tlong sg a => Tlong sg noattr
| Tfloat sz a => Tfloat sz noattr
| _ => Tvoid
end.
Section GENERIC_INJECTION.
Variable f: meminj.
Variables m m´: mem.
Hypothesis valid_pointer_inj:
forall b1 ofs b2 delta,
f b1 = Some(b2, delta) ->
Mem.valid_pointer m b1 (Int.unsigned ofs) = true ->
Mem.valid_pointer m´ b2 (Int.unsigned (Int.add ofs (Int.repr delta))) = true.
Hypothesis weak_valid_pointer_inj:
forall b1 ofs b2 delta,
f b1 = Some(b2, delta) ->
Mem.weak_valid_pointer m b1 (Int.unsigned ofs) = true ->
Mem.weak_valid_pointer m´ b2 (Int.unsigned (Int.add ofs (Int.repr delta))) = true.
Hypothesis weak_valid_pointer_no_overflow:
forall b1 ofs b2 delta,
f b1 = Some(b2, delta) ->
Mem.weak_valid_pointer m b1 (Int.unsigned ofs) = true ->
0 <= Int.unsigned ofs + Int.unsigned (Int.repr delta) <= Int.max_unsigned.
Hypothesis valid_different_pointers_inj:
forall b1 ofs1 b2 ofs2 b1´ delta1 b2´ delta2,
b1 <> b2 ->
Mem.valid_pointer m b1 (Int.unsigned ofs1) = true ->
Mem.valid_pointer m b2 (Int.unsigned ofs2) = true ->
f b1 = Some (b1´, delta1) ->
f b2 = Some (b2´, delta2) ->
b1´ <> b2´ \/
Int.unsigned (Int.add ofs1 (Int.repr delta1)) <> Int.unsigned (Int.add ofs2 (Int.repr delta2)).
Remark val_inject_vtrue: forall f, val_inject f Vtrue Vtrue.
Proof. unfold Vtrue; auto. Qed.
Remark val_inject_vfalse: forall f, val_inject f Vfalse Vfalse.
Proof. unfold Vfalse; auto. Qed.
Remark val_inject_of_bool: forall f b, val_inject f (Val.of_bool b) (Val.of_bool b).
Proof. intros. unfold Val.of_bool. destruct b; [apply val_inject_vtrue|apply val_inject_vfalse].
Qed.
Hint Resolve val_inject_vtrue val_inject_vfalse val_inject_of_bool.
Ltac TrivialInject :=
match goal with
| |- exists v´, Some ?v = Some v´ /\ _ => exists v; split; auto
| _ => idtac
end.
Lemma sem_cast_inject:
forall v1 ty1 ty v tv1,
sem_cast v1 ty1 ty = Some v ->
val_inject f v1 tv1 ->
exists tv, sem_cast tv1 ty1 ty = Some tv /\ val_inject f v tv.
Proof.
unfold sem_cast; intros; destruct (classify_cast ty1 ty);
inv H0; inv H; TrivialInject.
- econstructor; eauto.
- destruct (cast_float_int si2 f0); inv H1; TrivialInject.
- destruct (cast_float_long si2 f0); inv H1; TrivialInject.
- destruct (ident_eq id1 id2 && fieldlist_eq fld1 fld2); inv H2; TrivialInject. econstructor; eauto.
- destruct (ident_eq id1 id2 && fieldlist_eq fld1 fld2); inv H2; TrivialInject. econstructor; eauto.
- econstructor; eauto.
Qed.
Lemma sem_unary_operation_inject:
forall op v1 ty v tv1,
sem_unary_operation op v1 ty = Some v ->
val_inject f v1 tv1 ->
exists tv, sem_unary_operation op tv1 ty = Some tv /\ val_inject f v tv.
Proof.
unfold sem_unary_operation; intros. destruct op.
unfold sem_notbool in *; destruct (classify_bool ty); inv H0; inv H; TrivialInject.
unfold sem_notint in *; destruct (classify_notint ty); inv H0; inv H; TrivialInject.
unfold sem_neg in *; destruct (classify_neg ty); inv H0; inv H; TrivialInject.
unfold sem_absfloat in *; destruct (classify_neg ty); inv H0; inv H; TrivialInject.
Qed.
Definition optval_self_injects (ov: option val) : Prop :=
match ov with
| Some (Vptr b ofs) => False
| _ => True
end.
Remark sem_binarith_inject:
forall sem_int sem_long sem_float v1 t1 v2 t2 v v1´ v2´,
sem_binarith sem_int sem_long sem_float v1 t1 v2 t2 = Some v ->
val_inject f v1 v1´ -> val_inject f v2 v2´ ->
(forall sg n1 n2, optval_self_injects (sem_int sg n1 n2)) ->
(forall sg n1 n2, optval_self_injects (sem_long sg n1 n2)) ->
(forall n1 n2, optval_self_injects (sem_float n1 n2)) ->
exists v´, sem_binarith sem_int sem_long sem_float v1´ t1 v2´ t2 = Some v´ /\ val_inject f v v´.
Proof.
intros.
assert (SELF: forall ov v, ov = Some v -> optval_self_injects ov -> val_inject f v v).
{
intros. subst ov; simpl in H6. destruct v0; contradiction || constructor.
}
unfold sem_binarith in *.
set (c := classify_binarith t1 t2) in *.
set (t := binarith_type c) in *.
destruct (sem_cast v1 t1 t) as [w1|] eqn:C1; try discriminate.
destruct (sem_cast v2 t2 t) as [w2|] eqn:C2; try discriminate.
exploit (sem_cast_inject v1); eauto. intros (w1´ & C1´ & INJ1).
exploit (sem_cast_inject v2); eauto. intros (w2´ & C2´ & INJ2).
rewrite C1´; rewrite C2´.
destruct c; inv INJ1; inv INJ2; discriminate || eauto.
Qed.
Remark sem_shift_inject:
forall sem_int sem_long v1 t1 v2 t2 v v1´ v2´,
sem_shift sem_int sem_long v1 t1 v2 t2 = Some v ->
val_inject f v1 v1´ -> val_inject f v2 v2´ ->
exists v´, sem_shift sem_int sem_long v1´ t1 v2´ t2 = Some v´ /\ val_inject f v v´.
Proof.
intros. exists v.
unfold sem_shift in *; destruct (classify_shift t1 t2); inv H0; inv H1; try discriminate.
destruct (Int.ltu i0 Int.iwordsize); inv H; auto.
destruct (Int64.ltu i0 Int64.iwordsize); inv H; auto.
destruct (Int64.ltu i0 (Int64.repr 32)); inv H; auto.
destruct (Int.ltu i0 Int64.iwordsize´); inv H; auto.
Qed.
Remark sem_cmp_inj:
forall cmp v1 tv1 ty1 v2 tv2 ty2 v,
sem_cmp cmp v1 ty1 v2 ty2 m = Some v ->
val_inject f v1 tv1 ->
val_inject f v2 tv2 ->
exists tv, sem_cmp cmp tv1 ty1 tv2 ty2 m´ = Some tv /\ val_inject f v tv.
Proof.
intros.
unfold sem_cmp in *; destruct (classify_cmp ty1 ty2).
-
destruct (Val.cmpu_bool (Mem.valid_pointer m) cmp v1 v2) as [b|] eqn:E; simpl in H; inv H.
replace (Val.cmpu_bool (Mem.valid_pointer m´) cmp tv1 tv2) with (Some b).
simpl. TrivialInject.
symmetry. eapply val_cmpu_bool_inject; eauto.
-
destruct v2; try discriminate. inv H1.
set (v2 := Vint (Int.repr (Int64.unsigned i))) in *.
destruct (Val.cmpu_bool (Mem.valid_pointer m) cmp v1 v2) as [b|] eqn:E; simpl in H; inv H.
replace (Val.cmpu_bool (Mem.valid_pointer m´) cmp tv1 v2) with (Some b).
simpl. TrivialInject.
symmetry. eapply val_cmpu_bool_inject with (v2 := v2); eauto. constructor.
-
destruct v1; try discriminate. inv H0.
set (v1 := Vint (Int.repr (Int64.unsigned i))) in *.
destruct (Val.cmpu_bool (Mem.valid_pointer m) cmp v1 v2) as [b|] eqn:E; simpl in H; inv H.
replace (Val.cmpu_bool (Mem.valid_pointer m´) cmp v1 tv2) with (Some b).
simpl. TrivialInject.
symmetry. eapply val_cmpu_bool_inject with (v1 := v1); eauto. constructor.
-
assert (SELF: forall b, optval_self_injects (Some (Val.of_bool b))).
{
destruct b; exact I.
}
eapply sem_binarith_inject; eauto.
Qed.
Lemma sem_binary_operation_inj:
forall op v1 ty1 v2 ty2 v tv1 tv2,
sem_binary_operation op v1 ty1 v2 ty2 m = Some v ->
val_inject f v1 tv1 -> val_inject f v2 tv2 ->
exists tv, sem_binary_operation op tv1 ty1 tv2 ty2 m´ = Some tv /\ val_inject f v tv.
Proof.
unfold sem_binary_operation; intros; destruct op.
-
unfold sem_add in *; destruct (classify_add ty1 ty2).
+ inv H0; inv H1; inv H. TrivialInject.
econstructor. eauto. repeat rewrite Int.add_assoc. decEq. apply Int.add_commut.
+ inv H0; inv H1; inv H. TrivialInject.
econstructor. eauto. repeat rewrite Int.add_assoc. decEq. apply Int.add_commut.
+ inv H0; inv H1; inv H. TrivialInject.
econstructor. eauto. repeat rewrite Int.add_assoc. decEq. apply Int.add_commut.
+ inv H0; inv H1; inv H. TrivialInject.
econstructor. eauto. repeat rewrite Int.add_assoc. decEq. apply Int.add_commut.
+ eapply sem_binarith_inject; eauto; intros; exact I.
-
unfold sem_sub in *; destruct (classify_sub ty1 ty2).
+ inv H0; inv H1; inv H. TrivialInject.
econstructor. eauto. rewrite Int.sub_add_l. auto.
+ inv H0; inv H1; inv H. TrivialInject.
destruct (eq_block b1 b0); try discriminate. subst b1.
rewrite H0 in H2; inv H2. rewrite dec_eq_true.
destruct (Int.eq (Int.repr (sizeof ty)) Int.zero); inv H3.
rewrite Int.sub_shifted. TrivialInject.
+ inv H0; inv H1; inv H. TrivialInject.
econstructor. eauto. rewrite Int.sub_add_l. auto.
+ eapply sem_binarith_inject; eauto; intros; exact I.
-
eapply sem_binarith_inject; eauto; intros; exact I.
-
eapply sem_binarith_inject; eauto; intros.
destruct sg.
destruct (Int.eq n2 Int.zero
|| Int.eq n1 (Int.repr Int.min_signed) && Int.eq n2 Int.mone); exact I.
destruct (Int.eq n2 Int.zero); exact I.
destruct sg.
destruct (Int64.eq n2 Int64.zero
|| Int64.eq n1 (Int64.repr Int64.min_signed) && Int64.eq n2 Int64.mone); exact I.
destruct (Int64.eq n2 Int64.zero); exact I.
exact I.
-
eapply sem_binarith_inject; eauto; intros.
destruct sg.
destruct (Int.eq n2 Int.zero
|| Int.eq n1 (Int.repr Int.min_signed) && Int.eq n2 Int.mone); exact I.
destruct (Int.eq n2 Int.zero); exact I.
destruct sg.
destruct (Int64.eq n2 Int64.zero
|| Int64.eq n1 (Int64.repr Int64.min_signed) && Int64.eq n2 Int64.mone); exact I.
destruct (Int64.eq n2 Int64.zero); exact I.
exact I.
-
eapply sem_binarith_inject; eauto; intros; exact I.
-
eapply sem_binarith_inject; eauto; intros; exact I.
-
eapply sem_binarith_inject; eauto; intros; exact I.
-
eapply sem_shift_inject; eauto.
-
eapply sem_shift_inject; eauto.
- eapply sem_cmp_inj; eauto.
- eapply sem_cmp_inj; eauto.
- eapply sem_cmp_inj; eauto.
- eapply sem_cmp_inj; eauto.
- eapply sem_cmp_inj; eauto.
- eapply sem_cmp_inj; eauto.
Qed.
Lemma bool_val_inject:
forall v ty b tv,
bool_val v ty = Some b ->
val_inject f v tv ->
bool_val tv ty = Some b.
Proof.
unfold bool_val; intros.
destruct (classify_bool ty); inv H0; congruence.
Qed.
End GENERIC_INJECTION.
Lemma sem_binary_operation_inject:
forall f m m´ op v1 ty1 v2 ty2 v tv1 tv2,
sem_binary_operation op v1 ty1 v2 ty2 m = Some v ->
val_inject f v1 tv1 -> val_inject f v2 tv2 ->
Mem.inject f m m´ ->
exists tv, sem_binary_operation op tv1 ty1 tv2 ty2 m´ = Some tv /\ val_inject f v tv.
Proof.
intros. eapply sem_binary_operation_inj; eauto.
intros; eapply Mem.valid_pointer_inject_val; eauto.
intros; eapply Mem.weak_valid_pointer_inject_val; eauto.
intros; eapply Mem.weak_valid_pointer_inject_no_overflow; eauto.
intros; eapply Mem.different_pointers_inject; eauto.
Qed.
End WITHMEM.
Some properties of operator semantics
Lemma cast_bool_bool_val:
forall v t,
sem_cast v t (Tint IBool Signed noattr) =
match bool_val v t with None => None | Some b => Some(Val.of_bool b) end.
Proof.
intros.
assert (A: classify_bool t =
match t with
| Tint _ _ _ => bool_case_i
| Tpointer _ _ | Tcomp_ptr _ _ | Tarray _ _ _ | Tfunction _ _ _ => bool_case_p
| Tfloat _ _ => bool_case_f
| Tlong _ _ => bool_case_l
| _ => bool_default
end).
{
unfold classify_bool; destruct t; simpl; auto. destruct i; auto.
}
unfold bool_val. rewrite A. unfold sem_cast. destruct t; simpl; auto; destruct v; auto.
destruct (Int.eq i0 Int.zero); auto.
destruct (Int64.eq i Int64.zero); auto.
destruct (Float.cmp Ceq f0 Float.zero); auto.
destruct (Int.eq i Int.zero); auto.
destruct (Int.eq i Int.zero); auto.
destruct (Int.eq i Int.zero); auto.
destruct (Int.eq i0 Int.zero); auto.
Qed.
Relation between Boolean value and Boolean negation.
Lemma notbool_bool_val:
forall v t,
sem_notbool v t =
match bool_val v t with None => None | Some b => Some(Val.of_bool (negb b)) end.
Proof.
intros. unfold sem_notbool, bool_val.
destruct (classify_bool t); auto; destruct v; auto; rewrite negb_involutive; auto.
Qed.
Relation with the arithmetic conversions of ISO C99, section 6.3.1
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.
Definition eq_int_type: forall (x y: int_type), {x=y} + {x<>y}.
Proof. decide equality. Defined.
Definition is_unsigned (t: int_type) : bool :=
match t with
| _Bool => true
| Char => false
| 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
| Longdouble, _ | _, Longdouble => Longdouble
| Double, _ | _, Double => Double
| Float, _ | _, Float => Float
| I i1, I i2 =>
let j1 := integer_promotion i1 in
let j2 := integer_promotion i2 in
if eq_int_type j1 j2 then I j1 else
match is_unsigned j1, is_unsigned j2 with
| true, true | false, false =>
if zlt (rank j1) (rank j2) then I j2 else I j1
| true, false =>
if zle (rank j2) (rank j1) then I j1 else
if zlt (int_sizeof j1) (int_sizeof j2) then I j2 else
I (unsigned_type j2)
| false, true =>
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.
Relation between typeconv and integer promotion.
Lemma typeconv_integer_promotion:
forall i, typeconv (proj_type (I i)) = proj_type (I (integer_promotion i)).
Proof.
destruct i; reflexivity.
Qed.
Relation between classify_binarith and arithmetic conversion.
Lemma classify_binarith_arithmetic_conversion:
forall t1 t2,
binarith_result_type (classify_binarith (proj_type t1) (proj_type t2)) =
Some (proj_type (usual_arithmetic_conversion t1 t2)).
Proof.
destruct t1; destruct t2; try reflexivity.
- destruct it; destruct it0; reflexivity.
- destruct it; reflexivity.
- destruct it; reflexivity.
- destruct it; reflexivity.
- destruct it; reflexivity.
- destruct it; reflexivity.
- destruct it; reflexivity.
Qed.
End ArithConv.