(*
Lemma sel_exprlist_correct:
  forall sp e m a v,
  Cminor.eval_exprlist ge sp e m a v ->
  forall e' le m',
  env_lessdef e e' -> Mem.extends m m' ->
  exists v', eval_exprlist tge sp e' m' le (sel_exprlist hf a) v' /\ Val.lessdef_list v v'.
Proof.
  induction 1; intros; simpl.
  exists (@nil val); split; auto. constructor.
  exploit sel_expr_correct; eauto. intros [v1' [A B]].
  exploit IHeval_exprlist; eauto. intros [vl' [C D]].
  exists (v1' :: vl'); split; auto. constructor; eauto.
Qed.
*)

(** Semantic preservation for functions and statements. *)

Inductive match_cont (*NEW:*)(j:meminj): Cminor.cont -> CminorSel.cont -> Prop :=
  | match_cont_stop:
      match_cont j Cminor.Kstop Kstop
  | match_cont_seq: forall s k k',
      match_cont j k k' ->
      match_cont j (Cminor.Kseq s k) (Kseq (sel_stmt hf ge s) k')
  | match_cont_block: forall k k',
      match_cont j k k' ->
      match_cont j (Cminor.Kblock k) (Kblock k')
  (*sp' and sp_preserved_condition are new*)
  | match_cont_call: forall id f sp e k sp' e' k',
      match_cont j k k' ->
      (*env_lessdef e e' ->*)
      env_inject j e e' -> sp_preserved j sp sp' ->
      match_cont j (Cminor.Kcall id f sp e k) (Kcall id (sel_function hf ge f) sp' e' k').(*
Lemma sel_exprlist_correct:
  forall sp e m a v,
  Cminor.eval_exprlist ge sp e m a v ->
  forall e' le m',
  env_lessdef e e' -> Mem.extends m m' ->
  exists v', eval_exprlist tge sp e' m' le (sel_exprlist hf a) v' /\ Val.lessdef_list v v'.
Proof.
  induction 1; intros; simpl.
  exists (@nil val); split; auto. constructor.
  exploit sel_expr_correct; eauto. intros [v1' [A B]].
  exploit IHeval_exprlist; eauto. intros [vl' [C D]].
  exists (v1' :: vl'); split; auto. constructor; eauto.
Qed.
*)

(** Semantic preservation for functions and statements. *)

Inductive match_cont (*NEW:*)(j:meminj): Cminor.cont -> CminorSel.cont -> Prop :=
  | match_cont_stop:
      match_cont j Cminor.Kstop Kstop
  | match_cont_seq: forall s k k',
      match_cont j k k' ->
      match_cont j (Cminor.Kseq s k) (Kseq (sel_stmt hf ge s) k')
  | match_cont_block: forall k k',
      match_cont j k k' ->
      match_cont j (Cminor.Kblock k) (Kblock k')
  (*sp' and sp_preserved_condition are new*)
  | match_cont_call: forall id f sp e k sp' e' k',
      match_cont j k k' ->
      (*env_lessdef e e' ->*)
      env_inject j e e' -> sp_preserved j sp sp' ->
      match_cont j (Cminor.Kcall id f sp e k) (Kcall id (sel_function hf ge f) sp' e' k').(*
Lemma sel_exprlist_correct:
  forall sp e m a v,
  Cminor.eval_exprlist ge sp e m a v ->
  forall e' le m',
  env_lessdef e e' -> Mem.extends m m' ->
  exists v', eval_exprlist tge sp e' m' le (sel_exprlist hf a) v' /\ Val.lessdef_list v v'.
Proof.
  induction 1; intros; simpl.
  exists (@nil val); split; auto. constructor.
  exploit sel_expr_correct; eauto. intros [v1' [A B]].
  exploit IHeval_exprlist; eauto. intros [vl' [C D]].
  exists (v1' :: vl'); split; auto. constructor; eauto.
Qed.
*)

(** Semantic preservation for functions and statements. *)

Inductive match_cont (*NEW:*)(j:meminj): Cminor.cont -> CminorSel.cont -> Prop :=
  | match_cont_stop:
      match_cont j Cminor.Kstop Kstop
  | match_cont_seq: forall s k k',
      match_cont j k k' ->
      match_cont j (Cminor.Kseq s k) (Kseq (sel_stmt hf ge s) k')
  | match_cont_block: forall k k',
      match_cont j k k' ->
      match_cont j (Cminor.Kblock k) (Kblock k')
  (*sp' and sp_preserved_condition are new*)
  | match_cont_call: forall id f sp e k sp' e' k',
      match_cont j k k' ->
      (*env_lessdef e e' ->*)
      env_inject j e e' -> sp_preserved j sp sp' ->
      match_cont j (Cminor.Kcall id f sp e k) (Kcall id (sel_function hf ge f) sp' e' k').(*
Lemma sel_exprlist_correct:
  forall sp e m a v,
  Cminor.eval_exprlist ge sp e m a v ->
  forall e' le m',
  env_lessdef e e' -> Mem.extends m m' ->
  exists v', eval_exprlist tge sp e' m' le (sel_exprlist hf a) v' /\ Val.lessdef_list v v'.
Proof.
  induction 1; intros; simpl.
  exists (@nil val); split; auto. constructor.
  exploit sel_expr_correct; eauto. intros [v1' [A B]].
  exploit IHeval_exprlist; eauto. intros [vl' [C D]].
  exists (v1' :: vl'); split; auto. constructor; eauto.
Qed.
*)

(** Semantic preservation for functions and statements. *)

Inductive match_cont (*NEW:*)(j:meminj): Cminor.cont -> CminorSel.cont -> Prop :=
  | match_cont_stop:
      match_cont j Cminor.Kstop Kstop
  | match_cont_seq: forall s k k',
      match_cont j k k' ->
      match_cont j (Cminor.Kseq s k) (Kseq (sel_stmt hf ge s) k')
  | match_cont_block: forall k k',
      match_cont j k k' ->
      match_cont j (Cminor.Kblock k) (Kblock k')
  (*sp' and sp_preserved_condition are new*)
  | match_cont_call: forall id f sp e k sp' e' k',
      match_cont j k k' ->
      (*env_lessdef e e' ->*)
      env_inject j e e' -> sp_preserved j sp sp' ->
      match_cont j (Cminor.Kcall id f sp e k) (Kcall id (sel_function hf ge f) sp' e' k').(*
Lemma sel_exprlist_correct:
  forall sp e m a v,
  Cminor.eval_exprlist ge sp e m a v ->
  forall e' le m',
  env_lessdef e e' -> Mem.extends m m' ->
  exists v', eval_exprlist tge sp e' m' le (sel_exprlist hf a) v' /\ Val.lessdef_list v v'.
Proof.
  induction 1; intros; simpl.
  exists (@nil val); split; auto. constructor.
  exploit sel_expr_correct; eauto. intros [v1' [A B]].
  exploit IHeval_exprlist; eauto. intros [vl' [C D]].
  exists (v1' :: vl'); split; auto. constructor; eauto.
Qed.
*)

(** Semantic preservation for functions and statements. *)

Inductive match_cont (*NEW:*)(j:meminj): Cminor.cont -> CminorSel.cont -> Prop :=
  | match_cont_stop:
      match_cont j Cminor.Kstop Kstop
  | match_cont_seq: forall s k k',
      match_cont j k k' ->
      match_cont j (Cminor.Kseq s k) (Kseq (sel_stmt hf ge s) k')
  | match_cont_block: forall k k',
      match_cont j k k' ->
      match_cont j (Cminor.Kblock k) (Kblock k')
  (*sp' and sp_preserved_condition are new*)
  | match_cont_call: forall id f sp e k sp' e' k',
      match_cont j k k' ->
      (*env_lessdef e e' ->*)
      env_inject j e e' -> sp_preserved j sp sp' ->
      match_cont j (Cminor.Kcall id f sp e k) (Kcall id (sel_function hf ge f) sp' e' k').Inductive match_states (j:meminj) : CMin_core -> mem -> CMinSel_core -> mem -> Prop :=
  | match_state: forall f s k s' k' sp e m sp' e' m',
      s' = sel_stmt hf ge s ->
      match_cont j k k' ->
      (*      env_lessdef e e' -> Mem.extends m m' ->*)
      env_inject j e e' -> Mem.inject j m m' -> sp_preserved j sp sp' ->
      match_states j
        (CMin_State f s k sp e) m
        (CMinSel_State (sel_function hf ge f) s' k' sp' e') m'
  | match_callstate: forall f args args' k k' m m',
      match_cont j k k' ->
      (*      Val.lessdef_list args args' -> Mem.extends m m' ->*)
      val_list_inject j args args' -> Mem.inject j m m' ->
      match_states j
        (CMin_Callstate f args k) m
        (CMinSel_Callstate (sel_fundef hf ge f) args' k') m'
  | match_returnstate: forall v v' k k' m m',
      match_cont j k k' ->
      (*Val.lessdef v v' -> Mem.extends m m' ->*)
      val_inject j v v' -> Mem.inject j m m' ->
      match_states j
        (CMin_Returnstate v k) m
        (CMinSel_Returnstate v' k') m'
  | match_builtin_1: forall ef args args' optid f sp e k m al sp' e' k' m',
      match_cont j k k' ->
      (*Val.lessdef_list args args' -> env_lessdef e e' -> Mem.extends m m' -> *)
      val_list_inject j args args' -> env_inject j e e' -> Mem.inject j m m' ->
      sp_preserved j sp sp' ->
      CminorSel.eval_exprlist tge sp' e' m' nil al args' ->
      match_states j
        (CMin_Callstate (External ef) args (Cminor.Kcall optid f sp e k)) m
        (CMinSel_State (sel_function hf ge f) (Sbuiltin optid ef al) k' sp' e') m'
  | match_builtin_2: forall v v' optid f sp e k m sp' e' m' k',
      match_cont j k k' ->
      (*Val.lessdef v v' -> env_lessdef e e' -> Mem.extends m m' ->*)
      val_inject j v v' -> env_inject j e e' -> Mem.inject j m m' -> sp_preserved j sp sp' ->
      match_states j
        (CMin_Returnstate v (Cminor.Kcall optid f sp e k)) m
        (CMinSel_State (sel_function hf ge f) Sskip k' sp' (set_optvar optid v' e')) m'.Inductive match_states (j:meminj) : CMin_core -> mem -> CMinSel_core -> mem -> Prop :=
  | match_state: forall f s k s' k' sp e m sp' e' m',
      s' = sel_stmt hf ge s ->
      match_cont j k k' ->
      (*      env_lessdef e e' -> Mem.extends m m' ->*)
      env_inject j e e' -> Mem.inject j m m' -> sp_preserved j sp sp' ->
      match_states j
        (CMin_State f s k sp e) m
        (CMinSel_State (sel_function hf ge f) s' k' sp' e') m'
  | match_callstate: forall f args args' k k' m m',
      match_cont j k k' ->
      (*      Val.lessdef_list args args' -> Mem.extends m m' ->*)
      val_list_inject j args args' -> Mem.inject j m m' ->
      match_states j
        (CMin_Callstate f args k) m
        (CMinSel_Callstate (sel_fundef hf ge f) args' k') m'
  | match_returnstate: forall v v' k k' m m',
      match_cont j k k' ->
      (*Val.lessdef v v' -> Mem.extends m m' ->*)
      val_inject j v v' -> Mem.inject j m m' ->
      match_states j
        (CMin_Returnstate v k) m
        (CMinSel_Returnstate v' k') m'
  | match_builtin_1: forall ef args args' optid f sp e k m al sp' e' k' m',
      match_cont j k k' ->
      (*Val.lessdef_list args args' -> env_lessdef e e' -> Mem.extends m m' -> *)
      val_list_inject j args args' -> env_inject j e e' -> Mem.inject j m m' ->
      sp_preserved j sp sp' ->
      CminorSel.eval_exprlist tge sp' e' m' nil al args' ->
      match_states j
        (CMin_Callstate (External ef) args (Cminor.Kcall optid f sp e k)) m
        (CMinSel_State (sel_function hf ge f) (Sbuiltin optid ef al) k' sp' e') m'
  | match_builtin_2: forall v v' optid f sp e k m sp' e' m' k',
      match_cont j k k' ->
      (*Val.lessdef v v' -> env_lessdef e e' -> Mem.extends m m' ->*)
      val_inject j v v' -> env_inject j e e' -> Mem.inject j m m' -> sp_preserved j sp sp' ->
      match_states j
        (CMin_Returnstate v (Cminor.Kcall optid f sp e k)) m
        (CMinSel_State (sel_function hf ge f) Sskip k' sp' (set_optvar optid v' e')) m'.Inductive match_states (j:meminj) : CMin_core -> mem -> CMinSel_core -> mem -> Prop :=
  | match_state: forall f s k s' k' sp e m sp' e' m',
      s' = sel_stmt hf ge s ->
      match_cont j k k' ->
      (*      env_lessdef e e' -> Mem.extends m m' ->*)
      env_inject j e e' -> Mem.inject j m m' -> sp_preserved j sp sp' ->
      match_states j
        (CMin_State f s k sp e) m
        (CMinSel_State (sel_function hf ge f) s' k' sp' e') m'
  | match_callstate: forall f args args' k k' m m',
      match_cont j k k' ->
      (*      Val.lessdef_list args args' -> Mem.extends m m' ->*)
      val_list_inject j args args' -> Mem.inject j m m' ->
      match_states j
        (CMin_Callstate f args k) m
        (CMinSel_Callstate (sel_fundef hf ge f) args' k') m'
  | match_returnstate: forall v v' k k' m m',
      match_cont j k k' ->
      (*Val.lessdef v v' -> Mem.extends m m' ->*)
      val_inject j v v' -> Mem.inject j m m' ->
      match_states j
        (CMin_Returnstate v k) m
        (CMinSel_Returnstate v' k') m'
  | match_builtin_1: forall ef args args' optid f sp e k m al sp' e' k' m',
      match_cont j k k' ->
      (*Val.lessdef_list args args' -> env_lessdef e e' -> Mem.extends m m' -> *)
      val_list_inject j args args' -> env_inject j e e' -> Mem.inject j m m' ->
      sp_preserved j sp sp' ->
      CminorSel.eval_exprlist tge sp' e' m' nil al args' ->
      match_states j
        (CMin_Callstate (External ef) args (Cminor.Kcall optid f sp e k)) m
        (CMinSel_State (sel_function hf ge f) (Sbuiltin optid ef al) k' sp' e') m'
  | match_builtin_2: forall v v' optid f sp e k m sp' e' m' k',
      match_cont j k k' ->
      (*Val.lessdef v v' -> env_lessdef e e' -> Mem.extends m m' ->*)
      val_inject j v v' -> env_inject j e e' -> Mem.inject j m m' -> sp_preserved j sp sp' ->
      match_states j
        (CMin_Returnstate v (Cminor.Kcall optid f sp e k)) m
        (CMinSel_State (sel_function hf ge f) Sskip k' sp' (set_optvar optid v' e')) m'.Inductive match_states (j:meminj) : CMin_core -> mem -> CMinSel_core -> mem -> Prop :=
  | match_state: forall f s k s' k' sp e m sp' e' m',
      s' = sel_stmt hf ge s ->
      match_cont j k k' ->
      (*      env_lessdef e e' -> Mem.extends m m' ->*)
      env_inject j e e' -> Mem.inject j m m' -> sp_preserved j sp sp' ->
      match_states j
        (CMin_State f s k sp e) m
        (CMinSel_State (sel_function hf ge f) s' k' sp' e') m'
  | match_callstate: forall f args args' k k' m m',
      match_cont j k k' ->
      (*      Val.lessdef_list args args' -> Mem.extends m m' ->*)
      val_list_inject j args args' -> Mem.inject j m m' ->
      match_states j
        (CMin_Callstate f args k) m
        (CMinSel_Callstate (sel_fundef hf ge f) args' k') m'
  | match_returnstate: forall v v' k k' m m',
      match_cont j k k' ->
      (*Val.lessdef v v' -> Mem.extends m m' ->*)
      val_inject j v v' -> Mem.inject j m m' ->
      match_states j
        (CMin_Returnstate v k) m
        (CMinSel_Returnstate v' k') m'
  | match_builtin_1: forall ef args args' optid f sp e k m al sp' e' k' m',
      match_cont j k k' ->
      (*Val.lessdef_list args args' -> env_lessdef e e' -> Mem.extends m m' -> *)
      val_list_inject j args args' -> env_inject j e e' -> Mem.inject j m m' ->
      sp_preserved j sp sp' ->
      CminorSel.eval_exprlist tge sp' e' m' nil al args' ->
      match_states j
        (CMin_Callstate (External ef) args (Cminor.Kcall optid f sp e k)) m
        (CMinSel_State (sel_function hf ge f) (Sbuiltin optid ef al) k' sp' e') m'
  | match_builtin_2: forall v v' optid f sp e k m sp' e' m' k',
      match_cont j k k' ->
      (*Val.lessdef v v' -> env_lessdef e e' -> Mem.extends m m' ->*)
      val_inject j v v' -> env_inject j e e' -> Mem.inject j m m' -> sp_preserved j sp sp' ->
      match_states j
        (CMin_Returnstate v (Cminor.Kcall optid f sp e k)) m
        (CMinSel_State (sel_function hf ge f) Sskip k' sp' (set_optvar optid v' e')) m'.Inductive match_states (j:meminj) : CMin_core -> mem -> CMinSel_core -> mem -> Prop :=
  | match_state: forall f s k s' k' sp e m sp' e' m',
      s' = sel_stmt hf ge s ->
      match_cont j k k' ->
      (*      env_lessdef e e' -> Mem.extends m m' ->*)
      env_inject j e e' -> Mem.inject j m m' -> sp_preserved j sp sp' ->
      match_states j
        (CMin_State f s k sp e) m
        (CMinSel_State (sel_function hf ge f) s' k' sp' e') m'
  | match_callstate: forall f args args' k k' m m',
      match_cont j k k' ->
      (*      Val.lessdef_list args args' -> Mem.extends m m' ->*)
      val_list_inject j args args' -> Mem.inject j m m' ->
      match_states j
        (CMin_Callstate f args k) m
        (CMinSel_Callstate (sel_fundef hf ge f) args' k') m'
  | match_returnstate: forall v v' k k' m m',
      match_cont j k k' ->
      (*Val.lessdef v v' -> Mem.extends m m' ->*)
      val_inject j v v' -> Mem.inject j m m' ->
      match_states j
        (CMin_Returnstate v k) m
        (CMinSel_Returnstate v' k') m'
  | match_builtin_1: forall ef args args' optid f sp e k m al sp' e' k' m',
      match_cont j k k' ->
      (*Val.lessdef_list args args' -> env_lessdef e e' -> Mem.extends m m' -> *)
      val_list_inject j args args' -> env_inject j e e' -> Mem.inject j m m' ->
      sp_preserved j sp sp' ->
      CminorSel.eval_exprlist tge sp' e' m' nil al args' ->
      match_states j
        (CMin_Callstate (External ef) args (Cminor.Kcall optid f sp e k)) m
        (CMinSel_State (sel_function hf ge f) (Sbuiltin optid ef al) k' sp' e') m'
  | match_builtin_2: forall v v' optid f sp e k m sp' e' m' k',
      match_cont j k k' ->
      (*Val.lessdef v v' -> env_lessdef e e' -> Mem.extends m m' ->*)
      val_inject j v v' -> env_inject j e e' -> Mem.inject j m m' -> sp_preserved j sp sp' ->
      match_states j
        (CMin_Returnstate v (Cminor.Kcall optid f sp e k)) m
        (CMinSel_State (sel_function hf ge f) Sskip k' sp' (set_optvar optid v' e')) m'.Inductive match_states (j:meminj) : CMin_core -> mem -> CMinSel_core -> mem -> Prop :=
  | match_state: forall f s k s' k' sp e m sp' e' m',
      s' = sel_stmt hf ge s ->
      match_cont j k k' ->
      (*      env_lessdef e e' -> Mem.extends m m' ->*)
      env_inject j e e' -> Mem.inject j m m' -> sp_preserved j sp sp' ->
      match_states j
        (CMin_State f s k sp e) m
        (CMinSel_State (sel_function hf ge f) s' k' sp' e') m'
  | match_callstate: forall f args args' k k' m m',
      match_cont j k k' ->
      (*      Val.lessdef_list args args' -> Mem.extends m m' ->*)
      val_list_inject j args args' -> Mem.inject j m m' ->
      match_states j
        (CMin_Callstate f args k) m
        (CMinSel_Callstate (sel_fundef hf ge f) args' k') m'
  | match_returnstate: forall v v' k k' m m',
      match_cont j k k' ->
      (*Val.lessdef v v' -> Mem.extends m m' ->*)
      val_inject j v v' -> Mem.inject j m m' ->
      match_states j
        (CMin_Returnstate v k) m
        (CMinSel_Returnstate v' k') m'
  | match_builtin_1: forall ef args args' optid f sp e k m al sp' e' k' m',
      match_cont j k k' ->
      (*Val.lessdef_list args args' -> env_lessdef e e' -> Mem.extends m m' -> *)
      val_list_inject j args args' -> env_inject j e e' -> Mem.inject j m m' ->
      sp_preserved j sp sp' ->
      CminorSel.eval_exprlist tge sp' e' m' nil al args' ->
      match_states j
        (CMin_Callstate (External ef) args (Cminor.Kcall optid f sp e k)) m
        (CMinSel_State (sel_function hf ge f) (Sbuiltin optid ef al) k' sp' e') m'
  | match_builtin_2: forall v v' optid f sp e k m sp' e' m' k',
      match_cont j k k' ->
      (*Val.lessdef v v' -> env_lessdef e e' -> Mem.extends m m' ->*)
      val_inject j v v' -> env_inject j e e' -> Mem.inject j m m' -> sp_preserved j sp sp' ->
      match_states j
        (CMin_Returnstate v (Cminor.Kcall optid f sp e k)) m
        (CMinSel_State (sel_function hf ge f) Sskip k' sp' (set_optvar optid v' e')) m'.Definition Match_cores (d:CMin_core) mu c1 m1 c2 m2:Prop :=
  match_states (restrict (as_inj mu) (vis mu)) c1 m1 c2 m2 /\
  REACH_closed m1 (vis mu) /\
  meminj_preserves_globals ge (as_inj mu) /\
  globalfunction_ptr_inject (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.

Lemma match_cont_sub: forall j k k' (K: match_cont j k k') j' (I: inject_incr j j'), match_cont j' k k'.