(*LENB: We omit the clauses INJ and PG, since they are required for the enitre mu, not just restrict mu (vis mu), and hence better enforced uniformly in definition MatchCore below*)
Inductive structured_match_cores: core_data -> SM_Injection -> CSharpMin_core -> mem -> CMin_core -> mem -> Prop :=
| SMC_states:
forall d fn s k e le m tfn ts tk sp te tm cenv xenv mu lo hi cs sz
(TRF: transl_funbody cenv sz fn = OK tfn)
(TR: transl_stmt cenv xenv s = OK ts)
(*(MINJ: Mem.inject (as_inj mu) m tm)*)
(MCS: structured_match_callstack mu m tm
(Frame cenv tfn e le te sp lo hi :: cs)
(Mem.nextblock m) (Mem.nextblock tm))
(MK: match_cont k tk  cenv xenv cs)
(*(PG: meminj_preserves_globals ge (as_inj mu))*), structured_match_cores d mu (CSharpMin_State fn s k e le) m (CMin_State tfn ts tk (Vptr sp Int.zero) te) tm | SMC_state_seq: forall d fn s1 s2 k e le m tfn ts1 tk sp te tm cenv xenv mu lo hi cs sz (TRF: transl_funbody cenv sz fn = OK tfn) (TR: transl_stmt cenv xenv s1 = OK ts1) (*(MINJ: Mem.inject (as_inj mu) m tm)*)
(MCS: structured_match_callstack mu m tm
(Frame cenv tfn e le te sp lo hi :: cs)
(Mem.nextblock m) (Mem.nextblock tm))
(MK: match_cont (Csharpminor.Kseq s2 k) tk cenv xenv cs)
(*(PG: meminj_preserves_globals ge (as_inj mu))*), structured_match_cores d mu (CSharpMin_State fn (Csharpminor.Sseq s1 s2) k e le) m (CMin_State tfn ts1 tk (Vptr sp Int.zero) te) tm | SMC_callstate: forall d fd args k m tfd targs tk tm mu cs cenv (TR: transl_fundef fd = OK tfd) (*(MINJ: Mem.inject (as_inj mu) m tm)*)
(MCS: structured_match_callstack mu m tm cs (Mem.nextblock m) (Mem.nextblock tm))
(MK: match_cont k tk cenv nil cs)
(ISCC: Csharpminor.is_call_cont k)
(ARGSINJ: val_list_inject (restrict (as_inj mu) (vis mu)) args targs)
(*(PG: meminj_preserves_globals ge (as_inj mu))*),  structured_match_cores d mu (CSharpMin_Callstate fd args k) m (CMin_Callstate tfd targs tk) tm | SMC_returnstate: forall d v k m tv tk tm mu cs cenv (*(MINJ: Mem.inject (as_inj mu) m tm)*)
(MCS: structured_match_callstack mu m tm cs (Mem.nextblock m) (Mem.nextblock tm))
(MK: match_cont k tk cenv nil cs)
(RESINJ: val_inject (restrict (as_inj mu) (vis mu)) v tv)
(*(PG: meminj_preserves_globals ge (as_inj mu))*), structured_match_cores d mu (CSharpMin_Returnstate v k) m (CMin_Returnstate tv tk) tm. (* Definition protected m mu:= forall b, REACH m (extBlocksSrc mu) b = true -> locBlocksSrc mu b = true -> REACH m (frgnBlocksSrc mu) b = true.  Lemma protected_restr: forall m mu X (PROT : protected m mu), protected m (restrict_sm mu X). *)
Definition Match_cores d mu c1 m1 c2 m2:Prop :=
structured_match_cores d mu c1 m1 c2 m2 (*(restrict_sm mu (vis mu)) doesn't work here, since
some of the conditions of match_env are "global"*) /\
REACH_closed m1 (vis mu) /\
meminj_preserves_globals ge (as_inj mu) /\
(forall b, isGlobalBlock ge b = true -> frgnBlocksSrc mu b = true) /\
sm_valid mu m1 m2 /\ SM_wd mu /\
Mem.inject (as_inj mu) m1 m2(* /\ protected m1 mu*).

(* Specifications: *)
Lemma Match_sm_wd: forall d mu c1 m1 c2 m2,
Match_cores d mu c1 m1 c2 m2 ->
SM_wd mu.
Lemma Match_visible: forall d mu c1 m1 c2 m2,
Match_cores d mu c1 m1 c2 m2 ->
REACH_closed m1 (vis mu).
Lemma structured_match_cores_restrict: forall mu d m1 m2 c1 c2 X
(HX: forall b, vis mu b = true -> X b = true)
(RC: REACH_closed m1 X)
(MC: structured_match_cores d mu c1 m1 c2 m2),
structured_match_cores d (restrict_sm mu X) c1 m1 c2 m2.
Lemma Match_restrict: forall d mu c1 m1 c2 m2 X
(MC: Match_cores d mu c1 m1 c2 m2)
(HX: forall b, vis mu b = true -> X b = true)
(RC: REACH_closed m1 X),
Match_cores d (restrict_sm mu X) c1 m1 c2 m2.
Lemma Match_validblocks:
forall d mu c1 m1 c2 m2, Match_cores d mu c1 m1 c2 m2 ->
sm_valid mu m1 m2.
Lemma Match_AfterExternal:
forall mu st1 st2 m1 e vals1 m2 ef_sig vals2 e' ef_sig'
(MemInjMu : Mem.inject (as_inj mu) m1 m2)
(MatchMu : Match_cores st1 mu st1 m1 st2 m2)
(AtExtSrc : at_external csharpmin_eff_sem st1 = Some (e, ef_sig, vals1))
(AtExtTgt : at_external cmin_eff_sem st2 = Some (e', ef_sig', vals2))
(ValInjMu : Forall2 (val_inject (restrict (as_inj mu) (vis mu))) vals1 vals2)
(pubSrc' : Values.block -> bool)
(pubSrcHyp : pubSrc' =
(fun b : Values.block =>
locBlocksSrc mu b && REACH m1 (exportedSrc mu vals1) b))
(pubTgt' : Values.block -> bool)
(pubTgtHyp : pubTgt' =
(fun b : Values.block =>
locBlocksTgt mu b && REACH m2 (exportedTgt mu vals2) b))
nu
(NuHyp : nu = replace_locals mu pubSrc' pubTgt')
nu' ret1 m1' ret2 m2'
(INC : extern_incr nu nu')
(SEP : sm_inject_separated nu nu' m1 m2)
(WDnu' : SM_wd nu')
(SMvalNu' : sm_valid nu' m1' m2')
(MemInjNu' : Mem.inject (as_inj nu') m1' m2')
(RValInjNu' : val_inject (as_inj nu') ret1 ret2)
(FwdSrc : mem_forward m1 m1')
(FwdTgt : mem_forward m2 m2')
(frgnSrc' : Values.block -> bool)
(frgnSrcHyp : frgnSrc' =
(fun b : Values.block =>
DomSrc nu' b &&
(negb (locBlocksSrc nu' b) &&
REACH m1' (exportedSrc nu' (ret1 :: nil)) b)))
(frgnTgt' : Values.block -> bool)
(frgnTgtHyp : frgnTgt' =
(fun b : Values.block =>
DomTgt nu' b &&
(negb (locBlocksTgt nu' b) &&
REACH m2' (exportedTgt nu' (ret2 :: nil)) b)))
mu'
(Mu'Hyp : mu' = replace_externs nu' frgnSrc' frgnTgt')
(UnchPrivSrc : Mem.unchanged_on
(fun (b : Values.block) (_ : Z) =>
locBlocksSrc nu b = true /\ pubBlocksSrc nu b = false) m1
m1')
(UnchLOOR : Mem.unchanged_on (local_out_of_reach nu m1) m2 m2'),
exists (st1' : CSharpMin_core) (st2' : CMin_core),
after_external csharpmin_eff_sem (Some ret1) st1 = Some st1' /\
after_external cmin_eff_sem (Some ret2) st2 = Some st2' /\
Match_cores st1' mu' st1' m1' st2' m2'.
Lemma MATCH_safely_halted: forall cd mu c1 m1 c2 m2 v1
(SMC: structured_match_cores cd mu c1 m1 c2 m2)
(HALT: halted CSharpMin_core_sem  c1 = Some v1),
exists v2, halted CMin_core_sem c2 = Some v2 /\
val_inject (restrict (as_inj mu) (vis mu)) v1 v2.
Lemma Match_at_external: forall mu st1 m1 st2 m2 e vals1 sig
(MC: structured_match_cores st1 mu st1 m1 st2 m2)
(AtExt: at_external CSharpMin_core_sem st1 = Some (e, sig, vals1)),
exists vals2, Forall2 (val_inject (restrict (as_inj mu) (vis mu))) vals1 vals2 /\
at_external CMin_core_sem st2 = Some (e, sig, vals2).
Lemma match_callstack_freelist:
forall mu cenv tf e le te sp lo hi cs m m' tm (WD: SM_wd mu),
Mem.inject (as_inj mu) m tm ->
Mem.free_list m (blocks_of_env e) = Some m' ->
structured_match_callstack mu m tm (Frame cenv tf e le te sp lo hi :: cs) (Mem.nextblock m) (Mem.nextblock tm) ->
exists tm',
Mem.free tm sp 0 tf.(fn_stackspace) = Some tm'
/\ structured_match_callstack mu m' tm' cs (Mem.nextblock m') (Mem.nextblock tm')
/\ Mem.inject (as_inj mu) m' tm'.
Lemma var_addr_correct:
forall cenv id mu tf e le te sp lo hi m cs tm b,
structured_match_callstack mu m tm (Frame cenv tf e le te sp lo hi :: cs) (Mem.nextblock m) (Mem.nextblock tm) ->
eval_var_addr ge e id b ->
exists tv,
eval_expr tge (Vptr sp Int.zero) te tm (var_addr cenv id) tv
/\ val_inject (restrict (as_inj mu) (vis mu)) (Vptr b Int.zero) tv.
Lemma transl_expr_correct:
forall mu m tm cenv tf e lenv te sp lo hi cs
(MINJ: Mem.inject (as_inj mu) m tm)
(RC: REACH_closed m (vis mu))
(MATCH: structured_match_callstack mu m tm
(Frame cenv tf e lenv te sp lo hi :: cs)
(Mem.nextblock m) (Mem.nextblock tm)),
forall a v,
Csharpminor.eval_expr ge e lenv m a v ->
forall ta app
(TR: transl_expr cenv a = OK (ta, app)),
exists tv,
eval_expr tge (Vptr sp Int.zero) te tm ta tv
/\ val_inject (restrict (as_inj mu) (vis mu)) v tv
/\ val_match_approx app v.
Lemma transl_exprlist_correct:
forall mu m tm cenv tf e lenv te sp lo hi cs
(MINJ: Mem.inject (as_inj mu) m tm)
(RC: REACH_closed m (vis mu))
(MATCH: structured_match_callstack mu m tm
(Frame cenv tf e lenv te sp lo hi :: cs)
(Mem.nextblock m) (Mem.nextblock tm)),
forall a v,
Csharpminor.eval_exprlist ge e lenv m a v ->
forall ta
(TR: transl_exprlist cenv a = OK ta),
exists tv,
eval_exprlist tge (Vptr sp Int.zero) te tm ta tv
/\ val_list_inject (restrict (as_inj mu) (vis mu)) v tv.