(** * A big-step semantics for CompCert C implementing the reduction strategy. *)
Section BIGSTEP.
Variable ge: genv.
(** The execution of a statement produces an ``outcome'', indicating how the execution terminated: either normally or prematurely through the execution of a [break], [continue] or [return] statement. *)
Inductive outcome: Type :=
| Out_break: outcome                 (**r terminated by [break] *)
| Out_continue: outcome              (**r terminated by [continue] *)
| Out_normal: outcome                (**r terminated normally *)
| Out_return: option (val * type) -> outcome. (**r terminated by [return] *)
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) (m: mem) : Prop :=
match out, t with
| Out_normal, Tvoid => v = Vundef
| Out_return None, Tvoid => v = Vundef
| Out_return (Some (v', ty')), ty => ty <> Tvoid /\ sem_cast v' ty' ty m = Some v
| _, _ => False
end.
(** [eval_expression ge e m1 a t m2 a'] describes the evaluation of the complex expression e.  [v] is the resulting value, [m2] the final memory state, and [t] the trace of input/output events performed during this evaluation.  *)
Inductive eval_expression: env -> mem -> expr -> trace -> mem -> val -> Prop :=
| eval_expression_intro: forall e m a t m' a' v,
eval_expr e m RV a t m' a' -> eval_simple_rvalue ge e m' a' v ->
eval_expression e m a t m' v
with eval_expr: env -> mem -> kind -> expr -> trace -> mem -> expr -> Prop :=
| eval_val: forall e m v ty,
eval_expr e m RV (Eval v ty) E0 m (Eval v ty)
| eval_var: forall e m x ty,
eval_expr e m LV (Evar x ty) E0 m (Evar x ty)
| eval_field: forall e m a t m' a' f ty,
eval_expr e m RV a t m' a' ->
eval_expr e m LV (Efield a f ty) t m' (Efield a' f ty)
| eval_valof: forall e m a t m' a' ty,
type_is_volatile (typeof a) = false ->
eval_expr e m LV a t m' a' ->
eval_expr e m RV (Evalof a ty) t m' (Evalof a' ty)
| eval_valof_volatile: forall e m a t1 m' a' ty b ofs t2 v,
type_is_volatile (typeof a) = true ->
eval_expr e m LV a t1 m' a' ->
eval_simple_lvalue ge e m' a' b ofs ->
deref_loc ge (typeof a) m' b ofs t2 v ->
ty = typeof a ->
eval_expr e m RV (Evalof a ty) (t1 ** t2) m' (Eval v ty)
| eval_deref: forall e m a t m' a' ty,
eval_expr e m RV a t m' a' ->
eval_expr e m LV (Ederef a ty) t m' (Ederef a' ty)
| eval_addrof: forall e m a t m' a' ty,
eval_expr e m LV a t m' a' ->
eval_expr e m RV (Eaddrof a ty) t m' (Eaddrof a' ty)
| eval_unop: forall e m a t m' a' op ty,
eval_expr e m RV a t m' a' ->
eval_expr e m RV (Eunop op a ty) t m' (Eunop op a' ty)
| eval_binop: forall e m a1 t1 m' a1' a2 t2 m'' a2' op ty,
eval_expr e m RV a1 t1 m' a1' -> eval_expr e m' RV a2 t2 m'' a2' ->
eval_expr e m RV (Ebinop op a1 a2 ty) (t1 ** t2) m'' (Ebinop op a1' a2' ty)
| eval_cast: forall e m a t m' a' ty,
eval_expr e m RV a t m' a' ->
eval_expr e m RV (Ecast a ty) t m' (Ecast a' ty)
| eval_seqand_true: forall e m a1 a2 ty t1 m' a1' v1 t2 m'' a2' v2 v,
eval_expr e m RV a1 t1 m' a1' -> eval_simple_rvalue ge e m' a1' v1 ->
bool_val v1 (typeof a1) m' = Some true ->
eval_expr e m' RV a2 t2 m'' a2' -> eval_simple_rvalue ge e m'' a2' v2 ->
sem_cast v2 (typeof a2) type_bool m'' = Some v ->
eval_expr e m RV (Eseqand a1 a2 ty) (t1**t2) m'' (Eval v ty)
| eval_seqand_false: forall e m a1 a2 ty t1 m' a1' v1,
eval_expr e m RV a1 t1 m' a1' -> eval_simple_rvalue ge e m' a1' v1 ->
bool_val v1 (typeof a1) m' = Some false ->
eval_expr e m RV (Eseqand a1 a2 ty) t1 m' (Eval (Vint Int.zero) ty)
| eval_seqor_false: forall e m a1 a2 ty t1 m' a1' v1 t2 m'' a2' v2 v,
eval_expr e m RV a1 t1 m' a1' -> eval_simple_rvalue ge e m' a1' v1 ->
bool_val v1 (typeof a1) m' = Some false ->
eval_expr e m' RV a2 t2 m'' a2' -> eval_simple_rvalue ge e m'' a2' v2 ->
sem_cast v2 (typeof a2) type_bool m'' = Some v ->
eval_expr e m RV (Eseqor a1 a2 ty) (t1**t2) m'' (Eval v ty)
| eval_seqor_true: forall e m a1 a2 ty t1 m' a1' v1,
eval_expr e m RV a1 t1 m' a1' -> eval_simple_rvalue ge e m' a1' v1 ->
bool_val v1 (typeof a1) m' = Some true ->
eval_expr e m RV (Eseqor a1 a2 ty) t1 m' (Eval (Vint Int.one) ty)
| eval_condition: forall e m a1 a2 a3 ty t1 m' a1' v1 t2 m'' a' v' b v,
eval_expr e m RV a1 t1 m' a1' -> eval_simple_rvalue ge e m' a1' v1 ->
bool_val v1 (typeof a1) m' = Some b ->
eval_expr e m' RV (if b then a2 else a3) t2 m'' a' -> eval_simple_rvalue ge e m'' a' v' ->
sem_cast v' (typeof (if b then a2 else a3)) ty m'' = Some v ->
eval_expr e m RV (Econdition a1 a2 a3 ty) (t1**t2) m'' (Eval v ty)
| eval_sizeof: forall e m ty' ty,
eval_expr e m RV (Esizeof ty' ty) E0 m (Esizeof ty' ty)
| eval_alignof: forall e m ty' ty,
eval_expr e m RV (Ealignof ty' ty) E0 m (Ealignof ty' ty)
| eval_assign: forall e m l r ty t1 m1 l' t2 m2 r' b ofs v v' t3 m3,
eval_expr e m LV l t1 m1 l' -> eval_expr e m1 RV r t2 m2 r' ->
eval_simple_lvalue ge e m2 l' b ofs ->
eval_simple_rvalue ge e m2 r' v ->
sem_cast v (typeof r) (typeof l) m2 = Some v' ->
assign_loc ge (typeof l) m2 b ofs v' t3 m3 ->
ty = typeof l ->
eval_expr e m RV (Eassign l r ty) (t1**t2**t3) m3 (Eval v' ty)
| eval_assignop: forall e m op l r tyres ty t1 m1 l' t2 m2 r' b ofs
v1 v2 v3 v4 t3 t4 m3,
eval_expr e m LV l t1 m1 l' -> eval_expr e m1 RV r t2 m2 r' ->
eval_simple_lvalue ge e m2 l' b ofs ->
deref_loc ge (typeof l) m2 b ofs t3 v1 ->
eval_simple_rvalue ge e m2 r' v2 ->
sem_binary_operation ge op v1 (typeof l) v2 (typeof r) m2 = Some v3 ->
sem_cast v3 tyres (typeof l) m2 = Some v4 ->
assign_loc ge (typeof l) m2 b ofs v4 t4 m3 ->
ty = typeof l ->
eval_expr e m RV (Eassignop op l r tyres ty) (t1**t2**t3**t4) m3 (Eval v4 ty)
| eval_postincr: forall e m id l ty t1 m1 l' b ofs v1 v2 v3 m2 t2 t3,
eval_expr e m LV l t1 m1 l' ->
eval_simple_lvalue ge e m1 l' b ofs ->
deref_loc ge ty m1 b ofs t2 v1 ->
sem_incrdecr ge id v1 ty m1 = Some v2 ->
sem_cast v2 (incrdecr_type ty) ty m1 = Some v3 ->
assign_loc ge ty m1 b ofs v3 t3 m2 ->
ty = typeof l ->
eval_expr e m RV (Epostincr id l ty) (t1**t2**t3) m2 (Eval v1 ty)
| eval_comma: forall e m r1 r2 ty t1 m1 r1' v1 t2 m2 r2',
eval_expr e m RV r1 t1 m1 r1' ->
eval_simple_rvalue ge e m1 r1' v1 ->
eval_expr e m1 RV r2 t2 m2 r2' ->
ty = typeof r2 ->
eval_expr e m RV (Ecomma r1 r2 ty) (t1**t2) m2 r2'
| eval_call: forall e m rf rargs ty t1 m1 rf' t2 m2 rargs' vf vargs
targs tres cconv fd t3 m3 vres,
eval_expr e m RV rf t1 m1 rf' -> eval_exprlist e m1 rargs t2 m2 rargs' ->
eval_simple_rvalue ge e m2 rf' vf ->
eval_simple_list ge e m2 rargs' targs vargs ->
classify_fun (typeof rf) = fun_case_f targs tres cconv ->
Genv.find_funct ge vf = Some fd ->
type_of_fundef fd = Tfunction targs tres cconv ->
eval_funcall m2 fd vargs t3 m3 vres ->
eval_expr e m RV (Ecall rf rargs ty) (t1**t2**t3) m3 (Eval vres ty)
with eval_exprlist: env -> mem -> exprlist -> trace -> mem -> exprlist -> Prop :=
| eval_nil: forall e m,
eval_exprlist e m Enil E0 m Enil
| eval_cons: forall e m a1 al t1 m1 a1' t2 m2 al',
eval_expr e m RV a1 t1 m1 a1' -> eval_exprlist e m1 al t2 m2 al' ->
eval_exprlist e m (Econs a1 al) (t1**t2) m2 (Econs a1' al')
(** [exec_stmt ge e m1 s t m2 out] describes the execution of the statement [s].  [out] is the outcome for this execution. [m1] is the initial memory state, [m2] the final memory state. [t] is the trace of input/output events performed during this evaluation. *)
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_Sdo:     forall e m a t m' v,
eval_expression e m a t m' v ->
exec_stmt e m (Sdo a)
t m' 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: forall e m a s1 s2 t1 m1 v1 t2 m2 b out,
eval_expression e m a t1 m1 v1 ->
bool_val v1 (typeof a) m1 = Some b ->
exec_stmt e m1 (if b then s1 else 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 m' v,
eval_expression e m a t m' v ->
exec_stmt e m (Sreturn (Some a))
t m' (Out_return (Some(v, typeof a)))
| 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 a s t m' v,
eval_expression e m a t m' v ->
bool_val v (typeof a) m' = Some false ->
exec_stmt e m (Swhile a s)
t m' Out_normal
| exec_Swhile_stop: forall e m a s t1 m1 v t2 m2 out' out,
eval_expression e m a t1 m1 v ->
bool_val v (typeof a) m1 = Some true ->
exec_stmt e m1 s t2 m2 out' ->
out_break_or_return out' out ->
exec_stmt e m (Swhile a s)
(t1**t2) m2 out
| exec_Swhile_loop: forall e m a s t1 m1 v t2 m2 out1 t3 m3 out,
eval_expression e m a t1 m1 v ->
bool_val v (typeof a) m1 = Some true ->
exec_stmt e m1 s t2 m2 out1 ->
out_normal_or_continue out1 ->
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 t2 m2 v,
exec_stmt e m s t1 m1 out1 ->
out_normal_or_continue out1 ->
eval_expression e m1 a t2 m2 v ->
bool_val v (typeof a) m2 = Some false ->
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 t1 m1 out1 t2 m2 v t3 m3 out,
exec_stmt e m s t1 m1 out1 ->
out_normal_or_continue out1 ->
eval_expression e m1 a t2 m2 v ->
bool_val v (typeof a) m2 = Some true ->
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 m' v,
eval_expression e m a2 t m' v ->
bool_val v (typeof a2) m' = Some false ->
exec_stmt e m (Sfor Sskip a2 a3 s)
t m' Out_normal
| exec_Sfor_stop: forall e m s a2 a3 t1 m1 v t2 m2 out1 out,
eval_expression e m a2 t1 m1 v ->
bool_val v (typeof a2) m1 = Some true ->
exec_stmt e m1 s t2 m2 out1 ->
out_break_or_return out1 out ->
exec_stmt e m (Sfor Sskip a2 a3 s)
(t1 ** t2) m2 out
| exec_Sfor_loop: forall e m s a2 a3 t1 m1 v t2 m2 out1 t3 m3 t4 m4 out,
eval_expression e m a2 t1 m1 v ->
bool_val v (typeof a2) m1 = Some true ->
exec_stmt e m1 s t2 m2 out1 ->
out_normal_or_continue out1 ->
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 sl t1 m1 v n t2 m2 out,
eval_expression e m a t1 m1 v ->
sem_switch_arg v (typeof a) = Some n ->
exec_stmt e m1 (seq_of_labeled_statement (select_switch n sl)) t2 m2 out ->
exec_stmt e m (Sswitch a sl)
(t1 ** t2) m2 (outcome_switch out)
(** [eval_funcall m1 fd args t m2 res] describes the invocation of function [fd] with arguments [args].  [res] is the value returned by the call.  *)
with eval_funcall: mem -> fundef -> list val -> trace -> mem -> val -> Prop :=
| eval_funcall_internal: forall m f vargs t e m1 m2 m3 out vres m4,
list_norepet (var_names f.(fn_params) ++ var_names f.(fn_vars)) ->
alloc_variables ge empty_env m (f.(fn_params) ++ f.(fn_vars)) e m1 ->
bind_parameters ge 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 m3 ->
Mem.free_list m3 (blocks_of_env ge e) = Some m4 ->
eval_funcall m (Internal f) vargs t m4 vres
| eval_funcall_external: forall m ef targs tres cconv vargs t vres m',
external_call ef ge vargs m t vres m' ->
eval_funcall m (External ef targs tres cconv) vargs t m' vres.
Scheme eval_expression_ind5 := Minimality for eval_expression Sort Prop
with eval_expr_ind5 := Minimality for eval_expr Sort Prop
with eval_exprlist_ind5 := Minimality for eval_exprlist Sort Prop
with exec_stmt_ind5 := Minimality for exec_stmt Sort Prop
with eval_funcall_ind5 := Minimality for eval_funcall Sort Prop.
Combined Scheme bigstep_induction from
eval_expression_ind5,  eval_expr_ind5,  eval_exprlist_ind5,
exec_stmt_ind5, eval_funcall_ind5.
(** [evalinf_expr ge e m1 K a T] denotes the fact that expression [a] diverges in initial state [m1].  [T] is the trace of input/output events performed during this evaluation.  *)
CoInductive evalinf_expr: env -> mem -> kind -> expr -> traceinf -> Prop :=
| evalinf_field: forall e m a t f ty,
evalinf_expr e m RV a t ->
evalinf_expr e m LV (Efield a f ty) t
| evalinf_valof: forall e m a t ty,
evalinf_expr e m LV a t ->
evalinf_expr e m RV (Evalof a ty) t
| evalinf_deref: forall e m a t ty,
evalinf_expr e m RV a t ->
evalinf_expr e m LV (Ederef a ty) t
| evalinf_addrof: forall e m a t ty,
evalinf_expr e m LV a t ->
evalinf_expr e m RV (Eaddrof a ty) t
| evalinf_unop: forall e m a t op ty,
evalinf_expr e m RV a t ->
evalinf_expr e m RV (Eunop op a ty) t
| evalinf_binop_left: forall e m a1 t1 a2 op ty,
evalinf_expr e m RV a1 t1 ->
evalinf_expr e m RV (Ebinop op a1 a2 ty) t1
| evalinf_binop_right: forall e m a1 t1 m' a1' a2 t2 op ty,
eval_expr e m RV a1 t1 m' a1' -> evalinf_expr e m' RV a2 t2 ->
evalinf_expr e m RV (Ebinop op a1 a2 ty) (t1 *** t2)
| evalinf_cast: forall e m a t ty,
evalinf_expr e m RV a t ->
evalinf_expr e m RV (Ecast a ty) t
| evalinf_seqand: forall e m a1 a2 ty t1,
evalinf_expr e m RV a1 t1 ->
evalinf_expr e m RV (Eseqand a1 a2 ty) t1
| evalinf_seqand_2: forall e m a1 a2 ty t1 m' a1' v1 t2,
eval_expr e m RV a1 t1 m' a1' -> eval_simple_rvalue ge e m' a1' v1 ->
bool_val v1 (typeof a1) m' = Some true ->
evalinf_expr e m' RV a2 t2 ->
evalinf_expr e m RV (Eseqand a1 a2 ty) (t1***t2)
| evalinf_seqor: forall e m a1 a2 ty t1,
evalinf_expr e m RV a1 t1 ->
evalinf_expr e m RV (Eseqor a1 a2 ty) t1
| evalinf_seqor_2: forall e m a1 a2 ty t1 m' a1' v1 t2,
eval_expr e m RV a1 t1 m' a1' -> eval_simple_rvalue ge e m' a1' v1 ->
bool_val v1 (typeof a1) m' = Some false ->
evalinf_expr e m' RV a2 t2 ->
evalinf_expr e m RV (Eseqor a1 a2 ty) (t1***t2)
| evalinf_condition: forall e m a1 a2 a3 ty t1,
evalinf_expr e m RV a1 t1 ->
evalinf_expr e m RV (Econdition a1 a2 a3 ty) t1
| evalinf_condition_2: forall e m a1 a2 a3 ty t1 m' a1' v1 t2 b,
eval_expr e m RV a1 t1 m' a1' -> eval_simple_rvalue ge e m' a1' v1 ->
bool_val v1 (typeof a1) m' = Some b ->
evalinf_expr e m' RV (if b then a2 else a3) t2 ->
evalinf_expr e m RV (Econdition a1 a2 a3 ty) (t1***t2)
| evalinf_assign_left: forall e m a1 t1 a2 ty,
evalinf_expr e m LV a1 t1 ->
evalinf_expr e m RV (Eassign a1 a2 ty) t1
| evalinf_assign_right: forall e m a1 t1 m' a1' a2 t2 ty,
eval_expr e m LV a1 t1 m' a1' -> evalinf_expr e m' RV a2 t2 ->
evalinf_expr e m RV (Eassign a1 a2 ty) (t1 *** t2)
| evalinf_assignop_left: forall e m a1 t1 a2 op tyres ty,
evalinf_expr e m LV a1 t1 ->
evalinf_expr e m RV (Eassignop op a1 a2 tyres ty) t1
| evalinf_assignop_right: forall e m a1 t1 m' a1' a2 t2 op tyres ty,
eval_expr e m LV a1 t1 m' a1' -> evalinf_expr e m' RV a2 t2 ->
evalinf_expr e m RV (Eassignop op a1 a2 tyres ty) (t1 *** t2)
| evalinf_postincr: forall e m a t id ty,
evalinf_expr e m LV a t ->
evalinf_expr e m RV (Epostincr id a ty) t
| evalinf_comma_left: forall e m a1 t1 a2 ty,
evalinf_expr e m RV a1 t1 ->
evalinf_expr e m RV (Ecomma a1 a2 ty) t1
| evalinf_comma_right: forall e m a1 t1 m1 a1' v1 a2 t2 ty,
eval_expr e m RV a1 t1 m1 a1' -> eval_simple_rvalue ge e m1 a1' v1 ->
ty = typeof a2 ->
evalinf_expr e m1 RV a2 t2 ->
evalinf_expr e m RV (Ecomma a1 a2 ty) (t1 *** t2)
| evalinf_call_left: forall e m a1 t1 a2 ty,
evalinf_expr e m RV a1 t1 ->
evalinf_expr e m RV (Ecall a1 a2 ty) t1
| evalinf_call_right: forall e m a1 t1 m1 a1' a2 t2 ty,
eval_expr e m RV a1 t1 m1 a1' ->
evalinf_exprlist e m1 a2 t2 ->
evalinf_expr e m RV (Ecall a1 a2 ty) (t1 *** t2)
| evalinf_call: forall e m rf rargs ty t1 m1 rf' t2 m2 rargs' vf vargs
targs tres cconv fd t3,
eval_expr e m RV rf t1 m1 rf' -> eval_exprlist e m1 rargs t2 m2 rargs' ->
eval_simple_rvalue ge e m2 rf' vf ->
eval_simple_list ge e m2 rargs' targs vargs ->
classify_fun (typeof rf) = fun_case_f targs tres cconv ->
Genv.find_funct ge vf = Some fd ->
type_of_fundef fd = Tfunction targs tres cconv ->
evalinf_funcall m2 fd vargs t3 ->
evalinf_expr e m RV (Ecall rf rargs ty) (t1***t2***t3)
with evalinf_exprlist: env -> mem -> exprlist -> traceinf -> Prop :=
| evalinf_cons_left: forall e m a1 al t1,
evalinf_expr e m RV a1 t1 ->
evalinf_exprlist e m (Econs a1 al) t1
| evalinf_cons_right: forall e m a1 al t1 m1 a1' t2,
eval_expr e m RV a1 t1 m1 a1' -> evalinf_exprlist e m1 al t2 ->
evalinf_exprlist e m (Econs a1 al) (t1***t2)
(** [execinf_stmt ge e m1 s t] describes the diverging execution of the statement [s].  *)
with execinf_stmt: env -> mem -> statement -> traceinf -> Prop :=
| execinf_Sdo:     forall e m a t,
evalinf_expr e m RV a t ->
execinf_stmt e m (Sdo a) t
| execinf_Sseq_1:   forall e m s1 s2 t1,
execinf_stmt e m s1 t1 ->
execinf_stmt e m (Ssequence s1 s2) t1
| execinf_Sseq_2:   forall e m s1 s2 t1 m1 t2,
exec_stmt e m s1 t1 m1 Out_normal ->
execinf_stmt e m1 s2 t2 ->
execinf_stmt e m (Ssequence s1 s2) (t1***t2)
| execinf_Sifthenelse_test: forall e m a s1 s2 t1,
evalinf_expr e m RV a t1 ->
execinf_stmt e m (Sifthenelse a s1 s2) t1
| execinf_Sifthenelse: forall e m a s1 s2 t1 m1 v1 t2 b,
eval_expression e m a t1 m1 v1 ->
bool_val v1 (typeof a) m1 = Some b ->
execinf_stmt e m1 (if b then s1 else s2) t2 ->
execinf_stmt e m (Sifthenelse a s1 s2) (t1***t2)
| execinf_Sreturn_some: forall e m a t,
evalinf_expr e m RV a t ->
execinf_stmt e m (Sreturn (Some a)) t
| execinf_Swhile_test: forall e m a s t1,
evalinf_expr e m RV a t1 ->
execinf_stmt e m (Swhile a s) t1
| execinf_Swhile_body: forall e m a s t1 m1 v t2,
eval_expression e m a t1 m1 v ->
bool_val v (typeof a) m1 = Some true ->
execinf_stmt e m1 s t2 ->
execinf_stmt e m (Swhile a s) (t1***t2)
| execinf_Swhile_loop: forall e m a s t1 m1 v t2 m2 out1 t3,
eval_expression e m a t1 m1 v ->
bool_val v (typeof a) m1 = Some true ->
exec_stmt e m1 s t2 m2 out1 ->
out_normal_or_continue out1 ->
execinf_stmt e m2 (Swhile a s) t3 ->
execinf_stmt e m (Swhile a s) (t1***t2***t3)
| execinf_Sdowhile_body: forall e m s a t1,
execinf_stmt e m s t1 ->
execinf_stmt e m (Sdowhile a s) t1
| execinf_Sdowhile_test: forall e m s a t1 m1 out1 t2,
exec_stmt e m s t1 m1 out1 ->
out_normal_or_continue out1 ->
evalinf_expr e m1 RV a t2 ->
execinf_stmt e m (Sdowhile a s) (t1***t2)
| execinf_Sdowhile_loop: forall e m s a t1 m1 out1 t2 m2 v t3,
exec_stmt e m s t1 m1 out1 ->
out_normal_or_continue out1 ->
eval_expression e m1 a t2 m2 v ->
bool_val v (typeof a) m2 = Some true ->
execinf_stmt e m2 (Sdowhile a s) t3 ->
execinf_stmt e m (Sdowhile a s) (t1***t2***t3)
| execinf_Sfor_start_1: forall e m s a1 a2 a3 t1,
execinf_stmt e m a1 t1 ->
execinf_stmt e m (Sfor a1 a2 a3 s) t1
| execinf_Sfor_start_2: forall e m s a1 a2 a3 m1 t1 t2,
exec_stmt e m a1 t1 m1 Out_normal -> a1 <> Sskip ->
execinf_stmt e m1 (Sfor Sskip a2 a3 s) t2 ->
execinf_stmt e m (Sfor a1 a2 a3 s) (t1***t2)
| execinf_Sfor_test: forall e m s a2 a3 t,
evalinf_expr e m RV a2 t ->
execinf_stmt e m (Sfor Sskip a2 a3 s) t
| execinf_Sfor_body: forall e m s a2 a3 t1 m1 v t2,
eval_expression e m a2 t1 m1 v ->
bool_val v (typeof a2) m1 = Some true ->
execinf_stmt e m1 s t2 ->
execinf_stmt e m (Sfor Sskip a2 a3 s) (t1***t2)
| execinf_Sfor_next: forall e m s a2 a3 t1 m1 v t2 m2 out1 t3,
eval_expression e m a2 t1 m1 v ->
bool_val v (typeof a2) m1 = Some true ->
exec_stmt e m1 s t2 m2 out1 ->
out_normal_or_continue out1 ->
execinf_stmt e m2 a3 t3 ->
execinf_stmt e m (Sfor Sskip a2 a3 s) (t1***t2***t3)
| execinf_Sfor_loop: forall e m s a2 a3 t1 m1 v t2 m2 out1 t3 m3 t4,
eval_expression e m a2 t1 m1 v ->
bool_val v (typeof a2) m1 = Some true ->
exec_stmt e m1 s t2 m2 out1 ->
out_normal_or_continue out1 ->
exec_stmt e m2 a3 t3 m3 Out_normal ->
execinf_stmt e m3 (Sfor Sskip a2 a3 s) t4 ->
execinf_stmt e m (Sfor Sskip a2 a3 s) (t1***t2***t3***t4)
| execinf_Sswitch_expr:   forall e m a sl t1,
evalinf_expr e m RV a t1 ->
execinf_stmt e m (Sswitch a sl) t1
| execinf_Sswitch_body:   forall e m a sl t1 m1 v n t2,
eval_expression e m a t1 m1 v ->
sem_switch_arg v (typeof a) = Some n ->
execinf_stmt e m1 (seq_of_labeled_statement (select_switch n sl)) t2 ->
execinf_stmt e m (Sswitch a sl) (t1***t2)
(** [evalinf_funcall m1 fd args t m2 res] describes a diverging invocation of function [fd] with arguments [args].  *)
with evalinf_funcall: mem -> fundef -> list val -> traceinf -> Prop :=
| evalinf_funcall_internal: forall m f vargs t e m1 m2,
list_norepet (var_names f.(fn_params) ++ var_names f.(fn_vars)) ->
alloc_variables ge empty_env m (f.(fn_params) ++ f.(fn_vars)) e m1 ->
bind_parameters ge e m1 f.(fn_params) vargs m2 ->
execinf_stmt e m2 f.(fn_body) t ->
evalinf_funcall m (Internal f) vargs t.
(** ** Implication from big-step semantics to transition semantics *)
Inductive outcome_state_match
(e: env) (m: mem) (f: function) (k: cont): outcome -> state -> Prop :=
| osm_normal:
outcome_state_match e m f k Out_normal (State f Sskip k e m)
| osm_break:
outcome_state_match e m f k Out_break (State f Sbreak k e m)
| osm_continue:
outcome_state_match e m f k Out_continue (State f Scontinue k e m)
| osm_return_none: forall k',
call_cont k' = call_cont k ->
outcome_state_match e m f k
(Out_return None) (State f (Sreturn None) k' e m)
| osm_return_some: forall v ty k',
call_cont k' = call_cont k ->
outcome_state_match e m f k
(Out_return (Some (v, ty))) (ExprState f (Eval v ty) (Kreturn k') e m).

Lemma eval_expression_to_steps:
forall e m a t m' v,
eval_expression e m a t m' v ->
forall f k,
star step ge (ExprState f a k e m) t (ExprState f (Eval v (typeof a)) k e m').