Module Cshmannotgenproof

Require Import Coqlib.
Require Import Errors.
Require Import Maps.
Require Import Integers.
Require Import Floats.
Require Import AST.
Require Import Values.
Require Import Events.
Require Import Memory.
Require Import Globalenvs.
Require Import Smallstep.
Require Import Csharpminor.
Require Import Csharpminorannot.
Require Import Cshmannotgen.

Section CORRECTNESS.

Variable prog: Csharpminor.program.
Variable tprog: Csharpminorannot.program.

Hypothesis TRANSL: transl_program prog = OK tprog.
Definition ge := Genv.globalenv prog.
Definition tge := Genv.globalenv tprog.

Inductive tr_fundef: Csharpminor.fundef -> fundef -> Prop :=
| tr_internal: forall f tf n1 n2,
                 transl_function f n1 = OK (n2, tf) ->
                 tr_fundef (Internal f) (Internal tf)
| tr_external: forall ef,
                 tr_fundef (External ef) (External ef).

Lemma transl_globdefs_spec:
  forall l n l',
    transl_globdefs l n = OK l' ->
    list_forall2 (match_globdef tr_fundef (fun v1 v2 => v1 = v2)) l l'.
Proof.
  induction l; simpl; intros.
  - inv H. constructor.
  - destruct a as [id g]. destruct g.
    + monadInv H.
      econstructor.
      * econstructor. unfold transl_fundef in EQ.
        destruct f.
        { monadInv EQ. econstructor; eauto. }
        { inv EQ. econstructor; eauto. }
      * eapply IHl; eauto.
    + monadInv H. econstructor; eauto.
      destruct v. constructor. reflexivity.
Qed.

Lemma transl_program_spec:
  forall p tp,
  transl_program p = OK tp ->
  match_program tr_fundef (fun v1 v2 => v1 = v2) nil p.(prog_main) p tp.
Proof.
  unfold transl_program; intros.
  monadInv H. destruct (list_norepet_dec peq (map fst x)); inv EQ0. econstructor; simpl; auto.
  eapply transl_globdefs_spec in EQ.
  exists x. split; try assumption.
  rewrite <- app_nil_end; auto.
Qed.

Lemma symbols_preserved:
  forall s, Genv.find_symbol tge s = Genv.find_symbol ge s.
Proof.
  intros. eapply Genv.find_symbol_match.
  eapply transl_program_spec; eauto.
  simpl; tauto.
Qed.

Lemma function_ptr_translated:
  forall (b: block) (f: Csharpminor.fundef),
  Genv.find_funct_ptr ge b = Some f ->
  exists tf, Genv.find_funct_ptr tge b = Some tf /\ tr_fundef f tf.
Proof.
  intros. eapply Genv.find_funct_ptr_match.
  - eapply transl_program_spec; eauto.
  - assumption.
Qed.

Lemma functions_translated:
  forall (v: val) (f: Csharpminor.fundef),
  Genv.find_funct ge v = Some f ->
  exists tf, Genv.find_funct tge v = Some tf /\ tr_fundef f tf.
Proof.
  intros. eapply Genv.find_funct_match.
  - eapply transl_program_spec; eauto.
  - assumption.
Qed.

Lemma public_preserved:
  forall (s: ident), Genv.public_symbol tge s = Genv.public_symbol ge s.
Proof.
  intros. eapply Genv.public_symbol_match.
  - eapply transl_program_spec; eauto.
  - simpl. tauto.
Qed.

Lemma varinfo_preserved:
  forall b, Genv.find_var_info tge b = Genv.find_var_info ge b.
Proof.
  intros. destruct (Genv.find_var_info ge b) as [v|] eqn: V.
  - exploit Genv.find_var_info_match.
    + eapply transl_program_spec; eauto.
    + exact V.
    + intros [tv [A B]]. inv B. assumption.
  - destruct (Genv.find_var_info tge b) as [v'|] eqn:V'; auto.
    exploit Genv.find_var_info_rev_match. eapply transl_program_spec; eauto. eassumption.
    simpl. destruct (plt b (Genv.genv_next (Genv.globalenv prog))); try tauto.
    intros [v [A B]]. inv B. unfold ge in V. congruence.
Qed.

Lemma init_mem_preserved:
  forall m,
    Genv.init_mem prog = Some m ->
    Genv.init_mem tprog = Some m.
Proof.
  intros.
  erewrite Genv.init_mem_match.
  + instantiate (2 := m). instantiate (1 := nil).
    simpl. auto.
  + eapply transl_program_spec; eauto.
  + simpl; intros; assumption.
  + assumption.
Qed.

Lemma sig_preserved:
  forall fd tfd,
    tr_fundef fd tfd ->
    Csharpminor.funsig fd = funsig tfd.
Proof.
  induction fd; intros.
  - inv H. simpl. monadInv H1. simpl. auto.
  - inv H. simpl. auto.
Qed.

Lemma tr_fundef_transl_fundef:
  forall fd tfd,
    tr_fundef fd tfd ->
    exists n1 n2, transl_fundef fd n1 = OK (n2, tfd).
Proof.
  destruct fd; intros.
  - inv H. exists n1. exists n2; simpl; rewrite H1; auto.
  - inv H. econstructor. econstructor. simpl; eauto.
    Grab Existential Variables.
    eapply 1%positive.
Qed.

Section EVAL_EXPR.

  Lemma eval_var_addr_preserved:
    forall e id b,
      Csharpminor.eval_var_addr ge e id b ->
      eval_var_addr tge e id b.
Proof.
    induction 1; intros.
    - econstructor; eauto.
    - econstructor 2; eauto; rewrite symbols_preserved; eauto.
  Qed.

  Lemma eval_expr_preserved:
    forall e le m a v,
      Csharpminor.eval_expr ge e le m a v ->
      forall ta n1 n2, transl_expr a n1 = OK (n2, ta) ->
                    eval_expr tge e le m (expr_erase ta) v.
Proof.
    induction 1; intros.
    - monadInv H0. econstructor; auto.
    - monadInv H0. econstructor; auto.
      eapply eval_var_addr_preserved; eauto.
    - monadInv H0. econstructor; auto.
    - monadInv H1. econstructor; eauto.
    - monadInv H2. econstructor; eauto.
    - monadInv H1. econstructor; eauto.
  Qed.

  Lemma eval_exprlist_preserved:
    forall e le m al vl,
      Csharpminor.eval_exprlist ge e le m al vl ->
      forall tal n1 n2, transl_exprlist al n1 = OK (n2, tal) ->
                   eval_exprlist tge e le m (List.map expr_erase tal) vl.
Proof.
    induction 1; intros.
    - monadInv H; econstructor; eauto.
    - monadInv H1. econstructor; eauto.
      eapply eval_expr_preserved; eauto.
  Qed.

End EVAL_EXPR.

Lemma transl_lstatement_select_switch_case:
  forall ls ls' ls1 n m m',
    transl_lstatement ls m = OK (m', ls') ->
    Csharpminor.select_switch_case n ls = Some ls1 ->
    exists m'' ls2,
      select_switch_case n ls' = Some ls2 /\
      transl_lstatement ls1 m'' = OK (m', ls2).
Proof.
  induction ls; intros.
  - simpl in H0. inv H0.
  - monadInv H. destruct o.
    + simpl in H0. simpl. destruct (zeq z n).
      * inv H0. simpl. exists m. econstructor; split.
        { reflexivity. }
        { rewrite EQ; simpl. rewrite EQ1; simpl. reflexivity. }
      * eapply IHls; eauto.
    + simpl. simpl in H0.
      eapply IHls; eauto.
Qed.

Lemma transl_lstatement_select_switch_case_none:
  forall ls ls' n m m',
    transl_lstatement ls m = OK (m', ls') ->
    Csharpminor.select_switch_case n ls = None ->
    select_switch_case n ls' = None.
Proof.
  induction ls; intros.
  - simpl in H; inv H. simpl; reflexivity.
  - monadInv H. simpl in H0. destruct o.
    + simpl. destruct (zeq z n).
      * inv H0.
      * eapply IHls; eauto.
    + simpl; eapply IHls; eauto.
Qed.

Lemma transl_lstatement_select_switch:
  forall ls ls' n m m',
    transl_lstatement ls m = OK (m', ls') ->
    exists m'', transl_lstatement (Csharpminor.select_switch n ls) m'' = OK (m', select_switch n ls').
Proof.
  induction ls; intros.
  - exists m'; simpl in *; inv H; eauto.
  - monadInv H. destruct o.
    + unfold select_switch, Csharpminor.select_switch.
      simpl. destruct (zeq z n).
      * exists m. simpl; rewrite EQ.
        simpl. rewrite EQ1. simpl. reflexivity.
      * eapply IHls in EQ1. eexact EQ1.
    + unfold select_switch, Csharpminor.select_switch.
      simpl. case_eq (Csharpminor.select_switch_case n ls); intros.
      * generalize (transl_lstatement_select_switch_case _ _ _ _ _ _ EQ1 H).
        intros [m'' [ls2 [A B]]]. exists m''. rewrite B. rewrite A. reflexivity.
      * generalize (transl_lstatement_select_switch_case_none _ _ _ _ _ EQ1 H).
        intros A. rewrite A. simpl. exists m. rewrite EQ. simpl. rewrite EQ1; simpl. reflexivity.
Qed.

Lemma transl_statement_seq_of_lbl_stmt:
  forall ls ls' m m',
    transl_lstatement ls m = OK (m', ls') ->
    transl_statement (Csharpminor.seq_of_lbl_stmt ls) m = OK (m', seq_of_lbl_stmt ls').
Proof.
  induction ls; intros.
  - simpl in H; inv H. simpl. reflexivity.
  - monadInv H. simpl. rewrite EQ; simpl.
    eapply IHls in EQ1. rewrite EQ1. simpl. reflexivity.
Qed.

Lemma transl_statement_seq_of_lbl_statements:
  forall ls ls' n m m',
    transl_lstatement ls m = OK (m', ls') ->
    exists m'', transl_statement (Csharpminor.seq_of_lbl_stmt (Csharpminor.select_switch n ls)) m'' = OK (m', seq_of_lbl_stmt (select_switch n ls')).
Proof.
  intros. generalize (transl_lstatement_select_switch _ _ n _ _ H). intros [m'' A].
  eexists. eapply transl_statement_seq_of_lbl_stmt.
  rewrite <- A. reflexivity.
Qed.

Inductive match_cont: Csharpminor.cont -> Csharpminorannot.cont -> list (ident * env) -> Prop :=
| match_stop:
    match_cont Csharpminor.Kstop Kstop nil
| match_seq:
    forall s ts k tk stk n m,
      transl_statement s n = OK (m, ts) ->
      match_cont k tk stk ->
      match_cont (Csharpminor.Kseq s k) (Kseq ts tk) stk
| match_block:
    forall k tk stk,
      match_cont k tk stk ->
      match_cont (Csharpminor.Kblock k) (Kblock tk) stk
| match_call:
    forall optid f tf e le k tk nm stk n m,
      transl_function f n = OK (m, tf) ->
      match_cont k tk stk ->
      match_cont (Csharpminor.Kcall optid f e le k) (Kcall optid tf e le tk) ((nm, e)::stk).

Inductive match_states: Csharpminor.state -> Csharpminorannot.state -> Prop :=
| match_regular_states:
    forall f tf s ts k tk e le m stk n1 n2 m1 m2
      (TF: transl_function f m1 = OK (m2, tf))
      (TS: transl_statement s n1 = OK (n2, ts))
      (MCONT: match_cont k tk stk),
      match_states (Csharpminor.State f s k e le m) (State tf ts tk e le m)
| match_call_states:
    forall fd tfd args k tk m stk n1 n2
      (TFD: transl_fundef fd n1 = OK (n2, tfd))
      (MCONT: match_cont k tk stk),
      match_states (Csharpminor.Callstate fd args k m) (Callstate tfd args tk m)
| match_return_states:
    forall v k tk m stk
      (MCONT: match_cont k tk stk),
      match_states (Csharpminor.Returnstate v k m) (Returnstate v tk m).

Lemma is_call_cont_preserved:
  forall k tk stk,
    Csharpminor.is_call_cont k ->
    match_cont k tk stk ->
    is_call_cont tk.
Proof.
  induction k; intros.
  - inv H0; eauto.
  - inv H.
  - inv H.
  - inv H0; eauto.
Qed.

Lemma match_cont_call_cont:
  forall k tk stk,
    match_cont k tk stk ->
    match_cont (Csharpminor.call_cont k) (call_cont tk) stk.
Proof.
  induction k; intros.
  - inv H; simpl; econstructor.
  - inv H. simpl; eauto.
  - inv H. simpl; eauto.
  - inv H. simpl; econstructor; eauto.
Qed.

Lemma find_label_none_transl_statement:
  forall lbl s ts k tk stk n1 n2,
    transl_statement s n1 = OK (n2, ts) ->
    Csharpminor.find_label lbl s k = None ->
    match_cont k tk stk ->
    find_label lbl ts tk = None
with find_label_ls_none_transl_lstatement:
           forall lbl s ts k tk stk n1 n2,
             transl_lstatement s n1 = OK (n2, ts) ->
             Csharpminor.find_label_ls lbl s k = None ->
             match_cont k tk stk ->
             find_label_ls lbl ts tk = None.
Proof.
  { clear find_label_none_transl_statement. induction s; intros; try (monadInv H; simpl; auto; fail).
    - monadInv H. simpl in H0. simpl.
      case_eq (Csharpminor.find_label lbl s1 (Csharpminor.Kseq s2 k)); intros.
      + destruct p. rewrite H in H0. inv H0.
      + rewrite H in H0.
        erewrite IHs1; eauto.
        econstructor; eauto.
    - monadInv H. simpl in H0.
      case_eq (Csharpminor.find_label lbl s1 k); intros.
      + destruct p. rewrite H in H0. inv H0.
      + rewrite H in H0. simpl. erewrite IHs1; eauto.
    - monadInv H. simpl in H0.
      simpl. eapply IHs; eauto. econstructor; eauto.
      simpl. instantiate (2 := n1). rewrite EQ. simpl. eauto.
    - monadInv H. simpl in H0.
      simpl. eapply IHs; eauto. econstructor; eauto.
    - monadInv H. simpl in H0. simpl.
      eapply find_label_ls_none_transl_lstatement; eauto.
    - destruct o; monadInv H; simpl; eauto.
    - monadInv H. simpl in H0. simpl. destruct (ident_eq lbl l). inv H0. eapply IHs; eauto. }
  { destruct s; intros.
    - monadInv H. simpl; auto.
    - monadInv H. simpl in H0. simpl.
      case_eq (Csharpminor.find_label lbl s (Csharpminor.Kseq (Csharpminor.seq_of_lbl_stmt s0) k)); intros.
      + destruct p; rewrite H in H0. inv H0.
      + rewrite H in H0. erewrite find_label_none_transl_statement; eauto.
        econstructor; eauto. eapply transl_statement_seq_of_lbl_stmt; eauto. }
Qed.

Lemma find_label_transl_statement:
  forall lbl s ts k tk s' k' stk n1 n2,
    transl_statement s n1 = OK (n2, ts) ->
    Csharpminor.find_label lbl s k = Some (s', k') ->
    match_cont k tk stk ->
    exists n3 n4 ts' tk', find_label lbl ts tk = Some (ts', tk') /\
                     transl_statement s' n3 = OK (n4, ts') /\
                     match_cont k' tk' stk
with find_label_ls_transl_statement:
  forall lbl s ts k tk s' k' stk n1 n2,
    transl_lstatement s n1 = OK (n2, ts) ->
    Csharpminor.find_label_ls lbl s k = Some (s', k') ->
    match_cont k tk stk ->
    exists n3 n4 ts' tk', find_label_ls lbl ts tk = Some (ts', tk') /\
                     transl_statement s' n3 = OK (n4, ts') /\
                     match_cont k' tk' stk.
Proof.
  { clear find_label_transl_statement.
    induction s; intros; try (simpl in H0; inv H0; fail).
    - monadInv H. simpl in H0.
      case_eq (Csharpminor.find_label lbl s1 (Csharpminor.Kseq s2 k)); intros.
      + rewrite H in H0. destruct p.
        simpl. exploit (IHs1 _ _ (Kseq x2 tk) _ _ stk _ _ EQ H).
        * econstructor; eauto.
        * intros [n3 [n4 [ts' [tk' [A [B C]]]]]].
          rewrite A. exists n3. exists n4. exists ts'. exists tk'. split; auto. inv H0. split; auto.
      + rewrite H in H0.
        simpl. generalize (IHs2 _ _ _ _ _ _ _ _ EQ1 H0 H1).
        intros [n3 [n4 [ts' [tk' [A [B C]]]]]].
        rewrite A.
        exploit (find_label_none_transl_statement lbl _ _ _ (Kseq x2 tk) stk _ _ EQ H).
        * econstructor; eauto.
        * intros D. rewrite D. repeat econstructor; eauto.
    - monadInv H. simpl in H0.
      case_eq (Csharpminor.find_label lbl s1 k); intros.
      + destruct p. rewrite H in H0. inv H0.
        simpl. generalize (IHs1 _ _ _ _ _ _ _ _ EQ1 H H1).
        intros [n3 [n4 [ts' [tk' [A [B C]]]]]].
        repeat econstructor; eauto. rewrite A; eauto.
      + rewrite H in H0. simpl. generalize (IHs2 _ _ _ _ _ _ _ _ EQ0 H0 H1).
        intros [n3 [n4 [ts' [tk' [A [B C]]]]]].
        exploit (find_label_none_transl_statement lbl _ _ _ tk stk _ _ EQ1 H); eauto.
        intros D. rewrite D. repeat econstructor; eauto.
    - monadInv H. simpl in H0. exploit IHs; eauto.
      econstructor; eauto. simpl; eauto. instantiate (2 := n1); rewrite EQ; simpl; eauto.
    - monadInv H. simpl in H0. exploit IHs; eauto.
      econstructor; eauto.
    - monadInv H. simpl in H0. simpl.
      eapply find_label_ls_transl_statement; eauto.
    - monadInv H. simpl in H0. simpl. destruct (ident_eq lbl l).
      + inv H0. repeat econstructor; eauto.
      + eapply IHs; eauto. }
  { destruct s; intros.
    - monadInv H. simpl in H0. inv H0.
    - monadInv H. simpl in H0. simpl.
      case_eq (Csharpminor.find_label lbl s (Csharpminor.Kseq (Csharpminor.seq_of_lbl_stmt s0) k)); intros.
      + destruct p. rewrite H in H0. inv H0.
        exploit find_label_transl_statement; eauto.
        * econstructor; eauto. eapply transl_statement_seq_of_lbl_stmt; eauto.
        * intros [n3 [n4 [ts' [tk' [A [B C]]]]]].
          rewrite A. repeat econstructor; eauto.
      + rewrite H in H0. exploit find_label_none_transl_statement; eauto.
        * econstructor; eauto. eapply transl_statement_seq_of_lbl_stmt; eauto.
        * intros A. rewrite A. eapply find_label_ls_transl_statement; eauto. }
Qed.

Lemma add_globals_preserves:
  forall P gl (ge: Genv.t fundef unit),
    (forall ge id g, P ge -> In (id, g) gl -> PTree.get id ge.(Genv.genv_symb) = None -> P (Genv.add_global ge (id, g))) ->
    (forall id g, In (id, g) gl -> PTree.get id ge.(Genv.genv_symb) = None) ->
    list_norepet (List.map fst gl) ->
    P ge ->
    P (Genv.add_globals ge gl).
Proof.
  induction gl; simpl; intros.
  - auto.
  - destruct a. apply IHgl; auto.
    + intros. unfold Genv.add_global; simpl. simpl in H0. inv H0.
      rewrite in_map_iff in H4. destruct (peq id p).
      * subst. exfalso. apply H4.
        exists (p, g0); split; auto.
      * rewrite PTree.gso; auto. eapply H. right; eauto.
    + inv H0; auto.
    + apply X; auto.
      eapply H; left; eauto.
Qed.

Lemma find_funct_ptr_inversion':
  forall b f,
  Genv.find_funct_ptr tge b = Some f ->
  exists id, Genv.find_symbol tge id = Some b.
Proof.
  intros until f. unfold tge. unfold Genv.globalenv.
  eapply add_globals_preserves.
  - intros. unfold Genv.find_funct_ptr in H2. unfold Genv.add_global in H2. simpl in H2.
    destruct g.
    + destruct (peq b (Genv.genv_next ge0)).
      * subst b. rewrite PTree.gss in H2. inv H2.
        exists id. unfold Genv.find_symbol; unfold Genv.add_global; simpl.
        rewrite PTree.gss; auto.
      * rewrite PTree.gso in H2; auto.
        apply H in H2. destruct H2 as [id' A].
        exists id'. destruct (peq id id').
        { subst id'; unfold Genv.find_symbol in A; rewrite A in H1; inv H1. }
        { unfold Genv.find_symbol; unfold Genv.add_global; simpl. rewrite PTree.gso; auto. }
    + eapply H in H2. destruct H2 as [id' A].
      exists id'. unfold Genv.find_symbol; unfold Genv.add_global; simpl. rewrite PTree.gso; auto.
      unfold not; intros. unfold Genv.find_symbol in A. subst id'; rewrite A in H1; inv H1.
  - intros. unfold Genv.empty_genv; simpl. eapply PTree.gempty.
  - monadInv TRANSL. destruct (list_norepet_dec peq (map fst x)); monadInv EQ0; auto.
  - intros. unfold Genv.empty_genv in H. unfold Genv.find_funct_ptr in H; simpl in H. rewrite PTree.gempty in H; inv H.
Qed.

Lemma initial_states_simulation:
  forall S, Csharpminor.initial_state prog S ->
       exists R, initial_state tprog R /\ match_states S R.
Proof.
  intros; inv H.
  replace ge0 with ge in *; auto.
  exploit function_ptr_translated; eauto. intros [tf [FIND TRF]].
  remember TRF. clear Heqt.
  inv t.
  { econstructor; split.
    - econstructor.
      + rewrite <- init_mem_preserved; eauto.
      + rewrite symbols_preserved. monadInv TRANSL.
        destruct (list_norepet_dec peq (map fst x)); monadInv EQ0; simpl. eauto.
      + eapply FIND.
      + rewrite <- (sig_preserved (Internal f0) (Internal tf0)); auto.
    - econstructor; eauto.
      instantiate (2 := n1). simpl. rewrite H. simpl. reflexivity.
      econstructor; eauto. }
  { econstructor; split.
    - econstructor.
      + rewrite <- init_mem_preserved; eauto.
      + rewrite symbols_preserved. monadInv TRANSL.
        destruct (list_norepet_dec peq (map fst x)); monadInv EQ0; simpl. eauto.
      + eapply FIND.
      + rewrite <- (sig_preserved (External ef) (External ef)); auto.
    - econstructor; eauto. simpl. eauto.
      econstructor; eauto. }
Grab Existential Variables. eapply b.
Qed.

Lemma final_states_simulation:
  forall S R r,
    match_states S R ->
    Csharpminor.final_state S r ->
    final_state R r.
Proof.
  intros. inv H0. inv H. inv MCONT. econstructor.
Qed.

Lemma step_simulation:
  forall s1 t s1',
    Csharpminor.step ge s1 t s1' ->
    forall s2, match_states s1 s2 ->
          exists s2', step tge s2 t s2' /\ match_states s1' s2'.
Proof.
  induction 1; intros.
  - inv H; monadInv TS; inv MCONT.
    econstructor; split.
    + econstructor.
    + econstructor; eauto.
  - inv H; monadInv TS; inv MCONT.
    econstructor; split.
    + econstructor.
    + econstructor; eauto. simpl. reflexivity.
  - inv H1. monadInv TS.
    econstructor; split.
    + econstructor; eauto.
      eapply is_call_cont_preserved; eauto.
    + econstructor; eauto.
  - inv H0. monadInv TS.
    econstructor; split.
    + econstructor; eauto. eapply eval_expr_preserved; eauto.
    + econstructor; eauto. simpl. reflexivity.
  - inv H2. monadInv TS.
    econstructor; split.
    + econstructor; eauto.
      * eapply eval_expr_preserved; eauto.
      * eapply eval_expr_preserved; eauto.
    + econstructor; eauto. simpl. reflexivity.
  - inv H3. monadInv TS.
    exploit functions_translated; eauto. intros [tfd [FIND TRANSF]].
    generalize (tr_fundef_transl_fundef fd tfd TRANSF). intros [u [v A]].
    econstructor; split.
    + econstructor; eauto.
      * eapply eval_expr_preserved; eauto.
      * eapply eval_exprlist_preserved; eauto.
      * rewrite (sig_preserved fd tfd TRANSF). auto.
    + econstructor; eauto. econstructor; eauto.
  - inv H1. monadInv TS.
    econstructor; split.
    + econstructor; eauto.
      * eapply eval_exprlist_preserved; eauto.
      * eapply external_call_symbols_preserved; eauto.
        { eapply symbols_preserved. }
        { eapply public_preserved. }
        { eapply varinfo_preserved. }
    + econstructor; eauto. econstructor; eauto.
  - inv H. monadInv TS.
    econstructor; split.
    + econstructor; eauto.
    + econstructor; eauto.
      econstructor; eauto.
  - inv H1. monadInv TS.
    econstructor; split.
    + econstructor; eauto.
      eapply eval_expr_preserved; eauto.
    + destruct b; econstructor; eauto.
  - inv H. monadInv TS.
    econstructor; split.
    + econstructor; eauto.
    + econstructor; eauto.
      econstructor; eauto.
      instantiate (1 := n2). instantiate (1 := n1).
      simpl; rewrite EQ. simpl. reflexivity.
  - inv H. monadInv TS.
    econstructor; split.
    + econstructor; eauto.
    + econstructor; eauto.
      econstructor; eauto.
  - inv H. monadInv TS. inv MCONT.
    econstructor; split.
    + eapply step_exit_seq; eauto.
    + econstructor; eauto. simpl; eauto.
  - inv H. monadInv TS. inv MCONT.
    econstructor; split.
    + econstructor; eauto.
    + econstructor; eauto. reflexivity.
  - inv H. monadInv TS. inv MCONT.
    econstructor; split.
    + econstructor; eauto.
    + econstructor; eauto. reflexivity.
  - inv H1. monadInv TS.
    econstructor; split.
    + econstructor; eauto.
      eapply eval_expr_preserved; eauto.
    + generalize (transl_statement_seq_of_lbl_statements _ _ n _ _ EQ1). intros [m'' A].
      econstructor; eauto.
  - inv H0. monadInv TS.
    econstructor; split.
    + econstructor; eauto.
    + econstructor; eauto.
      eapply match_cont_call_cont; eauto.
  - inv H1. monadInv TS.
    econstructor; split.
    + econstructor; eauto. eapply eval_expr_preserved; eauto.
    + econstructor; eauto. eapply match_cont_call_cont; eauto.
  - inv H. monadInv TS.
    econstructor; split.
    + econstructor; eauto.
    + econstructor; eauto.
  - inv H0. monadInv TS.
    remember TF. clear Heqe0.
    unfold transl_function in TF. monadInv TF.
    exploit find_label_transl_statement; eauto.
    + eapply match_cont_call_cont; eauto.
    + intros [n3 [n4 [ts' [tk' [A [B C]]]]]].
      econstructor; split.
      * econstructor; eauto.
      * econstructor; eauto.
  - inv H4. monadInv TFD.
    monadInv EQ.
    econstructor; split.
    + econstructor; eauto.
    + econstructor; eauto. unfold transl_function. instantiate (2 := n1). rewrite EQ0; simpl. eauto.
  - inv H0. monadInv TFD.
    econstructor; split.
    + econstructor; eauto.
      eapply external_call_symbols_preserved; eauto.
      * eapply symbols_preserved.
      * eapply public_preserved.
      * eapply varinfo_preserved.
    + econstructor; eauto.
  - inv H. inv MCONT. econstructor; split.
    + econstructor; eauto.
    + econstructor; eauto.
      instantiate (1 := n). reflexivity.
Grab Existential Variables.
apply m1. apply m1. apply n0. apply m1. apply n1. apply n1. apply m1. exact 42%positive.
Qed.

Theorem transl_program_correct:
  forward_simulation (Csharpminor.semantics prog) (Csharpminorannot.semantics tprog).
Proof.
  eapply forward_simulation_step; eauto.
  - eapply public_preserved.
  - eapply initial_states_simulation.
  - eapply final_states_simulation.
  - eapply step_simulation.
Qed.

End CORRECTNESS.