A deterministic evaluation strategy for C.
Require Import Axioms.
Require Import Coqlib.
Require Import Errors.
Require Import Maps.
Require Import Integers.
Require Import Floats.
Require Import Values.
Require Import AST.
Require Import Memory.
Require Import Events.
Require Import Globalenvs.
Require Import Smallstep.
Require Import Ctypes.
Require Import Cop.
Require Import Csyntax.
Require Import Csem.
Require Import Values_symbolictype.
Require Import Values_symbolic.
Require Import VarSort.
Section STRATEGY.
Variable ge:
genv.
Variable needed_stackspace :
ident ->
nat.
Definition of the strategy
We now formalize a particular strategy for reducing expressions which
is the one implemented by the CompCert compiler. It evaluates effectful
subexpressions first, in leftmost-innermost order, then finishes
with the evaluation of the remaining simple expression.
Simple expressions are defined as follows.
Fixpoint simple (
a:
expr) :
bool :=
match a with
|
Eloc _ _ =>
true
|
Evar _ _ =>
true
|
Ederef r _ =>
simple r
|
Efield r _ _ =>
simple r
|
Csyntax.Eval _ _ =>
true
|
Evalof l _ =>
simple l &&
negb(
type_is_volatile (
typeof l))
|
Eaddrof l _ =>
simple l
|
Csyntax.Eunop _ r1 _ =>
simple r1
|
Csyntax.Ebinop _ r1 r2 _ =>
simple r1 &&
simple r2
|
Ecast r1 _ =>
simple r1
|
Eseqand _ _ _ =>
false
|
Eseqor _ _ _ =>
false
|
Econdition _ _ _ _ =>
false
|
Esizeof _ _ =>
true
|
Ealignof _ _ =>
true
|
Eassign _ _ _ =>
false
|
Eassignop _ _ _ _ _ =>
false
|
Epostincr _ _ _ =>
false
|
Ecomma _ _ _ =>
false
|
Ecall _ _ _ =>
false
|
Ebuiltin _ _ _ _ =>
false
|
Eparen _ _ =>
false
end.
Fixpoint simplelist (
rl:
exprlist) :
bool :=
match rl with Enil =>
true |
Econs r rl' =>
simple r &&
simplelist rl'
end.
Simple expressions have interesting properties: their evaluations always
terminate, are deterministic, and preserve the memory state.
We seize this opportunity to define a big-step semantics for simple
expressions.
Section SIMPLE_EXPRS.
Variable e:
env.
Variable m:
mem.
Inductive eval_simple_lvalue:
expr ->
expr_sym ->
Prop :=
|
esl_loc:
forall ptr ty,
eval_simple_lvalue (
Eloc ptr ty)
ptr
|
esl_var_local:
forall x ty b,
e!
x =
Some(
b,
ty) ->
eval_simple_lvalue (
Evar x ty) (
Eval (
Vptr b Int.zero))
|
esl_var_global:
forall x ty b,
e!
x =
None ->
Genv.find_symbol ge x =
Some b ->
eval_simple_lvalue (
Evar x ty) (
Eval (
Vptr b Int.zero))
|
esl_deref:
forall r ty v,
eval_simple_rvalue r v ->
eval_simple_lvalue (
Ederef r ty)
v
|
esl_field_struct:
forall r f ty id fList a delta v,
eval_simple_rvalue r v ->
typeof r =
Tstruct id fList a ->
field_offset f fList =
OK delta ->
eval_simple_lvalue (
Efield r f ty) (
Val.add v (
Eval (
Vint (
Int.repr delta))))
|
esl_field_union:
forall r f ty id fList a v,
eval_simple_rvalue r v ->
typeof r =
Tunion id fList a ->
eval_simple_lvalue (
Efield r f ty)
v
with eval_simple_rvalue:
expr ->
expr_sym ->
Prop :=
|
esr_val:
forall v ty,
eval_simple_rvalue (
Csyntax.Eval v ty)
v
|
esr_rvalof:
forall ptr l ty v ,
eval_simple_lvalue l ptr ->
ty =
typeof l ->
type_is_volatile ty =
false ->
deref_loc ge ty m ptr E0 v ->
eval_simple_rvalue (
Evalof l ty)
v
|
esr_addrof:
forall ptr l ty,
eval_simple_lvalue l ptr ->
eval_simple_rvalue (
Eaddrof l ty)
ptr
|
esr_unop:
forall op r1 ty v1 v,
eval_simple_rvalue r1 v1 ->
sem_unary_operation_expr op v1 (
typeof r1) =
v ->
eval_simple_rvalue (
Csyntax.Eunop op r1 ty)
v
|
esr_binop:
forall op r1 r2 ty v1 v2 v,
eval_simple_rvalue r1 v1 ->
eval_simple_rvalue r2 v2 ->
sem_binary_operation_expr op v1 (
typeof r1)
v2 (
typeof r2) =
Some v ->
eval_simple_rvalue (
Csyntax.Ebinop op r1 r2 ty)
v
|
esr_cast:
forall ty r1 v1 v,
eval_simple_rvalue r1 v1 ->
sem_cast_expr v1 (
typeof r1)
ty =
Some v ->
eval_simple_rvalue (
Ecast r1 ty)
v
|
esr_sizeof:
forall ty1 ty,
eval_simple_rvalue (
Esizeof ty1 ty) (
Eval (
Vint (
Int.repr (
sizeof ty1))))
|
esr_alignof:
forall ty1 ty,
eval_simple_rvalue (
Ealignof ty1 ty) (
Eval (
Vint (
Int.repr (
alignof ty1)))).
Inductive eval_simple_list:
exprlist ->
typelist ->
list expr_sym ->
Prop :=
|
esrl_nil:
eval_simple_list Enil Tnil nil
|
esrl_cons:
forall r rl ty tyl v vl v',
eval_simple_rvalue r v' ->
sem_cast_expr v' (
typeof r)
ty =
Some v ->
eval_simple_list rl tyl vl ->
eval_simple_list (
Econs r rl) (
Tcons ty tyl) (
v ::
vl).
Scheme eval_simple_rvalue_ind2 :=
Minimality for eval_simple_rvalue Sort Prop
with eval_simple_lvalue_ind2 :=
Minimality for eval_simple_lvalue Sort Prop.
Combined Scheme eval_simple_rvalue_lvalue_ind from eval_simple_rvalue_ind2,
eval_simple_lvalue_ind2.
End SIMPLE_EXPRS.
Left reduction contexts. These contexts allow reducing to the right
of a binary operator only if the left subexpression is simple.
Inductive leftcontext:
kind ->
kind -> (
expr ->
expr) ->
Prop :=
|
lctx_top:
forall k,
leftcontext k k (
fun x =>
x)
|
lctx_deref:
forall k C ty,
leftcontext k RV C ->
leftcontext k LV (
fun x =>
Ederef (
C x)
ty)
|
lctx_field:
forall k C f ty,
leftcontext k RV C ->
leftcontext k LV (
fun x =>
Efield (
C x)
f ty)
|
lctx_rvalof:
forall k C ty,
leftcontext k LV C ->
leftcontext k RV (
fun x =>
Evalof (
C x)
ty)
|
lctx_addrof:
forall k C ty,
leftcontext k LV C ->
leftcontext k RV (
fun x =>
Eaddrof (
C x)
ty)
|
lctx_unop:
forall k C op ty,
leftcontext k RV C ->
leftcontext k RV (
fun x =>
Csyntax.Eunop op (
C x)
ty)
|
lctx_binop_left:
forall k C op e2 ty,
leftcontext k RV C ->
leftcontext k RV (
fun x =>
Csyntax.Ebinop op (
C x)
e2 ty)
|
lctx_binop_right:
forall k C op e1 ty,
simple e1 =
true ->
leftcontext k RV C ->
leftcontext k RV (
fun x =>
Csyntax.Ebinop op e1 (
C x)
ty)
|
lctx_cast:
forall k C ty,
leftcontext k RV C ->
leftcontext k RV (
fun x =>
Ecast (
C x)
ty)
|
lctx_seqand:
forall k C r2 ty,
leftcontext k RV C ->
leftcontext k RV (
fun x =>
Eseqand (
C x)
r2 ty)
|
lctx_seqor:
forall k C r2 ty,
leftcontext k RV C ->
leftcontext k RV (
fun x =>
Eseqor (
C x)
r2 ty)
|
lctx_condition:
forall k C r2 r3 ty,
leftcontext k RV C ->
leftcontext k RV (
fun x =>
Econdition (
C x)
r2 r3 ty)
|
lctx_assign_left:
forall k C e2 ty,
leftcontext k LV C ->
leftcontext k RV (
fun x =>
Eassign (
C x)
e2 ty)
|
lctx_assign_right:
forall k C e1 ty,
simple e1 =
true ->
leftcontext k RV C ->
leftcontext k RV (
fun x =>
Eassign e1 (
C x)
ty)
|
lctx_assignop_left:
forall k C op e2 tyres ty,
leftcontext k LV C ->
leftcontext k RV (
fun x =>
Eassignop op (
C x)
e2 tyres ty)
|
lctx_assignop_right:
forall k C op e1 tyres ty,
simple e1 =
true ->
leftcontext k RV C ->
leftcontext k RV (
fun x =>
Eassignop op e1 (
C x)
tyres ty)
|
lctx_postincr:
forall k C id ty,
leftcontext k LV C ->
leftcontext k RV (
fun x =>
Epostincr id (
C x)
ty)
|
lctx_call_left:
forall k C el ty,
leftcontext k RV C ->
leftcontext k RV (
fun x =>
Ecall (
C x)
el ty)
|
lctx_call_right:
forall k C e1 ty,
simple e1 =
true ->
leftcontextlist k C ->
leftcontext k RV (
fun x =>
Ecall e1 (
C x)
ty)
|
lctx_builtin:
forall k C ef tyargs ty,
leftcontextlist k C ->
leftcontext k RV (
fun x =>
Ebuiltin ef tyargs (
C x)
ty)
|
lctx_comma:
forall k C e2 ty,
leftcontext k RV C ->
leftcontext k RV (
fun x =>
Ecomma (
C x)
e2 ty)
|
lctx_paren:
forall k C ty,
leftcontext k RV C ->
leftcontext k RV (
fun x =>
Eparen (
C x)
ty)
with leftcontextlist:
kind -> (
expr ->
exprlist) ->
Prop :=
|
lctx_list_head:
forall k C el,
leftcontext k RV C ->
leftcontextlist k (
fun x =>
Econs (
C x)
el)
|
lctx_list_tail:
forall k C e1,
simple e1 =
true ->
leftcontextlist k C ->
leftcontextlist k (
fun x =>
Econs e1 (
C x)).
Lemma leftcontext_context:
forall k1 k2 C,
leftcontext k1 k2 C ->
context k1 k2 C
with leftcontextlist_contextlist:
forall k C,
leftcontextlist k C ->
contextlist k C.
Proof.
induction 1; constructor; auto.
induction 1; constructor; auto.
Qed.
Hint Resolve leftcontext_context.
Strategy for reducing expressions. We reduce the leftmost innermost
non-simple subexpression, evaluating its arguments (which are necessarily
simple expressions) with the big-step semantics.
If there are none, the whole expression is simple and is evaluated in
one big step.
Inductive estep:
state ->
trace ->
state ->
Prop :=
|
step_expr:
forall f r k e m v ty,
eval_simple_rvalue e m r v ->
match r with Csyntax.Eval _ _ =>
False |
_ =>
True end ->
ty =
typeof r ->
estep (
ExprState f r k e m)
E0 (
ExprState f (
Csyntax.Eval v ty)
k e m)
|
step_rvalof_volatile:
forall f C l ty k e m ptr t v ,
leftcontext RV RV C ->
eval_simple_lvalue e m l ptr ->
deref_loc ge ty m ptr t v ->
ty =
typeof l ->
type_is_volatile ty =
true ->
estep (
ExprState f (
C (
Evalof l ty))
k e m)
t (
ExprState f (
C (
Csyntax.Eval v ty))
k e m)
|
step_seqand_true:
forall f C r1 r2 ty k e m v,
leftcontext RV RV C ->
eval_simple_rvalue e m r1 v ->
Mem.mem_norm m (
bool_expr v (
typeof r1)) =
Vtrue ->
estep (
ExprState f (
C (
Eseqand r1 r2 ty))
k e m)
E0 (
ExprState f (
C (
Eparen (
Eparen r2 type_bool)
ty))
k e m)
|
step_seqand_false:
forall f C r1 r2 ty k e m v,
leftcontext RV RV C ->
eval_simple_rvalue e m r1 v ->
Mem.mem_norm m (
bool_expr v (
typeof r1)) =
Vfalse ->
estep (
ExprState f (
C (
Eseqand r1 r2 ty))
k e m)
E0 (
ExprState f (
C (
Csyntax.Eval (
Eval (
Vint Int.zero))
ty))
k e m)
|
step_seqor_true:
forall f C r1 r2 ty k e m v,
leftcontext RV RV C ->
eval_simple_rvalue e m r1 v ->
Mem.mem_norm m (
bool_expr v (
typeof r1)) =
Vtrue ->
estep (
ExprState f (
C (
Eseqor r1 r2 ty))
k e m)
E0 (
ExprState f (
C (
Csyntax.Eval (
Eval (
Vint Int.one))
ty))
k e m)
|
step_seqor_false:
forall f C r1 r2 ty k e m v,
leftcontext RV RV C ->
eval_simple_rvalue e m r1 v ->
Mem.mem_norm m (
bool_expr v (
typeof r1)) =
Vfalse ->
estep (
ExprState f (
C (
Eseqor r1 r2 ty))
k e m)
E0 (
ExprState f (
C (
Eparen (
Eparen r2 type_bool)
ty))
k e m)
|
step_condition:
forall f C r1 r2 r3 ty k e m v b,
leftcontext RV RV C ->
eval_simple_rvalue e m r1 v ->
Mem.mem_norm m (
bool_expr v (
typeof r1)) =
Vint b ->
estep (
ExprState f (
C (
Econdition r1 r2 r3 ty))
k e m)
E0 (
ExprState f (
C (
Eparen (
if negb (
Int.eq b Int.zero)
then r2 else r3)
ty))
k e m)
|
step_assign:
forall f C l r ty k e m ptr v v'
t m' ,
leftcontext RV RV C ->
eval_simple_lvalue e m l ptr ->
eval_simple_rvalue e m r v ->
sem_cast_expr v (
typeof r) (
typeof l) =
Some v' ->
assign_loc ge (
typeof l)
m ptr v'
t m' ->
ty =
typeof l ->
estep (
ExprState f (
C (
Eassign l r ty))
k e m)
t (
ExprState f (
C (
Csyntax.Eval v'
ty))
k e m')
|
step_assignop:
forall f C op l r tyres ty k e m ptr v1 v2 v3 v4 t1 t2 m'
t ,
leftcontext RV RV C ->
eval_simple_lvalue e m l ptr ->
deref_loc ge (
typeof l)
m ptr t1 v1 ->
eval_simple_rvalue e m r v2 ->
sem_binary_operation_expr op v1 (
typeof l)
v2 (
typeof r) =
Some v3 ->
sem_cast_expr v3 tyres (
typeof l) =
Some v4 ->
assign_loc ge (
typeof l)
m ptr v4 t2 m' ->
ty =
typeof l ->
t =
t1 **
t2 ->
estep (
ExprState f (
C (
Eassignop op l r tyres ty))
k e m)
t (
ExprState f (
C (
Csyntax.Eval v4 ty))
k e m')
|
step_assignop_stuck:
forall f C op l r tyres ty k e m ptr v1 v2 t ,
leftcontext RV RV C ->
eval_simple_lvalue e m l ptr ->
deref_loc ge (
typeof l)
m ptr t v1 ->
eval_simple_rvalue e m r v2 ->
match sem_binary_operation_expr op v1 (
typeof l)
v2 (
typeof r)
with
|
None =>
True
|
Some v3 =>
match sem_cast_expr v3 tyres (
typeof l)
with
|
None =>
True
|
Some v4 =>
forall t2 m', ~(
assign_loc ge (
typeof l)
m ptr v4 t2 m')
end
end ->
ty =
typeof l ->
estep (
ExprState f (
C (
Eassignop op l r tyres ty))
k e m)
t Stuckstate
|
step_postincr:
forall f C id l ty k e m ptr v1 v2 v3 t1 t2 m'
t ,
leftcontext RV RV C ->
eval_simple_lvalue e m l ptr ->
deref_loc ge ty m ptr t1 v1 ->
sem_incrdecr_expr id v1 ty =
Some v2 ->
sem_cast_expr v2 (
incrdecr_type ty)
ty =
Some v3 ->
assign_loc ge ty m ptr v3 t2 m' ->
ty =
typeof l ->
t =
t1 **
t2 ->
estep (
ExprState f (
C (
Epostincr id l ty))
k e m)
t (
ExprState f (
C (
Csyntax.Eval v1 ty))
k e m')
|
step_postincr_stuck:
forall f C id l ty k e m ptr v1 t ,
leftcontext RV RV C ->
eval_simple_lvalue e m l ptr ->
deref_loc ge ty m ptr t v1 ->
match sem_incrdecr_expr id v1 ty with
Some v2 =>
match sem_cast_expr v2 (
incrdecr_type ty)
ty with
|
None =>
True
|
Some v3 =>
forall t2 m', ~(
assign_loc ge (
typeof l)
m ptr v3 t2 m')
end
|
_ =>
True
end ->
ty =
typeof l ->
estep (
ExprState f (
C (
Epostincr id l ty))
k e m)
t Stuckstate
|
step_comma:
forall f C r1 r2 ty k e m v,
leftcontext RV RV C ->
eval_simple_rvalue e m r1 v ->
ty =
typeof r2 ->
estep (
ExprState f (
C (
Ecomma r1 r2 ty))
k e m)
E0 (
ExprState f (
C r2)
k e m)
|
step_paren:
forall f C r ty k e m v1 v,
leftcontext RV RV C ->
eval_simple_rvalue e m r v1 ->
sem_cast_expr v1 (
typeof r)
ty =
Some v ->
estep (
ExprState f (
C (
Eparen r ty))
k e m)
E0 (
ExprState f (
C (
Csyntax.Eval v ty))
k e m)
|
step_call:
forall f C rf rargs ty k e m targs tres cconv vf vargs fd,
leftcontext RV RV C ->
classify_fun (
typeof rf) =
fun_case_f targs tres cconv ->
eval_simple_rvalue e m rf vf ->
eval_simple_list e m rargs targs vargs ->
Genv.find_funct m ge vf =
Some fd ->
type_of_fundef fd =
Tfunction targs tres cconv ->
estep (
ExprState f (
C (
Ecall rf rargs ty))
k e m)
E0 (
Callstate fd vargs (
Kcall f e C ty k)
m)
|
step_builtin:
forall f C ef tyargs rargs ty k e m vargs t vres m',
leftcontext RV RV C ->
eval_simple_list e m rargs tyargs vargs ->
external_call ef ge vargs m t vres m' ->
estep (
ExprState f (
C (
Ebuiltin ef tyargs rargs ty))
k e m)
t (
ExprState f (
C (
Csyntax.Eval vres ty))
k e m').
Definition step (
S:
state) (
t:
trace) (
S':
state) :
Prop :=
estep S t S' \/
sstep ge needed_stackspace S t S'.
Properties of contexts
Lemma context_compose:
forall k2 k3 C2,
context k2 k3 C2 ->
forall k1 C1,
context k1 k2 C1 ->
context k1 k3 (
fun x =>
C2(
C1 x))
with contextlist_compose:
forall k2 C2,
contextlist k2 C2 ->
forall k1 C1,
context k1 k2 C1 ->
contextlist k1 (
fun x =>
C2(
C1 x)).
Proof.
induction 1;
intros;
try (
constructor;
eauto).
replace (
fun x =>
C1 x)
with C1.
auto.
apply extensionality;
auto.
induction 1;
intros;
constructor;
eauto.
Qed.
Hint Constructors context contextlist.
Hint Resolve context_compose contextlist_compose.
Safe executions.
A state is safe according to the nondeterministic semantics
if it cannot get stuck by doing silent transitions only.
Definition safe (
s:
Csem.state) :
Prop :=
forall s',
star (
fun ge =>
Csem.step ge needed_stackspace)
ge s E0 s' ->
(
exists r,
final_state s'
r) \/ (
exists t,
exists s'', (
fun ge =>
Csem.step ge needed_stackspace)
ge s'
t s'').
Lemma safe_steps:
forall s s',
safe s ->
star (
fun ge =>
Csem.step ge needed_stackspace)
ge s E0 s' ->
safe s'.
Proof.
intros;
red;
intros.
eapply H.
eapply star_trans;
eauto.
Qed.
Lemma star_safe:
forall s1 s2 t s3,
safe s1 ->
star (
fun ge =>
Csem.step ge needed_stackspace)
ge s1 E0 s2 ->
(
safe s2 ->
star (
fun ge =>
Csem.step ge needed_stackspace)
ge s2 t s3) ->
star (
fun ge =>
Csem.step ge needed_stackspace)
ge s1 t s3.
Proof.
Lemma plus_safe:
forall s1 s2 t s3,
safe s1 ->
star (
fun ge =>
Csem.step ge needed_stackspace)
ge s1 E0 s2 -> (
safe s2 ->
plus (
fun ge =>
Csem.step ge needed_stackspace)
ge s2 t s3) ->
plus (
fun ge =>
Csem.step ge needed_stackspace)
ge s1 t s3.
Proof.
Require Import Classical.
Lemma safe_imm_safe:
forall f C a k e m K,
safe (
ExprState f (
C a)
k e m) ->
context K RV C ->
imm_safe ge e K a m.
Proof.
intros.
destruct (
classic (
imm_safe ge e K a m));
auto.
destruct (
H Stuckstate).
apply star_one.
left.
econstructor;
eauto.
destruct H2 as [
r F].
inv F.
destruct H2 as [
t [
s'
S]].
inv S.
inv H2.
inv H2.
Qed.
Safe expressions are well-formed with respect to l-values and r-values.
Definition expr_kind (
a:
expr) :
kind :=
match a with
|
Eloc _ _ =>
LV
|
Evar _ _ =>
LV
|
Ederef _ _ =>
LV
|
Efield _ _ _ =>
LV
|
_ =>
RV
end.
Lemma lred_kind:
forall e a m a'
m',
lred ge e a m a'
m' ->
expr_kind a =
LV.
Proof.
induction 1; auto.
Qed.
Lemma rred_kind:
forall a m t a'
m',
rred ge a m t a'
m' ->
expr_kind a =
RV.
Proof.
induction 1; auto.
Qed.
Lemma callred_kind:
forall m a fd args ty,
callred ge m a fd args ty ->
expr_kind a =
RV.
Proof.
induction 1; auto.
Qed.
Lemma context_kind:
forall a from to C,
context from to C ->
expr_kind a =
from ->
expr_kind (
C a) =
to.
Proof.
induction 1; intros; simpl; auto.
Qed.
Lemma imm_safe_kind:
forall e k a m,
imm_safe ge e k a m ->
expr_kind a =
k.
Proof.
Lemma safe_expr_kind:
forall from C f a k e m,
context from RV C ->
safe (
ExprState f (
C a)
k e m) ->
expr_kind a =
from.
Proof.
Painful inversion lemmas on particular states that are safe.
Section INVERSION_LEMMAS.
Variable e:
env.
Fixpoint exprlist_all_values (
rl:
exprlist) :
Prop :=
match rl with
|
Enil =>
True
|
Econs (
Csyntax.Eval v ty)
rl' =>
exprlist_all_values rl'
|
Econs _ _ =>
False
end.
Definition invert_expr_prop (
a:
expr) (
m:
mem) :
Prop :=
match a with
|
Eloc ptr ty =>
False
|
Evar x ty =>
exists b,
e!
x =
Some(
b,
ty)
\/ (
e!
x =
None /\
Genv.find_symbol ge x =
Some b)
|
Ederef (
Csyntax.Eval v ty1)
ty =>
True
|
Efield (
Csyntax.Eval v ty1)
f ty =>
match ty1 with
|
Tstruct _ fList _ =>
exists delta,
field_offset f fList =
Errors.OK delta
|
Tunion _ _ _ =>
True
|
_ =>
False
end
|
Csyntax.Eval v ty =>
False
|
Csyntax.Evalof (
Eloc ptr ty')
ty =>
ty' =
ty /\
exists t,
exists v,
deref_loc ge ty m ptr t v
|
Csyntax.Eunop op (
Csyntax.Eval v1 ty1)
ty =>
exists v,
sem_unary_operation_expr op v1 ty1 =
v
|
Csyntax.Ebinop op (
Csyntax.Eval v1 ty1) (
Csyntax.Eval v2 ty2)
ty =>
exists v,
sem_binary_operation_expr op v1 ty1 v2 ty2 =
Some v
|
Ecast (
Csyntax.Eval v1 ty1)
ty =>
exists v,
sem_cast_expr v1 ty1 ty =
Some v
|
Eseqand (
Csyntax.Eval v1 ty1)
r2 ty =>
exists b,
Mem.mem_norm m (
bool_expr v1 ty1) =
Values.Val.of_bool b
|
Eseqor (
Csyntax.Eval v1 ty1)
r2 ty =>
exists b,
Mem.mem_norm m (
bool_expr v1 ty1) =
Values.Val.of_bool b
|
Econdition (
Csyntax.Eval v1 ty1)
r1 r2 ty =>
exists b,
Mem.mem_norm m (
bool_expr v1 ty1) =
Vint b
|
Eassign (
Eloc ptr ty1) (
Csyntax.Eval v2 ty2)
ty =>
exists v,
exists m',
exists t,
ty =
ty1 /\
sem_cast_expr v2 ty2 ty1 =
Some v /\
assign_loc ge ty1 m ptr v t m'
|
Eassignop op (
Eloc ptr ty1) (
Csyntax.Eval v2 ty2)
tyres ty =>
exists t,
exists v1 ,
ty =
ty1
/\
deref_loc ge ty1 m ptr t v1
|
Epostincr id (
Eloc ptr ty1)
ty =>
exists t,
exists v1,
ty =
ty1
/\
deref_loc ge ty m ptr t v1
|
Ecomma (
Csyntax.Eval v ty1)
r2 ty =>
typeof r2 =
ty
|
Eparen (
Csyntax.Eval v1 ty1)
ty =>
exists v,
sem_cast_expr v1 ty1 ty =
Some v
|
Ecall (
Csyntax.Eval vf tyf)
rargs ty =>
exprlist_all_values rargs ->
exists tyargs tyres cconv fd vl,
classify_fun tyf =
fun_case_f tyargs tyres cconv
/\
Genv.find_funct m ge vf =
Some fd
/\
cast_arguments rargs tyargs vl
/\
type_of_fundef fd =
Tfunction tyargs tyres cconv
|
Ebuiltin ef tyargs rargs ty =>
exprlist_all_values rargs ->
exists vargs,
exists t,
exists vres,
exists m',
cast_arguments rargs tyargs vargs
/\
external_call ef ge vargs m t vres m'
|
_ =>
True
end.
Lemma lred_invert:
forall l m l'
m',
lred ge e l m l'
m' ->
invert_expr_prop l m.
Proof.
induction 1; red; auto.
exists b; auto.
exists b; auto.
exists delta; auto.
Qed.
Lemma rred_invert:
forall r m t r'
m',
rred ge r m t r'
m' ->
invert_expr_prop r m.
Proof.
induction 1;
red;
auto.
split;
auto;
exists t;
exists v;
auto.
exists v;
auto.
exists v;
auto.
exists v;
auto.
exists true;
subst;
auto.
exists false;
subst;
auto.
exists true;
subst;
auto.
exists false;
subst;
auto.
exists b;
subst;
auto.
exists v;
exists m';
exists t;
auto.
exists t;
exists v1;
auto.
exists t;
exists v1;
auto.
exists v;
auto.
intros.
exists vargs;
exists t;
exists vres;
exists m';
auto.
Qed.
Lemma callred_invert:
forall r fd args ty m,
callred ge m r fd args ty ->
invert_expr_prop r m.
Proof.
intros. inv H. simpl.
intros. exists tyargs, tyres, cconv, fd, args; auto.
Qed.
Scheme context_ind2 :=
Minimality for context Sort Prop
with contextlist_ind2 :=
Minimality for contextlist Sort Prop.
Combined Scheme context_contextlist_ind from context_ind2,
contextlist_ind2.
Lemma invert_expr_context:
(
forall from to C,
context from to C ->
forall a m,
invert_expr_prop a m ->
invert_expr_prop (
C a)
m)
/\(
forall from C,
contextlist from C ->
forall a m,
invert_expr_prop a m ->
~
exprlist_all_values (
C a)).
Proof.
apply context_contextlist_ind;
intros;
try (
exploit H0; [
eauto|
intros]);
simpl.
auto.
destruct (
C a);
auto;
contradiction.
destruct (
C a);
auto;
contradiction.
destruct (
C a);
auto;
contradiction.
auto.
destruct (
C a);
auto;
contradiction.
destruct (
C a);
auto;
contradiction.
destruct e1;
auto;
destruct (
C a);
auto;
contradiction.
destruct (
C a);
auto;
contradiction.
destruct (
C a);
auto;
contradiction.
destruct (
C a);
auto;
contradiction.
destruct (
C a);
auto;
contradiction.
destruct (
C a);
auto;
contradiction.
destruct e1;
auto;
destruct (
C a);
auto;
contradiction.
destruct (
C a);
auto;
contradiction.
destruct e1;
auto;
destruct (
C a);
auto;
contradiction.
destruct (
C a);
auto;
contradiction.
destruct (
C a);
auto;
contradiction.
destruct e1;
auto.
intros.
elim (
H0 a m);
auto.
intros.
elim (
H0 a m);
auto.
destruct (
C a);
auto;
contradiction.
destruct (
C a);
auto;
contradiction.
red;
intros.
destruct (
C a);
auto.
red;
intros.
destruct e1;
auto.
elim (
H0 a m);
auto.
Qed.
Lemma imm_safe_inv:
forall k a m,
imm_safe ge e k a m ->
match a with
|
Eloc _ _ =>
True
|
Csyntax.Eval _ _ =>
True
|
_ =>
invert_expr_prop a m
end.
Proof.
Lemma safe_inv:
forall k C f a K m,
safe (
ExprState f (
C a)
K e m) ->
context k RV C ->
match a with
|
Eloc _ _ =>
True
|
Csyntax.Eval _ _ =>
True
|
_ =>
invert_expr_prop a m
end.
Proof.
End INVERSION_LEMMAS.
Correctness of the strategy.
Section SIMPLE_EVAL.
Variable f:
function.
Variable k:
cont.
Variable e:
env.
Variable m:
mem.
Lemma eval_simple_steps:
(
forall a v,
eval_simple_rvalue e m a v ->
forall C,
context RV RV C ->
star (
fun ge =>
Csem.step ge needed_stackspace)
ge (
ExprState f (
C a)
k e m)
E0 (
ExprState f (
C (
Csyntax.Eval v (
typeof a)))
k e m))
/\ (
forall a ptr,
eval_simple_lvalue e m a ptr ->
forall C,
context LV RV C ->
star (
fun ge =>
Csem.step ge needed_stackspace)
ge (
ExprState f (
C a)
k e m)
E0 (
ExprState f (
C (
Eloc ptr (
typeof a)))
k e m)).
Proof.
Lemma eval_simple_rvalue_steps:
forall a v,
eval_simple_rvalue e m a v ->
forall C,
context RV RV C ->
star (
fun ge =>
Csem.step ge needed_stackspace)
ge (
ExprState f (
C a)
k e m)
E0 (
ExprState f (
C (
Csyntax.Eval v (
typeof a)))
k e m).
Proof (
proj1 eval_simple_steps).
Lemma eval_simple_lvalue_steps:
forall a ptr,
eval_simple_lvalue e m a ptr ->
forall C,
context LV RV C ->
star (
fun ge =>
Csem.step ge needed_stackspace)
ge (
ExprState f (
C a)
k e m)
E0 (
ExprState f (
C (
Eloc ptr (
typeof a)))
k e m).
Proof (
proj2 eval_simple_steps).
Corollary eval_simple_rvalue_safe:
forall C a v,
eval_simple_rvalue e m a v ->
context RV RV C ->
safe (
ExprState f (
C a)
k e m) ->
safe (
ExprState f (
C (
Csyntax.Eval v (
typeof a)))
k e m).
Proof.
Corollary eval_simple_lvalue_safe:
forall C a ptr,
eval_simple_lvalue e m a ptr ->
context LV RV C ->
safe (
ExprState f (
C a)
k e m) ->
safe (
ExprState f (
C (
Eloc ptr (
typeof a)))
k e m).
Proof.
Lemma simple_can_eval:
forall a from C,
simple a =
true ->
context from RV C ->
safe (
ExprState f (
C a)
k e m) ->
match from with
|
LV =>
exists ptr,
eval_simple_lvalue e m a ptr
|
RV =>
exists v,
eval_simple_rvalue e m a v
end.
Proof.
Ltac StepL REC C'
a :=
let ptr :=
fresh "
ptr"
in
let E :=
fresh "
E"
in let S :=
fresh "
SAFE"
in
exploit (
REC LV C');
eauto;
intros [
ptr E];
assert (
S:
safe (
ExprState f (
C' (
Eloc ptr (
typeof a)))
k e m))
by
(
eapply (
eval_simple_lvalue_safe C');
eauto);
simpl in S.
Ltac StepR REC C'
a :=
let v :=
fresh "
v"
in let E :=
fresh "
E"
in let S :=
fresh "
SAFE"
in
exploit (
REC RV C');
eauto;
intros [
v E];
assert (
S:
safe (
ExprState f (
C' (
Csyntax.Eval v (
typeof a)))
k e m))
by
(
eapply (
eval_simple_rvalue_safe C');
eauto);
simpl in S.
induction a;
intros from C S CTX SAFE;
generalize (
safe_expr_kind _ _ _ _ _ _ _ CTX SAFE);
intro K;
subst;
simpl in S;
try discriminate;
simpl.
-
exists v;
constructor.
-
exploit safe_inv;
eauto;
simpl.
intros [
b A].
exists (
Eval (
Vptr b Int.zero)).
intuition.
apply esl_var_local;
auto.
apply esl_var_global;
auto.
-
StepR IHa (
fun x =>
C(
Efield x f0 ty))
a.
exploit safe_inv.
eexact SAFE0.
eauto.
simpl.
destruct (
typeof a)
eqn:?;
try contradiction.
intros [
delta OFS].
eexists;
eauto.
econstructor;
eauto.
eexists;
eauto.
eapply esl_field_union;
eauto.
-
destruct (
andb_prop _ _ S)
as [
S1 S2].
clear S.
rewrite negb_true_iff in S2.
StepL IHa (
fun x =>
C(
Csyntax.Evalof x ty))
a.
exploit safe_inv.
eexact SAFE0.
eauto.
simpl.
intros [
TY [
t [
v LOAD]]].
assert (
t =
E0).
inv LOAD;
auto.
congruence.
subst t.
eexists.
econstructor;
eauto.
congruence.
-
StepR IHa (
fun x =>
C(
Ederef x ty))
a.
exploit safe_inv.
eexact SAFE0.
eauto.
simpl.
eexists;
econstructor;
eauto.
-
StepL IHa (
fun x =>
C(
Eaddrof x ty))
a.
eexists;
econstructor;
eauto.
-
StepR IHa (
fun x =>
C(
Csyntax.Eunop op x ty))
a.
exploit safe_inv.
eexact SAFE0.
eauto.
simpl.
intros [
v'
EQ].
eexists;
econstructor;
eauto.
-
destruct (
andb_prop _ _ S)
as [
S1 S2];
clear S.
StepR IHa1 (
fun x =>
C(
Csyntax.Ebinop op x a2 ty))
a1.
StepR IHa2 (
fun x =>
C(
Csyntax.Ebinop op (
Csyntax.Eval v (
typeof a1))
x ty))
a2.
exploit safe_inv.
eexact SAFE1.
eauto.
simpl.
intros [
v'
EQ].
exists v';
econstructor;
eauto.
-
StepR IHa (
fun x =>
C(
Ecast x ty))
a.
exploit safe_inv.
eexact SAFE0.
eauto.
simpl.
intros [
v'
CAST].
exists v';
econstructor;
eauto.
-
econstructor;
econstructor.
-
econstructor;
econstructor.
-
exists addr;
constructor.
Qed.
Lemma simple_can_eval_rval:
forall r C,
simple r =
true ->
context RV RV C ->
safe (
ExprState f (
C r)
k e m) ->
exists v,
eval_simple_rvalue e m r v
/\
safe (
ExprState f (
C (
Csyntax.Eval v (
typeof r)))
k e m).
Proof.
Lemma simple_can_eval_lval:
forall ll C,
simple ll =
true ->
context LV RV C ->
safe (
ExprState f (
C ll)
k e m) ->
exists ptr,
eval_simple_lvalue e m ll ptr
/\
safe (
ExprState f (
C (
Eloc ptr (
typeof ll)))
k e m).
Proof.
Fixpoint rval_list (
vl:
list expr_sym) (
rl:
exprlist) :
exprlist :=
match vl,
rl with
|
v1 ::
vl',
Econs r1 rl' =>
Econs (
Csyntax.Eval v1 (
typeof r1)) (
rval_list vl'
rl')
|
_,
_ =>
Enil
end.
Inductive eval_simple_list':
exprlist ->
list expr_sym ->
Prop :=
|
esrl'
_nil:
eval_simple_list'
Enil nil
|
esrl'
_cons:
forall r rl v vl,
eval_simple_rvalue e m r v ->
eval_simple_list'
rl vl ->
eval_simple_list' (
Econs r rl) (
v ::
vl).
Lemma eval_simple_list_implies:
forall rl tyl vl,
eval_simple_list e m rl tyl vl ->
exists vl',
cast_arguments (
rval_list vl'
rl)
tyl vl /\
eval_simple_list'
rl vl'.
Proof.
induction 1.
exists (@
nil expr_sym);
split.
constructor.
constructor.
destruct IHeval_simple_list as [
vl' [
A B]].
exists (
v' ::
vl');
split.
constructor;
auto.
constructor;
auto.
Qed.
Lemma can_eval_simple_list:
forall rl vl,
eval_simple_list'
rl vl ->
forall tyl vl',
cast_arguments (
rval_list vl rl)
tyl vl' ->
eval_simple_list e m rl tyl vl'.
Proof.
induction 1; simpl; intros.
inv H. constructor.
inv H1. econstructor; eauto.
Qed.
Fixpoint exprlist_app (
rl1 rl2:
exprlist) :
exprlist :=
match rl1 with
|
Enil =>
rl2
|
Econs r1 rl1' =>
Econs r1 (
exprlist_app rl1'
rl2)
end.
Lemma exprlist_app_assoc:
forall rl2 rl3 rl1,
exprlist_app (
exprlist_app rl1 rl2)
rl3 =
exprlist_app rl1 (
exprlist_app rl2 rl3).
Proof.
induction rl1; auto. simpl. congruence.
Qed.
Inductive contextlist' : (
exprlist ->
expr) ->
Prop :=
|
contextlist'
_call:
forall r1 rl0 ty C,
context RV RV C ->
contextlist' (
fun rl =>
C (
Ecall r1 (
exprlist_app rl0 rl)
ty))
|
contextlist'
_builtin:
forall ef tyargs rl0 ty C,
context RV RV C ->
contextlist' (
fun rl =>
C (
Ebuiltin ef tyargs (
exprlist_app rl0 rl)
ty)).
Lemma exprlist_app_context:
forall rl1 rl2,
contextlist RV (
fun x =>
exprlist_app rl1 (
Econs x rl2)).
Proof.
Lemma contextlist'
_head:
forall rl C,
contextlist'
C ->
context RV RV (
fun x =>
C (
Econs x rl)).
Proof.
Lemma contextlist'
_tail:
forall r1 C,
contextlist'
C ->
contextlist' (
fun x =>
C (
Econs r1 x)).
Proof.
Hint Resolve contextlist'
_head contextlist'
_tail.
Lemma eval_simple_list_steps:
forall rl vl,
eval_simple_list'
rl vl ->
forall C,
contextlist'
C ->
star (
fun ge =>
Csem.step ge needed_stackspace)
ge (
ExprState f (
C rl)
k e m)
E0 (
ExprState f (
C (
rval_list vl rl))
k e m).
Proof.
Lemma simple_list_can_eval:
forall rl C,
simplelist rl =
true ->
contextlist'
C ->
safe (
ExprState f (
C rl)
k e m) ->
exists vl,
eval_simple_list'
rl vl.
Proof.
Lemma rval_list_all_values:
forall vl rl,
exprlist_all_values (
rval_list vl rl).
Proof.
induction vl; simpl; intros. auto.
destruct rl; simpl; auto.
Qed.
End SIMPLE_EVAL.
Decomposition
Section DECOMPOSITION.
Variable f:
function.
Variable k:
cont.
Variable e:
env.
Variable m:
mem.
Variable l :
list block.
Definition simple_side_effect (
r:
expr) :
Prop :=
match r with
|
Csyntax.Evalof l _ =>
simple l =
true /\
type_is_volatile (
typeof l) =
true
|
Eseqand r1 r2 _ =>
simple r1 =
true
|
Eseqor r1 r2 _ =>
simple r1 =
true
|
Econdition r1 r2 r3 _ =>
simple r1 =
true
|
Eassign l1 r2 _ =>
simple l1 =
true /\
simple r2 =
true
|
Eassignop _ l1 r2 _ _ =>
simple l1 =
true /\
simple r2 =
true
|
Epostincr _ l1 _ =>
simple l1 =
true
|
Ecomma r1 r2 _ =>
simple r1 =
true
|
Ecall r1 rl _ =>
simple r1 =
true /\
simplelist rl =
true
|
Ebuiltin ef tyargs rl _ =>
simplelist rl =
true
|
Eparen r1 _ =>
simple r1 =
true
|
_ =>
False
end.
Scheme expr_ind2 :=
Induction for expr Sort Prop
with exprlist_ind2 :=
Induction for exprlist Sort Prop.
Combined Scheme expr_expr_list_ind from expr_ind2,
exprlist_ind2.
Hint Constructors leftcontext leftcontextlist.
Lemma decompose_expr:
(
forall a from C,
context from RV C ->
safe (
ExprState f (
C a)
k e m) ->
simple a =
true
\/
exists C',
exists a',
a =
C'
a' /\
simple_side_effect a' /\
leftcontext RV from C')
/\(
forall rl C,
contextlist'
C ->
safe (
ExprState f (
C rl)
k e m) ->
simplelist rl =
true
\/
exists C',
exists a',
rl =
C'
a' /\
simple_side_effect a' /\
leftcontextlist RV C').
Proof.
apply expr_expr_list_ind;
intros;
simpl;
auto.
Ltac Kind :=
exploit safe_expr_kind;
eauto;
simpl;
intros X;
rewrite <-
X in *;
clear X.
Ltac Rec HR kind C C' :=
destruct (
HR kind (
fun x =>
C(
C'
x)))
as [? | [
C'' [
a' [
D [
A B]]]]];
[
eauto |
eauto |
auto |
right;
exists (
fun x =>
C'(
C''
x));
exists a';
rewrite D;
auto].
Ltac Base :=
right;
exists (
fun x =>
x);
econstructor;
split; [
eauto |
simpl;
auto].
Kind.
Rec H RV C (
fun x =>
Efield x f0 ty).
Kind.
Rec H LV C (
fun x =>
Csyntax.Evalof x ty).
destruct (
type_is_volatile (
typeof l0))
eqn:?.
Base.
rewrite H2;
auto.
Kind.
Rec H RV C (
fun x =>
Ederef x ty).
Kind.
Rec H LV C (
fun x =>
Eaddrof x ty).
Kind.
Rec H RV C (
fun x =>
Csyntax.Eunop op x ty).
Kind.
Rec H RV C (
fun x =>
Csyntax.Ebinop op x r2 ty).
rewrite H3.
Rec H0 RV C (
fun x =>
Csyntax.Ebinop op r1 x ty).
Kind.
Rec H RV C (
fun x =>
Ecast x ty).
Kind.
Rec H RV C (
fun x =>
Eseqand x r2 ty).
Base.
Kind.
Rec H RV C (
fun x =>
Eseqor x r2 ty).
Base.
Kind.
Rec H RV C (
fun x =>
Econdition x r2 r3 ty).
Base.
Kind.
Rec H LV C (
fun x =>
Eassign x r ty).
Rec H0 RV C (
fun x =>
Eassign l0 x ty).
Base.
Kind.
Rec H LV C (
fun x =>
Eassignop op x r tyres ty).
Rec H0 RV C (
fun x =>
Eassignop op l0 x tyres ty).
Base.
Kind.
Rec H LV C (
fun x =>
Epostincr id x ty).
Base.
Kind.
Rec H RV C (
fun x =>
Ecomma x r2 ty).
Base.
Kind.
Rec H RV C (
fun x =>
Ecall x rargs ty).
destruct (
H0 (
fun x =>
C (
Ecall r1 x ty)))
as [
A | [
C' [
a' [
D [
A B]]]]].
eapply contextlist'
_call with (
C :=
C) (
rl0 :=
Enil).
auto.
auto.
Base.
right;
exists (
fun x =>
Ecall r1 (
C'
x)
ty);
exists a'.
rewrite D;
simpl;
auto.
Kind.
destruct (
H (
fun x =>
C (
Ebuiltin ef tyargs x ty)))
as [
A | [
C' [
a' [
D [
A B]]]]].
eapply contextlist'
_builtin with (
C :=
C) (
rl0 :=
Enil).
auto.
auto.
Base.
right;
exists (
fun x =>
Ebuiltin ef tyargs (
C'
x)
ty);
exists a'.
rewrite D;
simpl;
auto.
Kind.
Rec H RV C (
fun x => (
Eparen x ty)).
Base.
destruct (
H RV (
fun x =>
C (
Econs x rl)))
as [
A | [
C' [
a' [
A [
B D]]]]].
eapply contextlist'
_head;
eauto.
auto.
destruct (
H0 (
fun x =>
C (
Econs r1 x)))
as [
A' | [
C' [
a' [
A' [
B D]]]]].
eapply contextlist'
_tail;
eauto.
auto.
rewrite A;
rewrite A';
auto.
right;
exists (
fun x =>
Econs r1 (
C'
x));
exists a'.
rewrite A';
eauto.
right;
exists (
fun x =>
Econs (
C'
x)
rl);
exists a'.
rewrite A;
eauto.
Qed.
Lemma decompose_topexpr:
forall a,
safe (
ExprState f a k e m) ->
simple a =
true
\/
exists C,
exists a',
a =
C a' /\
simple_side_effect a' /\
leftcontext RV RV C.
Proof.
End DECOMPOSITION.
Simulation for expressions.
Lemma estep_simulation:
forall S t S',
estep S t S' ->
plus (
fun ge =>
Csem.step ge needed_stackspace)
ge S t S'.
Proof.
Lemma can_estep:
forall f a k e m,
safe (
ExprState f a k e m) ->
match a with Csyntax.Eval _ _ =>
False |
_ =>
True end ->
exists t,
exists S,
estep (
ExprState f a k e m)
t S.
Proof.
Simulation for all states
Theorem step_simulation:
forall S1 t S2,
step S1 t S2 ->
plus (
fun ge =>
Csem.step ge needed_stackspace)
ge S1 t S2.
Proof.
Theorem progress:
forall S,
safe S -> (
exists r,
final_state S r) \/ (
exists t,
exists S',
step S t S').
Proof.
intros.
exploit H.
apply star_refl.
intros [
FIN | [
t [
S'
STEP]]].
auto.
right.
destruct STEP.
assert (
exists t,
exists S',
estep S t S').
inv H0.
eapply can_estep;
eauto.
inv H2;
auto.
eapply can_estep;
eauto.
inv H2;
auto.
inv H1;
auto.
eapply can_estep;
eauto.
inv H2;
auto.
inv H1;
auto.
exploit (
H Stuckstate).
apply star_one.
left.
econstructor;
eauto.
intros [[
r F] | [
t [
S'
R]]].
inv F.
inv R.
inv H0.
inv H0.
destruct H1 as [
t' [
S''
ESTEP]].
exists t';
exists S'';
left;
auto.
exists t;
exists S';
right;
auto.
Qed.
End STRATEGY.
The semantics that follows the strategy.
Definition semantics (
p:
program)
ns sg :=
Semantics (
fun ge =>
step ge ns) (
initial_state p sg)
final_state (
Genv.globalenv p).
This semantics is receptive to changes in events.
Remark deref_loc_trace:
forall F V (
ge:
Genv.t F V)
ty m ptr t v ,
deref_loc ge ty m ptr t v ->
match t with nil =>
True |
ev ::
nil =>
True |
_ =>
False end.
Proof.
intros. inv H; simpl; auto. inv H2; simpl; auto.
Qed.
Remark deref_loc_receptive:
forall F V (
ge:
Genv.t F V)
ty m ptr ev1 t1 v ev2 ,
deref_loc ge ty m ptr (
ev1 ::
t1)
v ->
match_traces ge (
ev1 ::
nil) (
ev2 ::
nil) ->
t1 =
nil /\
exists v',
deref_loc ge ty m ptr (
ev2 ::
nil)
v'.
Proof.
Remark assign_loc_trace:
forall F V (
ge:
Genv.t F V)
ty m bofs t v m' ,
assign_loc ge ty m bofs v t m' ->
match t with nil =>
True |
ev ::
nil =>
output_event ev |
_ =>
False end.
Proof.
intros. inv H; simpl; auto. inv H2; simpl; auto.
Qed.
Remark assign_loc_receptive:
forall F V (
ge:
Genv.t F V)
ty m bofs ev1 t1 v m'
ev2 ,
assign_loc ge ty m bofs v (
ev1 ::
t1)
m' ->
match_traces ge (
ev1 ::
nil) (
ev2 ::
nil) ->
ev1 ::
t1 =
ev2 ::
nil.
Proof.
Lemma semantics_strongly_receptive:
forall p ns sg,
strongly_receptive (
semantics p ns sg).
Proof.
The main simulation result.
Theorem strategy_simulation:
forall p ns sg,
backward_simulation (
Csem.semantics p ns sg) (
semantics p ns sg).
Proof.
intros.
apply backward_simulation_plus with (
match_states :=
fun (
S1 S2:
state) =>
S1 =
S2);
simpl.
-
auto.
-
intros.
exists s1;
auto.
-
intros.
exists s2;
auto.
-
intros.
subst s2.
auto.
-
intros.
subst s2.
apply progress.
auto.
-
intros.
subst s1.
exists s2';
split;
auto.
apply step_simulation;
auto.
Qed.
A big-step semantics for CompCert C implementing the reduction strategy.
Section BIGSTEP.
Variable ge:
genv.
Variable needed_stackspace :
ident ->
nat.
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 (* terminated by break *)
|
Out_continue:
outcome (* terminated by continue *)
|
Out_normal:
outcome (* terminated normally *)
|
Out_return:
option (
expr_sym *
type) ->
outcome.
(* 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:
expr_sym) :
Prop :=
match out,
t with
|
Out_normal,
Tvoid =>
v =
Eval Vundef
|
Out_return None,
Tvoid =>
v =
Eval Vundef
|
Out_return (
Some (
v',
ty')),
ty =>
ty <>
Tvoid /\
sem_cast_expr v'
ty'
ty =
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.
Require Import MemReserve.
Inductive eval_expression:
env ->
mem ->
expr ->
trace ->
mem ->
expr_sym ->
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 (
Csyntax.Eval v ty)
E0 m (
Csyntax.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 (
Csyntax.Evalof a ty)
t m' (
Csyntax.Evalof a'
ty)
|
eval_valof_volatile:
forall e m a t1 m'
a'
ty ptr t2 v ,
type_is_volatile (
typeof a) =
true ->
eval_expr e m LV a t1 m'
a' ->
eval_simple_lvalue ge e m'
a'
ptr ->
deref_loc ge (
typeof a)
m'
ptr t2 v ->
ty =
typeof a ->
eval_expr e m RV (
Csyntax.Evalof a ty) (
t1 **
t2)
m' (
Csyntax.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 (
Csyntax.Eunop op a ty)
t m' (
Csyntax.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 (
Csyntax.Ebinop op a1 a2 ty) (
t1 **
t2)
m'' (
Csyntax.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'
v,
eval_expr e m RV a1 t1 m'
a1' ->
eval_simple_rvalue ge e m'
a1'
v1 ->
Mem.mem_norm m' (
bool_expr v1 (
typeof a1)) =
Vtrue ->
eval_expr e m'
RV a2 t2 m''
a2' ->
eval_simple_rvalue ge e m''
a2'
v2 ->
sem_cast_expr v2 (
typeof a2)
type_bool =
Some v' ->
sem_cast_expr v'
type_bool ty =
Some v ->
eval_expr e m RV (
Eseqand a1 a2 ty) (
t1**
t2)
m'' (
Csyntax.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 ->
Mem.mem_norm m' (
bool_expr v1 (
typeof a1)) =
Vfalse ->
eval_expr e m RV (
Eseqand a1 a2 ty)
t1 m' (
Csyntax.Eval (
Eval (
Vint Int.zero))
ty)
|
eval_seqor_false:
forall e m a1 a2 ty t1 m'
a1'
v1 t2 m''
a2'
v2 v'
v,
eval_expr e m RV a1 t1 m'
a1' ->
eval_simple_rvalue ge e m'
a1'
v1 ->
Mem.mem_norm m' (
bool_expr v1 (
typeof a1)) =
Vfalse ->
eval_expr e m'
RV a2 t2 m''
a2' ->
eval_simple_rvalue ge e m''
a2'
v2 ->
sem_cast_expr v2 (
typeof a2)
type_bool =
Some v' ->
sem_cast_expr v'
type_bool ty =
Some v ->
eval_expr e m RV (
Eseqor a1 a2 ty) (
t1**
t2)
m'' (
Csyntax.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 ->
Mem.mem_norm m' (
bool_expr v1 (
typeof a1)) =
Vtrue ->
eval_expr e m RV (
Eseqor a1 a2 ty)
t1 m' (
Csyntax.Eval (
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 ->
Mem.mem_norm m' (
bool_expr v1 (
typeof a1)) =
Vint b ->
eval_expr e m'
RV (
if negb (
Int.eq b Int.zero)
then a2 else a3)
t2 m''
a' ->
eval_simple_rvalue ge e m''
a'
v' ->
sem_cast_expr v' (
typeof (
if negb (
Int.eq b Int.zero)
then a2 else a3))
ty =
Some v ->
eval_expr e m RV (
Econdition a1 a2 a3 ty) (
t1**
t2)
m'' (
Csyntax.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'
ptr 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'
ptr ->
eval_simple_rvalue ge e m2 r'
v ->
sem_cast_expr v (
typeof r) (
typeof l) =
Some v' ->
assign_loc ge (
typeof l)
m2 ptr v'
t3 m3 ->
ty =
typeof l ->
eval_expr e m RV (
Eassign l r ty) (
t1**
t2**
t3)
m3 (
Csyntax.Eval v'
ty)
|
eval_assignop:
forall e m op l r tyres ty t1 m1 l'
t2 m2 r'
ptr
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'
ptr ->
deref_loc ge (
typeof l)
m2 ptr t3 v1 ->
eval_simple_rvalue ge e m2 r'
v2 ->
sem_binary_operation_expr op v1 (
typeof l)
v2 (
typeof r) =
Some v3 ->
sem_cast_expr v3 tyres (
typeof l) =
Some v4 ->
assign_loc ge (
typeof l)
m2 ptr v4 t4 m3 ->
ty =
typeof l ->
eval_expr e m RV (
Eassignop op l r tyres ty) (
t1**
t2**
t3**
t4)
m3 (
Csyntax.Eval v4 ty)
|
eval_postincr:
forall e m id l ty t1 m1 l'
ptr v1 v2 v3 m2 t2 t3 ,
eval_expr e m LV l t1 m1 l' ->
eval_simple_lvalue ge e m1 l'
ptr ->
deref_loc ge ty m1 ptr t2 v1 ->
sem_incrdecr_expr id v1 ty =
Some v2 ->
sem_cast_expr v2 (
incrdecr_type ty)
ty =
Some v3 ->
assign_loc ge ty m1 ptr v3 t3 m2 ->
ty =
typeof l ->
eval_expr e m RV (
Epostincr id l ty) (
t1**
t2**
t3)
m2 (
Csyntax.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 m2 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 (
Csyntax.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 ->
Mem.mem_norm m1 (
bool_expr v1 (
typeof a)) =
Vint b ->
exec_stmt e m1 (
if negb (
Int.eq b Int.zero)
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 ->
Mem.mem_norm m' (
bool_expr v (
typeof a)) =
Vfalse ->
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 ->
Mem.mem_norm m1 (
bool_expr v (
typeof a)) =
Vtrue ->
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 ->
Mem.mem_norm m1 (
bool_expr v (
typeof a)) =
Vtrue ->
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 ->
Mem.mem_norm m2 (
bool_expr v (
typeof a)) =
Vfalse ->
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 ->
Mem.mem_norm m2 (
bool_expr v (
typeof a)) =
Vtrue ->
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 ->
Mem.mem_norm m' (
bool_expr v (
typeof a2)) =
Vfalse ->
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 ->
Mem.mem_norm m1 (
bool_expr v (
typeof a2)) =
Vtrue ->
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 ->
Mem.mem_norm m1 (
bool_expr v (
typeof a2)) =
Vtrue ->
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_expr m1 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 expr_sym ->
trace ->
mem ->
expr_sym ->
Prop :=
|
eval_funcall_internal:
forall m f vargs t e m1 m2 m2'
m3 out vres m4 m5,
list_norepet (
var_names f.(
fn_params) ++
var_names f.(
fn_vars)) ->
alloc_variables empty_env m (
VarSort.varsort (
f.(
fn_params) ++
f.(
fn_vars)))
e m1 ->
reserve_boxes m1 (
needed_stackspace f.(
fn_id)) =
Some (
m2) ->
bind_parameters ge e m2 f.(
fn_params)
vargs m2' ->
exec_stmt e m2'
f.(
fn_body)
t m3 out ->
outcome_result_value out f.(
fn_return)
vres ->
Mem.free_list m3 (
blocks_of_env e) =
Some m4 ->
release_boxes m4 (
needed_stackspace f.(
fn_id)) =
Some m5 ->
eval_funcall m (
Internal f)
vargs t m5 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.
Scheme eval_expression_mut :=
Induction for eval_expression Sort Prop
with eval_expr_mut :=
Induction for eval_expr Sort Prop
with eval_exprlist_mut :=
Induction for eval_exprlist Sort Prop
with exec_stmt_mut :=
Induction for exec_stmt Sort Prop
with eval_funcall_mut :=
Induction 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 (
Csyntax.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 (
Csyntax.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 (
Csyntax.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 (
Csyntax.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 ->
Mem.mem_norm m' (
bool_expr v1 (
typeof a1)) =
Vtrue ->
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 ->
Mem.mem_norm m' (
bool_expr v1 (
typeof a1)) =
Vfalse ->
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 ->
Mem.mem_norm m' (
bool_expr v1 (
typeof a1)) =
Vint b ->
evalinf_expr e m'
RV (
if negb (
Int.eq b Int.zero)
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 m2 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 ->
Mem.mem_norm m1 (
bool_expr v1 (
typeof a)) =
Vint b ->
execinf_stmt e m1 (
if negb (
Int.eq b Int.zero)
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 ->
Mem.mem_norm m1 (
bool_expr v (
typeof a)) =
Vtrue ->
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 ->
Mem.mem_norm m1 (
bool_expr v (
typeof a)) =
Vtrue ->
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 ->
Mem.mem_norm m2 (
bool_expr v (
typeof a)) =
Vtrue ->
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 ->
Mem.mem_norm m1 (
bool_expr v (
typeof a2)) =
Vtrue ->
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 ->
Mem.mem_norm m1 (
bool_expr v (
typeof a2)) =
Vtrue ->
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 ->
Mem.mem_norm m1 (
bool_expr v (
typeof a2)) =
Vtrue ->
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_expr m1 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 expr_sym ->
traceinf ->
Prop :=
|
evalinf_funcall_internal:
forall m f vargs t e m1 m2 m2',
list_norepet (
var_names f.(
fn_params) ++
var_names f.(
fn_vars)) ->
alloc_variables empty_env m (
VarSort.varsort (
f.(
fn_params) ++
f.(
fn_vars)))
e m1 ->
reserve_boxes m1 (
needed_stackspace f.(
fn_id)) =
Some (
m2) ->
bind_parameters ge e m2 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 (
Csyntax.Eval v ty) (
Kreturn k')
e m).
Lemma is_call_cont_call_cont:
forall k,
is_call_cont k ->
call_cont k =
k.
Proof.
destruct k; simpl; intros; contradiction || auto.
Qed.
Lemma leftcontext_compose:
forall k2 k3 C2,
leftcontext k2 k3 C2 ->
forall k1 C1,
leftcontext k1 k2 C1 ->
leftcontext k1 k3 (
fun x =>
C2(
C1 x))
with leftcontextlist_compose:
forall k2 C2,
leftcontextlist k2 C2 ->
forall k1 C1,
leftcontext k1 k2 C1 ->
leftcontextlist k1 (
fun x =>
C2(
C1 x)).
Proof.
induction 1;
intros;
try (
constructor;
eauto).
replace (
fun x =>
C1 x)
with C1.
auto.
apply extensionality;
auto.
induction 1;
intros;
constructor;
eauto.
Qed.
Lemma exprlist_app_leftcontext:
forall rl1 rl2,
simplelist rl1 =
true ->
leftcontextlist RV (
fun x =>
exprlist_app rl1 (
Econs x rl2)).
Proof.
Lemma exprlist_app_simple:
forall rl1 rl2,
simplelist (
exprlist_app rl1 rl2) =
simplelist rl1 &&
simplelist rl2.
Proof.
induction rl1;
intros;
simpl.
auto.
rewrite IHrl1.
apply andb_assoc.
Qed.
Lemma bigstep_to_steps:
(
forall e m a t m'
v,
eval_expression e m a t m'
v ->
forall f k,
star (
fun ge =>
step ge needed_stackspace)
ge (
ExprState f a k e m)
t (
ExprState f (
Csyntax.Eval v (
typeof a))
k e m'))
/\(
forall e m K a t m'
a',
eval_expr e m K a t m'
a' ->
forall C f k,
leftcontext K RV C ->
simple a' =
true /\
typeof a' =
typeof a /\
star (
fun ge =>
step ge needed_stackspace)
ge (
ExprState f (
C a)
k e m)
t (
ExprState f (
C a')
k e m'))
/\(
forall e m al t m'
al',
eval_exprlist e m al t m'
al' ->
forall a1 al2 ty C f k,
leftcontext RV RV C ->
simple a1 =
true ->
simplelist al2 =
true ->
simplelist al' =
true /\
star (
fun ge =>
step ge needed_stackspace)
ge (
ExprState f (
C (
Ecall a1 (
exprlist_app al2 al)
ty))
k e m)
t (
ExprState f (
C (
Ecall a1 (
exprlist_app al2 al')
ty))
k e m'))
/\(
forall e m s t m'
out,
exec_stmt e m s t m'
out ->
forall f k,
exists S,
star (
fun ge =>
step ge needed_stackspace)
ge (
State f s k e m)
t S /\
outcome_state_match e m'
f k out S)
/\(
forall m fd args t m'
res,
eval_funcall m fd args t m'
res ->
forall k,
is_call_cont k ->
star (
fun ge =>
step ge needed_stackspace)
ge (
Callstate fd args k m)
t (
Returnstate res k m')).
Proof.
Lemma eval_expression_to_steps:
forall e m a t m'
v,
eval_expression e m a t m'
v ->
forall f k,
star (
fun ge =>
step ge needed_stackspace)
ge (
ExprState f a k e m)
t (
ExprState f (
Csyntax.Eval v (
typeof a))
k e m').
Proof (
proj1 bigstep_to_steps).
Lemma eval_expr_to_steps:
forall e m K a t m'
a',
eval_expr e m K a t m'
a' ->
forall C f k,
leftcontext K RV C ->
simple a' =
true /\
typeof a' =
typeof a /\
star (
fun ge =>
step ge needed_stackspace)
ge (
ExprState f (
C a)
k e m)
t (
ExprState f (
C a')
k e m').
Proof (
proj1 (
proj2 bigstep_to_steps)).
Lemma eval_exprlist_to_steps:
forall e m al t m'
al',
eval_exprlist e m al t m'
al' ->
forall a1 al2 ty C f k,
leftcontext RV RV C ->
simple a1 =
true ->
simplelist al2 =
true ->
simplelist al' =
true /\
star (
fun ge =>
step ge needed_stackspace)
ge (
ExprState f (
C (
Ecall a1 (
exprlist_app al2 al)
ty))
k e m)
t (
ExprState f (
C (
Ecall a1 (
exprlist_app al2 al')
ty))
k e m').
Proof (
proj1 (
proj2 (
proj2 bigstep_to_steps))).
Lemma exec_stmt_to_steps:
forall e m s t m'
out,
exec_stmt e m s t m'
out ->
forall f k,
exists S,
star (
fun ge =>
step ge needed_stackspace)
ge (
State f s k e m)
t S /\
outcome_state_match e m'
f k out S.
Proof (
proj1 (
proj2 (
proj2 (
proj2 bigstep_to_steps)))).
Lemma eval_funcall_to_steps:
forall m fd args t m'
res,
eval_funcall m fd args t m'
res ->
forall k,
is_call_cont k ->
star (
fun ge =>
step ge needed_stackspace)
ge (
Callstate fd args k m)
t (
Returnstate res k m').
Proof (
proj2 (
proj2 (
proj2 (
proj2 bigstep_to_steps)))).
Fixpoint esize (
a:
expr) :
nat :=
match a with
|
Eloc _ _ => 1%
nat
|
Evar _ _ => 1%
nat
|
Ederef r1 _ =>
S(
esize r1)
|
Efield l1 _ _ =>
S(
esize l1)
|
Csyntax.Eval _ _ =>
O
|
Csyntax.Evalof l1 _ =>
S(
esize l1)
|
Eaddrof l1 _ =>
S(
esize l1)
|
Csyntax.Eunop _ r1 _ =>
S(
esize r1)
|
Csyntax.Ebinop _ r1 r2 _ =>
S(
esize r1 +
esize r2)%
nat
|
Ecast r1 _ =>
S(
esize r1)
|
Eseqand r1 r2 _ =>
S(
esize r1)
|
Eseqor r1 r2 _ =>
S(
esize r1)
|
Econdition r1 _ _ _ =>
S(
esize r1)
|
Esizeof _ _ => 1%
nat
|
Ealignof _ _ => 1%
nat
|
Eassign l1 r2 _ =>
S(
esize l1 +
esize r2)%
nat
|
Eassignop _ l1 r2 _ _ =>
S(
esize l1 +
esize r2)%
nat
|
Epostincr _ l1 _ =>
S(
esize l1)
|
Ecomma r1 r2 _ =>
S(
esize r1 +
esize r2)%
nat
|
Ecall r1 rl2 _ =>
S(
esize r1 +
esizelist rl2)%
nat
|
Ebuiltin ef tyargs rl _ =>
S(
esizelist rl)
|
Eparen r1 _ =>
S(
esize r1)
end
with esizelist (
el:
exprlist) :
nat :=
match el with
|
Enil =>
O
|
Econs r1 rl2 =>
S(
esize r1 +
esizelist rl2)%
nat
end.
Lemma leftcontext_size:
forall from to C,
leftcontext from to C ->
forall e1 e2,
(
esize e1 <
esize e2)%
nat ->
(
esize (
C e1) <
esize (
C e2))%
nat
with leftcontextlist_size:
forall from C,
leftcontextlist from C ->
forall e1 e2,
(
esize e1 <
esize e2)%
nat ->
(
esizelist (
C e1) <
esizelist (
C e2))%
nat.
Proof.
induction 1; intros; simpl; auto with arith.
exploit leftcontextlist_size; eauto. auto with arith.
exploit leftcontextlist_size; eauto. auto with arith.
induction 1; intros; simpl; auto with arith.
exploit leftcontext_size; eauto. auto with arith.
Qed.
Lemma evalinf_funcall_steps:
forall m fd args t k,
evalinf_funcall m fd args t ->
forever_N (
fun ge =>
step ge needed_stackspace)
lt ge O (
Callstate fd args k m)
t.
Proof.
End BIGSTEP.
Whole-program behaviors, big-step style.
Inductive bigstep_program_terminates (
p:
program)
ns sg:
trace ->
int ->
Prop :=
|
bigstep_program_terminates_intro:
forall b f m0 m1 t r,
let ge :=
Genv.globalenv p in
Genv.init_mem fid sg p =
Some m0 ->
Genv.find_symbol ge p.(
prog_main) =
Some b ->
Genv.find_funct_ptr ge b =
Some f ->
type_of_fundef f =
Tfunction Tnil type_int32s cc_default ->
eval_funcall ge ns m0 f nil t m1 (
Eval (
Vint r)) ->
bigstep_program_terminates p ns sg t r.
Inductive bigstep_program_diverges (
p:
program)
ns sg:
traceinf ->
Prop :=
|
bigstep_program_diverges_intro:
forall b f m0 t,
let ge :=
Genv.globalenv p in
Genv.init_mem fid sg p =
Some m0 ->
Genv.find_symbol ge p.(
prog_main) =
Some b ->
Genv.find_funct_ptr ge b =
Some f ->
type_of_fundef f =
Tfunction Tnil type_int32s cc_default ->
evalinf_funcall ge ns m0 f nil t ->
bigstep_program_diverges p ns sg t.
Definition bigstep_semantics (
p:
program)
ns sg :=
Bigstep_semantics (
bigstep_program_terminates p ns sg)
(
bigstep_program_diverges p ns sg).
Theorem bigstep_semantics_sound:
forall p ns sg,
bigstep_sound (
bigstep_semantics p ns sg)
(
semantics p ns sg).
Proof.