(** 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 (Eval v ty) rl' => exprlist_all_values rl'
| Econs _ _ => False
end.
Definition invert_expr_prop (a: expr) (m: mem) : Prop :=
match a with
| Eloc b ofs ty => False
| Evar x ty =>
exists b,
e!x = Some(b, ty)
\/ (e!x = None /\ Genv.find_symbol ge x = Some b)
| Ederef (Eval v ty1) ty =>
exists b, exists ofs, v = Vptr b ofs
| Efield (Eval v ty1) f ty =>
exists b, exists ofs, v = Vptr b ofs /\
match ty1 with
| Tstruct id _ => exists co delta, ge.(genv_cenv)!id = Some co /\ field_offset ge f (co_members co) = Errors.OK delta
| Tunion id _ => exists co, ge.(genv_cenv)!id = Some co
| _ => False
end
| Eval v ty => False
| Evalof (Eloc b ofs ty') ty =>
ty' = ty /\ exists t, exists v, deref_loc ge ty m b ofs t v
| Eunop op (Eval v1 ty1) ty =>
exists v, sem_unary_operation op v1 ty1 m = Some v
| Ebinop op (Eval v1 ty1) (Eval v2 ty2) ty =>
exists v, sem_binary_operation ge op v1 ty1 v2 ty2 m = Some v
| Ecast (Eval v1 ty1) ty =>
exists v, sem_cast v1 ty1 ty m = Some v
| Eseqand (Eval v1 ty1) r2 ty =>
exists b, bool_val v1 ty1 m = Some b
| Eseqor (Eval v1 ty1) r2 ty =>
exists b, bool_val v1 ty1 m = Some b
| Econdition (Eval v1 ty1) r1 r2 ty =>
exists b, bool_val v1 ty1 m = Some b
| Eassign (Eloc b ofs ty1) (Eval v2 ty2) ty =>
exists v, exists m', exists t,
ty = ty1 /\ sem_cast v2 ty2 ty1 m = Some v /\ assign_loc ge ty1 m b ofs v t m'
| Eassignop op (Eloc b ofs ty1) (Eval v2 ty2) tyres ty =>
exists t, exists v1,
ty = ty1
/\ deref_loc ge ty1 m b ofs t v1
| Epostincr id (Eloc b ofs ty1) ty =>
exists t, exists v1,
ty = ty1
/\ deref_loc ge ty m b ofs t v1
| Ecomma (Eval v ty1) r2 ty =>
typeof r2 = ty
| Eparen (Eval v1 ty1) ty2 ty =>
exists v, sem_cast v1 ty1 ty2 m = Some v
| Ecall (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 ge vf = Some fd
/\ cast_arguments m 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 m rargs tyargs vargs
/\ external_call ef ge vargs m t vres m'
| _ => True
end.

Lemma callred_invert:
forall r fd args ty m,
callred ge r m fd args ty ->
invert_expr_prop r m.