summaryrefslogtreecommitdiff
path: root/cfrontend
diff options
context:
space:
mode:
authorGravatar xleroy <xleroy@fca1b0fc-160b-0410-b1d3-a4f43f01ea2e>2006-09-04 15:08:29 +0000
committerGravatar xleroy <xleroy@fca1b0fc-160b-0410-b1d3-a4f43f01ea2e>2006-09-04 15:08:29 +0000
commit73729d23ac13275c0d28d23bc1b1f6056104e5d9 (patch)
treee3044ce75edb30377bd8c87356b7617eba5ed223 /cfrontend
parentc79434827bf2bd71f857f4471f7bbf381fddd189 (diff)
Fusion de la branche "traces":
- Ajout de traces d'evenements d'E/S dans les semantiques - Ajout constructions switch et allocation dynamique - Initialisation des variables globales - Portage Coq 8.1 beta Debut d'integration du front-end C: - Traduction Clight -> Csharpminor dans cfrontend/ - Modifications de Csharpminor et Globalenvs en consequence. git-svn-id: https://yquem.inria.fr/compcert/svn/compcert/trunk@72 fca1b0fc-160b-0410-b1d3-a4f43f01ea2e
Diffstat (limited to 'cfrontend')
-rw-r--r--cfrontend/Csem.v752
-rw-r--r--cfrontend/Cshmgen.v598
-rw-r--r--cfrontend/Cshmgenproof1.v288
-rw-r--r--cfrontend/Cshmgenproof2.v419
-rw-r--r--cfrontend/Cshmgenproof3.v1503
-rw-r--r--cfrontend/Csyntax.v456
-rw-r--r--cfrontend/Ctyping.v420
7 files changed, 4436 insertions, 0 deletions
diff --git a/cfrontend/Csem.v b/cfrontend/Csem.v
new file mode 100644
index 0000000..b73e83c
--- /dev/null
+++ b/cfrontend/Csem.v
@@ -0,0 +1,752 @@
+(** * Dynamic semantics for the Clight language *)
+
+Require Import Coqlib.
+Require Import Maps.
+Require Import Integers.
+Require Import Floats.
+Require Import Values.
+Require Import AST.
+Require Import Mem.
+Require Import Events.
+Require Import Globalenvs.
+Require Import Csyntax.
+
+(** ** Semantics of type-dependent operations *)
+
+Inductive is_false: val -> type -> Prop :=
+ | is_false_int: forall sz sg,
+ is_false (Vint Int.zero) (Tint sz sg)
+ | is_false_pointer: forall t,
+ is_false (Vint Int.zero) (Tpointer t)
+ | is_false_float: forall sz,
+ is_false (Vfloat Float.zero) (Tfloat sz).
+
+Inductive is_true: val -> type -> Prop :=
+ | is_true_int_int: forall n sz sg,
+ n <> Int.zero ->
+ is_true (Vint n) (Tint sz sg)
+ | is_true_pointer_int: forall b ofs sz sg,
+ is_true (Vptr b ofs) (Tint sz sg)
+ | is_true_int_pointer: forall n t,
+ n <> Int.zero ->
+ is_true (Vint n) (Tpointer t)
+ | is_true_pointer_pointer: forall b ofs t,
+ is_true (Vptr b ofs) (Tpointer t)
+ | is_true_float: forall f sz,
+ f <> Float.zero ->
+ is_true (Vfloat f) (Tfloat sz).
+
+Inductive bool_of_val : val -> type -> val -> Prop :=
+ | bool_of_val_true: forall v ty,
+ is_true v ty ->
+ bool_of_val v ty Vtrue
+ | bool_of_val_false: forall v ty,
+ is_false v ty ->
+ bool_of_val v ty Vfalse.
+
+Function sem_neg (v: val) (ty: type) : option val :=
+ match ty with
+ | Tint _ _ =>
+ match v with
+ | Vint n => Some (Vint (Int.neg n))
+ | _ => None
+ end
+ | Tfloat _ =>
+ match v with
+ | Vfloat f => Some (Vfloat (Float.neg f))
+ | _ => None
+ end
+ | _ => None
+ end.
+
+Function sem_notint (v: val) : option val :=
+ match v with
+ | Vint n => Some (Vint (Int.xor n Int.mone))
+ | _ => None
+ end.
+
+Function sem_notbool (v: val) (ty: type) : option val :=
+ match ty with
+ | Tint _ _ =>
+ match v with
+ | Vint n => Some (Val.of_bool (Int.eq n Int.zero))
+ | Vptr _ _ => Some Vfalse
+ | _ => None
+ end
+ | Tpointer _ =>
+ match v with
+ | Vint n => Some (Val.of_bool (Int.eq n Int.zero))
+ | Vptr _ _ => Some Vfalse
+ | _ => None
+ end
+ | Tfloat _ =>
+ match v with
+ | Vfloat f => Some (Val.of_bool (Float.cmp Ceq f Float.zero))
+ | _ => None
+ end
+ | _ => None
+ end.
+
+Function sem_add (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
+ match classify_add t1 t2 with
+ | add_case_ii =>
+ match v1, v2 with
+ | Vint n1, Vint n2 => Some (Vint (Int.add n1 n2))
+ | _, _ => None
+ end
+ | add_case_ff =>
+ match v1, v2 with
+ | Vfloat n1, Vfloat n2 => Some (Vfloat (Float.add n1 n2))
+ | _, _ => None
+ end
+ | 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_default => None
+end.
+
+Function sem_sub (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
+ match classify_sub t1 t2 with
+ | sub_case_ii => (* integer subtraction *)
+ match v1,v2 with
+ | Vint n1, Vint n2 => Some (Vint (Int.sub n1 n2))
+ | _, _ => None
+ end
+ | sub_case_ff => (* float subtraction *)
+ match v1,v2 with
+ | Vfloat f1, Vfloat f2 => Some (Vfloat(Float.sub f1 f2))
+ | _, _ => None
+ end
+ | sub_case_pi ty => (*array| pointer - offset *)
+ 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_pp ty => (* array|pointer - array|pointer *)
+ match v1,v2 with
+ | Vptr b1 ofs1, Vptr b2 ofs2 =>
+ if zeq 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 => None
+ end.
+
+Function sem_mul (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
+ match classify_mul t1 t2 with
+ | mul_case_ii =>
+ match v1,v2 with
+ | Vint n1, Vint n2 => Some (Vint (Int.mul n1 n2))
+ | _, _ => None
+ end
+ | mul_case_ff =>
+ match v1,v2 with
+ | Vfloat f1, Vfloat f2 => Some (Vfloat (Float.mul f1 f2))
+ | _, _ => None
+ end
+ | mul_default =>
+ None
+end.
+
+Function sem_div (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
+ match classify_div t1 t2 with
+ | div_case_I32unsi =>
+ match v1,v2 with
+ | Vint n1, Vint n2 =>
+ if Int.eq n2 Int.zero then None else Some (Vint (Int.divu n1 n2))
+ | _,_ => None
+ end
+ | div_case_ii =>
+ match v1,v2 with
+ | Vint n1, Vint n2 =>
+ if Int.eq n2 Int.zero then None else Some (Vint(Int.divs n1 n2))
+ | _,_ => None
+ end
+ | div_case_ff =>
+ match v1,v2 with
+ | Vfloat f1, Vfloat f2 => Some (Vfloat(Float.div f1 f2))
+ | _, _ => None
+ end
+ | div_default =>
+ None
+end.
+
+Function sem_mod (v1:val) (t1:type) (v2: val) (t2:type) : option val :=
+ match classify_mod t1 t2 with
+ | mod_case_I32unsi =>
+ match v1, v2 with
+ | Vint n1, Vint n2 =>
+ if Int.eq n2 Int.zero then None else Some (Vint (Int.modu n1 n2))
+ | _, _ => None
+ end
+ | mod_case_ii =>
+ match v1,v2 with
+ | Vint n1, Vint n2 =>
+ if Int.eq n2 Int.zero then None else Some (Vint (Int.mods n1 n2))
+ | _, _ => None
+ end
+ | mod_default =>
+ None
+ end.
+
+Function sem_and (v1 v2: val) : option val :=
+ match v1, v2 with
+ | Vint n1, Vint n2 => Some (Vint(Int.and n1 n2))
+ | _, _ => None
+ end .
+
+Function sem_or (v1 v2: val) : option val :=
+ match v1, v2 with
+ | Vint n1, Vint n2 => Some (Vint(Int.or n1 n2))
+ | _, _ => None
+ end.
+
+Function sem_xor (v1 v2: val): option val :=
+ match v1, v2 with
+ | Vint n1, Vint n2 => Some (Vint(Int.xor n1 n2))
+ | _, _ => None
+ end.
+
+Function sem_shl (v1 v2: val): option val :=
+ match v1, v2 with
+ | Vint n1, Vint n2 =>
+ if Int.ltu n2 (Int.repr 32) then Some (Vint(Int.shl n1 n2)) else None
+ | _, _ => None
+ end.
+
+Function sem_shr (v1: val) (t1: type) (v2: val) (t2: type): option val :=
+ match classify_shr t1 t2 with
+ | shr_case_I32unsi =>
+ match v1,v2 with
+ | Vint n1, Vint n2 =>
+ if Int.ltu n2 (Int.repr 32) then Some (Vint (Int.shru n1 n2)) else None
+ | _,_ => None
+ end
+ | shr_case_ii =>
+ match v1,v2 with
+ | Vint n1, Vint n2 =>
+ if Int.ltu n2 (Int.repr 32) then Some (Vint (Int.shr n1 n2)) else None
+ | _, _ => None
+ end
+ | shr_default=>
+ None
+ end.
+
+Function sem_cmp_mismatch (c: comparison): option val :=
+ match c with
+ | Ceq => Some Vfalse
+ | Cne => Some Vtrue
+ | _ => None
+ end.
+
+Function sem_cmp (c:comparison)
+ (v1: val) (t1: type) (v2: val) (t2: type)
+ (m: mem): option val :=
+ match classify_cmp t1 t2 with
+ | cmp_case_I32unsi =>
+ match v1,v2 with
+ | Vint n1, Vint n2 =>Some (Val.of_bool (Int.cmpu c n1 n2))
+ | _, _ => None
+ end
+ | cmp_case_ii =>
+ match v1,v2 with
+ | Vint n1, Vint n2 =>Some (Val.of_bool (Int.cmp c n1 n2))
+ | _, _ => None
+ end
+ | cmp_case_ff =>
+ match v1,v2 with
+ | Vfloat f1, Vfloat f2 =>Some (Val.of_bool (Float.cmp c f1 f2))
+ | _, _ => None
+ end
+ | cmp_case_pi =>
+ match v1,v2 with
+ | Vptr b ofs, Vint n2 =>
+ if Int.eq n2 Int.zero then sem_cmp_mismatch c else None
+ | _, _ => None
+ end
+ | cmp_case_pp =>
+ match v1,v2 with
+ | Vptr b1 ofs1, Vptr b2 ofs2 =>
+ if valid_pointer m b1 (Int.signed ofs1) && valid_pointer m b2 (Int.signed ofs2) then
+ if zeq b1 b2
+ then Some (Val.of_bool (Int.cmp c ofs1 ofs2))
+ else None
+ else None
+ | _, _ => None
+ end
+ | cmp_default => None
+ 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
+ | Oneg => sem_neg 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 v2
+ | Oor => sem_or v1 v2
+ | Oxor => sem_xor v1 v2
+ | Oshl => sem_shl v1 v2
+ | 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 cast_int_int (sz: intsize) (sg: signedness) (i: int) : int :=
+ match sz, sg with
+ | I8, Signed => Int.cast8signed i
+ | I8, Unsigned => Int.cast8unsigned i
+ | I16, Signed => Int.cast16signed i
+ | I16, Unsigned => Int.cast16unsigned i
+ | I32 , _ => i
+ end.
+
+Definition cast_int_float (si : signedness) (i: int) : float :=
+ match si with
+ | Signed => Float.floatofint i
+ | Unsigned => Float.floatofintu i
+ end.
+
+Definition cast_float_float (sz: floatsize) (f: float) : float :=
+ match sz with
+ | F32 => Float.singleoffloat f
+ | F64 => f
+ end.
+
+Inductive cast : val -> type -> type -> val -> Prop :=
+ | cast_ii: forall i sz2 sz1 si1 si2,
+ cast (Vint i) (Tint sz1 si1) (Tint sz2 si2)
+ (Vint (cast_int_int sz2 si2 i))
+ | cast_fi: forall f sz1 sz2 si2,
+ cast (Vfloat f) (Tfloat sz1) (Tint sz2 si2)
+ (Vint (cast_int_int sz2 si2 (Float.intoffloat f)))
+ | cast_if: forall i sz1 sz2 si1,
+ cast (Vint i) (Tint sz1 si1) (Tfloat sz2)
+ (Vfloat (cast_float_float sz2 (cast_int_float si1 i)))
+ | cast_ff: forall f sz1 sz2,
+ cast (Vfloat f) (Tfloat sz1) (Tfloat sz2)
+ (Vfloat (cast_float_float sz2 f))
+ | cast_ip_p: forall b ofs t1 si2,
+ cast (Vptr b ofs) (Tint I32 si2) (Tpointer t1) (Vptr b ofs)
+ | cast_pi_p: forall b ofs t1 si2,
+ cast (Vptr b ofs) (Tpointer t1) (Tint I32 si2) (Vptr b ofs)
+ | cast_pp_p: forall b ofs t1 t2,
+ cast (Vptr b ofs) (Tpointer t1) (Tpointer t2) (Vptr b ofs)
+ | cast_ip_i: forall n t1 si2,
+ cast (Vint n) (Tint I32 si2) (Tpointer t1) (Vint n)
+ | cast_pi_i: forall n t1 si2,
+ cast (Vint n) (Tpointer t1) (Tint I32 si2) (Vint n)
+ | cast_pp_i: forall n t1 t2,
+ cast (Vint n) (Tpointer t1) (Tpointer t2) (Vint n).
+
+(** ** Operational semantics *)
+
+(** Global environment *)
+
+Definition genv := Genv.t fundef.
+
+Definition globalenv (p: program) : genv :=
+ Genv.globalenv (program_of_program p).
+
+Definition init_mem (p: program) : mem :=
+ Genv.init_mem (program_of_program p).
+
+(** Local environment *)
+
+Definition env := PTree.t block. (* map variable -> location *)
+
+Definition empty_env: env := (PTree.empty block).
+
+(** Outcomes for statements *)
+
+Inductive outcome: Set :=
+ | Out_break: outcome
+ | Out_continue: outcome
+ | Out_normal: outcome
+ | Out_return: option val -> outcome.
+
+Inductive out_normal_or_continue : outcome -> Prop :=
+ | Out_normal_or_continue_N: out_normal_or_continue Out_normal
+ | Out_normal_or_continue_C: out_normal_or_continue Out_continue.
+
+Inductive out_break_or_return : outcome -> outcome -> Prop :=
+ | Out_break_or_return_B: out_break_or_return Out_break Out_normal
+ | Out_break_or_return_R: forall ov,
+ out_break_or_return (Out_return ov) (Out_return ov).
+
+Definition outcome_switch (out: outcome) : outcome :=
+ match out with
+ | Out_break => Out_normal
+ | o => o
+ end.
+
+Definition outcome_result_value (out: outcome) (t: type) (v: val) : Prop :=
+ match out, t with
+ | Out_normal, Tvoid => v = Vundef
+ | Out_return None, Tvoid => v = Vundef
+ | Out_return (Some v'), ty => ty <> Tvoid /\ v'=v
+ | _, _ => False
+ end.
+
+(** Selection of the appropriate case of a [switch] *)
+
+Fixpoint select_switch (n: int) (sl: labeled_statements)
+ {struct sl}: labeled_statements :=
+ match sl with
+ | LSdefault _ => sl
+ | LScase c s sl' => if Int.eq c n then sl else select_switch n sl'
+ end.
+
+(** Loads and stores by type *)
+
+Definition load_value_of_type (ty: type) (m: mem) (b: block) (ofs: int) : option val :=
+ match access_mode ty with
+ | By_value chunk => Mem.loadv chunk m (Vptr b ofs)
+ | By_reference => Some (Vptr b ofs)
+ | By_nothing => None
+ end.
+
+Definition store_value_of_type (ty_dest: type) (m: mem) (loc: block) (ofs: int) (v: val) : option mem :=
+ match access_mode ty_dest with
+ | By_value chunk => Mem.storev chunk m (Vptr loc ofs) v
+ | By_reference => None
+ | By_nothing => None
+ end.
+
+(** Allocation and initialization of function-local variables *)
+
+Inductive alloc_variables: env -> mem ->
+ list (ident * type) ->
+ env -> mem -> list block -> Prop :=
+ | alloc_variables_nil:
+ forall e m,
+ alloc_variables e m nil e m nil
+ | alloc_variables_cons:
+ forall e m id ty vars m1 b1 m2 e2 lb,
+ Mem.alloc m 0 (sizeof ty) = (m1, b1) ->
+ alloc_variables (PTree.set id b1 e) m1 vars e2 m2 lb ->
+ alloc_variables e m ((id, ty) :: vars) e2 m2 (b1 :: lb).
+
+Inductive bind_parameters: env ->
+ mem -> list (ident * type) -> list val ->
+ mem -> Prop :=
+ | bind_parameters_nil:
+ forall e m,
+ bind_parameters e m nil nil m
+ | bind_parameters_cons:
+ forall e m id ty params v1 vl b m1 m2,
+ PTree.get id e = Some b ->
+ store_value_of_type ty m b Int.zero v1 = Some m1 ->
+ bind_parameters e m1 params vl m2 ->
+ bind_parameters e m ((id, ty) :: params) (v1 :: vl) m2.
+
+Section RELSEM.
+
+Variable ge: genv.
+
+(** Evaluation of an expression in r-value position *)
+
+Inductive eval_expr: env -> mem -> expr -> trace -> mem -> val -> Prop :=
+ | eval_Econst_int: forall e m i ty,
+ eval_expr e m (Expr (Econst_int i) ty)
+ E0 m (Vint i)
+ | eval_Econst_float: forall e m f ty,
+ eval_expr e m (Expr (Econst_float f) ty)
+ E0 m (Vfloat f)
+ | eval_Elvalue: forall e m a ty t m1 loc ofs v,
+ eval_lvalue e m (Expr a ty) t m1 loc ofs ->
+ load_value_of_type ty m1 loc ofs = Some v ->
+ eval_expr e m (Expr a ty)
+ t m1 v
+ | eval_Eaddrof: forall e m a t m1 loc ofs ty,
+ eval_lvalue e m a t m1 loc ofs ->
+ eval_expr e m (Expr (Eaddrof a) ty)
+ t m1 (Vptr loc ofs)
+ | eval_Esizeof: forall e m ty' ty,
+ eval_expr e m (Expr (Esizeof ty') ty)
+ E0 m (Vint (Int.repr (sizeof ty')))
+ | eval_Eunop: forall e m op a ty t m1 v1 v,
+ eval_expr e m a t m1 v1 ->
+ sem_unary_operation op v1 (typeof a) = Some v ->
+ eval_expr e m (Expr (Eunop op a) ty)
+ t m1 v
+ | eval_Ebinop: forall e m op a1 a2 ty t1 m1 v1 t2 m2 v2 v,
+ eval_expr e m a1 t1 m1 v1 ->
+ eval_expr e m1 a2 t2 m2 v2 ->
+ sem_binary_operation op v1 (typeof a1) v2 (typeof a2) m2 = Some v ->
+ eval_expr e m (Expr (Ebinop op a1 a2) ty)
+ (t1 ** t2) m2 v
+ | eval_Eorbool_1: forall e m a1 a2 t m1 v1 ty,
+ eval_expr e m a1 t m1 v1 ->
+ is_true v1 (typeof a1) ->
+ eval_expr e m (Expr (Eorbool a1 a2) ty)
+ t m1 Vtrue
+ | eval_Eorbool_2: forall e m a1 a2 ty t1 m1 v1 t2 m2 v2 v,
+ eval_expr e m a1 t1 m1 v1 ->
+ is_false v1 (typeof a1) ->
+ eval_expr e m1 a2 t2 m2 v2 ->
+ bool_of_val v2 (typeof a2) v ->
+ eval_expr e m (Expr (Eorbool a1 a2) ty)
+ (t1 ** t2) m2 v
+ | eval_Eandbool_1: forall e m a1 a2 t m1 v1 ty,
+ eval_expr e m a1 t m1 v1 ->
+ is_false v1 (typeof a1) ->
+ eval_expr e m (Expr (Eandbool a1 a2) ty)
+ t m1 Vfalse
+ | eval_Eandbool_2: forall e m a1 a2 ty t1 m1 v1 t2 m2 v2 v,
+ eval_expr e m a1 t1 m1 v1 ->
+ is_true v1 (typeof a1) ->
+ eval_expr e m1 a2 t2 m2 v2 ->
+ bool_of_val v2 (typeof a2) v ->
+ eval_expr e m (Expr (Eandbool a1 a2) ty)
+ (t1 ** t2) m2 v
+ | eval_Ecast: forall e m a ty t m1 v1 v,
+ eval_expr e m a t m1 v1 ->
+ cast v1 (typeof a) ty v ->
+ eval_expr e m (Expr (Ecast ty a) ty)
+ t m1 v
+ | eval_Ecall: forall e m a bl ty m3 vres t1 m1 vf t2 m2 vargs f t3,
+ eval_expr e m a t1 m1 vf ->
+ eval_exprlist e m1 bl t2 m2 vargs ->
+ Genv.find_funct ge vf = Some f ->
+ type_of_fundef f = typeof a ->
+ eval_funcall m2 f vargs t3 m3 vres ->
+ eval_expr e m (Expr (Ecall a bl) ty)
+ (t1 ** t2 ** t3) m3 vres
+
+(** Evaluation of an expression in l-value position *)
+
+with eval_lvalue: env -> mem -> expr -> trace -> mem -> block -> int -> Prop :=
+ | eval_Evar_local: forall e m id l ty,
+ e!id = Some l ->
+ eval_lvalue e m (Expr (Evar id) ty)
+ E0 m l Int.zero
+ | eval_Evar_global: forall e m id l ty,
+ e!id = None ->
+ Genv.find_symbol ge id = Some l ->
+ eval_lvalue e m (Expr (Evar id) ty)
+ E0 m l Int.zero
+ | eval_Ederef: forall e m m1 a t ofs ty l,
+ eval_expr e m a t m1 (Vptr l ofs) ->
+ eval_lvalue e m (Expr (Ederef a) ty)
+ t m1 l ofs
+ | eval_Eindex: forall e m a1 t1 m1 v1 a2 t2 m2 v2 l ofs ty,
+ eval_expr e m a1 t1 m1 v1 ->
+ eval_expr e m1 a2 t2 m2 v2 ->
+ sem_add v1 (typeof a1) v2 (typeof a2) = Some (Vptr l ofs) ->
+ eval_lvalue e m (Expr (Eindex a1 a2) ty)
+ (t1 ** t2) m2 l ofs
+ | eval_Efield_struct: forall e m a t m1 l ofs fList i ty delta,
+ eval_lvalue e m a t m1 l ofs ->
+ typeof a = Tstruct fList ->
+ field_offset i fList = Some delta ->
+ eval_lvalue e m (Expr (Efield a i) ty)
+ t m1 l (Int.add ofs (Int.repr delta))
+ | eval_Efield_union: forall e m a t m1 l ofs fList i ty,
+ eval_lvalue e m a t m1 l ofs ->
+ typeof a = Tunion fList ->
+ eval_lvalue e m (Expr (Efield a i) ty)
+ t m1 l ofs
+
+(** Evaluation of a list of expressions *)
+
+with eval_exprlist: env -> mem -> exprlist -> trace -> mem -> list val -> Prop :=
+ | eval_Enil: forall e m,
+ eval_exprlist e m Enil E0 m nil
+ | eval_Econs: forall e m a bl t1 m1 v t2 m2 vl,
+ eval_expr e m a t1 m1 v ->
+ eval_exprlist e m1 bl t2 m2 vl ->
+ eval_exprlist e m (Econs a bl)
+ (t1 ** t2) m2 (v :: vl)
+
+(** Execution of a statement *)
+
+with exec_stmt: env -> mem -> statement -> trace -> mem -> outcome -> Prop :=
+ | exec_Sskip: forall e m,
+ exec_stmt e m Sskip
+ E0 m Out_normal
+ | exec_Sexpr: forall e m a t m1 v,
+ eval_expr e m a t m1 v ->
+ exec_stmt e m (Sexpr a)
+ t m1 Out_normal
+ | exec_Sassign: forall e m a1 a2 t1 m1 loc ofs t2 m2 v2 m3,
+ eval_lvalue e m a1 t1 m1 loc ofs ->
+ eval_expr e m1 a2 t2 m2 v2 ->
+ store_value_of_type (typeof a1) m2 loc ofs v2 = Some m3 ->
+ exec_stmt e m (Sassign a1 a2)
+ (t1 ** t2) m3 Out_normal
+ | exec_Sseq_1: forall e m s1 s2 t1 m1 t2 m2 out,
+ exec_stmt e m s1 t1 m1 Out_normal ->
+ exec_stmt e m1 s2 t2 m2 out ->
+ exec_stmt e m (Ssequence s1 s2)
+ (t1 ** t2) m2 out
+ | exec_Sseq_2: forall e m s1 s2 t1 m1 out,
+ exec_stmt e m s1 t1 m1 out ->
+ out <> Out_normal ->
+ exec_stmt e m (Ssequence s1 s2)
+ t1 m1 out
+ | exec_Sifthenelse_true: forall e m a s1 s2 t1 m1 v1 t2 m2 out,
+ eval_expr e m a t1 m1 v1 ->
+ is_true v1 (typeof a) ->
+ exec_stmt e m1 s1 t2 m2 out ->
+ exec_stmt e m (Sifthenelse a s1 s2)
+ (t1 ** t2) m2 out
+ | exec_Sifthenelse_false: forall e m a s1 s2 t1 m1 v1 t2 m2 out,
+ eval_expr e m a t1 m1 v1 ->
+ is_false v1 (typeof a) ->
+ exec_stmt e m1 s2 t2 m2 out ->
+ exec_stmt e m (Sifthenelse a s1 s2)
+ (t1 ** t2) m2 out
+ | exec_Sreturn_none: forall e m,
+ exec_stmt e m (Sreturn None)
+ E0 m (Out_return None)
+ | exec_Sreturn_some: forall e m a t m1 v,
+ eval_expr e m a t m1 v ->
+ exec_stmt e m (Sreturn (Some a))
+ t m1 (Out_return (Some v))
+ | exec_Sbreak: forall e m,
+ exec_stmt e m Sbreak
+ E0 m Out_break
+ | exec_Scontinue: forall e m,
+ exec_stmt e m Scontinue
+ E0 m Out_continue
+ | exec_Swhile_false: forall e m s a t v m1,
+ eval_expr e m a t m1 v ->
+ is_false v (typeof a) ->
+ exec_stmt e m (Swhile a s)
+ t m1 Out_normal
+ | exec_Swhile_stop: forall e m a t1 m1 v s m2 t2 out2 out,
+ eval_expr e m a t1 m1 v ->
+ is_true v (typeof a) ->
+ exec_stmt e m1 s t2 m2 out2 ->
+ out_break_or_return out2 out ->
+ exec_stmt e m (Swhile a s)
+ (t1 ** t2) m2 out
+ | exec_Swhile_loop: forall e m a t1 m1 v s out2 out t2 m2 t3 m3,
+ eval_expr e m a t1 m1 v ->
+ is_true v (typeof a) ->
+ exec_stmt e m1 s t2 m2 out2 ->
+ out_normal_or_continue out2 ->
+ exec_stmt e m2 (Swhile a s) t3 m3 out ->
+ exec_stmt e m (Swhile a s)
+ (t1 ** t2 ** t3) m3 out
+ | exec_Sdowhile_false: forall e m s a t1 m1 out1 v t2 m2,
+ exec_stmt e m s t1 m1 out1 ->
+ out_normal_or_continue out1 ->
+ eval_expr e m1 a t2 m2 v ->
+ is_false v (typeof a) ->
+ exec_stmt e m (Sdowhile a s)
+ (t1 ** t2) m2 Out_normal
+ | exec_Sdowhile_stop: forall e m s a t m1 out1 out,
+ exec_stmt e m s t m1 out1 ->
+ out_break_or_return out1 out ->
+ exec_stmt e m (Sdowhile a s)
+ t m1 out
+ | exec_Sdowhile_loop: forall e m s a m1 m2 m3 t1 t2 t3 out out1 v,
+ exec_stmt e m s t1 m1 out1 ->
+ out_normal_or_continue out1 ->
+ eval_expr e m1 a t2 m2 v ->
+ is_true v (typeof a) ->
+ exec_stmt e m2 (Sdowhile a s) t3 m3 out ->
+ exec_stmt e m (Sdowhile a s)
+ (t1 ** t2 ** t3) m3 out
+ | exec_Sfor_start: forall e m s a1 a2 a3 out m1 m2 t1 t2,
+ exec_stmt e m a1 t1 m1 Out_normal ->
+ exec_stmt e m1 (Sfor Sskip a2 a3 s) t2 m2 out ->
+ exec_stmt e m (Sfor a1 a2 a3 s)
+ (t1 ** t2) m2 out
+ | exec_Sfor_false: forall e m s a2 a3 t v m1,
+ eval_expr e m a2 t m1 v ->
+ is_false v (typeof a2) ->
+ exec_stmt e m (Sfor Sskip a2 a3 s)
+ t m1 Out_normal
+ | exec_Sfor_stop: forall e m s a2 a3 v m1 m2 t1 t2 out2 out,
+ eval_expr e m a2 t1 m1 v ->
+ is_true v (typeof a2) ->
+ exec_stmt e m1 s t2 m2 out2 ->
+ out_break_or_return out2 out ->
+ exec_stmt e m (Sfor Sskip a2 a3 s)
+ (t1 ** t2) m2 out
+ | exec_Sfor_loop: forall e m s a2 a3 v m1 m2 m3 m4 t1 t2 t3 t4 out2 out,
+ eval_expr e m a2 t1 m1 v ->
+ is_true v (typeof a2) ->
+ exec_stmt e m1 s t2 m2 out2 ->
+ out_normal_or_continue out2 ->
+ exec_stmt e m2 a3 t3 m3 Out_normal ->
+ exec_stmt e m3 (Sfor Sskip a2 a3 s) t4 m4 out ->
+ exec_stmt e m (Sfor Sskip a2 a3 s)
+ (t1 ** t2 ** t3 ** t4) m4 out
+ | exec_Sswitch: forall e m a t1 m1 n sl t2 m2 out,
+ eval_expr e m a t1 m1 (Vint n) ->
+ exec_lblstmts e m1 (select_switch n sl) t2 m2 out ->
+ exec_stmt e m (Sswitch a sl)
+ (t1 ** t2) m2 (outcome_switch out)
+
+(** Execution of a list of labeled statements *)
+
+with exec_lblstmts: env -> mem -> labeled_statements -> trace -> mem -> outcome -> Prop :=
+ | exec_LSdefault: forall e m s t m1 out,
+ exec_stmt e m s t m1 out ->
+ exec_lblstmts e m (LSdefault s) t m1 out
+ | exec_LScase_fallthrough: forall e m n s ls t1 m1 t2 m2 out,
+ exec_stmt e m s t1 m1 Out_normal ->
+ exec_lblstmts e m1 ls t2 m2 out ->
+ exec_lblstmts e m (LScase n s ls) (t1 ** t2) m2 out
+ | exec_LScase_stop: forall e m n s ls t m1 out,
+ exec_stmt e m s t m1 out -> out <> Out_normal ->
+ exec_lblstmts e m (LScase n s ls) t m1 out
+
+(** Evaluation of a function invocation *)
+
+with eval_funcall: mem -> fundef -> list val -> trace -> mem -> val -> Prop :=
+ | eval_funcall_internal: forall m f vargs t e m1 lb m2 m3 out vres,
+ alloc_variables empty_env m (f.(fn_params) ++ f.(fn_vars)) e m1 lb ->
+ bind_parameters e m1 f.(fn_params) vargs m2 ->
+ exec_stmt e m2 f.(fn_body) t m3 out ->
+ outcome_result_value out f.(fn_return) vres ->
+ eval_funcall m (Internal f) vargs t (Mem.free_list m3 lb) vres
+ | eval_funcall_external: forall m id targs tres vargs t vres,
+ event_match (external_function id targs tres) vargs t vres ->
+ eval_funcall m (External id targs tres) vargs t m vres.
+
+Scheme eval_expr_ind6 := Minimality for eval_expr Sort Prop
+ with eval_lvalue_ind6 := Minimality for eval_lvalue Sort Prop
+ with eval_exprlist_ind6 := Minimality for eval_exprlist Sort Prop
+ with exec_stmt_ind6 := Minimality for exec_stmt Sort Prop
+ with exec_lblstmts_ind6 := Minimality for exec_lblstmts Sort Prop
+ with eval_funcall_ind6 := Minimality for eval_funcall Sort Prop.
+
+End RELSEM.
+
+(** Execution of a whole program *)
+
+Definition exec_program (p: program) (t: trace) (r: val) : Prop :=
+ let ge := globalenv p in
+ let m0 := init_mem p in
+ exists b, exists f, exists m1,
+ Genv.find_symbol ge p.(prog_main) = Some b /\
+ Genv.find_funct_ptr ge b = Some f /\
+ type_of_fundef f = Tfunction Tnil (Tint I32 Signed) /\
+ eval_funcall ge m0 f nil t m1 r.
diff --git a/cfrontend/Cshmgen.v b/cfrontend/Cshmgen.v
new file mode 100644
index 0000000..58c0bb8
--- /dev/null
+++ b/cfrontend/Cshmgen.v
@@ -0,0 +1,598 @@
+Require Import Coqlib.
+Require Import Integers.
+Require Import Floats.
+Require Import AST.
+Require Import Csyntax.
+Require Import Csharpminor.
+
+(** The error monad *)
+
+Definition bind (A B: Set) (f: option A) (g: A -> option B) :=
+ match f with None => None | Some x => g x end.
+
+Implicit Arguments bind [A B].
+
+Notation "'do' X <- A ; B" := (bind A (fun X => B))
+ (at level 200, X ident, A at level 100, B at level 200).
+
+(** ** Operations on C types *)
+
+Definition signature_of_function (f: Csyntax.function) : signature :=
+ mksignature
+ (typlist_of_typelist (type_of_params (Csyntax.fn_params f)))
+ (opttyp_of_type (Csyntax.fn_return f)).
+
+Definition chunk_of_type (ty: type): option memory_chunk :=
+ match access_mode ty with
+ | By_value chunk => Some chunk
+ | _ => None
+ end.
+
+Definition var_kind_of_type (ty: type): option var_kind :=
+ match ty with
+ | Tint I8 Signed => Some(Vscalar Mint8signed)
+ | Tint I8 Unsigned => Some(Vscalar Mint8unsigned)
+ | Tint I16 Signed => Some(Vscalar Mint16signed)
+ | Tint I16 Unsigned => Some(Vscalar Mint16unsigned)
+ | Tint I32 _ => Some(Vscalar Mint32)
+ | Tfloat F32 => Some(Vscalar Mfloat32)
+ | Tfloat F64 => Some(Vscalar Mfloat64)
+ | Tvoid => None
+ | Tpointer _ => Some(Vscalar Mint32)
+ | Tarray _ _ => Some(Varray (Csyntax.sizeof ty))
+ | Tfunction _ _ => None
+ | Tstruct fList => Some(Varray (Csyntax.sizeof ty))
+ | Tunion fList => Some(Varray (Csyntax.sizeof ty))
+end.
+
+(** ** Csharpminor constructors *)
+
+(* The following functions build Csharpminor expressions that compute
+ the value of a C operation. Most construction functions take
+ as arguments
+ - Csharpminor subexpressions that compute the values of the
+ arguments of the operation;
+ - The C types of the arguments of the operation. These types
+ are used to insert the necessary numeric conversions and to
+ resolve operation overloading.
+ Most of these functions return an [option expr], with [None]
+ denoting a case where the operation is not defined at the given types.
+*)
+
+Definition make_intconst (n: int) := Eop (Ointconst n) Enil.
+
+Definition make_floatconst (f: float) := Eop (Ofloatconst f) Enil.
+
+Definition make_unop (op: operation) (e: expr) := Eop op (Econs e Enil).
+
+Definition make_binop (op: operation) (e1 e2: expr) :=
+ Eop op (Econs e1 (Econs e2 Enil)).
+
+Definition make_floatofint (e: expr) (sg: signedness) :=
+ match sg with
+ | Signed => make_unop Ofloatofint e
+ | Unsigned => make_unop Ofloatofintu e
+ end.
+
+(* [make_boolean e ty] returns a Csharpminor expression that evaluates
+ to the boolean value of [e]. Recall that:
+ - in Csharpminor, [false] is the integer 0,
+ [true] any non-zero integer or any pointer
+ - in C, [false] is the integer 0, the null pointer, the float 0.0
+ [true] is any non-zero integer, non-null pointer, non-null float.
+*)
+Definition make_boolean (e: expr) (ty: type) :=
+ match ty with
+ | Tfloat _ => make_binop (Ocmpf Cne) e (make_floatconst Float.zero)
+ | _ => e
+ end.
+
+Definition make_neg (e: expr) (ty: type) :=
+ match ty with
+ | Tint _ _ => Some (make_binop Osub (make_intconst Int.zero) e)
+ | Tfloat _ => Some (make_unop Onegf e)
+ | _ => None
+ end.
+
+Definition make_notbool (e: expr) (ty: type) :=
+ make_binop (Ocmp Ceq) (make_boolean e ty) (make_intconst Int.zero).
+
+Definition make_notint (e: expr) (ty: type) :=
+ make_unop Onotint e.
+
+Definition make_add (e1: expr) (ty1: type) (e2: expr) (ty2: type) :=
+ match classify_add ty1 ty2 with
+ | add_case_ii => Some (make_binop Oadd e1 e2)
+ | add_case_ff => Some (make_binop Oaddf e1 e2)
+ | add_case_pi ty =>
+ let n := make_intconst (Int.repr (Csyntax.sizeof ty)) in
+ Some (make_binop Oadd e1 (make_binop Omul n e2))
+ | add_default => None
+ end.
+
+Definition make_sub (e1: expr) (ty1: type) (e2: expr) (ty2: type) :=
+ match classify_sub ty1 ty2 with
+ | sub_case_ii => Some (make_binop Osub e1 e2)
+ | sub_case_ff => Some (make_binop Osubf e1 e2)
+ | sub_case_pi ty =>
+ let n := make_intconst (Int.repr (Csyntax.sizeof ty)) in
+ Some (make_binop Osub e1 (make_binop Omul n e2))
+ | sub_case_pp ty =>
+ let n := make_intconst (Int.repr (Csyntax.sizeof ty)) in
+ Some (make_binop Odivu (make_binop Osub e1 e2) n)
+ | sub_default => None
+ end.
+
+Definition make_mul (e1: expr) (ty1: type) (e2: expr) (ty2: type) :=
+ match classify_mul ty1 ty2 with
+ | mul_case_ii => Some (make_binop Omul e1 e2)
+ | mul_case_ff => Some (make_binop Omulf e1 e2)
+ | mul_default => None
+ end.
+
+Definition make_div (e1: expr) (ty1: type) (e2: expr) (ty2: type) :=
+ match classify_div ty1 ty2 with
+ | div_case_I32unsi => Some (make_binop Odivu e1 e2)
+ | div_case_ii => Some (make_binop Odiv e1 e2)
+ | div_case_ff => Some (make_binop Odivf e1 e2)
+ | div_default => None
+ end.
+
+Definition make_mod (e1: expr) (ty1: type) (e2: expr) (ty2: type) :=
+ match classify_mod ty1 ty2 with
+ | mod_case_I32unsi => Some (make_binop Omodu e1 e2)
+ | mod_case_ii=> Some (make_binop Omod e1 e2)
+ | mod_default => None
+ end.
+
+Definition make_and (e1: expr) (ty1: type) (e2: expr) (ty2: type) :=
+ Some(make_binop Oand e1 e2).
+
+Definition make_or (e1: expr) (ty1: type) (e2: expr) (ty2: type) :=
+ Some(make_binop Oor e1 e2).
+
+Definition make_xor (e1: expr) (ty1: type) (e2: expr) (ty2: type) :=
+ Some(make_binop Oxor e1 e2).
+
+Definition make_shl (e1: expr) (ty1: type) (e2: expr) (ty2: type) :=
+ Some(make_binop Oshl e1 e2).
+
+Definition make_shr (e1: expr) (ty1: type) (e2: expr) (ty2: type) :=
+ match classify_shr ty1 ty2 with
+ | shr_case_I32unsi => Some (make_binop Oshru e1 e2)
+ | shr_case_ii=> Some (make_binop Oshr e1 e2)
+ | shr_default => None
+ end.
+
+Definition make_cmp (c: comparison) (e1: expr) (ty1: type) (e2: expr) (ty2: type) :=
+ match classify_cmp ty1 ty2 with
+ | cmp_case_I32unsi => Some (make_binop (Ocmpu c) e1 e2)
+ | cmp_case_ii => Some (make_binop (Ocmp c) e1 e2)
+ | cmp_case_ff => Some (make_binop (Ocmpf c) e1 e2)
+ | cmp_case_pi => Some (make_binop (Ocmp c) e1 e2)
+ | cmp_case_pp => Some (make_binop (Ocmp c) e1 e2)
+ | cmp_default => None
+ end.
+
+Definition make_andbool (e1: expr) (ty1: type) (e2: expr) (ty2: type) :=
+ Econdition
+ (make_boolean e1 ty1)
+ (Econdition
+ (make_boolean e2 ty2)
+ (make_intconst Int.one)
+ (make_intconst Int.zero))
+ (make_intconst Int.zero).
+
+Definition make_orbool (e1: expr) (ty1: type) (e2: expr) (ty2: type) :=
+ Econdition
+ (make_boolean e1 ty1)
+ (make_intconst Int.one)
+ (Econdition
+ (make_boolean e2 ty2)
+ (make_intconst Int.one)
+ (make_intconst Int.zero)).
+
+(* [make_cast from to e] applies to [e] the numeric conversions needed
+ to transform a result of type [from] to a result of type [to].
+ It is decomposed in two functions:
+ - [make_cast1] converts between int/pointer and float if necessary
+ - [make_cast2] converts to a "smaller" int or float type if necessary.
+*)
+
+Definition make_cast1 (from to: type) (e: expr) :=
+ match from, to with
+ | Tint _ uns, Tfloat _ => make_floatofint e uns
+ | Tfloat _, Tint _ _ => make_unop Ointoffloat e
+ | _, _ => e
+ end.
+
+Definition make_cast2 (from to: type) (e: expr) :=
+ match to with
+ | Tint I8 Signed => make_unop Ocast8signed e
+ | Tint I8 Unsigned => make_unop Ocast8unsigned e
+ | Tint I16 Signed => make_unop Ocast16signed e
+ | Tint I16 Unsigned => make_unop Ocast16unsigned e
+ | Tfloat F32 => make_unop Osingleoffloat e
+ | _ => e
+ end.
+
+Definition make_cast (from to: type) (e: expr) :=
+ make_cast2 from to (make_cast1 from to e).
+
+(* [make_load addr ty_res] loads a value of type [ty_res] from
+ the memory location denoted by the Csharpminor expression [addr].
+ If [ty_res] is an array or function type, returns [addr] instead,
+ as consistent with C semantics.
+*)
+
+Definition make_load (addr: expr) (ty_res: type) :=
+ match (access_mode ty_res) with
+ | By_value chunk => Some (Eload chunk addr)
+ | By_reference => Some addr
+ | By_nothing => None
+ end.
+
+(* [make_store addr ty_res rhs ty_rhs] stores the value of the
+ Csharpminor expression [rhs] into the memory location denoted by the
+ Csharpminor expression [addr].
+ [ty] is the type of the memory location. *)
+
+Definition make_store (addr: expr) (ty: type) (rhs: expr) :=
+ match access_mode ty with
+ | By_value chunk => Some (Sstore chunk addr rhs)
+ | _ => None
+ end.
+
+(** ** Reading and writing variables *)
+
+(* [var_get id ty] builds Csharpminor code that evaluates to the
+ value of C variable [id] with type [ty]. Note that
+ C variables of array or function type evaluate to the address
+ of the corresponding CabsCoq memory block, while variables of other types
+ evaluate to the contents of the corresponding C memory block.
+*)
+
+Definition var_get (id: ident) (ty: type) :=
+ match access_mode ty with
+ | By_value chunk => Some (Evar id)
+ | By_reference => Some (Eaddrof id)
+ | _ => None
+ end.
+
+(* [var_set id ty rhs] stores the value of the Csharpminor
+ expression [rhs] into the CabsCoq variable [id] of type [ty].
+*)
+
+Definition var_set (id: ident) (ty: type) (rhs: expr) :=
+ match access_mode ty with
+ | By_value chunk => Some (Sassign id rhs)
+ | _ => None
+ end.
+
+(** ** Translation of operators *)
+
+Definition transl_unop (op: unary_operation) (a: expr) (ta: type) : option expr :=
+ match op with
+ | Csyntax.Onotbool => Some(make_notbool a ta)
+ | Csyntax.Onotint => Some(make_notint a ta)
+ | Csyntax.Oneg => make_neg a ta
+ end.
+
+Definition transl_binop (op: binary_operation) (a: expr) (ta: type)
+ (b: expr) (tb: type) : option expr :=
+ match op with
+ | Csyntax.Oadd => make_add a ta b tb
+ | Csyntax.Osub => make_sub a ta b tb
+ | Csyntax.Omul => make_mul a ta b tb
+ | Csyntax.Odiv => make_div a ta b tb
+ | Csyntax.Omod => make_mod a ta b tb
+ | Csyntax.Oand => make_and a ta b tb
+ | Csyntax.Oor => make_or a ta b tb
+ | Csyntax.Oxor => make_xor a ta b tb
+ | Csyntax.Oshl => make_shl a ta b tb
+ | Csyntax.Oshr => make_shr a ta b tb
+ | Csyntax.Oeq => make_cmp Ceq a ta b tb
+ | Csyntax.One => make_cmp Cne a ta b tb
+ | Csyntax.Olt => make_cmp Clt a ta b tb
+ | Csyntax.Ogt => make_cmp Cgt a ta b tb
+ | Csyntax.Ole => make_cmp Cle a ta b tb
+ | Csyntax.Oge => make_cmp Cge a ta b tb
+ end.
+
+(** ** Translation of expressions *)
+
+(* [transl_expr a] returns the Csharpminor code that computes the value
+ of expression [a]. The result is an option type to enable error reporting.
+
+ Most cases are self-explanatory. We outline the non-obvious cases:
+
+ a && b ---> a ? (b ? 1 : 0) : 0
+
+ a || b ---> a ? 1 : (b ? 1 : 0)
+*)
+
+Fixpoint transl_expr (a: Csyntax.expr) {struct a} : option expr :=
+ match a with
+ | Expr (Csyntax.Econst_int n) _ =>
+ Some(make_intconst n)
+ | Expr (Csyntax.Econst_float n) _ =>
+ Some(make_floatconst n)
+ | Expr (Csyntax.Evar id) ty =>
+ var_get id ty
+ | Expr (Csyntax.Ederef b) _ =>
+ do tb <- transl_expr b;
+ make_load tb (typeof a)
+ | Expr (Csyntax.Eaddrof b) _ =>
+ transl_lvalue b
+ | Expr (Csyntax.Eunop op b) _ =>
+ do tb <- transl_expr b;
+ transl_unop op tb (typeof b)
+ | Expr (Csyntax.Ebinop op b c) _ =>
+ do tb <- transl_expr b;
+ do tc <- transl_expr c;
+ transl_binop op tb (typeof b) tc (typeof c)
+ | Expr (Csyntax.Ecast ty b) _ =>
+ do tb <- transl_expr b;
+ Some (make_cast (typeof b) ty tb)
+ | Expr (Csyntax.Eindex b c) ty =>
+ do tb <- transl_expr b;
+ do tc <- transl_expr c;
+ do ts <- make_add tb (typeof b) tc (typeof c);
+ make_load ts ty
+ | Expr (Csyntax.Ecall b cl) _ =>
+ match (classify_fun (typeof b)) with
+ | fun_case_f args res =>
+ do tb <- transl_expr b;
+ do tcl <- transl_exprlist cl;
+ Some(Ecall (signature_of_type args res) tb tcl)
+ | _ => None
+ end
+ | Expr (Csyntax.Eandbool b c) _ =>
+ do tb <- transl_expr b;
+ do tc <- transl_expr c;
+ Some(make_andbool tb (typeof b) tc (typeof c))
+ | Expr (Csyntax.Eorbool b c) _ =>
+ do tb <- transl_expr b;
+ do tc <- transl_expr c;
+ Some(make_orbool tb (typeof b) tc (typeof c))
+ | Expr (Csyntax.Esizeof ty) _ =>
+ Some(make_intconst (Int.repr (Csyntax.sizeof ty)))
+ | Expr (Csyntax.Efield b i) ty =>
+ match typeof b with
+ | Tstruct fld =>
+ do tb <- transl_lvalue b;
+ do ofs <- field_offset i fld;
+ make_load
+ (make_binop Oadd tb (make_intconst (Int.repr ofs)))
+ ty
+ | Tunion fld =>
+ do tb <- transl_lvalue b;
+ make_load tb ty
+ | _ => None
+ end
+ end
+
+(* [transl_lvalue a] returns the Csharpminor code that evaluates
+ [a] as a lvalue, that is, code that returns the memory address
+ where the value of [a] is stored.
+*)
+
+with transl_lvalue (a: Csyntax.expr) {struct a} : option expr :=
+ match a with
+ | Expr (Csyntax.Evar id) _ =>
+ Some (Eaddrof id)
+ | Expr (Csyntax.Ederef b) _ =>
+ transl_expr b
+ | Expr (Csyntax.Eindex b c) _ =>
+ do tb <- transl_expr b;
+ do tc <- transl_expr c;
+ make_add tb (typeof b) tc (typeof c)
+ | Expr (Csyntax.Efield b i) ty =>
+ match typeof b with
+ | Tstruct fld =>
+ do tb <- transl_lvalue b;
+ do ofs <- field_offset i fld;
+ Some (make_binop Oadd tb (make_intconst (Int.repr ofs)))
+ | Tunion fld =>
+ transl_lvalue b
+ | _ => None
+ end
+ | _ => None
+ end
+
+(* [transl_exprlist al] returns a list of Csharpminor expressions
+ that compute the values of the list [al] of Csyntax expressions.
+ Used for function applications. *)
+
+with transl_exprlist (al: Csyntax.exprlist): option exprlist :=
+ match al with
+ | Csyntax.Enil => Some Enil
+ | Csyntax.Econs a1 a2 =>
+ do ta1 <- transl_expr a1;
+ do ta2 <- transl_exprlist a2;
+ Some (Econs ta1 ta2)
+ end.
+
+(** ** Translation of statements *)
+
+(** Determine if a C expression is a variable *)
+
+Definition is_variable (e: Csyntax.expr) : option ident :=
+ match e with
+ | Expr (Csyntax.Evar id) _ => Some id
+ | _ => None
+ end.
+
+(* [exit_if_false e] return the statement that tests the boolean
+ value of the CabsCoq expression [e] and performs an [exit 0] if [e]
+ evaluates to false.
+*)
+Definition exit_if_false (e: Csyntax.expr) : option stmt :=
+ do te <- transl_expr e;
+ Some(Sifthenelse
+ (make_notbool te (typeof e))
+ (Sexit 0%nat)
+ Sskip).
+
+(* [transl_statement nbrk ncnt s] returns a Csharpminor statement
+ that performs the same computations as the CabsCoq statement [s].
+
+ If the statement [s] terminates prematurely on a [break] construct,
+ the generated Csharpminor statement terminates prematurely on an
+ [exit nbrk] construct.
+
+ If the statement [s] terminates prematurely on a [continue]
+ construct, the generated Csharpminor statement terminates
+ prematurely on an [exit ncnt] construct.
+
+ Immediately within a loop, [nbrk = 1] and [ncnt = 0], but this
+ changes when we're inside a [switch] construct.
+
+ The general translation for loops is as follows:
+
+while (e1) s; ---> block {
+ loop {
+ if (!e1) exit 0;
+ block { s }
+ // continue in s branches here
+ }
+ }
+ // break in s branches here
+
+do s; while (e1); ---> block {
+ loop {
+ block { s }
+ // continue in s branches here
+ if (!e1) exit 0;
+ }
+ }
+ // break in s branches here
+
+for (e1;e2;e3) s; ---> e1;
+ block {
+ loop {
+ if (!e2) exit 0;
+ block { s }
+ // continue in s branches here
+ e3;
+ }
+ }
+ // break in s branches here
+
+switch (e) { ---> block { block { block { block {
+ case N1: s1; switch (e) { N1: exit 0; N2: exit 1; default: exit 2; }
+ case N2: s2; } ; s1 // with break -> exit 2 and continue -> exit 3
+ default: s; } ; s2 // with break -> exit 1 and continue -> exit 2
+} } ; s // with break -> exit 0 and continue -> exit 1
+ }
+*)
+
+Fixpoint switch_table (sl: labeled_statements) (k: nat) {struct sl} : list (int * nat) :=
+ match sl with
+ | LSdefault _ => nil
+ | LScase ni _ rem => (ni, k) :: switch_table rem (k+1)
+ end.
+
+Fixpoint transl_statement (nbrk ncnt: nat) (s: Csyntax.statement) {struct s} : option stmt :=
+ match s with
+ | Csyntax.Sskip =>
+ Some Sskip
+ | Csyntax.Sexpr e =>
+ do te <- transl_expr e;
+ Some (Sexpr te)
+ | Csyntax.Sassign b c =>
+ match (is_variable b) with
+ | Some id =>
+ do tc <- transl_expr c;
+ var_set id (typeof b) tc
+ | None =>
+ do tb <- transl_lvalue b;
+ do tc <- transl_expr c;
+ make_store tb (typeof b) tc
+ end
+ | Csyntax.Ssequence s1 s2 =>
+ do ts1 <- transl_statement nbrk ncnt s1;
+ do ts2 <- transl_statement nbrk ncnt s2;
+ Some (Sseq ts1 ts2)
+ | Csyntax.Sifthenelse e s1 s2 =>
+ do te <- transl_expr e;
+ do ts1 <- transl_statement nbrk ncnt s1;
+ do ts2 <- transl_statement nbrk ncnt s2;
+ Some (Sifthenelse (make_boolean te (typeof e)) ts1 ts2)
+ | Csyntax.Swhile e s1 =>
+ do te <- exit_if_false e;
+ do ts1 <- transl_statement 1%nat 0%nat s1;
+ Some (Sblock (Sloop (Sseq te (Sblock ts1))))
+ | Csyntax.Sdowhile e s1 =>
+ do te <- exit_if_false e;
+ do ts1 <- transl_statement 1%nat 0%nat s1;
+ Some (Sblock (Sloop (Sseq (Sblock ts1) te)))
+ | Csyntax.Sfor e1 e2 e3 s1 =>
+ do te1 <- transl_statement nbrk ncnt e1;
+ do te2 <- exit_if_false e2;
+ do te3 <- transl_statement nbrk ncnt e3;
+ do ts1 <- transl_statement 1%nat 0%nat s1;
+ Some (Sseq te1 (Sblock (Sloop (Sseq te2 (Sseq (Sblock ts1) te3)))))
+ | Csyntax.Sbreak =>
+ Some (Sexit nbrk)
+ | Csyntax.Scontinue =>
+ Some (Sexit ncnt)
+ | Csyntax.Sreturn (Some e) =>
+ do te <- transl_expr e;
+ Some (Sreturn (Some te))
+ | Csyntax.Sreturn None =>
+ Some (Sreturn None)
+ | Csyntax.Sswitch e sl =>
+ let cases := switch_table sl 0 in
+ let ncases := List.length cases in
+ do te <- transl_expr e;
+ transl_lblstmts ncases (ncnt + ncases + 1)%nat sl (Sblock (Sswitch te cases ncases))
+ end
+
+with transl_lblstmts (nbrk ncnt: nat) (sl: labeled_statements) (body: stmt)
+ {struct sl}: option stmt :=
+ match sl with
+ | LSdefault s =>
+ do ts <- transl_statement nbrk ncnt s;
+ Some (Sblock (Sseq body ts))
+ | LScase _ s rem =>
+ do ts <- transl_statement nbrk ncnt s;
+ transl_lblstmts (pred nbrk) (pred ncnt) rem (Sblock (Sseq body ts))
+ end.
+
+(*** Translation of functions *)
+
+Definition transl_params := transf_partial_program chunk_of_type.
+Definition transl_vars := transf_partial_program var_kind_of_type.
+
+Definition transl_function (f: Csyntax.function) : option function :=
+ do tparams <- transl_params (Csyntax.fn_params f);
+ do tvars <- transl_vars (Csyntax.fn_vars f);
+ do tbody <- transl_statement 1%nat 0%nat (Csyntax.fn_body f);
+ Some (mkfunction (signature_of_function f) tparams tvars tbody).
+
+Definition transl_fundef (f: Csyntax.fundef) : option fundef :=
+ match f with
+ | Csyntax.Internal g =>
+ do tg <- transl_function g; Some(AST.Internal tg)
+ | Csyntax.External id args res =>
+ Some(AST.External (external_function id args res))
+ end.
+
+(** ** Translation of programs *)
+
+Fixpoint transl_global_vars
+ (vl: list (ident * type * list init_data)) :
+ option (list (ident * var_kind * list init_data)) :=
+ match vl with
+ | nil => Some nil
+ | (id, ty, init) :: rem =>
+ do vk <- var_kind_of_type ty;
+ do trem <- transl_global_vars rem;
+ Some ((id, vk, init) :: trem)
+ end.
+
+Definition transl_program (p: Csyntax.program) : option program :=
+ do tfun <- transf_partial_program transl_fundef (Csyntax.prog_funct p);
+ do tvars <- transl_global_vars (Csyntax.prog_defs p);
+ Some (mkprogram tfun (Csyntax.prog_main p) tvars).
diff --git a/cfrontend/Cshmgenproof1.v b/cfrontend/Cshmgenproof1.v
new file mode 100644
index 0000000..17f7aa9
--- /dev/null
+++ b/cfrontend/Cshmgenproof1.v
@@ -0,0 +1,288 @@
+(** * Correctness of the C front end, part 1: syntactic properties *)
+
+Require Import Coqlib.
+Require Import Maps.
+Require Import Integers.
+Require Import Floats.
+Require Import AST.
+Require Import Values.
+Require Import Events.
+Require Import Mem.
+Require Import Globalenvs.
+Require Import Csyntax.
+Require Import Csem.
+Require Import Ctyping.
+Require Import Csharpminor.
+Require Import Cshmgen.
+
+(** Monadic simplification *)
+
+Ltac monadSimpl1 :=
+ match goal with
+ | [ |- (bind ?F ?G = Some ?X) -> _ ] =>
+ unfold bind at 1;
+ generalize (refl_equal F);
+ pattern F at -1 in |- *;
+ case F;
+ [ (let EQ := fresh "EQ" in
+ (intro; intro EQ; try monadSimpl1))
+ | intro; intro; discriminate ]
+ | [ |- (None = Some _) -> _ ] =>
+ intro; discriminate
+ | [ |- (Some _ = Some _) -> _ ] =>
+ let h := fresh "H" in
+ (intro h; injection h; intro; clear h)
+ | [ |- (_ = Some _) -> _ ] =>
+ let EQ := fresh "EQ" in intro EQ
+ end.
+
+Ltac monadSimpl :=
+ match goal with
+ | [ |- (bind ?F ?G = Some ?X) -> _ ] => monadSimpl1
+ | [ |- (None = Some _) -> _ ] => monadSimpl1
+ | [ |- (Some _ = Some _) -> _ ] => monadSimpl1
+ | [ |- (?F _ _ _ _ _ _ = Some _) -> _ ] => unfold F; fold F; monadSimpl1
+ | [ |- (?F _ _ _ _ _ = Some _) -> _ ] => unfold F; fold F; monadSimpl1
+ | [ |- (?F _ _ _ _ = Some _) -> _ ] => unfold F; fold F; monadSimpl1
+ | [ |- (?F _ _ _ = Some _) -> _ ] => unfold F; fold F; monadSimpl1
+ | [ |- (?F _ _ = Some _) -> _ ] => unfold F; fold F; monadSimpl1
+ | [ |- (?F _ = Some _) -> _ ] => unfold F; fold F; monadSimpl1
+ end.
+
+Ltac monadInv H :=
+ generalize H; monadSimpl.
+
+(** Operations on types *)
+
+Lemma transl_fundef_sig1:
+ forall f tf args res,
+ transl_fundef f = Some tf ->
+ classify_fun (type_of_fundef f) = fun_case_f args res ->
+ funsig tf = signature_of_type args res.
+Proof.
+ intros. destruct f; monadInv H.
+ monadInv EQ. rewrite <- H2. rewrite <- H3. simpl.
+ simpl in H0. inversion H0. reflexivity.
+ rewrite <- H2. simpl.
+ simpl in H0. congruence.
+Qed.
+
+Lemma transl_fundef_sig2:
+ forall f tf args res,
+ transl_fundef f = Some tf ->
+ type_of_fundef f = Tfunction args res ->
+ funsig tf = signature_of_type args res.
+Proof.
+ intros. eapply transl_fundef_sig1; eauto.
+ rewrite H0; reflexivity.
+Qed.
+
+Lemma var_kind_by_value:
+ forall ty chunk,
+ access_mode ty = By_value chunk ->
+ var_kind_of_type ty = Some(Vscalar chunk).
+Proof.
+ intros ty chunk; destruct ty; simpl; try congruence.
+ destruct i; try congruence; destruct s; congruence.
+ destruct f; congruence.
+Qed.
+
+Lemma sizeof_var_kind_of_type:
+ forall ty vk,
+ var_kind_of_type ty = Some vk ->
+ Csharpminor.sizeof vk = Csyntax.sizeof ty.
+Proof.
+ intros ty vk.
+ assert (sizeof (Varray (Csyntax.sizeof ty)) = Csyntax.sizeof ty).
+ simpl. rewrite Zmax_spec. apply zlt_false.
+ generalize (Csyntax.sizeof_pos ty). omega.
+ destruct ty; try (destruct i; try destruct s); try (destruct f);
+ simpl; intro EQ; inversion EQ; subst vk; auto.
+Qed.
+
+(** Transformation of programs and functions *)
+
+Lemma transform_program_of_program:
+ forall prog tprog,
+ transl_program prog = Some tprog ->
+ transform_partial_program transl_fundef (Csyntax.program_of_program prog) =
+ Some (program_of_program tprog).
+Proof.
+ intros prog tprog TRANSL.
+ monadInv TRANSL. rewrite <- H0. unfold program_of_program; simpl.
+ unfold transform_partial_program, Csyntax.program_of_program; simpl.
+ rewrite EQ. decEq. decEq.
+ generalize EQ0. generalize l0. generalize (prog_defs prog).
+ induction l1; simpl; intros.
+ inversion EQ1; subst l1. reflexivity.
+ destruct a as [[id ty] init]. monadInv EQ1. subst l2. simpl. decEq. apply IHl1. auto.
+Qed.
+
+(** ** Some properties of the translation functions *)
+
+Lemma transf_partial_program_names:
+ forall (A B: Set) (f: A -> option B)
+ (l: list (ident * A)) (tl: list (ident * B)),
+ transf_partial_program f l = Some tl ->
+ List.map (@fst ident B) tl = List.map (@fst ident A) l.
+Proof.
+ induction l; simpl.
+ intros. inversion H. reflexivity.
+ intro tl. destruct a as [id x]. destruct (f x); try congruence.
+ caseEq (transf_partial_program f l); intros; try congruence.
+ inversion H0; subst tl. simpl. decEq. auto.
+Qed.
+
+Lemma transf_partial_program_append:
+ forall (A B: Set) (f: A -> option B)
+ (l1 l2: list (ident * A)) (tl1 tl2: list (ident * B)),
+ transf_partial_program f l1 = Some tl1 ->
+ transf_partial_program f l2 = Some tl2 ->
+ transf_partial_program f (l1 ++ l2) = Some (tl1 ++ tl2).
+Proof.
+ induction l1; intros until tl2; simpl.
+ intros. inversion H. simpl; auto.
+ destruct a as [id x]. destruct (f x); try congruence.
+ caseEq (transf_partial_program f l1); intros; try congruence.
+ inversion H0. rewrite (IHl1 _ _ _ H H1). auto.
+Qed.
+
+Lemma transl_params_names:
+ forall vars tvars,
+ transl_params vars = Some tvars ->
+ List.map (@fst ident memory_chunk) tvars = Ctyping.var_names vars.
+Proof.
+ exact (transf_partial_program_names _ _ chunk_of_type).
+Qed.
+
+Lemma transl_vars_names:
+ forall vars tvars,
+ transl_vars vars = Some tvars ->
+ List.map (@fst ident var_kind) tvars = Ctyping.var_names vars.
+Proof.
+ exact (transf_partial_program_names _ _ var_kind_of_type).
+Qed.
+
+Lemma transl_names_norepet:
+ forall params vars sg tparams tvars body,
+ list_norepet (var_names params ++ var_names vars) ->
+ transl_params params = Some tparams ->
+ transl_vars vars = Some tvars ->
+ let f := Csharpminor.mkfunction sg tparams tvars body in
+ list_norepet (fn_params_names f ++ fn_vars_names f).
+Proof.
+ intros. unfold fn_params_names, fn_vars_names, f. simpl.
+ rewrite (transl_params_names _ _ H0).
+ rewrite (transl_vars_names _ _ H1).
+ auto.
+Qed.
+
+Lemma transl_vars_append:
+ forall l1 l2 tl1 tl2,
+ transl_vars l1 = Some tl1 -> transl_vars l2 = Some tl2 ->
+ transl_vars (l1 ++ l2) = Some (tl1 ++ tl2).
+Proof.
+ exact (transf_partial_program_append _ _ var_kind_of_type).
+Qed.
+
+Lemma transl_params_vars:
+ forall params tparams,
+ transl_params params = Some tparams ->
+ transl_vars params =
+ Some (List.map (fun id_chunk => (fst id_chunk, Vscalar (snd id_chunk))) tparams).
+Proof.
+ induction params; intro tparams; simpl.
+ intros. inversion H. reflexivity.
+ destruct a as [id x].
+ unfold chunk_of_type. caseEq (access_mode x); try congruence.
+ intros chunk AM.
+ caseEq (transl_params params); intros; try congruence.
+ inversion H0.
+ rewrite (var_kind_by_value _ _ AM).
+ rewrite (IHparams _ H). reflexivity.
+Qed.
+
+Lemma transl_fn_variables:
+ forall params vars sg tparams tvars body,
+ transl_params params = Some tparams ->
+ transl_vars vars = Some tvars ->
+ let f := Csharpminor.mkfunction sg tparams tvars body in
+ transl_vars (params ++ vars) = Some (fn_variables f).
+Proof.
+ intros.
+ generalize (transl_params_vars _ _ H); intro.
+ rewrite (transl_vars_append _ _ _ _ H1 H0).
+ reflexivity.
+Qed.
+
+(** Transformation of expressions and statements *)
+
+Lemma is_variable_correct:
+ forall a id,
+ is_variable a = Some id ->
+ a = Csyntax.Expr (Csyntax.Evar id) (typeof a).
+Proof.
+ intros until id. destruct a as [ad aty]; simpl.
+ destruct ad; intros; try discriminate.
+ congruence.
+Qed.
+
+Lemma transl_expr_lvalue:
+ forall ge e m1 a ty t m2 loc ofs ta,
+ Csem.eval_lvalue ge e m1 (Expr a ty) t m2 loc ofs ->
+ transl_expr (Expr a ty) = Some ta ->
+ (exists id, a = Csyntax.Evar id /\ var_get id ty = Some ta) \/
+ (exists tb, transl_lvalue (Expr a ty) = Some tb /\
+ make_load tb ty = Some ta).
+Proof.
+ intros. inversion H; subst; clear H; simpl in H0.
+ left; exists id; auto.
+ left; exists id; auto.
+ monadInv H0. right. exists e0; split; auto.
+ simpl. monadInv H0. right. exists e2; split; auto.
+ simpl. rewrite H6 in H0. rewrite H6.
+ monadInv H0. right.
+ exists (make_binop Oadd e0 (make_intconst (Int.repr z))). split; auto.
+ simpl. rewrite H10 in H0. rewrite H10.
+ monadInv H0. right.
+ exists e0; auto.
+Qed.
+
+Lemma transl_stmt_Sfor_start:
+ forall nbrk ncnt s1 e2 s3 s4 ts,
+ transl_statement nbrk ncnt (Sfor s1 e2 s3 s4) = Some ts ->
+ exists ts1, exists ts2,
+ ts = Sseq ts1 ts2
+ /\ transl_statement nbrk ncnt s1 = Some ts1
+ /\ transl_statement nbrk ncnt (Sfor Csyntax.Sskip e2 s3 s4) = Some (Sseq Sskip ts2).
+Proof.
+ intros. monadInv H. simpl.
+ exists s; exists (Sblock (Sloop (Sseq s0 (Sseq (Sblock s5) s2)))).
+ intuition.
+Qed.
+
+(** Properties related to switch constructs *)
+
+Fixpoint lblstmts_length (sl: labeled_statements) : nat :=
+ match sl with
+ | LSdefault _ => 0%nat
+ | LScase _ _ sl' => S (lblstmts_length sl')
+ end.
+
+Lemma switch_target_table_shift:
+ forall n sl base dfl,
+ switch_target n (S dfl) (switch_table sl (S base)) =
+ S(switch_target n dfl (switch_table sl base)).
+Proof.
+ induction sl; intros; simpl.
+ auto.
+ case (Int.eq n i). auto. auto.
+Qed.
+
+Lemma length_switch_table:
+ forall sl base, List.length (switch_table sl base) = lblstmts_length sl.
+Proof.
+ induction sl; intro; simpl. auto. decEq; auto.
+Qed.
+
+
diff --git a/cfrontend/Cshmgenproof2.v b/cfrontend/Cshmgenproof2.v
new file mode 100644
index 0000000..602e33a
--- /dev/null
+++ b/cfrontend/Cshmgenproof2.v
@@ -0,0 +1,419 @@
+(** * Correctness of the C front end, part 2: Csharpminor construction functions *)
+
+Require Import Coqlib.
+Require Import Maps.
+Require Import Integers.
+Require Import Floats.
+Require Import AST.
+Require Import Values.
+Require Import Events.
+Require Import Mem.
+Require Import Globalenvs.
+Require Import Csyntax.
+Require Import Csem.
+Require Import Ctyping.
+Require Import Csharpminor.
+Require Import Cshmgen.
+Require Import Cshmgenproof1.
+
+Section CONSTRUCTORS.
+
+Variable tprog: Csharpminor.program.
+
+(** Properties of the translation of [switch] constructs. *)
+
+Lemma transl_lblstmts_exit:
+ forall e m1 t m2 sl body n tsl nbrk ncnt,
+ exec_stmt tprog e m1 body t m2 (Out_exit (lblstmts_length sl + n)) ->
+ transl_lblstmts nbrk ncnt sl body = Some tsl ->
+ exec_stmt tprog e m1 tsl t m2 (outcome_block (Out_exit n)).
+Proof.
+ induction sl; intros.
+ simpl in H; simpl in H0; monadInv H0.
+ rewrite <- H2. constructor. apply exec_Sseq_stop. auto. congruence.
+ simpl in H; simpl in H0; monadInv H0.
+ eapply IHsl with (body := Sblock (Sseq body s0)); eauto.
+ change (Out_exit (lblstmts_length sl + n))
+ with (outcome_block (Out_exit (S (lblstmts_length sl + n)))).
+ constructor. apply exec_Sseq_stop. auto. congruence.
+Qed.
+
+Lemma transl_lblstmts_return:
+ forall e m1 t m2 sl body optv tsl nbrk ncnt,
+ exec_stmt tprog e m1 body t m2 (Out_return optv) ->
+ transl_lblstmts nbrk ncnt sl body = Some tsl ->
+ exec_stmt tprog e m1 tsl t m2 (Out_return optv).
+Proof.
+ induction sl; intros.
+ simpl in H; simpl in H0; monadInv H0.
+ rewrite <- H2. change (Out_return optv) with (outcome_block (Out_return optv)).
+ constructor. apply exec_Sseq_stop. auto. congruence.
+ simpl in H; simpl in H0; monadInv H0.
+ eapply IHsl with (body := Sblock (Sseq body s0)); eauto.
+ change (Out_return optv) with (outcome_block (Out_return optv)).
+ constructor. apply exec_Sseq_stop. auto. congruence.
+Qed.
+
+
+(** Correctness of Csharpminor construction functions *)
+
+Lemma make_intconst_correct:
+ forall n le e m1,
+ Csharpminor.eval_expr tprog le e m1 (make_intconst n) E0 m1 (Vint n).
+Proof.
+ intros. unfold make_intconst. econstructor. constructor. reflexivity.
+Qed.
+
+Lemma make_floatconst_correct:
+ forall n le e m1,
+ Csharpminor.eval_expr tprog le e m1 (make_floatconst n) E0 m1 (Vfloat n).
+Proof.
+ intros. unfold make_floatconst. econstructor. constructor. reflexivity.
+Qed.
+
+Lemma make_unop_correct:
+ forall op le e m1 a ta m2 va v,
+ Csharpminor.eval_expr tprog le e m1 a ta m2 va ->
+ eval_operation op (va :: nil) m2 = Some v ->
+ Csharpminor.eval_expr tprog le e m1 (make_unop op a) ta m2 v.
+Proof.
+ intros. unfold make_unop. econstructor. econstructor. eauto. constructor.
+ traceEq. auto.
+Qed.
+
+Lemma make_binop_correct:
+ forall op le e m1 a ta m2 va b tb m3 vb t v,
+ Csharpminor.eval_expr tprog le e m1 a ta m2 va ->
+ Csharpminor.eval_expr tprog le e m2 b tb m3 vb ->
+ eval_operation op (va :: vb :: nil) m3 = Some v ->
+ t = ta ** tb ->
+ Csharpminor.eval_expr tprog le e m1 (make_binop op a b) t m3 v.
+Proof.
+ intros. unfold make_binop.
+ econstructor. econstructor. eauto. econstructor. eauto. constructor.
+ reflexivity. traceEq. auto.
+Qed.
+
+Hint Resolve make_intconst_correct make_floatconst_correct
+ make_unop_correct make_binop_correct: cshm.
+Hint Extern 2 (@eq trace _ _) => traceEq: cshm.
+
+Remark Vtrue_is_true: Val.is_true Vtrue.
+Proof.
+ simpl. apply Int.one_not_zero.
+Qed.
+
+Remark Vfalse_is_false: Val.is_false Vfalse.
+Proof.
+ simpl. auto.
+Qed.
+
+Lemma make_boolean_correct_true:
+ forall le e m1 a t m2 v ty,
+ Csharpminor.eval_expr tprog le e m1 a t m2 v ->
+ is_true v ty ->
+ exists vb,
+ Csharpminor.eval_expr tprog le e m1 (make_boolean a ty) t m2 vb
+ /\ Val.is_true vb.
+Proof.
+ intros until ty; intros EXEC VTRUE.
+ destruct ty; simpl;
+ try (exists v; intuition; inversion VTRUE; simpl; auto; fail).
+ exists Vtrue; split.
+ eapply make_binop_correct; eauto with cshm.
+ inversion VTRUE; simpl.
+ replace (Float.cmp Cne f0 Float.zero) with (negb (Float.cmp Ceq f0 Float.zero)).
+ rewrite Float.eq_zero_false. reflexivity. auto.
+ rewrite Float.cmp_ne_eq. auto.
+ apply Vtrue_is_true.
+Qed.
+
+Lemma make_boolean_correct_false:
+ forall le e m1 a t m2 v ty,
+ Csharpminor.eval_expr tprog le e m1 a t m2 v ->
+ is_false v ty ->
+ exists vb,
+ Csharpminor.eval_expr tprog le e m1 (make_boolean a ty) t m2 vb
+ /\ Val.is_false vb.
+Proof.
+ intros until ty; intros EXEC VFALSE.
+ destruct ty; simpl;
+ try (exists v; intuition; inversion VFALSE; simpl; auto; fail).
+ exists Vfalse; split.
+ eapply make_binop_correct; eauto with cshm.
+ inversion VFALSE; simpl.
+ replace (Float.cmp Cne Float.zero Float.zero) with (negb (Float.cmp Ceq Float.zero Float.zero)).
+ rewrite Float.eq_zero_true. reflexivity.
+ rewrite Float.cmp_ne_eq. auto.
+ apply Vfalse_is_false.
+Qed.
+
+Lemma make_neg_correct:
+ forall a tya c ta va v le e m1 m2,
+ sem_neg va tya = Some v ->
+ make_neg a tya = Some c ->
+ eval_expr tprog le e m1 a ta m2 va ->
+ eval_expr tprog le e m1 c ta m2 v.
+Proof.
+ intros until m2; intro SEM. unfold make_neg.
+ functional inversion SEM; intros.
+ inversion H4. eapply make_binop_correct; eauto with cshm.
+ inversion H4. eauto with cshm.
+Qed.
+
+Lemma make_notbool_correct:
+ forall a tya c ta va v le e m1 m2,
+ sem_notbool va tya = Some v ->
+ make_notbool a tya = c ->
+ eval_expr tprog le e m1 a ta m2 va ->
+ eval_expr tprog le e m1 c ta m2 v.
+Proof.
+ intros until m2; intro SEM. unfold make_notbool.
+ functional inversion SEM; intros; inversion H4; simpl;
+ eauto with cshm.
+ eapply make_binop_correct.
+ eapply make_binop_correct. eauto. eauto with cshm.
+ simpl; reflexivity. reflexivity. eauto with cshm.
+ simpl. rewrite Float.cmp_ne_eq.
+ destruct (Float.cmp Ceq f Float.zero); reflexivity.
+ traceEq.
+Qed.
+
+Lemma make_notint_correct:
+ forall a tya c ta va v le e m1 m2,
+ sem_notint va = Some v ->
+ make_notint a tya = c ->
+ eval_expr tprog le e m1 a ta m2 va ->
+ eval_expr tprog le e m1 c ta m2 v.
+Proof.
+ intros until m2; intro SEM. unfold make_notint.
+ functional inversion SEM; intros.
+ inversion H2; eauto with cshm.
+Qed.
+
+Definition binary_constructor_correct
+ (make: expr -> type -> expr -> type -> option expr)
+ (sem: val -> type -> val -> type -> option val): Prop :=
+ forall a tya b tyb c ta va tb vb v le e m1 m2 m3,
+ sem va tya vb tyb = Some v ->
+ make a tya b tyb = Some c ->
+ eval_expr tprog le e m1 a ta m2 va ->
+ eval_expr tprog le e m2 b tb m3 vb ->
+ eval_expr tprog le e m1 c (ta ** tb) m3 v.
+
+Definition binary_constructor_correct'
+ (make: expr -> type -> expr -> type -> option expr)
+ (sem: val -> val -> option val): Prop :=
+ forall a tya b tyb c ta va tb vb v le e m1 m2 m3,
+ sem va vb = Some v ->
+ make a tya b tyb = Some c ->
+ eval_expr tprog le e m1 a ta m2 va ->
+ eval_expr tprog le e m2 b tb m3 vb ->
+ eval_expr tprog le e m1 c (ta ** tb) m3 v.
+
+Lemma make_add_correct: binary_constructor_correct make_add sem_add.
+Proof.
+ red; intros until m3. intro SEM. unfold make_add.
+ functional inversion SEM; rewrite H0; intros.
+ inversion H7. eauto with cshm.
+ inversion H7. eauto with cshm.
+ inversion H7.
+ eapply make_binop_correct. eauto.
+ eapply make_binop_correct. eauto with cshm. eauto.
+ simpl. reflexivity. reflexivity.
+ simpl. reflexivity. traceEq.
+Qed.
+
+Lemma make_sub_correct: binary_constructor_correct make_sub sem_sub.
+Proof.
+ red; intros until m3. intro SEM. unfold make_sub.
+ functional inversion SEM; rewrite H0; intros;
+ inversion H7; eauto with cshm.
+ eapply make_binop_correct. eauto.
+ eapply make_binop_correct. eauto with cshm. eauto.
+ simpl. reflexivity. reflexivity.
+ simpl. reflexivity. traceEq.
+ inversion H9. eapply make_binop_correct.
+ eapply make_binop_correct; eauto.
+ simpl. unfold eq_block; rewrite H3. reflexivity.
+ eauto with cshm. simpl. rewrite H8. reflexivity. traceEq.
+Qed.
+
+Lemma make_mul_correct: binary_constructor_correct make_mul sem_mul.
+Proof.
+ red; intros until m3. intro SEM. unfold make_mul.
+ functional inversion SEM; rewrite H0; intros;
+ inversion H7; eauto with cshm.
+Qed.
+
+Lemma make_div_correct: binary_constructor_correct make_div sem_div.
+Proof.
+ red; intros until m3. intro SEM. unfold make_div.
+ functional inversion SEM; rewrite H0; intros.
+ inversion H8. eapply make_binop_correct; eauto with cshm.
+ simpl. rewrite H7; auto.
+ inversion H8. eapply make_binop_correct; eauto with cshm.
+ simpl. rewrite H7; auto.
+ inversion H7; eauto with cshm.
+Qed.
+
+Lemma make_mod_correct: binary_constructor_correct make_mod sem_mod.
+ red; intros until m3. intro SEM. unfold make_mod.
+ functional inversion SEM; rewrite H0; intros.
+ inversion H8. eapply make_binop_correct; eauto with cshm.
+ simpl. rewrite H7; auto.
+ inversion H8. eapply make_binop_correct; eauto with cshm.
+ simpl. rewrite H7; auto.
+Qed.
+
+Lemma make_and_correct: binary_constructor_correct' make_and sem_and.
+Proof.
+ red; intros until m3. intro SEM. unfold make_and.
+ functional inversion SEM. intros. inversion H4.
+ eauto with cshm.
+Qed.
+
+Lemma make_or_correct: binary_constructor_correct' make_or sem_or.
+Proof.
+ red; intros until m3. intro SEM. unfold make_or.
+ functional inversion SEM. intros. inversion H4.
+ eauto with cshm.
+Qed.
+
+Lemma make_xor_correct: binary_constructor_correct' make_xor sem_xor.
+Proof.
+ red; intros until m3. intro SEM. unfold make_xor.
+ functional inversion SEM. intros. inversion H4.
+ eauto with cshm.
+Qed.
+
+Lemma make_shl_correct: binary_constructor_correct' make_shl sem_shl.
+Proof.
+ red; intros until m3. intro SEM. unfold make_shl.
+ functional inversion SEM. intros. inversion H5.
+ eapply make_binop_correct; eauto with cshm.
+ simpl. rewrite H4. auto.
+Qed.
+
+Lemma make_shr_correct: binary_constructor_correct make_shr sem_shr.
+Proof.
+ red; intros until m3. intro SEM. unfold make_shr.
+ functional inversion SEM; intros; rewrite H0 in H8; inversion H8.
+ eapply make_binop_correct; eauto with cshm.
+ simpl; rewrite H7; auto.
+ eapply make_binop_correct; eauto with cshm.
+ simpl; rewrite H7; auto.
+Qed.
+
+Lemma make_cmp_correct:
+ forall cmp a tya b tyb c ta va tb vb v le e m1 m2 m3,
+ sem_cmp cmp va tya vb tyb m3 = Some v ->
+ make_cmp cmp a tya b tyb = Some c ->
+ eval_expr tprog le e m1 a ta m2 va ->
+ eval_expr tprog le e m2 b tb m3 vb ->
+ eval_expr tprog le e m1 c (ta ** tb) m3 v.
+Proof.
+ intros until m3. intro SEM. unfold make_cmp.
+ functional inversion SEM; rewrite H0; intros.
+ inversion H8. eauto with cshm.
+ inversion H8. eauto with cshm.
+ inversion H8. eauto with cshm.
+ inversion H9. eapply make_binop_correct; eauto with cshm.
+ simpl. functional inversion H; subst; unfold eval_compare_null;
+ rewrite H8; auto.
+ inversion H10. eapply make_binop_correct; eauto with cshm.
+ simpl. rewrite H3. unfold eq_block; rewrite H9. auto.
+Qed.
+
+Lemma transl_unop_correct:
+ forall op a tya c ta va v le e m1 m2,
+ transl_unop op a tya = Some c ->
+ sem_unary_operation op va tya = Some v ->
+ eval_expr tprog le e m1 a ta m2 va ->
+ eval_expr tprog le e m1 c ta m2 v.
+Proof.
+ intros. destruct op; simpl in *.
+ eapply make_notbool_correct; eauto. congruence.
+ eapply make_notint_correct with (tya := tya); eauto. congruence.
+ eapply make_neg_correct; eauto.
+Qed.
+
+Lemma transl_binop_correct:
+forall op a tya b tyb c ta va tb vb v le e m1 m2 m3,
+ transl_binop op a tya b tyb = Some c ->
+ sem_binary_operation op va tya vb tyb m3 = Some v ->
+ eval_expr tprog le e m1 a ta m2 va ->
+ eval_expr tprog le e m2 b tb m3 vb ->
+ eval_expr tprog le e m1 c (ta ** tb) m3 v.
+Proof.
+ intros. destruct op; simpl in *.
+ eapply make_add_correct; eauto.
+ eapply make_sub_correct; eauto.
+ eapply make_mul_correct; eauto.
+ eapply make_div_correct; eauto.
+ eapply make_mod_correct; eauto.
+ eapply make_and_correct; eauto.
+ eapply make_or_correct; eauto.
+ eapply make_xor_correct; eauto.
+ eapply make_shl_correct; eauto.
+ eapply make_shr_correct; eauto.
+ eapply make_cmp_correct; eauto.
+ eapply make_cmp_correct; eauto.
+ eapply make_cmp_correct; eauto.
+ eapply make_cmp_correct; eauto.
+ eapply make_cmp_correct; eauto.
+ eapply make_cmp_correct; eauto.
+Qed.
+
+Lemma make_cast_correct:
+ forall le e m1 a t m2 v ty1 ty2 v',
+ eval_expr tprog le e m1 a t m2 v ->
+ cast v ty1 ty2 v' ->
+ eval_expr tprog le e m1 (make_cast ty1 ty2 a) t m2 v'.
+Proof.
+ unfold make_cast, make_cast1, make_cast2, make_unop.
+ intros until v'; intros EVAL CAST.
+ inversion CAST; clear CAST; subst; auto.
+ (* cast_int_int *)
+ destruct sz2; destruct si2; repeat econstructor; eauto with cshm.
+ (* cast_float_int *)
+ destruct sz2; destruct si2; repeat econstructor; eauto with cshm; simpl; auto.
+ (* cast_int_float *)
+ destruct sz2; destruct si1; unfold make_floatofint, make_unop; repeat econstructor; eauto with cshm; simpl; auto.
+ (* cast_float_float *)
+ destruct sz2; repeat econstructor; eauto with cshm.
+Qed.
+
+Lemma make_load_correct:
+ forall addr ty code b ofs v le e m1 t m2,
+ make_load addr ty = Some code ->
+ eval_expr tprog le e m1 addr t m2 (Vptr b ofs) ->
+ load_value_of_type ty m2 b ofs = Some v ->
+ eval_expr tprog le e m1 code t m2 v.
+Proof.
+ unfold make_load, load_value_of_type.
+ intros until m2; intros MKLOAD EVEXP LDVAL.
+ destruct (access_mode ty); inversion MKLOAD.
+ (* access_mode ty = By_value m *)
+ apply eval_Eload with (Vptr b ofs); auto.
+ (* access_mode ty = By_reference *)
+ subst code. inversion LDVAL. auto.
+Qed.
+
+Lemma make_store_correct:
+ forall addr ty rhs code e m1 t1 m2 b ofs t2 m3 v m4,
+ make_store addr ty rhs = Some code ->
+ eval_expr tprog nil e m1 addr t1 m2 (Vptr b ofs) ->
+ eval_expr tprog nil e m2 rhs t2 m3 v ->
+ store_value_of_type ty m3 b ofs v = Some m4 ->
+ exec_stmt tprog e m1 code (t1 ** t2) m4 Out_normal.
+Proof.
+ unfold make_store, store_value_of_type.
+ intros until m4; intros MKSTORE EV1 EV2 STVAL.
+ destruct (access_mode ty); inversion MKSTORE.
+ (* access_mode ty = By_value m *)
+ eapply eval_Sstore; eauto.
+Qed.
+
+End CONSTRUCTORS.
+
diff --git a/cfrontend/Cshmgenproof3.v b/cfrontend/Cshmgenproof3.v
new file mode 100644
index 0000000..b33771b
--- /dev/null
+++ b/cfrontend/Cshmgenproof3.v
@@ -0,0 +1,1503 @@
+(** * Correctness of the C front end, part 3: semantic preservation *)
+
+Require Import Coqlib.
+Require Import Maps.
+Require Import Integers.
+Require Import Floats.
+Require Import AST.
+Require Import Values.
+Require Import Events.
+Require Import Mem.
+Require Import Globalenvs.
+Require Import Csyntax.
+Require Import Csem.
+Require Import Ctyping.
+Require Import Csharpminor.
+Require Import Cshmgen.
+Require Import Cshmgenproof1.
+Require Import Cshmgenproof2.
+
+Section CORRECTNESS.
+
+Variable prog: Csyntax.program.
+Variable tprog: Csharpminor.program.
+Hypothesis WTPROG: wt_program prog.
+Hypothesis TRANSL: transl_program prog = Some tprog.
+
+Let ge := Csem.globalenv prog.
+Let tge := Genv.globalenv (Csharpminor.program_of_program tprog).
+
+Lemma symbols_preserved:
+ forall s, Genv.find_symbol tge s = Genv.find_symbol ge s.
+Proof.
+ intros. unfold ge, Csem.globalenv, tge.
+ apply Genv.find_symbol_transf_partial with transl_fundef.
+ apply transform_program_of_program; auto.
+Qed.
+
+Lemma functions_translated:
+ forall v f,
+ Genv.find_funct ge v = Some f ->
+ exists tf, Genv.find_funct tge v = Some tf /\ transl_fundef f = Some tf.
+Proof.
+ intros.
+ generalize (Genv.find_funct_transf_partial transl_fundef (transform_program_of_program _ _ TRANSL) H).
+ intros [A B].
+ destruct (transl_fundef f). exists f0; split. assumption. auto. congruence.
+Qed.
+
+Lemma function_ptr_translated:
+ forall b f,
+ Genv.find_funct_ptr ge b = Some f ->
+ exists tf, Genv.find_funct_ptr tge b = Some tf /\ transl_fundef f = Some tf.
+Proof.
+ intros.
+ generalize (Genv.find_funct_ptr_transf_partial transl_fundef (transform_program_of_program _ _ TRANSL) H).
+ intros [A B].
+ destruct (transl_fundef f). exists f0; split. assumption. auto. congruence.
+Qed.
+
+Lemma functions_well_typed:
+ forall v f,
+ Genv.find_funct ge v = Some f ->
+ wt_fundef (global_typenv prog) f.
+Proof.
+ intros. inversion WTPROG.
+ apply (@Genv.find_funct_prop _ (wt_fundef (global_typenv prog))
+ (Csyntax.program_of_program prog) v f).
+ intros. apply wt_program_funct with id. assumption.
+ assumption.
+Qed.
+
+Lemma function_ptr_well_typed:
+ forall b f,
+ Genv.find_funct_ptr ge b = Some f ->
+ wt_fundef (global_typenv prog) f.
+Proof.
+ intros. inversion WTPROG.
+ apply (@Genv.find_funct_ptr_prop _ (wt_fundef (global_typenv prog))
+ (Csyntax.program_of_program prog) b f).
+ intros. apply wt_program_funct with id. assumption.
+ assumption.
+Qed.
+
+(** ** Matching between environments *)
+
+Definition match_var_kind (ty: type) (vk: var_kind) : Prop :=
+ match access_mode ty with
+ | By_value chunk => vk = Vscalar chunk
+ | _ => True
+ end.
+
+Record match_env (tyenv: typenv) (e: Csem.env) (te: Csharpminor.env) : Prop :=
+ mk_match_env {
+ me_local:
+ forall id b ty,
+ e!id = Some b -> tyenv!id = Some ty ->
+ exists vk, match_var_kind ty vk /\ te!id = Some (b, vk);
+ me_global:
+ forall id ty,
+ e!id = None -> tyenv!id = Some ty ->
+ te!id = None /\
+ (forall chunk, access_mode ty = By_value chunk -> (global_var_env tprog)!id = Some (Vscalar chunk))
+ }.
+
+Definition match_globalenv (tyenv: typenv) (gv: gvarenv): Prop :=
+ forall id ty chunk,
+ tyenv!id = Some ty -> access_mode ty = By_value chunk ->
+ gv!id = Some (Vscalar chunk).
+
+Lemma match_globalenv_match_env_empty:
+ forall tyenv,
+ match_globalenv tyenv (global_var_env tprog) ->
+ match_env tyenv Csem.empty_env Csharpminor.empty_env.
+Proof.
+ intros. unfold Csem.empty_env, Csharpminor.empty_env.
+ constructor.
+ intros until ty. repeat rewrite PTree.gempty. congruence.
+ intros. split.
+ apply PTree.gempty.
+ intros. red in H. eauto.
+Qed.
+
+Lemma match_var_kind_of_type:
+ forall ty vk, var_kind_of_type ty = Some vk -> match_var_kind ty vk.
+Proof.
+ intros; red.
+ caseEq (access_mode ty); auto.
+ intros chunk AM. generalize (var_kind_by_value _ _ AM). congruence.
+Qed.
+
+Lemma match_env_alloc_variables:
+ forall e1 m1 vars e2 m2 lb,
+ Csem.alloc_variables e1 m1 vars e2 m2 lb ->
+ forall tyenv te1 tvars,
+ match_env tyenv e1 te1 ->
+ transl_vars vars = Some tvars ->
+ exists te2,
+ Csharpminor.alloc_variables te1 m1 tvars te2 m2 lb
+ /\ match_env (Ctyping.add_vars tyenv vars) e2 te2.
+Proof.
+ induction 1; intros.
+ simpl in H0. inversion H0; subst; clear H0.
+ exists te1; split. constructor. simpl. auto.
+ generalize H2. simpl.
+ caseEq (var_kind_of_type ty); [intros vk VK | congruence].
+ caseEq (transl_vars vars); [intros tvrs TVARS | congruence].
+ intro EQ; inversion EQ; subst tvars; clear EQ.
+ set (te2 := PTree.set id (b1, vk) te1).
+ assert (match_env (add_var tyenv (id, ty)) (PTree.set id b1 e) te2).
+ inversion H1. unfold te2, add_var. constructor.
+ (* me_local *)
+ intros until ty0. repeat rewrite PTree.gsspec. simpl. destruct (peq id0 id); intros.
+ subst id0. exists vk; split.
+ apply match_var_kind_of_type. congruence. congruence.
+ auto.
+ (* me_global *)
+ intros until ty0. repeat rewrite PTree.gsspec. simpl. destruct (peq id0 id); intros.
+ discriminate.
+ auto.
+ destruct (IHalloc_variables _ _ _ H3 TVARS) as [te3 [ALLOC MENV]].
+ exists te3; split.
+ econstructor; eauto.
+ rewrite (sizeof_var_kind_of_type _ _ VK). auto.
+ auto.
+Qed.
+
+Lemma bind_parameters_match_rec:
+ forall e m1 vars vals m2,
+ Csem.bind_parameters e m1 vars vals m2 ->
+ forall tyenv te tvars,
+ (forall id ty, In (id, ty) vars -> tyenv!id = Some ty) ->
+ match_env tyenv e te ->
+ transl_params vars = Some tvars ->
+ Csharpminor.bind_parameters te m1 tvars vals m2.
+Proof.
+ induction 1; intros.
+ simpl in H1. inversion H1. constructor.
+ generalize H4; clear H4; simpl.
+ caseEq (chunk_of_type ty); [intros chunk CHK | congruence].
+ caseEq (transl_params params); [intros tparams TPARAMS | congruence].
+ intro EQ; inversion EQ; clear EQ; subst tvars.
+ generalize CHK. unfold chunk_of_type.
+ caseEq (access_mode ty); intros; try discriminate.
+ inversion CHK0; clear CHK0; subst m0.
+ unfold store_value_of_type in H0. rewrite H4 in H0.
+ apply bind_parameters_cons with b m1.
+ assert (tyenv!id = Some ty). apply H2. apply in_eq.
+ destruct (me_local _ _ _ H3 _ _ _ H H5) as [vk [A B]].
+ red in A; rewrite H4 in A. congruence.
+ assumption.
+ apply IHbind_parameters with tyenv; auto.
+ intros. apply H2. apply in_cons; auto.
+Qed.
+
+Lemma tyenv_add_vars_norepet:
+ forall vars tyenv,
+ list_norepet (var_names vars) ->
+ (forall id ty,
+ In (id, ty) vars -> (Ctyping.add_vars tyenv vars)!id = Some ty)
+ /\
+ (forall id,
+ ~In id (var_names vars) -> (Ctyping.add_vars tyenv vars)!id = tyenv!id).
+Proof.
+ induction vars; simpl; intros.
+ tauto.
+ destruct a as [id1 ty1]. simpl in *. inversion H; clear H; subst.
+ destruct (IHvars (add_var tyenv (id1, ty1)) H3) as [A B].
+ split; intros.
+ destruct H. inversion H; subst id1 ty1; clear H.
+ rewrite B. unfold add_var. simpl. apply PTree.gss. auto.
+ auto.
+ rewrite B. unfold add_var; simpl. apply PTree.gso. apply sym_not_equal; tauto. tauto.
+Qed.
+
+Lemma bind_parameters_match:
+ forall e m1 params vals vars m2 tyenv tvars te,
+ Csem.bind_parameters e m1 params vals m2 ->
+ list_norepet (var_names params ++ var_names vars) ->
+ match_env (Ctyping.add_vars tyenv (params ++ vars)) e te ->
+ transl_params params = Some tvars ->
+ Csharpminor.bind_parameters te m1 tvars vals m2.
+Proof.
+ intros.
+ eapply bind_parameters_match_rec; eauto.
+ assert (list_norepet (var_names (params ++ vars))).
+ unfold var_names. rewrite List.map_app. assumption.
+ destruct (tyenv_add_vars_norepet _ tyenv H3) as [A B].
+ intros. apply A. apply List.in_or_app. auto.
+Qed.
+
+Definition globvarenv
+ (gv: gvarenv)
+ (vars: list (ident * var_kind * list init_data)) :=
+ List.fold_left
+ (fun gve x => match x with (id, k, init) => PTree.set id k gve end)
+ vars gv.
+
+Definition type_not_by_value (ty: type) : Prop :=
+ match access_mode ty with
+ | By_value _ => False
+ | _ => True
+ end.
+
+Lemma add_global_funs_charact:
+ forall fns tyenv,
+ (forall id ty, tyenv!id = Some ty -> type_not_by_value ty) ->
+ (forall id ty, (add_global_funs tyenv fns)!id = Some ty -> type_not_by_value ty).
+Proof.
+ induction fns; simpl; intros.
+ eauto.
+ apply IHfns with (add_global_fun tyenv a) id.
+ intros until ty0. destruct a as [id1 fn1].
+ unfold add_global_fun; simpl. rewrite PTree.gsspec.
+ destruct (peq id0 id1).
+ intros. inversion H1.
+ unfold type_of_fundef. destruct fn1; exact I.
+ eauto.
+ auto.
+Qed.
+
+Definition global_fun_typenv :=
+ add_global_funs (PTree.empty type) (Csyntax.prog_funct prog).
+
+Lemma add_global_funs_match_global_env:
+ match_globalenv global_fun_typenv (PTree.empty var_kind).
+Proof.
+ intros; red; intros.
+ assert (type_not_by_value ty).
+ apply add_global_funs_charact with (Csyntax.prog_funct prog) (PTree.empty type) id.
+ intros until ty0. rewrite PTree.gempty. congruence.
+ assumption.
+ red in H1. rewrite H0 in H1. contradiction.
+Qed.
+
+Lemma add_global_var_match_globalenv:
+ forall vars tenv gv tvars,
+ match_globalenv tenv gv ->
+ transl_global_vars vars = Some tvars ->
+ match_globalenv (add_global_vars tenv vars) (globvarenv gv tvars).
+Proof.
+ induction vars; intros; simpl.
+ simpl in H0. inversion H0. simpl. auto.
+ destruct a as [[id ty] init]. monadInv H0. subst tvars.
+ simpl. apply IHvars; auto.
+ red. intros until chunk. repeat rewrite PTree.gsspec.
+ destruct (peq id0 id); intros.
+ inversion H1; clear H1; subst id0 ty0.
+ generalize (var_kind_by_value _ _ H2). congruence.
+ red in H. eauto.
+Qed.
+
+Lemma match_global_typenv:
+ match_globalenv (global_typenv prog) (global_var_env tprog).
+Proof.
+ change (global_var_env tprog)
+ with (globvarenv (PTree.empty var_kind) (prog_vars tprog)).
+ unfold global_typenv.
+ apply add_global_var_match_globalenv.
+ apply add_global_funs_match_global_env.
+ monadInv TRANSL. rewrite <- H0. reflexivity.
+Qed.
+
+(** ** Variable accessors *)
+
+Lemma var_get_correct:
+ forall e m id ty loc ofs v tyenv code te le,
+ Csem.eval_lvalue ge e m (Expr (Csyntax.Evar id) ty) E0 m loc ofs ->
+ load_value_of_type ty m loc ofs = Some v ->
+ wt_expr tyenv (Expr (Csyntax.Evar id) ty) ->
+ var_get id ty = Some code ->
+ match_env tyenv e te ->
+ eval_expr tprog le te m code E0 m v.
+Proof.
+ intros. inversion H1; subst; clear H1.
+ unfold load_value_of_type in H0.
+ unfold var_get in H2.
+ caseEq (access_mode ty).
+ (* access mode By_value *)
+ intros chunk ACC. rewrite ACC in H0. rewrite ACC in H2.
+ inversion H2; clear H2; subst.
+ inversion H; subst; clear H.
+ (* local variable *)
+ exploit me_local; eauto. intros [vk [A B]].
+ red in A; rewrite ACC in A.
+ subst vk.
+ eapply eval_Evar.
+ eapply eval_var_ref_local. eauto. assumption.
+ (* global variable *)
+ exploit me_global; eauto. intros [A B].
+ eapply eval_Evar.
+ eapply eval_var_ref_global. auto.
+ fold tge. rewrite symbols_preserved. eauto.
+ eauto. assumption.
+ (* access mode By_reference *)
+ intros ACC. rewrite ACC in H0. rewrite ACC in H2.
+ inversion H0; clear H0; subst.
+ inversion H2; clear H2; subst.
+ inversion H; subst; clear H.
+ (* local variable *)
+ exploit me_local; eauto. intros [vk [A B]].
+ eapply eval_Eaddrof.
+ eapply eval_var_addr_local. eauto.
+ (* global variable *)
+ exploit me_global; eauto. intros [A B].
+ eapply eval_Eaddrof.
+ eapply eval_var_addr_global. auto.
+ fold tge. rewrite symbols_preserved. eauto.
+ (* access mode By_nothing *)
+ intros. rewrite H1 in H0; discriminate.
+Qed.
+
+Lemma var_set_correct:
+ forall e m id ty m1 loc ofs t1 m2 v t2 m3 tyenv code te rhs,
+ Csem.eval_lvalue ge e m (Expr (Csyntax.Evar id) ty) t1 m1 loc ofs ->
+ store_value_of_type ty m2 loc ofs v = Some m3 ->
+ wt_expr tyenv (Expr (Csyntax.Evar id) ty) ->
+ var_set id ty rhs = Some code ->
+ match_env tyenv e te ->
+ eval_expr tprog nil te m1 rhs t2 m2 v ->
+ exec_stmt tprog te m code (t1 ** t2) m3 Out_normal.
+Proof.
+ intros. inversion H1; subst; clear H1.
+ unfold store_value_of_type in H0.
+ unfold var_set in H2.
+ caseEq (access_mode ty).
+ (* access mode By_value *)
+ intros chunk ACC. rewrite ACC in H0. rewrite ACC in H2.
+ inversion H2; clear H2; subst.
+ inversion H; subst; clear H; rewrite E0_left.
+ (* local variable *)
+ exploit me_local; eauto. intros [vk [A B]].
+ red in A; rewrite ACC in A; subst vk.
+ eapply eval_Sassign. eauto.
+ eapply eval_var_ref_local. eauto. assumption.
+ (* global variable *)
+ exploit me_global; eauto. intros [A B].
+ eapply eval_Sassign. eauto.
+ eapply eval_var_ref_global. auto.
+ fold tge. rewrite symbols_preserved. eauto.
+ eauto. assumption.
+ (* access mode By_reference *)
+ intros ACC. rewrite ACC in H0. discriminate.
+ (* access mode By_nothing *)
+ intros. rewrite H1 in H0; discriminate.
+Qed.
+
+(** ** Proof of semantic simulation *)
+
+(** Inductive properties *)
+
+Definition eval_expr_prop
+ (e: Csem.env) (m1: mem) (a: Csyntax.expr) (t: trace) (m2: mem) (v: val) : Prop :=
+ forall tyenv ta te tle
+ (WT: wt_expr tyenv a)
+ (TR: transl_expr a = Some ta)
+ (MENV: match_env tyenv e te),
+ Csharpminor.eval_expr tprog tle te m1 ta t m2 v.
+
+Definition eval_lvalue_prop
+ (e: Csem.env) (m1: mem) (a: Csyntax.expr) (t: trace)
+ (m2: mem) (b: block) (ofs: int) : Prop :=
+ forall tyenv ta te tle
+ (WT: wt_expr tyenv a)
+ (TR: transl_lvalue a = Some ta)
+ (MENV: match_env tyenv e te),
+ Csharpminor.eval_expr tprog tle te m1 ta t m2 (Vptr b ofs).
+
+Definition eval_exprlist_prop
+ (e: Csem.env) (m1: mem) (al: Csyntax.exprlist) (t: trace)
+ (m2: mem) (vl: list val) : Prop :=
+ forall tyenv tal te tle
+ (WT: wt_exprlist tyenv al)
+ (TR: transl_exprlist al = Some tal)
+ (MENV: match_env tyenv e te),
+ Csharpminor.eval_exprlist tprog tle te m1 tal t m2 vl.
+
+Definition transl_outcome (nbrk ncnt: nat) (out: Csem.outcome): Csharpminor.outcome :=
+ match out with
+ | Csem.Out_normal => Csharpminor.Out_normal
+ | Csem.Out_break => Csharpminor.Out_exit nbrk
+ | Csem.Out_continue => Csharpminor.Out_exit ncnt
+ | Csem.Out_return vopt => Csharpminor.Out_return vopt
+ end.
+
+Definition exec_stmt_prop
+ (e: Csem.env) (m1: mem) (s: Csyntax.statement) (t: trace)
+ (m2: mem) (out: Csem.outcome) : Prop :=
+ forall tyenv nbrk ncnt ts te
+ (WT: wt_stmt tyenv s)
+ (TR: transl_statement nbrk ncnt s = Some ts)
+ (MENV: match_env tyenv e te),
+ Csharpminor.exec_stmt tprog te m1 ts t m2 (transl_outcome nbrk ncnt out).
+
+Definition exec_lblstmts_prop
+ (e: Csem.env) (m1: mem) (s: Csyntax.labeled_statements)
+ (t: trace) (m2: mem) (out: Csem.outcome) : Prop :=
+ forall tyenv nbrk ncnt body ts te m0 t0
+ (WT: wt_lblstmts tyenv s)
+ (TR: transl_lblstmts (lblstmts_length s)
+ (1 + lblstmts_length s + ncnt)
+ s body = Some ts)
+ (MENV: match_env tyenv e te)
+ (BODY: Csharpminor.exec_stmt tprog te m0 body t0 m1 Out_normal),
+ Csharpminor.exec_stmt tprog te m0 ts (t0 ** t) m2
+ (transl_outcome nbrk ncnt (outcome_switch out)).
+
+Definition eval_funcall_prop
+ (m1: mem) (f: Csyntax.fundef) (params: list val)
+ (t: trace) (m2: mem) (res: val) : Prop :=
+ forall tf
+ (WT: wt_fundef (global_typenv prog) f)
+ (TR: transl_fundef f = Some tf),
+ Csharpminor.eval_funcall tprog m1 tf params t m2 res.
+
+(*
+Set Printing Depth 100.
+Check (Csem.eval_funcall_ind6 ge eval_expr_prop eval_lvalue_prop
+ eval_exprlist_prop exec_stmt_prop exec_lblstmts_prop eval_funcall_prop).
+*)
+
+Lemma transl_Econst_int_correct:
+ (forall (e : Csem.env) (m : mem) (i : int) (ty : type),
+ eval_expr_prop e m (Expr (Econst_int i) ty) E0 m (Vint i)).
+Proof.
+ intros; red; intros.
+ monadInv TR. subst ta. apply make_intconst_correct.
+Qed.
+
+Lemma transl_Econst_float_correct:
+ (forall (e : Csem.env) (m : mem) (f0 : float) (ty : type),
+ eval_expr_prop e m (Expr (Econst_float f0) ty) E0 m (Vfloat f0)).
+Proof.
+ intros; red; intros.
+ monadInv TR. subst ta. apply make_floatconst_correct.
+Qed.
+
+Lemma transl_Elvalue_correct:
+ (forall (e : Csem.env) (m : mem) (a : expr_descr) (ty : type)
+ (t : trace) (m1 : mem) (loc : block) (ofs : int) (v : val),
+ eval_lvalue ge e m (Expr a ty) t m1 loc ofs ->
+ eval_lvalue_prop e m (Expr a ty) t m1 loc ofs ->
+ load_value_of_type ty m1 loc ofs = Some v ->
+ eval_expr_prop e m (Expr a ty) t m1 v).
+Proof.
+ intros; red; intros.
+ exploit transl_expr_lvalue; eauto.
+ intros [[id [EQ VARGET]] | [tb [TRLVAL MKLOAD]]].
+ (* Case a is a variable *)
+ subst a.
+ assert (t = E0 /\ m1 = m). inversion H; auto.
+ destruct H2; subst t m1.
+ eapply var_get_correct; eauto.
+ (* Case a is another lvalue *)
+ eapply make_load_correct; eauto.
+Qed.
+
+Lemma transl_Eaddrof_correct:
+ (forall (e : Csem.env) (m : mem) (a : Csyntax.expr) (t : trace)
+ (m1 : mem) (loc : block) (ofs : int) (ty : type),
+ eval_lvalue ge e m a t m1 loc ofs ->
+ eval_lvalue_prop e m a t m1 loc ofs ->
+ eval_expr_prop e m (Expr (Csyntax.Eaddrof a) ty) t m1 (Vptr loc ofs)).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR.
+ eauto.
+Qed.
+
+Lemma transl_Esizeof_correct:
+ (forall (e : Csem.env) (m : mem) (ty' ty : type),
+ eval_expr_prop e m (Expr (Esizeof ty') ty) E0 m
+ (Vint (Int.repr (Csyntax.sizeof ty')))).
+Proof.
+ intros; red; intros. monadInv TR. subst ta. apply make_intconst_correct.
+Qed.
+
+Lemma transl_Eunop_correct:
+ (forall (e : Csem.env) (m : mem) (op : unary_operation)
+ (a : Csyntax.expr) (ty : type) (t : trace) (m1 : mem) (v1 v : val),
+ Csem.eval_expr ge e m a t m1 v1 ->
+ eval_expr_prop e m a t m1 v1 ->
+ sem_unary_operation op v1 (typeof a) = Some v ->
+ eval_expr_prop e m (Expr (Eunop op a) ty) t m1 v).
+Proof.
+ intros; red; intros.
+ inversion WT; clear WT; subst.
+ monadInv TR.
+ eapply transl_unop_correct; eauto.
+Qed.
+
+Lemma transl_Ebinop_correct:
+ (forall (e : Csem.env) (m : mem) (op : binary_operation)
+ (a1 a2 : Csyntax.expr) (ty : type) (t1 : trace) (m1 : mem)
+ (v1 : val) (t2 : trace) (m2 : mem) (v2 v : val),
+ Csem.eval_expr ge e m a1 t1 m1 v1 ->
+ eval_expr_prop e m a1 t1 m1 v1 ->
+ Csem.eval_expr ge e m1 a2 t2 m2 v2 ->
+ eval_expr_prop e m1 a2 t2 m2 v2 ->
+ sem_binary_operation op v1 (typeof a1) v2 (typeof a2) m2 = Some v ->
+ eval_expr_prop e m (Expr (Ebinop op a1 a2) ty) (t1 ** t2) m2 v).
+Proof.
+ intros; red; intros.
+ inversion WT; clear WT; subst.
+ monadInv TR.
+ eapply transl_binop_correct; eauto.
+Qed.
+
+Lemma transl_Eorbool_1_correct:
+ (forall (e : Csem.env) (m : mem) (a1 a2 : Csyntax.expr) (t : trace)
+ (m1 : mem) (v1 : val) (ty : type),
+ Csem.eval_expr ge e m a1 t m1 v1 ->
+ eval_expr_prop e m a1 t m1 v1 ->
+ is_true v1 (typeof a1) ->
+ eval_expr_prop e m (Expr (Eorbool a1 a2) ty) t m1 Vtrue).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. monadInv TR.
+ rewrite <- H3; unfold make_orbool.
+ exploit make_boolean_correct_true; eauto. intros [vb [EVAL ISTRUE]].
+ eapply eval_Econdition_true; eauto.
+ unfold Vtrue; apply make_intconst_correct. traceEq.
+Qed.
+
+Lemma transl_Eorbool_2_correct:
+ (forall (e : Csem.env) (m : mem) (a1 a2 : Csyntax.expr) (ty : type)
+ (t1 : trace) (m1 : mem) (v1 : val) (t2 : trace) (m2 : mem)
+ (v2 v : val),
+ Csem.eval_expr ge e m a1 t1 m1 v1 ->
+ eval_expr_prop e m a1 t1 m1 v1 ->
+ is_false v1 (typeof a1) ->
+ Csem.eval_expr ge e m1 a2 t2 m2 v2 ->
+ eval_expr_prop e m1 a2 t2 m2 v2 ->
+ bool_of_val v2 (typeof a2) v ->
+ eval_expr_prop e m (Expr (Eorbool a1 a2) ty) (t1 ** t2) m2 v).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. monadInv TR.
+ rewrite <- H6; unfold make_orbool.
+ exploit make_boolean_correct_false. eapply H0; eauto. eauto. intros [vb [EVAL ISFALSE]].
+ eapply eval_Econdition_false; eauto.
+ inversion H4; subst.
+ exploit make_boolean_correct_true. eapply H3; eauto. eauto. intros [vc [EVAL' ISTRUE']].
+ eapply eval_Econdition_true; eauto.
+ unfold Vtrue; apply make_intconst_correct. traceEq.
+ exploit make_boolean_correct_false. eapply H3; eauto. eauto. intros [vc [EVAL' ISFALSE']].
+ eapply eval_Econdition_false; eauto.
+ unfold Vfalse; apply make_intconst_correct. traceEq.
+Qed.
+
+Lemma transl_Eandbool_1_correct:
+ (forall (e : Csem.env) (m : mem) (a1 a2 : Csyntax.expr) (t : trace)
+ (m1 : mem) (v1 : val) (ty : type),
+ Csem.eval_expr ge e m a1 t m1 v1 ->
+ eval_expr_prop e m a1 t m1 v1 ->
+ is_false v1 (typeof a1) ->
+ eval_expr_prop e m (Expr (Eandbool a1 a2) ty) t m1 Vfalse).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. monadInv TR.
+ rewrite <- H3; unfold make_andbool.
+ exploit make_boolean_correct_false; eauto. intros [vb [EVAL ISFALSE]].
+ eapply eval_Econdition_false; eauto.
+ unfold Vfalse; apply make_intconst_correct. traceEq.
+Qed.
+
+Lemma transl_Eandbool_2_correct:
+ (forall (e : Csem.env) (m : mem) (a1 a2 : Csyntax.expr) (ty : type)
+ (t1 : trace) (m1 : mem) (v1 : val) (t2 : trace) (m2 : mem)
+ (v2 v : val),
+ Csem.eval_expr ge e m a1 t1 m1 v1 ->
+ eval_expr_prop e m a1 t1 m1 v1 ->
+ is_true v1 (typeof a1) ->
+ Csem.eval_expr ge e m1 a2 t2 m2 v2 ->
+ eval_expr_prop e m1 a2 t2 m2 v2 ->
+ bool_of_val v2 (typeof a2) v ->
+ eval_expr_prop e m (Expr (Eandbool a1 a2) ty) (t1 ** t2) m2 v).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. monadInv TR.
+ rewrite <- H6; unfold make_andbool.
+ exploit make_boolean_correct_true. eapply H0; eauto. eauto. intros [vb [EVAL ISTRUE]].
+ eapply eval_Econdition_true; eauto.
+ inversion H4; subst.
+ exploit make_boolean_correct_true. eapply H3; eauto. eauto. intros [vc [EVAL' ISTRUE']].
+ eapply eval_Econdition_true; eauto.
+ unfold Vtrue; apply make_intconst_correct. traceEq.
+ exploit make_boolean_correct_false. eapply H3; eauto. eauto. intros [vc [EVAL' ISFALSE']].
+ eapply eval_Econdition_false; eauto.
+ unfold Vfalse; apply make_intconst_correct. traceEq.
+Qed.
+
+Lemma transl_Ecast_correct:
+ (forall (e : Csem.env) (m : mem) (a : Csyntax.expr) (ty : type)
+ (t : trace) (m1 : mem) (v1 v : val),
+ Csem.eval_expr ge e m a t m1 v1 ->
+ eval_expr_prop e m a t m1 v1 ->
+ cast v1 (typeof a) ty v ->
+ eval_expr_prop e m (Expr (Ecast ty a) ty) t m1 v).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. monadInv TR. subst ta.
+ eapply make_cast_correct; eauto.
+Qed.
+
+Lemma transl_Ecall_correct:
+ (forall (e : Csem.env) (m : mem) (a : Csyntax.expr)
+ (bl : Csyntax.exprlist) (ty : type) (m3 : mem) (vres : val)
+ (t1 : trace) (m1 : mem) (vf : val) (t2 : trace) (m2 : mem)
+ (vargs : list val) (f : Csyntax.fundef) (t3 : trace),
+ Csem.eval_expr ge e m a t1 m1 vf ->
+ eval_expr_prop e m a t1 m1 vf ->
+ Csem.eval_exprlist ge e m1 bl t2 m2 vargs ->
+ eval_exprlist_prop e m1 bl t2 m2 vargs ->
+ Genv.find_funct ge vf = Some f ->
+ type_of_fundef f = typeof a ->
+ Csem.eval_funcall ge m2 f vargs t3 m3 vres ->
+ eval_funcall_prop m2 f vargs t3 m3 vres ->
+ eval_expr_prop e m (Expr (Csyntax.Ecall a bl) ty) (t1 ** t2 ** t3) m3
+ vres).
+Proof.
+ intros; red; intros.
+ inversion WT; clear WT; subst.
+ simpl in TR.
+ caseEq (classify_fun (typeof a)).
+ 2: intros; rewrite H7 in TR; discriminate.
+ intros targs tres EQ. rewrite EQ in TR.
+ monadInv TR. clear TR. subst ta.
+ rewrite <- H4 in EQ.
+ exploit functions_translated; eauto. intros [tf [FIND TRL]].
+ econstructor.
+ eapply H0; eauto.
+ eapply H2; eauto.
+ eexact FIND.
+ eapply transl_fundef_sig1; eauto.
+ eapply H6; eauto.
+ eapply functions_well_typed; eauto.
+ auto.
+Qed.
+
+Lemma transl_Evar_local_correct:
+ (forall (e : Csem.env) (m : mem) (id : positive) (l : block)
+ (ty : type),
+ e ! id = Some l ->
+ eval_lvalue_prop e m (Expr (Csyntax.Evar id) ty) E0 m l Int.zero).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. monadInv TR. subst ta.
+ exploit (me_local _ _ _ MENV); eauto. intros [vk [A B]].
+ econstructor. eapply eval_var_addr_local. eauto.
+Qed.
+
+Lemma transl_Evar_global_correct:
+ (forall (e : PTree.t block) (m : mem) (id : positive) (l : block)
+ (ty : type),
+ e ! id = None ->
+ Genv.find_symbol ge id = Some l ->
+ eval_lvalue_prop e m (Expr (Csyntax.Evar id) ty) E0 m l Int.zero).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. monadInv TR. subst ta.
+ exploit (me_global _ _ _ MENV); eauto. intros [A B].
+ econstructor. eapply eval_var_addr_global. eauto.
+ rewrite symbols_preserved. auto.
+Qed.
+
+Lemma transl_Ederef_correct:
+ (forall (e : Csem.env) (m m1 : mem) (a : Csyntax.expr) (t : trace)
+ (ofs : int) (ty : type) (l : block),
+ Csem.eval_expr ge e m a t m1 (Vptr l ofs) ->
+ eval_expr_prop e m a t m1 (Vptr l ofs) ->
+ eval_lvalue_prop e m (Expr (Ederef a) ty) t m1 l ofs).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR.
+ eauto.
+Qed.
+
+Lemma transl_Eindex_correct:
+ (forall (e : Csem.env) (m : mem) (a1 : Csyntax.expr) (t1 : trace)
+ (m1 : mem) (v1 : val) (a2 : Csyntax.expr) (t2 : trace) (m2 : mem)
+ (v2 : val) (l : block) (ofs : int) (ty : type),
+ Csem.eval_expr ge e m a1 t1 m1 v1 ->
+ eval_expr_prop e m a1 t1 m1 v1 ->
+ Csem.eval_expr ge e m1 a2 t2 m2 v2 ->
+ eval_expr_prop e m1 a2 t2 m2 v2 ->
+ sem_add v1 (typeof a1) v2 (typeof a2) = Some (Vptr l ofs) ->
+ eval_lvalue_prop e m (Expr (Eindex a1 a2) ty) (t1 ** t2) m2 l ofs).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR. monadInv TR.
+ eapply (make_add_correct tprog); eauto.
+Qed.
+
+Lemma transl_Efield_struct_correct:
+ (forall (e : Csem.env) (m : mem) (a : Csyntax.expr) (t : trace)
+ (m1 : mem) (l : block) (ofs : int) (fList : fieldlist) (i : ident)
+ (ty : type) (delta : Z),
+ eval_lvalue ge e m a t m1 l ofs ->
+ eval_lvalue_prop e m a t m1 l ofs ->
+ typeof a = Tstruct fList ->
+ field_offset i fList = Some delta ->
+ eval_lvalue_prop e m (Expr (Efield a i) ty) t m1 l
+ (Int.add ofs (Int.repr delta))).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst.
+ simpl in TR. rewrite H1 in TR. monadInv TR.
+ rewrite <- H5. eapply make_binop_correct; eauto.
+ apply make_intconst_correct.
+ simpl. congruence. traceEq.
+Qed.
+
+Lemma transl_Efield_union_correct:
+ (forall (e : Csem.env) (m : mem) (a : Csyntax.expr) (t : trace)
+ (m1 : mem) (l : block) (ofs : int) (fList : fieldlist) (i : ident)
+ (ty : type),
+ eval_lvalue ge e m a t m1 l ofs ->
+ eval_lvalue_prop e m a t m1 l ofs ->
+ typeof a = Tunion fList ->
+ eval_lvalue_prop e m (Expr (Efield a i) ty) t m1 l ofs).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst.
+ simpl in TR. rewrite H1 in TR. eauto.
+Qed.
+
+Lemma transl_Enil_correct:
+ (forall (e : Csem.env) (m : mem),
+ eval_exprlist_prop e m Csyntax.Enil E0 m nil).
+Proof.
+ intros; red; intros. monadInv TR. subst tal. constructor.
+Qed.
+
+Lemma transl_Econs_correct:
+ (forall (e : Csem.env) (m : mem) (a : Csyntax.expr)
+ (bl : Csyntax.exprlist) (t1 : trace) (m1 : mem) (v : val)
+ (t2 : trace) (m2 : mem) (vl : list val),
+ Csem.eval_expr ge e m a t1 m1 v ->
+ eval_expr_prop e m a t1 m1 v ->
+ Csem.eval_exprlist ge e m1 bl t2 m2 vl ->
+ eval_exprlist_prop e m1 bl t2 m2 vl ->
+ eval_exprlist_prop e m (Csyntax.Econs a bl) (t1 ** t2) m2 (v :: vl)).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst tal. econstructor; eauto.
+Qed.
+
+Lemma transl_Sskip_correct:
+ (forall (e : Csem.env) (m : mem),
+ exec_stmt_prop e m Csyntax.Sskip E0 m Csem.Out_normal).
+Proof.
+ intros; red; intros. monadInv TR. subst ts. simpl. constructor.
+Qed.
+
+Lemma transl_Sexpr_correct:
+ (forall (e : Csem.env) (m : mem) (a : Csyntax.expr) (t : trace)
+ (m1 : mem) (v : val),
+ Csem.eval_expr ge e m a t m1 v ->
+ eval_expr_prop e m a t m1 v ->
+ exec_stmt_prop e m (Csyntax.Sexpr a) t m1 Csem.Out_normal).
+Proof.
+ intros; red; intros; simpl. inversion WT; clear WT; subst.
+ monadInv TR. subst ts.
+ econstructor; eauto.
+Qed.
+
+Lemma transl_Sassign_correct:
+ (forall (e : Csem.env) (m : mem) (a1 a2 : Csyntax.expr) (t1 : trace)
+ (m1 : mem) (loc : block) (ofs : int) (t2 : trace) (m2 : mem)
+ (v2 : val) (m3 : mem),
+ eval_lvalue ge e m a1 t1 m1 loc ofs ->
+ eval_lvalue_prop e m a1 t1 m1 loc ofs ->
+ Csem.eval_expr ge e m1 a2 t2 m2 v2 ->
+ eval_expr_prop e m1 a2 t2 m2 v2 ->
+ store_value_of_type (typeof a1) m2 loc ofs v2 = Some m3 ->
+ exec_stmt_prop e m (Csyntax.Sassign a1 a2) (t1 ** t2) m3
+ Csem.Out_normal).
+Proof.
+ intros; red; intros.
+ inversion WT; subst; clear WT.
+ simpl in TR.
+ caseEq (is_variable a1).
+ (* a = variable id *)
+ intros id ISVAR. rewrite ISVAR in TR.
+ generalize (is_variable_correct _ _ ISVAR). intro EQ.
+ rewrite EQ in H; rewrite EQ in H0; rewrite EQ in H6.
+ monadInv TR.
+ eapply var_set_correct; eauto.
+ (* a is not a variable *)
+ intro ISVAR; rewrite ISVAR in TR. monadInv TR.
+ eapply make_store_correct; eauto.
+Qed.
+
+Lemma transl_Ssequence_1_correct:
+ (forall (e : Csem.env) (m : mem) (s1 s2 : statement) (t1 : trace)
+ (m1 : mem) (t2 : trace) (m2 : mem) (out : Csem.outcome),
+ Csem.exec_stmt ge e m s1 t1 m1 Csem.Out_normal ->
+ exec_stmt_prop e m s1 t1 m1 Csem.Out_normal ->
+ Csem.exec_stmt ge e m1 s2 t2 m2 out ->
+ exec_stmt_prop e m1 s2 t2 m2 out ->
+ exec_stmt_prop e m (Ssequence s1 s2) (t1 ** t2) m2 out).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts. red in H0; simpl in H0. eapply exec_Sseq_continue; eauto.
+Qed.
+
+Lemma transl_Ssequence_2_correct:
+ (forall (e : Csem.env) (m : mem) (s1 s2 : statement) (t1 : trace)
+ (m1 : mem) (out : Csem.outcome),
+ Csem.exec_stmt ge e m s1 t1 m1 out ->
+ exec_stmt_prop e m s1 t1 m1 out ->
+ out <> Csem.Out_normal ->
+ exec_stmt_prop e m (Ssequence s1 s2) t1 m1 out).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts. eapply exec_Sseq_stop; eauto.
+ destruct out; simpl; congruence.
+Qed.
+
+Lemma transl_Sifthenelse_true_correct:
+ (forall (e : Csem.env) (m : mem) (a : Csyntax.expr)
+ (s1 s2 : statement) (t1 : trace) (m1 : mem) (v1 : val) (t2 : trace)
+ (m2 : mem) (out : Csem.outcome),
+ Csem.eval_expr ge e m a t1 m1 v1 ->
+ eval_expr_prop e m a t1 m1 v1 ->
+ is_true v1 (typeof a) ->
+ Csem.exec_stmt ge e m1 s1 t2 m2 out ->
+ exec_stmt_prop e m1 s1 t2 m2 out ->
+ exec_stmt_prop e m (Csyntax.Sifthenelse a s1 s2) (t1 ** t2) m2 out).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ exploit make_boolean_correct_true. eapply H0; eauto. eauto. intros [vb [EVAL ISTRUE]].
+ subst ts. eapply exec_Sifthenelse_true; eauto.
+Qed.
+
+Lemma transl_Sifthenelse_false_correct:
+ (forall (e : Csem.env) (m : mem) (a : Csyntax.expr)
+ (s1 s2 : statement) (t1 : trace) (m1 : mem) (v1 : val) (t2 : trace)
+ (m2 : mem) (out : Csem.outcome),
+ Csem.eval_expr ge e m a t1 m1 v1 ->
+ eval_expr_prop e m a t1 m1 v1 ->
+ is_false v1 (typeof a) ->
+ Csem.exec_stmt ge e m1 s2 t2 m2 out ->
+ exec_stmt_prop e m1 s2 t2 m2 out ->
+ exec_stmt_prop e m (Csyntax.Sifthenelse a s1 s2) (t1 ** t2) m2 out).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ exploit make_boolean_correct_false. eapply H0; eauto. eauto. intros [vb [EVAL ISFALSE]].
+ subst ts. eapply exec_Sifthenelse_false; eauto.
+Qed.
+
+Lemma transl_Sreturn_none_correct:
+ (forall (e : Csem.env) (m : mem),
+ exec_stmt_prop e m (Csyntax.Sreturn None) E0 m (Csem.Out_return None)).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts. simpl. apply exec_Sreturn_none.
+Qed.
+
+Lemma transl_Sreturn_some_correct:
+ (forall (e : Csem.env) (m : mem) (a : Csyntax.expr) (t : trace)
+ (m1 : mem) (v : val),
+ Csem.eval_expr ge e m a t m1 v ->
+ eval_expr_prop e m a t m1 v ->
+ exec_stmt_prop e m (Csyntax.Sreturn (Some a)) t m1
+ (Csem.Out_return (Some v))).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts. simpl. eapply exec_Sreturn_some; eauto.
+Qed.
+
+Lemma transl_Sbreak_correct:
+ (forall (e : Csem.env) (m : mem),
+ exec_stmt_prop e m Sbreak E0 m Out_break).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts. simpl. apply exec_Sexit.
+Qed.
+
+Lemma transl_Scontinue_correct:
+ (forall (e : Csem.env) (m : mem),
+ exec_stmt_prop e m Scontinue E0 m Out_continue).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts. simpl. apply exec_Sexit.
+Qed.
+
+Lemma exit_if_false_true:
+ forall a ts e m1 t m2 v tyenv te,
+ exit_if_false a = Some ts ->
+ eval_expr_prop e m1 a t m2 v ->
+ match_env tyenv e te ->
+ wt_expr tyenv a ->
+ is_true v (typeof a) ->
+ exec_stmt tprog te m1 ts t m2 Out_normal.
+Proof.
+ intros. monadInv H. rewrite <- H5.
+ eapply exec_Sifthenelse_false with (v1 := Vfalse).
+ eapply make_notbool_correct with (va := v); eauto.
+ inversion H3; subst; simpl; auto.
+ rewrite Int.eq_false; auto.
+ rewrite Int.eq_false; auto.
+ rewrite Float.eq_zero_false; auto.
+ simpl; auto.
+ constructor. traceEq.
+Qed.
+
+Lemma exit_if_false_false:
+ forall a ts e m1 t m2 v tyenv te,
+ exit_if_false a = Some ts ->
+ eval_expr_prop e m1 a t m2 v ->
+ match_env tyenv e te ->
+ wt_expr tyenv a ->
+ is_false v (typeof a) ->
+ exec_stmt tprog te m1 ts t m2 (Out_exit 0).
+Proof.
+ intros. monadInv H. rewrite <- H5.
+ eapply exec_Sifthenelse_true with (v1 := Vtrue).
+ eapply make_notbool_correct with (va := v); eauto.
+ inversion H3; subst; simpl; auto.
+ rewrite Float.eq_zero_true; auto.
+ simpl; apply Int.one_not_zero.
+ constructor. traceEq.
+Qed.
+
+Lemma transl_Swhile_false_correct:
+ (forall (e : Csem.env) (m : mem) (s : statement) (a : Csyntax.expr)
+ (t : trace) (v : val) (m1 : mem),
+ Csem.eval_expr ge e m a t m1 v ->
+ eval_expr_prop e m a t m1 v ->
+ is_false v (typeof a) ->
+ exec_stmt_prop e m (Swhile a s) t m1 Csem.Out_normal).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts. simpl.
+ change Out_normal with (outcome_block (Out_exit 0)).
+ apply exec_Sblock. apply exec_Sloop_stop. apply exec_Sseq_stop.
+ eapply exit_if_false_false; eauto. congruence. congruence.
+Qed.
+
+Lemma transl_out_break_or_return:
+ forall out1 out2 nbrk ncnt,
+ out_break_or_return out1 out2 ->
+ transl_outcome nbrk ncnt out2 =
+ outcome_block (outcome_block (transl_outcome 1 0 out1)).
+Proof.
+ intros. inversion H; subst; reflexivity.
+Qed.
+
+Lemma transl_out_normal_or_continue:
+ forall out,
+ out_normal_or_continue out ->
+ Out_normal = outcome_block (transl_outcome 1 0 out).
+Proof.
+ intros; inversion H; reflexivity.
+Qed.
+
+Lemma transl_Swhile_stop_correct:
+ (forall (e : Csem.env) (m : mem) (a : Csyntax.expr) (t1 : trace)
+ (m1 : mem) (v : val) (s : statement) (m2 : mem) (t2 : trace)
+ (out2 out : Csem.outcome),
+ Csem.eval_expr ge e m a t1 m1 v ->
+ eval_expr_prop e m a t1 m1 v ->
+ is_true v (typeof a) ->
+ Csem.exec_stmt ge e m1 s t2 m2 out2 ->
+ exec_stmt_prop e m1 s t2 m2 out2 ->
+ out_break_or_return out2 out ->
+ exec_stmt_prop e m (Swhile a s) (t1 ** t2) m2 out).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts. rewrite (transl_out_break_or_return _ _ nbrk ncnt H4).
+ apply exec_Sblock. apply exec_Sloop_stop.
+ eapply exec_Sseq_continue.
+ eapply exit_if_false_true; eauto.
+ apply exec_Sblock. eauto.
+ auto. inversion H4; simpl; congruence.
+Qed.
+
+Lemma transl_Swhile_loop_correct:
+ (forall (e : Csem.env) (m : mem) (a : Csyntax.expr) (t1 : trace)
+ (m1 : mem) (v : val) (s : statement) (out2 out : Csem.outcome)
+ (t2 : trace) (m2 : mem) (t3 : trace) (m3 : mem),
+ Csem.eval_expr ge e m a t1 m1 v ->
+ eval_expr_prop e m a t1 m1 v ->
+ is_true v (typeof a) ->
+ Csem.exec_stmt ge e m1 s t2 m2 out2 ->
+ exec_stmt_prop e m1 s t2 m2 out2 ->
+ out_normal_or_continue out2 ->
+ Csem.exec_stmt ge e m2 (Swhile a s) t3 m3 out ->
+ exec_stmt_prop e m2 (Swhile a s) t3 m3 out ->
+ exec_stmt_prop e m (Swhile a s) (t1 ** t2 ** t3) m3 out).
+Proof.
+ intros; red; intros.
+ exploit H6; eauto. intro NEXTITER.
+ inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts.
+ inversion NEXTITER; subst.
+ apply exec_Sblock.
+ eapply exec_Sloop_loop. eapply exec_Sseq_continue.
+ eapply exit_if_false_true; eauto.
+ rewrite (transl_out_normal_or_continue _ H4).
+ apply exec_Sblock. eauto.
+ reflexivity. eassumption.
+ traceEq.
+Qed.
+
+Lemma transl_Sdowhile_false_correct:
+ (forall (e : Csem.env) (m : mem) (s : statement) (a : Csyntax.expr)
+ (t1 : trace) (m1 : mem) (out1 : Csem.outcome) (v : val)
+ (t2 : trace) (m2 : mem),
+ Csem.exec_stmt ge e m s t1 m1 out1 ->
+ exec_stmt_prop e m s t1 m1 out1 ->
+ out_normal_or_continue out1 ->
+ Csem.eval_expr ge e m1 a t2 m2 v ->
+ eval_expr_prop e m1 a t2 m2 v ->
+ is_false v (typeof a) ->
+ exec_stmt_prop e m (Sdowhile a s) (t1 ** t2) m2 Csem.Out_normal).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts. simpl.
+ change Out_normal with (outcome_block (Out_exit 0)).
+ apply exec_Sblock. apply exec_Sloop_stop. eapply exec_Sseq_continue.
+ rewrite (transl_out_normal_or_continue out1 H1).
+ apply exec_Sblock. eauto.
+ eapply exit_if_false_false; eauto. auto. congruence.
+Qed.
+
+Lemma transl_Sdowhile_stop_correct:
+ (forall (e : Csem.env) (m : mem) (s : statement) (a : Csyntax.expr)
+ (t : trace) (m1 : mem) (out1 out : Csem.outcome),
+ Csem.exec_stmt ge e m s t m1 out1 ->
+ exec_stmt_prop e m s t m1 out1 ->
+ out_break_or_return out1 out ->
+ exec_stmt_prop e m (Sdowhile a s) t m1 out).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts. simpl.
+ assert (outcome_block (transl_outcome 1 0 out1) <> Out_normal).
+ inversion H1; simpl; congruence.
+ rewrite (transl_out_break_or_return _ _ nbrk ncnt H1).
+ apply exec_Sblock. apply exec_Sloop_stop.
+ apply exec_Sseq_stop. apply exec_Sblock. eauto.
+ auto. auto.
+Qed.
+
+Lemma transl_Sdowhile_loop_correct:
+ (forall (e : Csem.env) (m : mem) (s : statement) (a : Csyntax.expr)
+ (m1 m2 m3 : mem) (t1 t2 t3 : trace) (out out1 : Csem.outcome)
+ (v : val),
+ Csem.exec_stmt ge e m s t1 m1 out1 ->
+ exec_stmt_prop e m s t1 m1 out1 ->
+ out_normal_or_continue out1 ->
+ Csem.eval_expr ge e m1 a t2 m2 v ->
+ eval_expr_prop e m1 a t2 m2 v ->
+ is_true v (typeof a) ->
+ Csem.exec_stmt ge e m2 (Sdowhile a s) t3 m3 out ->
+ exec_stmt_prop e m2 (Sdowhile a s) t3 m3 out ->
+ exec_stmt_prop e m (Sdowhile a s) (t1 ** t2 ** t3) m3 out).
+Proof.
+ intros; red; intros.
+ exploit H6; eauto. intro NEXTITER.
+ inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts.
+ inversion NEXTITER; subst.
+ apply exec_Sblock.
+ eapply exec_Sloop_loop. eapply exec_Sseq_continue.
+ rewrite (transl_out_normal_or_continue _ H1).
+ apply exec_Sblock. eauto.
+ eapply exit_if_false_true; eauto.
+ reflexivity. eassumption. traceEq.
+Qed.
+
+Lemma transl_Sfor_start_correct:
+ (forall (e : Csem.env) (m : mem) (s a1 : statement)
+ (a2 : Csyntax.expr) (a3 : statement) (out : Csem.outcome)
+ (m1 m2 : mem) (t1 t2 : trace),
+ Csem.exec_stmt ge e m a1 t1 m1 Csem.Out_normal ->
+ exec_stmt_prop e m a1 t1 m1 Csem.Out_normal ->
+ Csem.exec_stmt ge e m1 (Sfor Csyntax.Sskip a2 a3 s) t2 m2 out ->
+ exec_stmt_prop e m1 (Sfor Csyntax.Sskip a2 a3 s) t2 m2 out ->
+ exec_stmt_prop e m (Sfor a1 a2 a3 s) (t1 ** t2) m2 out).
+Proof.
+ intros; red; intros.
+ exploit transl_stmt_Sfor_start; eauto.
+ intros [ts1 [ts2 [A [B C]]]].
+ clear TR; subst ts.
+ inversion WT; subst.
+ assert (WT': wt_stmt tyenv (Sfor Csyntax.Sskip a2 a3 s)).
+ constructor; auto. constructor.
+ exploit H0; eauto. simpl. intro EXEC1.
+ exploit H2; eauto. intro EXEC2.
+ assert (EXEC3: exec_stmt tprog te m1 ts2 t2 m2 (transl_outcome nbrk ncnt out)).
+ inversion EXEC2; subst.
+ inversion H5; subst. rewrite E0_left; auto.
+ inversion H11; subst. congruence.
+ eapply exec_Sseq_continue; eauto.
+Qed.
+
+Lemma transl_Sfor_false_correct:
+ (forall (e : Csem.env) (m : mem) (s : statement) (a2 : Csyntax.expr)
+ (a3 : statement) (t : trace) (v : val) (m1 : mem),
+ Csem.eval_expr ge e m a2 t m1 v ->
+ eval_expr_prop e m a2 t m1 v ->
+ is_false v (typeof a2) ->
+ exec_stmt_prop e m (Sfor Csyntax.Sskip a2 a3 s) t m1 Csem.Out_normal).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts. simpl.
+ eapply exec_Sseq_continue. apply exec_Sskip.
+ change Out_normal with (outcome_block (Out_exit 0)).
+ apply exec_Sblock. apply exec_Sloop_stop.
+ apply exec_Sseq_stop. eapply exit_if_false_false; eauto.
+ congruence. congruence. traceEq.
+Qed.
+
+Lemma transl_Sfor_stop_correct:
+ (forall (e : Csem.env) (m : mem) (s : statement) (a2 : Csyntax.expr)
+ (a3 : statement) (v : val) (m1 m2 : mem) (t1 t2 : trace)
+ (out2 out : Csem.outcome),
+ Csem.eval_expr ge e m a2 t1 m1 v ->
+ eval_expr_prop e m a2 t1 m1 v ->
+ is_true v (typeof a2) ->
+ Csem.exec_stmt ge e m1 s t2 m2 out2 ->
+ exec_stmt_prop e m1 s t2 m2 out2 ->
+ out_break_or_return out2 out ->
+ exec_stmt_prop e m (Sfor Csyntax.Sskip a2 a3 s) (t1 ** t2) m2 out).
+Proof.
+ intros; red; intros. inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts. simpl.
+ assert (outcome_block (transl_outcome 1 0 out2) <> Out_normal).
+ inversion H4; simpl; congruence.
+ rewrite (transl_out_break_or_return _ _ nbrk ncnt H4).
+ eapply exec_Sseq_continue. apply exec_Sskip.
+ apply exec_Sblock. apply exec_Sloop_stop.
+ eapply exec_Sseq_continue. eapply exit_if_false_true; eauto.
+ apply exec_Sseq_stop. apply exec_Sblock. eauto.
+ auto. reflexivity. auto. traceEq.
+Qed.
+
+Lemma transl_Sfor_loop_correct:
+ (forall (e : Csem.env) (m : mem) (s : statement) (a2 : Csyntax.expr)
+ (a3 : statement) (v : val) (m1 m2 m3 m4 : mem)
+ (t1 t2 t3 t4 : trace) (out2 out : Csem.outcome),
+ Csem.eval_expr ge e m a2 t1 m1 v ->
+ eval_expr_prop e m a2 t1 m1 v ->
+ is_true v (typeof a2) ->
+ Csem.exec_stmt ge e m1 s t2 m2 out2 ->
+ exec_stmt_prop e m1 s t2 m2 out2 ->
+ out_normal_or_continue out2 ->
+ Csem.exec_stmt ge e m2 a3 t3 m3 Csem.Out_normal ->
+ exec_stmt_prop e m2 a3 t3 m3 Csem.Out_normal ->
+ Csem.exec_stmt ge e m3 (Sfor Csyntax.Sskip a2 a3 s) t4 m4 out ->
+ exec_stmt_prop e m3 (Sfor Csyntax.Sskip a2 a3 s) t4 m4 out ->
+ exec_stmt_prop e m (Sfor Csyntax.Sskip a2 a3 s)
+ (t1 ** t2 ** t3 ** t4) m4 out).
+Proof.
+ intros; red; intros.
+ exploit H8; eauto. intro NEXTITER.
+ inversion WT; clear WT; subst. simpl in TR; monadInv TR.
+ subst ts.
+ inversion NEXTITER; subst.
+ inversion H11; subst.
+ inversion H18; subst.
+ eapply exec_Sseq_continue. apply exec_Sskip.
+ apply exec_Sblock.
+ eapply exec_Sloop_loop. eapply exec_Sseq_continue.
+ eapply exit_if_false_true; eauto.
+ eapply exec_Sseq_continue.
+ rewrite (transl_out_normal_or_continue _ H4).
+ apply exec_Sblock. eauto.
+ red in H6; simpl in H6; eauto.
+ reflexivity. reflexivity. eassumption.
+ reflexivity. traceEq.
+ inversion H17. congruence.
+Qed.
+
+Lemma transl_lblstmts_switch:
+ forall e m0 t1 m1 n nbrk ncnt tyenv te t2 m2 out sl body ts,
+ exec_stmt tprog te m0 body t1 m1
+ (Out_exit (switch_target n (lblstmts_length sl) (switch_table sl 0))) ->
+ transl_lblstmts
+ (lblstmts_length sl)
+ (S (lblstmts_length sl + ncnt))
+ sl (Sblock body) = Some ts ->
+ wt_lblstmts tyenv sl ->
+ match_env tyenv e te ->
+ exec_lblstmts_prop e m1 (select_switch n sl) t2 m2 out ->
+ Csharpminor.exec_stmt tprog te m0 ts (t1 ** t2) m2
+ (transl_outcome nbrk ncnt (outcome_switch out)).
+Proof.
+ induction sl; intros.
+ simpl in H. simpl in H3.
+ eapply H3; eauto.
+ change Out_normal with (outcome_block (Out_exit 0)).
+ apply exec_Sblock. auto.
+ (* Inductive case *)
+ simpl in H. simpl in H3. rewrite Int.eq_sym in H3. destruct (Int.eq n i).
+ (* first case selected *)
+ eapply H3; eauto.
+ change Out_normal with (outcome_block (Out_exit 0)).
+ apply exec_Sblock. auto.
+ (* next case selected *)
+ inversion H1; clear H1; subst.
+ simpl in H0; monadInv H0.
+ eapply IHsl with (body := Sseq (Sblock body) s0); eauto.
+ apply exec_Sseq_stop.
+ change (Out_exit (switch_target n (lblstmts_length sl) (switch_table sl 0)))
+ with (outcome_block (Out_exit (S (switch_target n (lblstmts_length sl) (switch_table sl 0))))).
+ apply exec_Sblock.
+ rewrite switch_target_table_shift in H. auto. congruence.
+Qed.
+
+Lemma transl_Sswitch_correct:
+ (forall (e : Csem.env) (m : mem) (a : Csyntax.expr) (t1 : trace)
+ (m1 : mem) (n : int) (sl : labeled_statements) (t2 : trace)
+ (m2 : mem) (out : Csem.outcome),
+ Csem.eval_expr ge e m a t1 m1 (Vint n) ->
+ eval_expr_prop e m a t1 m1 (Vint n) ->
+ exec_lblstmts ge e m1 (select_switch n sl) t2 m2 out ->
+ exec_lblstmts_prop e m1 (select_switch n sl) t2 m2 out ->
+ exec_stmt_prop e m (Csyntax.Sswitch a sl) (t1 ** t2) m2
+ (outcome_switch out)).
+Proof.
+ intros; red; intros.
+ inversion WT; clear WT; subst.
+ simpl in TR. monadInv TR; clear TR.
+ rewrite length_switch_table in EQ0.
+ replace (ncnt + lblstmts_length sl + 1)%nat
+ with (S (lblstmts_length sl + ncnt))%nat in EQ0 by omega.
+ eapply transl_lblstmts_switch; eauto.
+ constructor. eapply H0; eauto.
+Qed.
+
+Lemma transl_LSdefault_correct:
+ (forall (e : Csem.env) (m : mem) (s : statement) (t : trace)
+ (m1 : mem) (out : Csem.outcome),
+ Csem.exec_stmt ge e m s t m1 out ->
+ exec_stmt_prop e m s t m1 out ->
+ exec_lblstmts_prop e m (LSdefault s) t m1 out).
+Proof.
+ intros; red; intros.
+ inversion WT; subst.
+ simpl in TR. monadInv TR.
+ rewrite <- H3.
+ replace (transl_outcome nbrk ncnt (outcome_switch out))
+ with (outcome_block (transl_outcome 0 (S ncnt) out)).
+ constructor.
+ eapply exec_Sseq_continue. eauto.
+ eapply H0; eauto. traceEq.
+ destruct out; simpl; auto.
+Qed.
+
+Lemma transl_LScase_fallthrough_correct:
+ (forall (e : Csem.env) (m : mem) (n : int) (s : statement)
+ (ls : labeled_statements) (t1 : trace) (m1 : mem) (t2 : trace)
+ (m2 : mem) (out : Csem.outcome),
+ Csem.exec_stmt ge e m s t1 m1 Csem.Out_normal ->
+ exec_stmt_prop e m s t1 m1 Csem.Out_normal ->
+ exec_lblstmts ge e m1 ls t2 m2 out ->
+ exec_lblstmts_prop e m1 ls t2 m2 out ->
+ exec_lblstmts_prop e m (LScase n s ls) (t1 ** t2) m2 out).
+Proof.
+ intros; red; intros.
+ inversion WT; subst.
+ simpl in TR. monadInv TR; clear TR.
+ assert (exec_stmt tprog te m0 (Sblock (Sseq body s0))
+ (t0 ** t1) m1 Out_normal).
+ change Out_normal with
+ (outcome_block (transl_outcome (S (lblstmts_length ls))
+ (S (S (lblstmts_length ls + ncnt)))
+ Csem.Out_normal)).
+ apply exec_Sblock. eapply exec_Sseq_continue. eexact BODY.
+ eapply H0; eauto.
+ auto.
+ exploit H2. eauto. simpl; eauto. eauto. eauto. simpl.
+ rewrite Eapp_assoc. eauto.
+Qed.
+
+Lemma transl_LScase_stop_correct:
+ (forall (e : Csem.env) (m : mem) (n : int) (s : statement)
+ (ls : labeled_statements) (t : trace) (m1 : mem)
+ (out : Csem.outcome),
+ Csem.exec_stmt ge e m s t m1 out ->
+ exec_stmt_prop e m s t m1 out ->
+ out <> Csem.Out_normal ->
+ exec_lblstmts_prop e m (LScase n s ls) t m1 out).
+Proof.
+ intros; red; intros.
+ inversion WT; subst.
+ simpl in TR. monadInv TR; clear TR.
+ exploit H0; eauto. intro EXEC.
+ destruct out; simpl; simpl in EXEC.
+ (* out = Out_break *)
+ change Out_normal with (outcome_block (Out_exit 0)).
+ eapply transl_lblstmts_exit with (body := Sblock (Sseq body s0)); eauto.
+ rewrite plus_0_r.
+ change (Out_exit (lblstmts_length ls))
+ with (outcome_block (Out_exit (S (lblstmts_length ls)))).
+ constructor. eapply exec_Sseq_continue; eauto.
+ (* out = Out_continue *)
+ change (Out_exit ncnt) with (outcome_block (Out_exit (S ncnt))).
+ eapply transl_lblstmts_exit with (body := Sblock (Sseq body s0)); eauto.
+ replace (Out_exit (lblstmts_length ls + S ncnt))
+ with (outcome_block (Out_exit (S (S (lblstmts_length ls + ncnt))))).
+ constructor. eapply exec_Sseq_continue; eauto.
+ simpl. decEq. omega.
+ (* out = Out_normal *)
+ congruence.
+ (* out = Out_return *)
+ eapply transl_lblstmts_return with (body := Sblock (Sseq body s0)); eauto.
+ change (Out_return o)
+ with (outcome_block (Out_return o)).
+ constructor. eapply exec_Sseq_continue; eauto.
+Qed.
+
+Remark outcome_result_value_match:
+ forall out ty v nbrk ncnt,
+ Csem.outcome_result_value out ty v ->
+ Csharpminor.outcome_result_value (transl_outcome nbrk ncnt out) (opttyp_of_type ty) v.
+Proof.
+ intros until ncnt.
+ destruct out; simpl; try contradiction.
+ destruct ty; simpl; auto.
+ destruct o. intros [A B]. destruct ty; simpl; congruence.
+ destruct ty; simpl; auto.
+Qed.
+
+Lemma transl_funcall_internal_correct:
+ (forall (m : mem) (f : Csyntax.function) (vargs : list val)
+ (t : trace) (e : Csem.env) (m1 : mem) (lb : list block)
+ (m2 m3 : mem) (out : Csem.outcome) (vres : val),
+ Csem.alloc_variables Csem.empty_env m
+ (Csyntax.fn_params f ++ Csyntax.fn_vars f) e m1 lb ->
+ Csem.bind_parameters e m1 (Csyntax.fn_params f) vargs m2 ->
+ Csem.exec_stmt ge e m2 (Csyntax.fn_body f) t m3 out ->
+ exec_stmt_prop e m2 (Csyntax.fn_body f) t m3 out ->
+ Csem.outcome_result_value out (fn_return f) vres ->
+ eval_funcall_prop m (Internal f) vargs t (free_list m3 lb) vres).
+Proof.
+ intros; red; intros.
+ (* Exploitation of typing hypothesis *)
+ inversion WT; clear WT; subst.
+ inversion H6; clear H6; subst.
+ (* Exploitation of translation hypothesis *)
+ monadInv TR. subst tf. clear TR.
+ monadInv EQ. clear EQ. subst f0.
+ (* Allocation of variables *)
+ exploit match_env_alloc_variables; eauto.
+ apply match_globalenv_match_env_empty.
+ apply match_global_typenv.
+ eexact (transl_fn_variables _ _ (signature_of_function f) _ _ s EQ0 EQ1).
+ intros [te [ALLOCVARS MATCHENV]].
+ (* Execution *)
+ econstructor; simpl.
+ (* Norepet *)
+ eapply transl_names_norepet; eauto.
+ (* Alloc *)
+ eexact ALLOCVARS.
+ (* Bind *)
+ eapply bind_parameters_match; eauto.
+ (* Execution of body *)
+ eapply H2; eauto.
+ (* Outcome_result_value *)
+ apply outcome_result_value_match; auto.
+Qed.
+
+Lemma transl_funcall_external_correct:
+ (forall (m : mem) (id : ident) (targs : typelist) (tres : type)
+ (vargs : list val) (t : trace) (vres : val),
+ event_match (external_function id targs tres) vargs t vres ->
+ eval_funcall_prop m (External id targs tres) vargs t m vres).
+Proof.
+ intros; red; intros.
+ monadInv TR. subst tf. constructor. auto.
+Qed.
+
+Theorem transl_funcall_correct:
+ forall (m : mem) (f : Csyntax.fundef) (l : list val) (t : trace)
+ (m0 : mem) (v : val),
+ Csem.eval_funcall ge m f l t m0 v ->
+ eval_funcall_prop m f l t m0 v.
+Proof
+ (Csem.eval_funcall_ind6 ge
+ eval_expr_prop
+ eval_lvalue_prop
+ eval_exprlist_prop
+ exec_stmt_prop
+ exec_lblstmts_prop
+ eval_funcall_prop
+
+ transl_Econst_int_correct
+ transl_Econst_float_correct
+ transl_Elvalue_correct
+ transl_Eaddrof_correct
+ transl_Esizeof_correct
+ transl_Eunop_correct
+ transl_Ebinop_correct
+ transl_Eorbool_1_correct
+ transl_Eorbool_2_correct
+ transl_Eandbool_1_correct
+ transl_Eandbool_2_correct
+ transl_Ecast_correct
+ transl_Ecall_correct
+ transl_Evar_local_correct
+ transl_Evar_global_correct
+ transl_Ederef_correct
+ transl_Eindex_correct
+ transl_Efield_struct_correct
+ transl_Efield_union_correct
+ transl_Enil_correct
+ transl_Econs_correct
+ transl_Sskip_correct
+ transl_Sexpr_correct
+ transl_Sassign_correct
+ transl_Ssequence_1_correct
+ transl_Ssequence_2_correct
+ transl_Sifthenelse_true_correct
+ transl_Sifthenelse_false_correct
+ transl_Sreturn_none_correct
+ transl_Sreturn_some_correct
+ transl_Sbreak_correct
+ transl_Scontinue_correct
+ transl_Swhile_false_correct
+ transl_Swhile_stop_correct
+ transl_Swhile_loop_correct
+ transl_Sdowhile_false_correct
+ transl_Sdowhile_stop_correct
+ transl_Sdowhile_loop_correct
+ transl_Sfor_start_correct
+ transl_Sfor_false_correct
+ transl_Sfor_stop_correct
+ transl_Sfor_loop_correct
+ transl_Sswitch_correct
+ transl_LSdefault_correct
+ transl_LScase_fallthrough_correct
+ transl_LScase_stop_correct
+ transl_funcall_internal_correct
+ transl_funcall_external_correct).
+
+End CORRECTNESS.
+
+(** Semantic preservation for whole programs. *)
+
+Theorem transl_program_correct:
+ forall prog tprog t r,
+ transl_program prog = Some tprog ->
+ Ctyping.wt_program prog ->
+ Csem.exec_program prog t r ->
+ Csharpminor.exec_program tprog t r.
+Proof.
+ intros until r. intros TRANSL WT [b [f [m1 [FINDS [FINDF [TYP EVAL]]]]]].
+ inversion WT; subst.
+
+ assert (type_of_fundef f = Tfunction Tnil (Tint I32 Signed)).
+ apply wt_program_main.
+ change (Csyntax.prog_funct prog)
+ with (AST.prog_funct (Csyntax.program_of_program prog)).
+ eapply Genv.find_funct_ptr_symbol_inversion; eauto.
+ exploit function_ptr_translated; eauto. intros [tf [TFINDF TRANSLFD]].
+ exists b; exists tf; exists m1.
+ split.
+ rewrite (symbols_preserved _ _ TRANSL).
+ monadInv TRANSL. rewrite <- H1. simpl. auto.
+ split. auto.
+ split.
+ generalize (transl_fundef_sig2 _ _ _ _ TRANSLFD H). simpl; auto.
+ rewrite (@Genv.init_mem_transf_partial _ _ transl_fundef
+ (Csyntax.program_of_program prog)
+ (Csharpminor.program_of_program tprog)).
+ generalize (transl_funcall_correct _ _ WT TRANSL _ _ _ _ _ _ EVAL).
+ intro. eapply H0.
+ eapply function_ptr_well_typed; eauto.
+ auto.
+ apply transform_program_of_program; auto.
+Qed.
diff --git a/cfrontend/Csyntax.v b/cfrontend/Csyntax.v
new file mode 100644
index 0000000..d3bd8d6
--- /dev/null
+++ b/cfrontend/Csyntax.v
@@ -0,0 +1,456 @@
+(** * Abstract syntax for the Clight language *)
+
+Require Import Coqlib.
+Require Import Integers.
+Require Import Floats.
+Require Import AST.
+
+(** ** Abstract syntax *)
+
+(** Types *)
+
+Inductive signedness : Set :=
+ | Signed: signedness
+ | Unsigned: signedness.
+
+Inductive intsize : Set :=
+ | I8: intsize
+ | I16: intsize
+ | I32: intsize.
+
+Inductive floatsize : Set :=
+ | F32: floatsize
+ | F64: floatsize.
+
+Inductive type : Set :=
+ | Tvoid: type
+ | Tint: intsize -> signedness -> type
+ | Tfloat: floatsize -> type
+ | Tpointer: type -> type
+ | Tarray: type -> Z -> type
+ | Tfunction: typelist -> type -> type
+ | Tstruct: fieldlist -> type
+ | Tunion: fieldlist -> type
+
+with typelist : Set :=
+ | Tnil: typelist
+ | Tcons: type -> typelist -> typelist
+
+with fieldlist : Set :=
+ | Fnil: fieldlist
+ | Fcons: ident -> type -> fieldlist -> fieldlist.
+
+(** Arithmetic and logical operators *)
+
+Inductive unary_operation : Set :=
+ | Onotbool : unary_operation
+ | Onotint : unary_operation
+ | Oneg : unary_operation.
+
+Inductive binary_operation : Set :=
+ | 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.
+
+(** Expressions *)
+
+Inductive expr : Set :=
+ | Expr: expr_descr -> type -> expr
+
+with expr_descr : Set :=
+ | Econst_int: int -> expr_descr
+ | Econst_float: float -> expr_descr
+ | Evar: ident -> expr_descr
+ | Ederef: expr -> expr_descr
+ | Eaddrof: expr -> expr_descr
+ | Eunop: unary_operation -> expr -> expr_descr
+ | Ebinop: binary_operation -> expr -> expr -> expr_descr
+ | Ecast: type -> expr -> expr_descr
+ | Eindex: expr -> expr -> expr_descr
+ | Ecall: expr -> exprlist -> expr_descr
+ | Eandbool: expr -> expr -> expr_descr
+ | Eorbool: expr -> expr -> expr_descr
+ | Esizeof: type -> expr_descr
+ | Efield: expr -> ident -> expr_descr
+
+with exprlist : Set :=
+ | Enil: exprlist
+ | Econs: expr -> exprlist -> exprlist.
+
+(** Extract the type part of a type-annotated Clight expression. *)
+
+Definition typeof (e: expr) : type :=
+ match e with Expr de te => te end.
+
+(** Statements *)
+
+Inductive statement : Set :=
+ | Sskip : statement
+ | Sexpr : expr -> statement
+ | Sassign : expr -> expr -> statement
+ | Ssequence : statement -> statement -> statement
+ | Sifthenelse : expr -> statement -> statement -> statement
+ | Swhile : expr -> statement -> statement
+ | Sdowhile : expr -> statement -> statement
+ | Sfor: statement -> expr -> statement -> statement -> statement
+ | Sbreak : statement
+ | Scontinue : statement
+ | Sreturn : option expr -> statement
+ | Sswitch : expr -> labeled_statements -> statement
+
+with labeled_statements : Set :=
+ | LSdefault: statement -> labeled_statements
+ | LScase: int -> statement -> labeled_statements -> labeled_statements.
+
+(** Function definition *)
+
+Record function : Set := mkfunction {
+ fn_return: type;
+ fn_params: list (ident * type);
+ fn_vars: list (ident * type);
+ fn_body: statement
+}.
+
+Inductive fundef : Set :=
+ | Internal: function -> fundef
+ | External: ident -> typelist -> type -> fundef.
+
+(** Program *)
+
+Record program : Set := mkprogram {
+ prog_funct: list (ident * fundef);
+ prog_defs: list (ident * type * list init_data);
+ prog_main: ident
+}.
+
+(** ** Operations over types *)
+
+(** The type of a function definition *)
+
+Fixpoint type_of_params (params: list (ident * type)) : typelist :=
+ match params with
+ | nil => Tnil
+ | (id, ty) :: rem => Tcons ty (type_of_params rem)
+ end.
+
+Definition type_of_function (f: function) : type :=
+ Tfunction (type_of_params (fn_params f)) (fn_return f).
+
+Definition type_of_fundef (f: fundef) : type :=
+ match f with
+ | Internal fd => type_of_function fd
+ | External id args res => Tfunction args res
+ end.
+
+(** Natural alignment of a type *)
+
+Fixpoint alignof (t: type) : Z :=
+ match t with
+ | Tvoid => 1
+ | Tint I8 _ => 1
+ | Tint I16 _ => 2
+ | Tint I32 _ => 4
+ | Tfloat F32 => 4
+ | Tfloat F64 => 8
+ | Tpointer _ => 4
+ | Tarray t' n => alignof t'
+ | Tfunction _ _ => 1
+ | Tstruct fld => alignof_fields fld
+ | Tunion fld => alignof_fields fld
+ end
+
+with alignof_fields (f: fieldlist) : Z :=
+ match f with
+ | Fnil => 1
+ | Fcons id t f' => Zmax (alignof t) (alignof_fields f')
+ end.
+
+Scheme type_ind2 := Induction for type Sort Prop
+ with fieldlist_ind2 := Induction for fieldlist Sort Prop.
+
+Lemma alignof_fields_pos:
+ forall f, alignof_fields f > 0.
+Proof.
+ induction f; simpl.
+ omega.
+ generalize (Zmax2 (alignof t) (alignof_fields f)). omega.
+Qed.
+
+Lemma alignof_pos:
+ forall t, alignof t > 0.
+Proof.
+ induction t; simpl; auto; try omega.
+ destruct i; omega.
+ destruct f; omega.
+ apply alignof_fields_pos.
+ apply alignof_fields_pos.
+Qed.
+
+(** Size of a type (in bytes) *)
+
+Fixpoint sizeof (t: type) : Z :=
+ match t with
+ | Tvoid => 1
+ | Tint I8 _ => 1
+ | Tint I16 _ => 2
+ | Tint I32 _ => 4
+ | Tfloat F32 => 4
+ | Tfloat F64 => 8
+ | Tpointer _ => 4
+ | Tarray t' n => sizeof t' * Zmax 1 n
+ | Tfunction _ _ => 1
+ | Tstruct fld => align (Zmax 1 (sizeof_struct fld 0)) (alignof t)
+ | Tunion fld => align (Zmax 1 (sizeof_union fld)) (alignof t)
+ end
+
+with sizeof_struct (fld: fieldlist) (pos: Z) {struct fld} : Z :=
+ match fld with
+ | Fnil => pos
+ | Fcons id t fld' => sizeof_struct fld' (align pos (alignof t) + sizeof t)
+ end
+
+with sizeof_union (fld: fieldlist) : Z :=
+ match fld with
+ | Fnil => 0
+ | Fcons id t fld' => Zmax (sizeof t) (sizeof_union fld')
+ end.
+
+Lemma sizeof_pos:
+ forall t, sizeof t > 0.
+Proof.
+ intro t0.
+ apply (type_ind2 (fun t => sizeof t > 0)
+ (fun f => sizeof_union f >= 0 /\ forall pos, pos >= 0 -> sizeof_struct f pos >= 0));
+ intros; simpl; auto; try omega.
+ destruct i; omega.
+ destruct f; omega.
+ apply Zmult_gt_0_compat. auto. generalize (Zmax1 1 z); omega.
+ destruct H.
+ generalize (align_le (Zmax 1 (sizeof_struct f 0)) (alignof_fields f) (alignof_fields_pos f)).
+ generalize (Zmax1 1 (sizeof_struct f 0)). omega.
+ generalize (align_le (Zmax 1 (sizeof_union f)) (alignof_fields f) (alignof_fields_pos f)).
+ generalize (Zmax1 1 (sizeof_union f)). omega.
+ split. omega. auto.
+ destruct H0. split; intros.
+ generalize (Zmax2 (sizeof t) (sizeof_union f)). omega.
+ apply H1.
+ generalize (align_le pos (alignof t) (alignof_pos t)). omega.
+Qed.
+
+(** Byte offset for a field in a struct. *)
+
+Fixpoint field_offset_rec (id: ident) (fld: fieldlist) (pos: Z)
+ {struct fld} : option Z :=
+ match fld with
+ | Fnil => None
+ | Fcons id' t fld' =>
+ if ident_eq id id'
+ then Some (align pos (alignof t))
+ else field_offset_rec id fld' (align pos (alignof t) + sizeof t)
+ end.
+
+Definition field_offset (id: ident) (fld: fieldlist) : option Z :=
+ field_offset_rec id fld 0.
+
+(* Describe how a variable of the given type must be accessed:
+ - by value, i.e. by loading from the address of the variable
+ with the given chunk
+ - by reference, i.e. by just returning the address of the variable
+ - not at all, e.g. the [void] type. *)
+
+Inductive mode: Set :=
+ | By_value: memory_chunk -> mode
+ | By_reference: mode
+ | By_nothing: mode.
+
+Definition access_mode (ty: type) : mode :=
+ match ty with
+ | Tint I8 Signed => By_value Mint8signed
+ | Tint I8 Unsigned => By_value Mint8unsigned
+ | Tint I16 Signed => By_value Mint16signed
+ | Tint I16 Unsigned => By_value Mint16unsigned
+ | Tint I32 _ => By_value Mint32
+ | Tfloat F32 => By_value Mfloat32
+ | Tfloat F64 => By_value Mfloat64
+ | Tvoid => By_nothing
+ | Tpointer _ => By_value Mint32
+ | Tarray _ _ => By_reference
+ | Tfunction _ _ => By_reference
+ | Tstruct fList => By_nothing
+ | Tunion fList => By_nothing
+end.
+
+(** Conversion of a Clight program into an AST program *)
+
+Definition extract_global_var (id_ty_init: ident * type * list init_data) :=
+ match id_ty_init with (id, ty, init) => (id, init) end.
+
+Definition program_of_program (p: program) : AST.program fundef :=
+ AST.mkprogram
+ p.(prog_funct)
+ p.(prog_main)
+ (List.map extract_global_var p.(prog_defs)).
+
+(** Classification of arithmetic operations and comparisons *)
+
+Inductive classify_add_cases : Set :=
+ | add_case_ii: classify_add_cases (* int , int *)
+ | add_case_ff: classify_add_cases (* float , float *)
+ | add_case_pi: type -> classify_add_cases (* ptr | array, int *)
+ | add_default: classify_add_cases. (* other *)
+
+Definition classify_add (ty1: type) (ty2: type) :=
+ match ty1, ty2 with
+ | Tint _ _, Tint _ _ => add_case_ii
+ | Tfloat _, Tfloat _ => add_case_ff
+ | Tpointer ty, Tint _ _ => add_case_pi ty
+ | Tarray ty _, Tint _ _ => add_case_pi ty
+ | _, _ => add_default
+ end.
+
+Inductive classify_sub_cases : Set :=
+ | sub_case_ii: classify_sub_cases (* int , int *)
+ | sub_case_ff: classify_sub_cases (* float , float *)
+ | sub_case_pi: type -> classify_sub_cases (* ptr | array , int *)
+ | sub_case_pp: type -> classify_sub_cases (* ptr | array , ptr | array *)
+ | sub_default: classify_sub_cases . (* other *)
+
+Definition classify_sub (ty1: type) (ty2: type) :=
+ match ty1, ty2 with
+ | Tint _ _ , Tint _ _ => sub_case_ii
+ | Tfloat _ , Tfloat _ => sub_case_ff
+ | Tpointer ty , Tint _ _ => sub_case_pi ty
+ | Tarray ty _ , Tint _ _ => sub_case_pi ty
+ | Tpointer ty , Tpointer _ => sub_case_pp ty
+ | Tpointer ty , Tarray _ _=> sub_case_pp ty
+ | Tarray ty _ , Tpointer _ => sub_case_pp ty
+ | Tarray ty _ , Tarray _ _ => sub_case_pp ty
+ | _ ,_ => sub_default
+ end.
+
+Inductive classify_mul_cases : Set:=
+ | mul_case_ii: classify_mul_cases (* int , int *)
+ | mul_case_ff: classify_mul_cases (* float , float *)
+ | mul_default: classify_mul_cases . (* other *)
+
+Definition classify_mul (ty1: type) (ty2: type) :=
+ match ty1,ty2 with
+ | Tint _ _, Tint _ _ => mul_case_ii
+ | Tfloat _ , Tfloat _ => mul_case_ff
+ | _,_ => mul_default
+end.
+
+Inductive classify_div_cases : Set:=
+ | div_case_I32unsi: classify_div_cases (* uns int32 , int *)
+ | div_case_ii: classify_div_cases (* int , int *)
+ | div_case_ff: classify_div_cases (* float , float *)
+ | div_default: classify_div_cases. (* other *)
+
+Definition classify_div (ty1: type) (ty2: type) :=
+ match ty1,ty2 with
+ | Tint I32 Unsigned, Tint _ _ => div_case_I32unsi
+ | Tint _ _ , Tint I32 Unsigned => div_case_I32unsi
+ | Tint _ _ , Tint _ _ => div_case_ii
+ | Tfloat _ , Tfloat _ => div_case_ff
+ | _ ,_ => div_default
+end.
+
+Inductive classify_mod_cases : Set:=
+ | mod_case_I32unsi: classify_mod_cases (* uns I32 , int *)
+ | mod_case_ii: classify_mod_cases (* int , int *)
+ | mod_default: classify_mod_cases . (* other *)
+
+Definition classify_mod (ty1: type) (ty2: type) :=
+ match ty1,ty2 with
+ | Tint I32 Unsigned , Tint _ _ => mod_case_I32unsi
+ | Tint _ _ , Tint I32 Unsigned => mod_case_I32unsi
+ | Tint _ _ , Tint _ _ => mod_case_ii
+ | _ , _ => mod_default
+end .
+
+Inductive classify_shr_cases :Set:=
+ | shr_case_I32unsi: classify_shr_cases (* uns I32 , int *)
+ | shr_case_ii :classify_shr_cases (* int , int *)
+ | shr_default : classify_shr_cases . (* other *)
+
+Definition classify_shr (ty1: type) (ty2: type) :=
+ match ty1,ty2 with
+ | Tint I32 Unsigned , Tint _ _ => shr_case_I32unsi
+ | Tint _ _ , Tint _ _ => shr_case_ii
+ | _ , _ => shr_default
+ end.
+
+Inductive classify_cmp_cases : Set:=
+ | cmp_case_I32unsi: classify_cmp_cases (* uns I32 , int *)
+ | cmp_case_ii: classify_cmp_cases (* int , int*)
+ | cmp_case_ff: classify_cmp_cases (* float , float *)
+ | cmp_case_pi: classify_cmp_cases (* ptr | array , int *)
+ | cmp_case_pp:classify_cmp_cases (* ptr | array , ptr | array *)
+ | cmp_default: classify_cmp_cases . (* other *)
+
+Definition classify_cmp (ty1: type) (ty2: type) :=
+ match ty1,ty2 with
+ | Tint I32 Unsigned , Tint _ _ => cmp_case_I32unsi
+ | Tint _ _ , Tint I32 Unsigned => cmp_case_I32unsi
+ | Tint _ _ , Tint _ _ => cmp_case_ii
+ | Tfloat _ , Tfloat _ => cmp_case_ff
+ | Tpointer _ , Tint _ _ => cmp_case_pi
+ | Tarray _ _ , Tint _ _ => cmp_case_pi
+ | Tpointer _ , Tpointer _ => cmp_case_pp
+ | Tpointer _ , Tarray _ _ => cmp_case_pp
+ | Tarray _ _ ,Tpointer _ => cmp_case_pp
+ | Tarray _ _ ,Tarray _ _ => cmp_case_pp
+ | _ , _ => cmp_default
+ end.
+
+Inductive classify_fun_cases : Set:=
+ | fun_case_f: typelist -> type -> classify_fun_cases (* type fun | ptr fun*)
+ | fun_default: classify_fun_cases . (* other *)
+
+Definition classify_fun (ty: type) :=
+ match ty with
+ | Tfunction args res => fun_case_f args res
+ | Tpointer (Tfunction args res) => fun_case_f args res
+ | _ => fun_default
+ end.
+
+(** Mapping between Clight types and Cminor types and external functions *)
+
+Definition typ_of_type (t: type) : AST.typ :=
+ match t with
+ | Tfloat _ => AST.Tfloat
+ | _ => AST.Tint
+ end.
+
+Definition opttyp_of_type (t: type) : option AST.typ :=
+ match t with
+ | Tvoid => None
+ | Tfloat _ => Some AST.Tfloat
+ | _ => Some AST.Tint
+ end.
+
+Fixpoint typlist_of_typelist (tl: typelist) : list AST.typ :=
+ match tl with
+ | Tnil => nil
+ | Tcons hd tl => typ_of_type hd :: typlist_of_typelist tl
+ end.
+
+Definition signature_of_type (args: typelist) (res: type) : signature :=
+ mksignature (typlist_of_typelist args) (opttyp_of_type res).
+
+Definition external_function
+ (id: ident) (targs: typelist) (tres: type) : AST.external_function :=
+ mkextfun id (signature_of_type targs tres).
diff --git a/cfrontend/Ctyping.v b/cfrontend/Ctyping.v
new file mode 100644
index 0000000..8b2f90f
--- /dev/null
+++ b/cfrontend/Ctyping.v
@@ -0,0 +1,420 @@
+(** * Type well-formedness of C programs *)
+
+Require Import Coqlib.
+Require Import Maps.
+Require Import AST.
+Require Import Csyntax.
+
+(** ** Typing rules *)
+
+(** This ``type system'' is very coarse: we check only the typing properties
+ that matter for the translation to be correct. Essentially,
+ we need to check that the types attached to variable references
+ match the declaration types for those variables. *)
+
+Definition typenv := PTree.t type.
+
+Section TYPING.
+
+Variable env: typenv.
+
+Inductive wt_expr: expr -> Prop :=
+ | wt_Econst_int: forall i ty,
+ wt_expr (Expr (Econst_int i) ty)
+ | wt_Econst_float: forall f ty,
+ wt_expr (Expr (Econst_float f) ty)
+ | wt_Evar: forall id ty,
+ env!id = Some ty ->
+ wt_expr (Expr (Evar id) ty)
+ | wt_Ederef: forall e ty,
+ wt_expr e ->
+ wt_expr (Expr (Ederef e) ty)
+ | wt_Eaddrof: forall e ty,
+ wt_expr e ->
+ wt_expr (Expr (Eaddrof e) ty)
+ | wt_Eunop: forall op e ty,
+ wt_expr e ->
+ wt_expr (Expr (Eunop op e) ty)
+ | wt_Ebinop: forall op e1 e2 ty,
+ wt_expr e1 -> wt_expr e2 ->
+ wt_expr (Expr (Ebinop op e1 e2) ty)
+ | wt_Ecast: forall e ty ty',
+ wt_expr e ->
+ wt_expr (Expr (Ecast ty' e) ty)
+ | wt_Eindex: forall e1 e2 ty,
+ wt_expr e1 -> wt_expr e2 ->
+ wt_expr (Expr (Eindex e1 e2) ty)
+ | wt_Ecall: forall e1 el ty,
+ wt_expr e1 ->
+ wt_exprlist el ->
+ wt_expr (Expr (Ecall e1 el) ty)
+ | wt_Eandbool: forall e1 e2 ty,
+ wt_expr e1 -> wt_expr e2 ->
+ wt_expr (Expr (Eandbool e1 e2) ty)
+ | wt_Eorbool: forall e1 e2 ty,
+ wt_expr e1 -> wt_expr e2 ->
+ wt_expr (Expr (Eorbool e1 e2) ty)
+ | wt_Esizeof: forall ty' ty,
+ wt_expr (Expr (Esizeof ty') ty)
+ | wt_Efield: forall e id ty,
+ wt_expr e ->
+ wt_expr (Expr (Efield e id) ty)
+
+with wt_exprlist: exprlist -> Prop :=
+ | wt_Enil:
+ wt_exprlist Enil
+ | wt_Econs: forall e el,
+ wt_expr e -> wt_exprlist el -> wt_exprlist (Econs e el).
+
+Inductive wt_stmt: statement -> Prop :=
+ | wt_Sskip:
+ wt_stmt Sskip
+ | wt_Sexpr: forall e,
+ wt_expr e ->
+ wt_stmt (Sexpr e)
+ | wt_Sassign: forall e1 e2,
+ wt_expr e1 -> wt_expr e2 ->
+ wt_stmt (Sassign e1 e2)
+ | wt_Ssequence: forall s1 s2,
+ wt_stmt s1 -> wt_stmt s2 ->
+ wt_stmt (Ssequence s1 s2)
+ | wt_Sifthenelse: forall e s1 s2,
+ wt_expr e -> wt_stmt s1 -> wt_stmt s2 ->
+ wt_stmt (Sifthenelse e s1 s2)
+ | wt_Swhile: forall e s,
+ wt_expr e -> wt_stmt s ->
+ wt_stmt (Swhile e s)
+ | wt_Sdowhile: forall e s,
+ wt_expr e -> wt_stmt s ->
+ wt_stmt (Sdowhile e s)
+ | wt_Sfor: forall e s1 s2 s3,
+ wt_expr e -> wt_stmt s1 -> wt_stmt s2 -> wt_stmt s3 ->
+ wt_stmt (Sfor s1 e s2 s3)
+ | wt_Sbreak:
+ wt_stmt Sbreak
+ | wt_Scontinue:
+ wt_stmt Scontinue
+ | wt_Sreturn_some: forall e,
+ wt_expr e ->
+ wt_stmt (Sreturn (Some e))
+ | wt_Sreturn_none:
+ wt_stmt (Sreturn None)
+ | wt_Sswitch: forall e sl,
+ wt_expr e -> wt_lblstmts sl ->
+ wt_stmt (Sswitch e sl)
+
+with wt_lblstmts: labeled_statements -> Prop :=
+ | wt_LSdefault: forall s,
+ wt_stmt s ->
+ wt_lblstmts (LSdefault s)
+ | wt_LScase: forall n s sl,
+ wt_stmt s -> wt_lblstmts sl ->
+ wt_lblstmts (LScase n s sl).
+
+End TYPING.
+
+Definition add_var (env: typenv) (id_ty: ident * type) : typenv :=
+ PTree.set (fst id_ty) (snd id_ty) env.
+
+Definition add_vars (env: typenv) (vars: list(ident * type)) : typenv :=
+ List.fold_left add_var vars env.
+
+Definition var_names (vars: list(ident * type)) : list ident :=
+ List.map (@fst ident type) vars.
+
+Inductive wt_function: typenv -> function -> Prop :=
+ | wt_function_intro: forall env f,
+ list_norepet (var_names f.(fn_params) ++ var_names f.(fn_vars)) ->
+ wt_stmt (add_vars env (f.(fn_params) ++ f.(fn_vars))) f.(fn_body) ->
+ wt_function env f.
+
+Inductive wt_fundef: typenv -> fundef -> Prop :=
+ | wt_fundef_Internal: forall env f,
+ wt_function env f ->
+ wt_fundef env (Internal f)
+ | wt_fundef_External: forall env id args res,
+ wt_fundef env (External id args res).
+
+Definition add_global_var
+ (env: typenv) (id_ty_init: ident * type * list init_data) : typenv :=
+ match id_ty_init with (id, ty, init) => PTree.set id ty env end.
+
+Definition add_global_vars
+ (env: typenv) (vars: list(ident * type * list init_data)) : typenv :=
+ List.fold_left add_global_var vars env.
+
+Definition add_global_fun
+ (env: typenv) (id_fd: ident * fundef) : typenv :=
+ PTree.set (fst id_fd) (type_of_fundef (snd id_fd)) env.
+
+Definition add_global_funs
+ (env: typenv) (funs: list(ident * fundef)) : typenv :=
+ List.fold_left add_global_fun funs env.
+
+Definition global_typenv (p: program) :=
+ add_global_vars (add_global_funs (PTree.empty type) p.(prog_funct)) p.(prog_defs).
+
+Record wt_program (p: program) : Prop := mk_wt_program {
+ wt_program_funct:
+ forall id fd,
+ In (id, fd) p.(prog_funct) ->
+ wt_fundef (global_typenv p) fd;
+ wt_program_main:
+ forall fd,
+ In (p.(prog_main), fd) p.(prog_funct) ->
+ type_of_fundef fd = Tfunction Tnil (Tint I32 Signed)
+}.
+
+(** ** Type-checking algorithm *)
+
+Lemma eq_signedness: forall (s1 s2: signedness), {s1=s2} + {s1<>s2}.
+Proof. decide equality. Qed.
+
+Lemma eq_intsize: forall (s1 s2: intsize), {s1=s2} + {s1<>s2}.
+Proof. decide equality. Qed.
+
+Lemma eq_floatsize: forall (s1 s2: floatsize), {s1=s2} + {s1<>s2}.
+Proof. decide equality. Qed.
+
+Fixpoint eq_type (t1 t2: type) {struct t1}: bool :=
+ match t1, t2 with
+ | Tvoid, Tvoid => true
+ | Tint sz1 sg1, Tint sz2 sg2 =>
+ if eq_intsize sz1 sz2
+ then if eq_signedness sg1 sg2 then true else false
+ else false
+ | Tfloat sz1, Tfloat sz2 =>
+ if eq_floatsize sz1 sz2 then true else false
+ | Tpointer u1, Tpointer u2 => eq_type u1 u2
+ | Tarray u1 sz1, Tarray u2 sz2 =>
+ eq_type u1 u2 && if zeq sz1 sz2 then true else false
+ | Tfunction args1 res1, Tfunction args2 res2 =>
+ eq_typelist args1 args2 && eq_type res1 res2
+ | Tstruct f1, Tstruct f2 => eq_fieldlist f1 f2
+ | Tunion f1, Tunion f2 => eq_fieldlist f1 f2
+ | _, _ => false
+ end
+
+with eq_typelist (t1 t2: typelist) {struct t1} : bool :=
+ match t1, t2 with
+ | Tnil, Tnil => true
+ | Tcons u1 r1, Tcons u2 r2 => eq_type u1 u2 && eq_typelist r1 r2
+ | _, _ => false
+ end
+
+with eq_fieldlist (f1 f2: fieldlist) {struct f1} : bool :=
+ match f1, f2 with
+ | Fnil, Fnil => true
+ | Fcons id1 t1 r1, Fcons id2 t2 r2 =>
+ if ident_eq id1 id2
+ then eq_type t1 t2 && eq_fieldlist r1 r2
+ else false
+ | _, _ => false
+ end.
+
+Ltac TrueInv :=
+ match goal with
+ | [ H: ((if ?x then ?y else false) = true) |- _ ] =>
+ destruct x; [TrueInv | discriminate]
+ | [ H: (?x && ?y = true) |- _ ] =>
+ elim (andb_prop _ _ H); clear H; intros; TrueInv
+ | _ =>
+ idtac
+ end.
+
+Scheme type_ind_3 := Induction for type Sort Prop
+ with typelist_ind_3 := Induction for typelist Sort Prop
+ with fieldlist_ind_3 := Induction for fieldlist Sort Prop.
+
+Lemma eq_type_correct:
+ forall t1 t2, eq_type t1 t2 = true -> t1 = t2.
+Proof.
+ apply (type_ind_3 (fun t1 => forall t2, eq_type t1 t2 = true -> t1 = t2)
+ (fun t1 => forall t2, eq_typelist t1 t2 = true -> t1 = t2)
+ (fun t1 => forall t2, eq_fieldlist t1 t2 = true -> t1 = t2));
+ intros; destruct t2; simpl in *; try discriminate.
+ auto.
+ TrueInv. congruence.
+ TrueInv. congruence.
+ decEq; auto.
+ TrueInv. decEq; auto.
+ TrueInv. decEq; auto.
+ decEq; auto.
+ decEq; auto.
+ auto.
+ TrueInv. decEq; auto.
+ auto.
+ TrueInv. decEq; auto.
+Qed.
+
+Section TYPECHECKING.
+
+Variable env: typenv.
+
+Fixpoint typecheck_expr (a: Csyntax.expr) {struct a} : bool :=
+ match a with
+ | Expr ad aty => typecheck_exprdescr ad aty
+ end
+
+with typecheck_exprdescr (a: Csyntax.expr_descr) (ty: type) {struct a} : bool :=
+ match a with
+ | Csyntax.Econst_int n => true
+ | Csyntax.Econst_float n => true
+ | Csyntax.Evar id =>
+ match env!id with
+ | None => false
+ | Some ty' => eq_type ty ty'
+ end
+ | Csyntax.Ederef b => typecheck_expr b
+ | Csyntax.Eaddrof b => typecheck_expr b
+ | Csyntax.Eunop op b => typecheck_expr b
+ | Csyntax.Ebinop op b c => typecheck_expr b && typecheck_expr c
+ | Csyntax.Ecast ty b => typecheck_expr b
+ | Csyntax.Eindex b c => typecheck_expr b && typecheck_expr c
+ | Csyntax.Ecall b cl => typecheck_expr b && typecheck_exprlist cl
+ | Csyntax.Eandbool b c => typecheck_expr b && typecheck_expr c
+ | Csyntax.Eorbool b c => typecheck_expr b && typecheck_expr c
+ | Csyntax.Esizeof ty => true
+ | Csyntax.Efield b i => typecheck_expr b
+ end
+
+with typecheck_exprlist (al: Csyntax.exprlist): bool :=
+ match al with
+ | Csyntax.Enil => true
+ | Csyntax.Econs a1 a2 => typecheck_expr a1 && typecheck_exprlist a2
+ end.
+
+Scheme expr_ind_3 := Induction for expr Sort Prop
+ with expr_descr_ind_3 := Induction for expr_descr Sort Prop
+ with exprlist_ind_3 := Induction for exprlist Sort Prop.
+
+Lemma typecheck_expr_correct:
+ forall a, typecheck_expr a = true -> wt_expr env a.
+Proof.
+ apply (expr_ind_3 (fun a => typecheck_expr a = true -> wt_expr env a)
+ (fun a => forall ty, typecheck_exprdescr a ty = true -> wt_expr env (Expr a ty))
+ (fun a => typecheck_exprlist a = true -> wt_exprlist env a));
+ simpl; intros; TrueInv.
+ auto.
+ constructor.
+ constructor.
+ constructor. destruct (env!i). decEq; symmetry; apply eq_type_correct; auto.
+ discriminate.
+ constructor; auto.
+ constructor; auto.
+ constructor; auto.
+ constructor; auto.
+ constructor; auto.
+ constructor; auto.
+ constructor; auto.
+ constructor; auto.
+ constructor; auto.
+ auto.
+ constructor; auto.
+ constructor; auto.
+ constructor.
+ constructor; auto.
+Qed.
+
+Lemma typecheck_exprlist_correct:
+ forall a, typecheck_exprlist a = true -> wt_exprlist env a.
+Proof.
+ induction a; simpl; intros.
+ constructor.
+ TrueInv. constructor; auto. apply typecheck_expr_correct; auto.
+Qed.
+
+Fixpoint typecheck_stmt (s: Csyntax.statement) {struct s} : bool :=
+ match s with
+ | Csyntax.Sskip => true
+ | Csyntax.Sexpr e => typecheck_expr e
+ | Csyntax.Sassign b c => typecheck_expr b && typecheck_expr c
+ | Csyntax.Ssequence s1 s2 => typecheck_stmt s1 && typecheck_stmt s2
+ | Csyntax.Sifthenelse e s1 s2 =>
+ typecheck_expr e && typecheck_stmt s1 && typecheck_stmt s2
+ | Csyntax.Swhile e s1 => typecheck_expr e && typecheck_stmt s1
+ | Csyntax.Sdowhile e s1 => typecheck_expr e && typecheck_stmt s1
+ | Csyntax.Sfor e1 e2 e3 s1 =>
+ typecheck_stmt e1 && typecheck_expr e2 &&
+ typecheck_stmt e3 && typecheck_stmt s1
+ | Csyntax.Sbreak => true
+ | Csyntax.Scontinue => true
+ | Csyntax.Sreturn (Some e) => typecheck_expr e
+ | Csyntax.Sreturn None => true
+ | Csyntax.Sswitch e sl => typecheck_expr e && typecheck_lblstmts sl
+ end
+
+with typecheck_lblstmts (sl: labeled_statements) {struct sl}: bool :=
+ match sl with
+ | LSdefault s => typecheck_stmt s
+ | LScase _ s rem => typecheck_stmt s && typecheck_lblstmts rem
+ end.
+
+Scheme stmt_ind_2 := Induction for statement Sort Prop
+ with lblstmts_ind_2 := Induction for labeled_statements Sort Prop.
+
+Lemma typecheck_stmt_correct:
+ forall s, typecheck_stmt s = true -> wt_stmt env s.
+Proof.
+ generalize typecheck_expr_correct; intro.
+ apply (stmt_ind_2 (fun s => typecheck_stmt s = true -> wt_stmt env s)
+ (fun s => typecheck_lblstmts s = true -> wt_lblstmts env s));
+ simpl; intros; TrueInv; try constructor; auto.
+ destruct o; constructor; auto.
+Qed.
+
+End TYPECHECKING.
+
+Definition typecheck_function (env: typenv) (f: function) : bool :=
+ if list_norepet_dec ident_eq
+ (var_names f.(fn_params) ++ var_names f.(fn_vars))
+ then typecheck_stmt (add_vars env (f.(fn_params) ++ f.(fn_vars)))
+ f.(fn_body)
+ else false.
+
+Lemma typecheck_function_correct:
+ forall env f, typecheck_function env f = true -> wt_function env f.
+Proof.
+ unfold typecheck_function; intros; TrueInv.
+ constructor. auto. apply typecheck_stmt_correct; auto.
+Qed.
+
+Definition typecheck_fundef (main: ident) (env: typenv) (id_fd: ident * fundef) : bool :=
+ let (id, fd) := id_fd in
+ match fd with
+ | Internal f => typecheck_function env f
+ | External _ _ _ => true
+ end &&
+ if ident_eq id main
+ then eq_type (type_of_fundef fd) (Tfunction Tnil (Tint I32 Signed))
+ else true.
+
+Lemma typecheck_fundef_correct:
+ forall main env id fd,
+ typecheck_fundef main env (id, fd) = true ->
+ wt_fundef env fd /\
+ (id = main -> type_of_fundef fd = Tfunction Tnil (Tint I32 Signed)).
+Proof.
+ intros. unfold typecheck_fundef in H; TrueInv.
+ split.
+ destruct fd.
+ constructor. apply typecheck_function_correct; auto.
+ constructor.
+ intro. destruct (ident_eq id main).
+ apply eq_type_correct; auto.
+ congruence.
+Qed.
+
+Definition typecheck_program (p: program) : bool :=
+ List.forallb (typecheck_fundef p.(prog_main) (global_typenv p))
+ p.(prog_funct).
+
+Lemma typecheck_program_correct:
+ forall p, typecheck_program p = true -> wt_program p.
+Proof.
+ unfold typecheck_program; intros.
+ rewrite List.forallb_forall in H.
+ constructor; intros.
+ exploit typecheck_fundef_correct; eauto. tauto.
+ exploit typecheck_fundef_correct; eauto. tauto.
+Qed.