Section MSUBST_DENOTE_TC_ASSERT.
Context {cs: compspecs} (Delta: tycontext) (T1: PTree.t val) (T2: PTree.t (type * val)) (GV: option globals).
Fixpoint msubst_denote_tc_assert (tc: tc_assert): mpred :=
match tc with
| tc_FF msg => !! (typecheck_error msg)
| tc_TT => TT
| tc_andp' b c => (msubst_denote_tc_assert b) && (msubst_denote_tc_assert c)
| tc_orp' b c => (msubst_denote_tc_assert b) || (msubst_denote_tc_assert c)
| tc_nonzero' e => denote_tc_nonzero (force_val (msubst_eval_expr Delta T1 T2 GV e))
| tc_isptr e => denote_tc_isptr (force_val (msubst_eval_expr Delta T1 T2 GV e))
| tc_isint e => denote_tc_isint (force_val (msubst_eval_expr Delta T1 T2 GV e))
| tc_islong e => denote_tc_islong (force_val (msubst_eval_expr Delta T1 T2 GV e))
| tc_test_eq' e1 e2 => denote_tc_test_eq (force_val (msubst_eval_expr Delta T1 T2 GV e1)) (force_val (msubst_eval_expr Delta T1 T2 GV e2))
| tc_test_order' e1 e2 => denote_tc_test_order (force_val (msubst_eval_expr Delta T1 T2 GV e1)) (force_val (msubst_eval_expr Delta T1 T2 GV e2))
| tc_ilt' e i => denote_tc_igt i (force_val (msubst_eval_expr Delta T1 T2 GV e))
| tc_llt' e i => denote_tc_lgt i (force_val (msubst_eval_expr Delta T1 T2 GV e))
| tc_Zle e z => denote_tc_Zge z (force_val (msubst_eval_expr Delta T1 T2 GV e))
| tc_Zge e z => denote_tc_Zle z (force_val (msubst_eval_expr Delta T1 T2 GV e))
| tc_samebase e1 e2 => denote_tc_samebase (force_val (msubst_eval_expr Delta T1 T2 GV e1)) (force_val (msubst_eval_expr Delta T1 T2 GV e2))
| tc_nodivover' v1 v2 => denote_tc_nodivover (force_val (msubst_eval_expr Delta T1 T2 GV v1)) (force_val (msubst_eval_expr Delta T1 T2 GV v2))
| tc_initialized id ty => FF
| tc_iszero' e => denote_tc_iszero (force_val (msubst_eval_expr Delta T1 T2 GV e))
| tc_nosignedover op e1 e2 => denote_tc_nosignedover op (force_val (msubst_eval_expr Delta T1 T2 GV e1)) (force_val (msubst_eval_expr Delta T1 T2 GV e2))
end.
Definition msubst_tc_lvalue (e: expr) :=
msubst_denote_tc_assert (msubst_simpl_tc_assert T1 (typecheck_lvalue Delta e)).
Definition msubst_tc_expr (e: expr) :=
msubst_denote_tc_assert (msubst_simpl_tc_assert T1 (typecheck_expr Delta e)).
Definition msubst_tc_LR (e: expr) (lr: LLRR) :=
msubst_denote_tc_assert (msubst_simpl_tc_assert T1 (typecheck_LR Delta e lr)).
Definition msubst_tc_efield (efs: list efield) :=
msubst_denote_tc_assert (msubst_simpl_tc_assert T1 (typecheck_efield Delta efs)).
Definition msubst_tc_exprlist (ts: list type) (es: list expr) :=
msubst_denote_tc_assert (msubst_simpl_tc_assert T1 (typecheck_exprlist Delta ts es)).
Definition msubst_tc_expropt (e: option expr) (t: type) :=
msubst_denote_tc_assert (msubst_simpl_tc_assert T1
(match e with
| None => tc_bool (eqb_type t Tvoid) wrong_signature
| Some e' => typecheck_expr Delta (Ecast e' t)
end)).
(* Soundness proof *)
End MSUBST_DENOTE_TC_ASSERT.
Definition legal_tc_init (Delta: tycontext): tc_assert -> Prop :=
fix legal_tc_init (tc: tc_assert): Prop :=
match tc with
| tc_andp' tc1 tc2 => legal_tc_init tc1 /\ legal_tc_init tc2
| tc_orp' tc1 tc2 => legal_tc_init tc1 /\ legal_tc_init tc2
| tc_initialized i t => (temp_types Delta) ! i = Some t
| _ => True
end.

Lemma msubst_simpl_tc_assert_sound: forall {cs: compspecs} Delta P T1 T2 Q R tc,
legal_tc_init Delta tc ->
local (tc_environ Delta) && PROPx P (LOCALx (LocalD T1 T2 Q) (SEPx R)) &&
denote_tc_assert (msubst_simpl_tc_assert T1 tc) |--
denote_tc_assert tc.