Module ControlFlowGraphFlatteningproof

Require Import Clight.
Require Import AST.
Require Import Integers.
Require Import Ctypes.
Require Import Maps.
Require Import Cop.
Require Import Coqlib.
Require Import Smallstep.
Require Import Errors.
Require Import Globalenvs.
Require Import Values.
Require Import Memory.
Require Import Events.

Require Import ControlFlowGraphFlattening.
Open Scope error_monad_scope.

Semantics preservation proof for the Control Flow Graph Flattening transformation

Shorthand definition for the type of unsigned 32 bits integers
Definition tint := Tint I32 Unsigned noattr.

Section Utils.

phi is the numerotation function
Variable phi: Z -> Int.int.

not_in_expr id e indicates that identifier id doesn't appear in expression e
Inductive not_in_expr (id: ident): expr -> Prop :=
  | not_in_int:
      forall i t,
        not_in_expr id (Econst_int i t)
  | not_in_float:
      forall f t,
        not_in_expr id (Econst_float f t)
  | not_in_single:
      forall s t,
        not_in_expr id (Econst_single s t)
  | not_in_long:
      forall l t,
        not_in_expr id (Econst_long l t)
  | not_in_var:
      forall v t,
        id <> v ->
        not_in_expr id (Evar v t)
  | not_in_tempvar:
      forall v t,
        id <> v ->
        not_in_expr id (Etempvar v t)
  | not_in_deref:
      forall e t,
      not_in_expr id e ->
      not_in_expr id (Ederef e t)
  | not_in_addrof:
      forall e t,
      not_in_expr id e ->
      not_in_expr id (Eaddrof e t)
  | not_in_unop:
      forall op e t,
      not_in_expr id e ->
      not_in_expr id (Eunop op e t)
  | not_in_binop:
      forall op e1 e2 t,
      not_in_expr id e1 ->
      not_in_expr id e2 ->
      not_in_expr id (Ebinop op e1 e2 t)
  | not_in_cast:
      forall e t,
        not_in_expr id e ->
        not_in_expr id (Ecast e t)
  | not_in_field:
      forall e f t,
        not_in_expr id e ->
        id <> f ->
        not_in_expr id (Efield e f t)
  | not_in_sizeof:
      forall t1 t2,
        not_in_expr id (Esizeof t1 t2)
  | not_in_alignof:
      forall t1 t2,
        not_in_expr id (Ealignof t1 t2).

not_in_stmt id s indicates that identifier id doesn't appear in statement s
Inductive not_in_stmt (id: ident): statement -> Prop :=
  | not_in_skip: not_in_stmt id Sskip
  | not_in_assign:
      forall e1 e2,
        not_in_expr id e1 ->
        not_in_expr id e2 ->
        not_in_stmt id (Sassign e1 e2)
  | not_in_set:
      forall i e,
        i <> id ->
        not_in_expr id e ->
        not_in_stmt id (Sset i e)
  | not_in_call_some:
      forall v e el,
        v <> id ->
        not_in_expr id e ->
        (forall e', In e' el -> not_in_expr id e') ->
        not_in_stmt id (Scall (Some v) e el)
  | not_in_call_none:
      forall e el,
        not_in_expr id e ->
        (forall e', In e' el -> not_in_expr id e') ->
        not_in_stmt id (Scall None e el)
  | not_in_builtin_some:
      forall v ef tl el,
        v <> id ->
        (forall e, In e el -> not_in_expr id e) ->
        not_in_stmt id (Sbuiltin (Some v) ef tl el)
  | not_in_builtin_none:
      forall ef tl el,
        (forall e, In e el -> not_in_expr id e) ->
        not_in_stmt id (Sbuiltin None ef tl el)
  | not_in_sequence:
      forall s1 s2,
        not_in_stmt id s1 ->
        not_in_stmt id s2 ->
        not_in_stmt id (Ssequence s1 s2)
  | not_in_ifthenelse:
      forall e s1 s2,
        not_in_expr id e ->
        not_in_stmt id s1 ->
        not_in_stmt id s2 ->
        not_in_stmt id (Sifthenelse e s1 s2)
  | not_in_loop:
      forall s1 s2,
        not_in_stmt id s1 ->
        not_in_stmt id s2 ->
        not_in_stmt id (Sloop s1 s2)
  | not_in_break:
      not_in_stmt id Sbreak
  | not_in_continue:
      not_in_stmt id Scontinue
  | not_in_return_some:
      forall e,
        not_in_expr id e ->
        not_in_stmt id (Sreturn (Some e))
  | not_in_return_none:
      not_in_stmt id (Sreturn None)
  | not_in_switch:
      forall e ls,
        not_in_expr id e ->
        not_in_lstmt id ls ->
        not_in_stmt id (Sswitch e ls)
  | not_in_label:
      forall l s,
        not_in_stmt id s ->
        not_in_stmt id (Slabel l s)
  | not_in_goto_some:
      forall l,
      not_in_stmt id (Sgoto l)
not_in_lstmt id ls indicates that identifier id doesn't appear in labeled statement ls
with not_in_lstmt (id: ident): labeled_statements -> Prop :=
     | not_in_nil:
         not_in_lstmt id LSnil
     | not_in_cons:
         forall l s ls,
           not_in_stmt id s ->
           not_in_lstmt id ls ->
           not_in_lstmt id (LScons l s ls).

Lemma ple_max_ident:
  forall e id,
    Ple id (max_ident_in_expr e id).
Proof.
induction e; intros; try (simpl; auto; xomega; fail).
- simpl; destruct (plt id i); xomega.
- simpl; destruct (plt id i); xomega.
- simpl; apply Ple_trans with (max_ident_in_expr e1 id); auto.
- simpl; destruct (plt id i); auto.
  apply Ple_trans with i; auto; xomega.
Qed.

Lemma max_ident_in_expr_monotone:
  forall e id1 id2,
    Ple id1 id2 ->
    Ple (max_ident_in_expr e id1) (max_ident_in_expr e id2).
Proof.
induction e; intros; try (simpl; auto; xomega; fail).
- simpl; destruct (plt id1 i); destruct (plt id2 i); xomega.
- simpl; destruct (plt id1 i); destruct (plt id2 i); xomega.
- simpl; destruct (plt id1 i); destruct (plt id2 i); try xomega.
  + apply IHe; xomega.
  + apply IHe; auto.
Qed.

Lemma ple_fold_max_ident:
  forall l i,
    Ple i (fold_right max_ident_in_expr i l).
Proof.
induction l; intros.
- simpl; xomega.
- simpl.
  generalize (max_ident_in_expr_monotone a i (fold_right max_ident_in_expr i l) (IHl i)); intros.
  generalize (ple_max_ident a i); intros; xomega.
Qed.

Lemma max_ident_in_expr_fold_monotone:
  forall l id1 id2,
    Ple id1 id2 ->
    Ple (fold_right max_ident_in_expr id1 l) (fold_right max_ident_in_expr id2 l).
Proof.
induction l; intros.
- simpl; xomega.
- simpl; eapply max_ident_in_expr_monotone; eauto.
Qed.

Any identifier strictly greater than max_ident_in_expr e 1%positive doesn't appear in e
Theorem not_in_expr_trans:
  forall e id,
    Plt (max_ident_in_expr e 1%positive) id ->
    not_in_expr id e.
Proof.
induction e; intros; try (constructor; auto; fail); simpl in H.
- destruct (plt 1 i).
  + econstructor; eauto.
    eapply Plt_ne in H; eauto.
  + econstructor; eauto.
    assert (Ple i 1) by xomega.
    assert (Plt i id) by xomega.
    eapply Plt_ne in H1; eauto.
- destruct (plt 1 i).
  + econstructor; eauto.
    eapply Plt_ne in H; eauto.
  + econstructor; eauto.
    assert (Ple i 1) by xomega.
    assert (Plt i id) by xomega.
    eapply Plt_ne in H1; eauto.
- econstructor; eauto.
  + eapply IHe1.
    generalize (ple_max_ident e2 (max_ident_in_expr e1 1%positive)).
    intros; xomega.
  + eapply IHe2.
    generalize (max_ident_in_expr_monotone e2 1%positive (max_ident_in_expr e1 1%positive) (ple_max_ident e1 1%positive)).
    intros; xomega.
- destruct (plt 1 i).
  + econstructor; eauto.
    * eapply IHe.
      generalize (max_ident_in_expr_monotone e 1%positive i (Plt_Ple 1%positive i p)).
      intros; xomega.
    * generalize (ple_max_ident e i); intros.
      assert (Plt i id) by xomega.
      eapply Plt_ne in H1; eauto.
  + econstructor; eauto.
    generalize (ple_max_ident e i); intros.
    assert (Ple i 1) by xomega.
    generalize (max_ident_in_expr_monotone e i 1 H1); intros.
    assert (Plt i id) by xomega.
    eapply Plt_ne in H3; eauto.
Qed.

Theorem not_in_expr_trans_fold:
  forall l i id,
    Plt (fold_right max_ident_in_expr i l) id ->
    forall e, In e l -> not_in_expr id e.
Proof.
induction l; intros.
- inversion H0.
- destruct H0 as [H0 | H0].
  + subst a; exploit not_in_expr_trans; eauto.
    simpl in H.
    assert (Ple 1 (fold_right max_ident_in_expr i l)) by xomega.
    generalize (max_ident_in_expr_monotone e 1 (fold_right max_ident_in_expr i l) H0); intros.
    xomega.
  + eapply IHl; eauto.
    simpl in H.
    generalize (ple_max_ident a (fold_right max_ident_in_expr i l)); intros.
    assert (Plt (fold_right max_ident_in_expr i l) id) by xomega.
    exact H2.
Qed.

Lemma ple_max_ident_stmt:
  forall s id,
    Ple id (max_ident_in_stmt s id)
with ple_max_ident_lstmt:
       forall ls id,
         Ple id (max_ident_in_lstmt ls id).
Proof.
{ destruct s; intros; try (simpl; auto; xomega; fail).
  - simpl; generalize (ple_max_ident e id); intros.
    generalize (ple_max_ident e0 (max_ident_in_expr e id)); intros; xomega.
  - simpl; destruct (plt id i).
    + generalize (ple_max_ident e i); intros; xomega.
    + eapply ple_max_ident; eauto.
  - simpl; destruct o.
    + destruct (plt id i).
      * generalize (ple_max_ident e (fold_right max_ident_in_expr i l)); intros.
        generalize (ple_fold_max_ident l i); intros.
        xomega.
      * generalize (ple_max_ident e (fold_right max_ident_in_expr id l)); intros.
        generalize (ple_fold_max_ident l id); intros; xomega.
    + generalize (ple_max_ident e (fold_right max_ident_in_expr id l)); intros.
      generalize (ple_fold_max_ident l id); intros; xomega.
  - simpl; destruct o.
    + destruct (plt id i).
      * generalize (ple_fold_max_ident l i); intros; xomega.
      * eapply ple_fold_max_ident; eauto.
    + eapply ple_fold_max_ident; eauto.
  - simpl; transitivity (max_ident_in_stmt s1 id); auto.
  - simpl; generalize (ple_max_ident e id); intros.
    transitivity (max_ident_in_expr e id); auto.
    transitivity (max_ident_in_stmt s1 (max_ident_in_expr e id)); auto.
  - simpl; transitivity (max_ident_in_stmt s1 id); auto.
  - simpl; destruct o; try xomega.
    eapply ple_max_ident; eauto.
  - simpl; transitivity (max_ident_in_expr e id); auto.
    eapply ple_max_ident; eauto. }
{ destruct ls; intros; simpl; try xomega.
  transitivity (max_ident_in_stmt s id); auto. }
Qed.

Lemma max_ident_in_stmt_monotone:
  forall s id1 id2,
    Ple id1 id2 ->
    Ple (max_ident_in_stmt s id1) (max_ident_in_stmt s id2)
with max_ident_in_lstmt_monotone:
       forall ls id1 id2,
         Ple id1 id2 ->
         Ple (max_ident_in_lstmt ls id1) (max_ident_in_lstmt ls id2).
Proof.
{ destruct s; intros; simpl; try (auto; xomega; fail).
  - eapply max_ident_in_expr_monotone; eauto.
    eapply max_ident_in_expr_monotone; eauto.
  - destruct (plt id1 i); destruct (plt id2 i); try xomega.
    + eapply max_ident_in_expr_monotone; eauto; xomega.
    + eapply max_ident_in_expr_monotone; eauto.
  - destruct o.
    + destruct (plt id1 i); destruct (plt id2 i); try xomega.
      * eapply max_ident_in_expr_monotone; eauto.
        eapply max_ident_in_expr_fold_monotone; eauto; xomega.
      * eapply max_ident_in_expr_monotone; eauto.
        eapply max_ident_in_expr_fold_monotone; eauto.
    + eapply max_ident_in_expr_monotone; eauto.
      eapply max_ident_in_expr_fold_monotone; eauto.
  - destruct o.
    + destruct (plt id1 i); destruct (plt id2 i); try xomega.
      * eapply max_ident_in_expr_fold_monotone; eauto; xomega.
      * eapply max_ident_in_expr_fold_monotone; eauto.
    + eapply max_ident_in_expr_fold_monotone; eauto.
  - eapply max_ident_in_stmt_monotone; eauto.
    eapply max_ident_in_stmt_monotone; eauto.
    eapply max_ident_in_expr_monotone; eauto.
  - destruct o.
    + eapply max_ident_in_expr_monotone; eauto.
    + auto.
  - eapply max_ident_in_lstmt_monotone; eauto.
    eapply max_ident_in_expr_monotone; eauto. }
{ destruct ls; intros; simpl; auto. }
Qed.

Any identifier strictly greater than max_ident_in_stmt s 1%positive doesn't appear in s
Theorem max_ident_not_in_stmt:
  forall s id,
    Plt (max_ident_in_stmt s 1%positive) id ->
    not_in_stmt id s
Any identifier strictly greater than max_ident_in_lstmt ls 1%positive doesn't appear in ls
with max_ident_not_in_lstmt:
       forall ls id,
         Plt (max_ident_in_lstmt ls 1%positive) id ->
         not_in_lstmt id ls.
Proof.
{ destruct s; intros id H; simpl in *; try (constructor; auto; fail).
  - econstructor; eauto.
    + exploit not_in_expr_trans; eauto.
      generalize (ple_max_ident e0 (max_ident_in_expr e 1%positive)); intros.
      xomega.
    + exploit not_in_expr_trans; eauto.
      generalize (max_ident_in_expr_monotone e0 1%positive (max_ident_in_expr e 1%positive) (ple_max_ident e 1%positive)); intros.
      xomega.
  - econstructor; eauto.
    + destruct (plt 1 i).
      * generalize (ple_max_ident e i); intros.
        assert (Plt i id) by xomega.
        apply Plt_ne in H1; auto.
      * assert (Ple i 1) by xomega.
        generalize (ple_max_ident e 1); intros.
        assert (Plt i id) by xomega.
        apply Plt_ne in H2; auto.
    + exploit not_in_expr_trans; eauto.
      destruct (plt 1 i).
      * generalize (max_ident_in_expr_monotone e 1 i (Plt_Ple 1 i p)); intros.
        xomega.
      * auto.
  - destruct o; econstructor; eauto.
    + destruct (plt 1 i).
      * generalize (max_ident_in_expr_monotone e i (fold_right max_ident_in_expr i l) (ple_fold_max_ident l i)); intros.
        generalize (ple_max_ident e i); intros.
        assert (Plt i id) by xomega.
        apply Plt_ne in H2; auto.
      * assert (Ple i 1) by xomega.
        generalize (max_ident_in_expr_monotone e 1 (fold_right max_ident_in_expr 1%positive l) (ple_fold_max_ident l 1)); intros.
        generalize (ple_max_ident e 1); intros.
        assert (Plt i id) by xomega.
        apply Plt_ne in H3; auto.
    + destruct (plt 1 i).
      * exploit not_in_expr_trans; eauto.
        generalize (max_ident_in_expr_monotone e i (fold_right max_ident_in_expr i l) (ple_fold_max_ident l i)); intros.
        generalize (max_ident_in_expr_monotone e 1 i (Plt_Ple 1 i p)); intros.
        xomega.
      * exploit not_in_expr_trans; eauto.
        generalize (max_ident_in_expr_monotone e 1 (fold_right max_ident_in_expr 1%positive l) (ple_fold_max_ident l 1)); intros.
        xomega.
    + destruct (plt 1 i).
      * eapply not_in_expr_trans_fold; eauto.
        generalize (ple_max_ident e (fold_right max_ident_in_expr i l)); intros.
        assert (Plt (fold_right max_ident_in_expr i l) id) by xomega.
        exact H1.
      * eapply not_in_expr_trans_fold; eauto.
        generalize (ple_max_ident e (fold_right max_ident_in_expr 1%positive l)); intros.
        assert (Plt (fold_right max_ident_in_expr 1%positive l) id) by xomega.
        exact H1.
    + eapply not_in_expr_trans; eauto.
      assert (Ple 1 (fold_right max_ident_in_expr 1%positive l)) by xomega.
      generalize (max_ident_in_expr_monotone e 1 (fold_right max_ident_in_expr 1%positive l) H0); intros.
      xomega.
    + eapply not_in_expr_trans_fold; eauto.
      generalize (ple_max_ident e (fold_right max_ident_in_expr 1%positive l)); intros.
      instantiate (1 := 1%positive); xomega.
  - destruct o; econstructor; eauto.
    + destruct (plt 1 i).
      * generalize (ple_fold_max_ident l i); intros.
        assert (Plt i id) by xomega.
        apply Plt_ne in H1; auto.
      * generalize (ple_fold_max_ident l 1); intros.
        assert (Plt i id) by xomega.
        apply Plt_ne in H1; auto.
    + destruct (plt 1 i).
      * eapply not_in_expr_trans_fold; eauto.
      * eapply not_in_expr_trans_fold; eauto.
    + eapply not_in_expr_trans_fold; eauto.
  - econstructor; eauto.
    + eapply max_ident_not_in_stmt; eauto.
      generalize (ple_max_ident_stmt s2 (max_ident_in_stmt s1 1%positive)); intros.
      xomega.
    + eapply max_ident_not_in_stmt; eauto.
      assert (Ple 1 (max_ident_in_stmt s1 1%positive)) by xomega.
      generalize (max_ident_in_stmt_monotone s2 _ _ H0); intros.
      xomega.
  - econstructor; eauto.
    + eapply not_in_expr_trans; eauto.
      generalize (ple_max_ident_stmt s2 (max_ident_in_stmt s1 (max_ident_in_expr e 1%positive))); intros.
      generalize (ple_max_ident_stmt s1 (max_ident_in_expr e 1%positive)); intros; xomega.
    + eapply max_ident_not_in_stmt; eauto.
      assert (Ple 1 (max_ident_in_expr e 1%positive)) by xomega.
      generalize (max_ident_in_stmt_monotone s1 _ _ H0); intros.
      generalize (ple_max_ident_stmt s2 (max_ident_in_stmt s1 (max_ident_in_expr e 1%positive))); intros; xomega.
    + eapply max_ident_not_in_stmt; eauto.
      assert (Ple 1 (max_ident_in_stmt s1 (max_ident_in_expr e 1%positive))) by xomega.
      generalize (max_ident_in_stmt_monotone s2 _ _ H0); intros; xomega.
  - econstructor; eauto.
    + eapply max_ident_not_in_stmt; eauto.
      generalize (ple_max_ident_stmt s2 (max_ident_in_stmt s1 1%positive)); intros; xomega.
    + eapply max_ident_not_in_stmt; eauto.
      assert (Ple 1 (max_ident_in_stmt s1 1%positive)) by xomega.
      generalize (max_ident_in_stmt_monotone s2 _ _ H0); intros; xomega.
  - destruct o; econstructor; eauto.
    eapply not_in_expr_trans; eauto.
  - econstructor; eauto.
    + eapply not_in_expr_trans; eauto.
      generalize (ple_max_ident_lstmt l (max_ident_in_expr e 1%positive)); intros; xomega.
    + eapply max_ident_not_in_lstmt; eauto.
      assert (Ple 1 (max_ident_in_expr e 1%positive)) by xomega.
      generalize (max_ident_in_lstmt_monotone l _ (max_ident_in_expr e 1%positive) H0); intros; xomega. }
{ destruct ls; intros.
  - econstructor.
  - econstructor; eauto.
    + eapply max_ident_not_in_stmt; eauto.
      simpl in H.
      generalize (ple_max_ident_lstmt ls (max_ident_in_stmt s 1%positive)); intros; xomega.
    + eapply max_ident_not_in_lstmt; eauto.
      simpl in H. assert (Ple 1 (max_ident_in_stmt s 1%positive)) by xomega.
      generalize (max_ident_in_lstmt_monotone ls _ _ H0); intros; xomega. }
Qed.

Currently unused, but will be useful when Sgotos are supported
Lemma find_label_not_in:
  forall s k s' k' lbl id,
    not_in_stmt id s ->
    find_label lbl s k = Some (s', k') ->
    not_in_stmt id s'
with find_label_ls_not_in:
       forall ls k s' k' lbl id,
         not_in_lstmt id ls ->
         find_label_ls lbl ls k = Some (s', k') ->
         not_in_stmt id s'.
Proof.
{ destruct s; intros; try (simpl in H0; inv H0; fail).
  - simpl in H0. case_eq (find_label lbl s1 (Kseq s2 k)).
    + intros; rewrite H1 in H0; rewrite <- H1 in H0; clear H1.
      inv H; eapply find_label_not_in. exact H3. exact H0.
    + intros; rewrite H1 in H0.
      inv H; eapply find_label_not_in. exact H5. exact H0.
  - simpl in H0. case_eq (find_label lbl s1 k); intros; rewrite H1 in H0.
    + rewrite <- H1 in H0.
      inv H; eapply find_label_not_in. exact H6. exact H0.
    + inv H; eapply find_label_not_in. exact H7. exact H0.
  - simpl in H0. case_eq (find_label lbl s1 (Kloop1 s1 s2 k)); intros; rewrite H1 in H0.
    + rewrite <- H1 in H0; inv H; eapply find_label_not_in. exact H4. exact H0.
    + inv H; eapply find_label_not_in. exact H5. exact H0.
  - simpl in H0. eapply find_label_ls_not_in; eauto.
    inv H; auto.
  - simpl in H0. destruct (ident_eq lbl l).
    + inv H0; inv H; auto.
    + inv H; eapply find_label_not_in; eauto. }
{ destruct ls; intros.
  - simpl in H0; inv H0.
  - simpl in H0; case_eq (find_label lbl s (Kseq (seq_of_labeled_statement ls) k)); intros; rewrite H1 in H0.
    + rewrite <- H1 in H0; inv H; eapply find_label_not_in; eauto.
    + inv H; eapply find_label_ls_not_in; eauto. }
Qed.

Lemma max_list_is_max:
  forall l x,
    In x l -> Ple x (fold_right (fun x y => if plt x y then y else x) (1%positive) l).
Proof.
induction l; intros.
- inv H.
- simpl; destruct H.
  + subst x. destruct (plt a (fold_right (fun x0 y : positive => if plt x0 y then y else x0) 1%positive l)); xomega.
  + destruct (plt a (fold_right (fun x0 y : positive => if plt x0 y then y else x0) 1%positive l)).
    * apply IHl; auto.
    * generalize (IHl x H); intros; xomega.
Qed.

new_ident_for_function f does return a fresh identifier for fn_body f
Theorem new_ident_not_in_body:
  forall f,
    not_in_stmt (new_ident_for_function f) (fn_body f).
Proof.
intros; eapply max_ident_not_in_stmt; eauto.
assert (Ple 1 (fold_right (fun x y => if plt x y then y else x) (1%positive) (var_names (fn_vars f) ++ var_names (fn_params f) ++ var_names (fn_temps f)))) by xomega.
generalize (max_ident_in_stmt_monotone (fn_body f) _ _ H); intros.
unfold new_ident_for_function; xomega.
Qed.

new_ident_for_function f is fresh for f
Theorem new_ident_no_repet:
  forall f x,
    In x (var_names (fn_vars f) ++ var_names (fn_params f) ++ var_names (fn_temps f)) -> Plt x (new_ident_for_function f).
Proof.
intros; unfold new_ident_for_function.
generalize (max_list_is_max (var_names (fn_vars f) ++ var_names (fn_params f) ++ var_names (fn_temps f)) x H); intros.
generalize (ple_max_ident_stmt (fn_body f) (fold_right (fun x0 y : positive => if plt x0 y then y else x0) 1%positive (var_names (fn_vars f) ++ var_names (fn_params f) ++ var_names (fn_temps f)))); intros; xomega.
Qed.

not_in_cont id k indicates the id doesn't appear in continuation k
Inductive not_in_cont (id: ident): cont -> Prop :=
| not_in_Kstop: not_in_cont id Kstop
| not_in_Kseq: forall s k,
                not_in_stmt id s ->
                not_in_cont id k ->
                not_in_cont id (Kseq s k)
| not_in_Kloop1: forall s1 s2 k,
                  not_in_stmt id s1 ->
                  not_in_stmt id s2 ->
                  not_in_cont id k ->
                  not_in_cont id (Kloop1 s1 s2 k)
| not_in_Kloop2: forall s1 s2 k,
                  not_in_stmt id s1 ->
                  not_in_stmt id s2 ->
                  not_in_cont id k ->
                  not_in_cont id (Kloop2 s1 s2 k)
| not_in_Kswitch: forall k,
                   not_in_cont id k ->
                   not_in_cont id (Kswitch k)
| not_in_Kcall_some: forall f e le k id',
                       id' <> new_ident_for_function f ->
                       not_in_cont (new_ident_for_function f) k ->
                       not_in_cont id (Kcall (Some id') f e le k)
| not_in_Kcall_none: forall f e le k,
                       not_in_cont (new_ident_for_function f) k ->
                       not_in_cont id (Kcall None f e le k).

not_in_cont is preserved by call_cont
Theorem not_in_cont_call_cont:
  forall id k,
    not_in_cont id k ->
    forall id', not_in_cont id' (call_cont k).
Proof.
induction k; intros; simpl.
- econstructor.
- inv H; eapply IHk; auto.
- inv H; eapply IHk; auto.
- inv H; eapply IHk; auto.
- inv H; eapply IHk; auto.
- inv H; econstructor; eauto.
Qed.

sizeof_stmt s is always strictly positive
Lemma sizeof_stmt_pos:
  forall s, sizeof_stmt s > 0.
Proof.
induction s; intros; unfold sizeof_stmt; fold sizeof_stmt; try omega. Qed.

no_switch_label_goto_in_stmt s indicates that there is no Sswitch nor Slabel nor Sgoto in s
Inductive no_switch_label_goto_in_stmt: statement -> Prop :=
| no_switch_label_goto_in_skip: no_switch_label_goto_in_stmt Sskip
| no_switch_label_goto_in_assign: forall e1 e2, no_switch_label_goto_in_stmt (Sassign e1 e2)
| no_switch_label_goto_in_set: forall id e, no_switch_label_goto_in_stmt (Sset id e)
| no_switch_label_goto_in_call: forall optid f args, no_switch_label_goto_in_stmt (Scall optid f args)
| no_switch_label_goto_in_builtin: forall optid ef tyl args, no_switch_label_goto_in_stmt (Sbuiltin optid ef tyl args)
| no_switch_label_goto_in_sequence: forall s1 s2, no_switch_label_goto_in_stmt s1 -> no_switch_label_goto_in_stmt s2 -> no_switch_label_goto_in_stmt (Ssequence s1 s2)
| no_switch_label_goto_in_ifthenelse: forall e s1 s2, no_switch_label_goto_in_stmt s1 -> no_switch_label_goto_in_stmt s2 -> no_switch_label_goto_in_stmt (Sifthenelse e s1 s2)
| no_switch_label_goto_in_loop: forall s1 s2, no_switch_label_goto_in_stmt s1 -> no_switch_label_goto_in_stmt s2 -> no_switch_label_goto_in_stmt (Sloop s1 s2)
| no_switch_label_goto_in_break: no_switch_label_goto_in_stmt Sbreak
| no_switch_label_goto_in_continue: no_switch_label_goto_in_stmt Scontinue
| no_switch_label_goto_in_return: forall e, no_switch_label_goto_in_stmt (Sreturn e).

Lemma no_switch_label_goto_loop1:
  forall id_t s counter k to_continue to_break ls,
    flatten_loop1 phi id_t s counter k to_continue to_break = OK ls ->
    no_switch_label_goto_in_stmt s
with no_switch_label_goto_loop2:
       forall id_t s counter k to_break ls,
         flatten_loop2 phi id_t s counter k to_break = OK ls ->
         no_switch_label_goto_in_stmt s.
Proof.
- destruct s; intros; try (econstructor; fail).
  + simpl in H; monadInv H.
    econstructor; eauto.
  + simpl in H; monadInv H.
    econstructor; eauto.
  + simpl in H; monadInv H.
    econstructor; eauto.
  + simpl in H; monadInv H.
  + simpl in H; monadInv H.
  + simpl in H; monadInv H.
- destruct s; intros; try (econstructor; fail).
  + simpl in H; monadInv H.
    econstructor; eauto.
  + simpl in H; monadInv H.
    econstructor; eauto.
  + simpl in H; monadInv H.
    econstructor; eauto.
  + simpl in H; monadInv H.
  + simpl in H; monadInv H.
  + simpl in H; monadInv H.
Qed.

Lemma no_switch_label_goto_stmt:
  forall id_t s counter k ls,
    flatten phi id_t s counter k = OK ls ->
    no_switch_label_goto_in_stmt s.
Proof.
induction s; intros; try (econstructor; fail).
- simpl in H; monadInv H.
  econstructor; eauto.
- simpl in H; monadInv H.
  econstructor; eauto.
- unfold flatten in H; fold flatten in H.
  monadInv H.
  econstructor; eauto.
  + eapply no_switch_label_goto_loop1; eauto.
  + eapply no_switch_label_goto_loop2; eauto.
- simpl in H; monadInv H.
- simpl in H; monadInv H.
- simpl in H; monadInv H.
Qed.

Lemma no_switch_label_goto_body:
  forall id_t s s',
    obf_body phi id_t s = OK s' ->
    no_switch_label_goto_in_stmt s.
Proof.
destruct s; intros; try (econstructor; fail); unfold obf_body in H.
- destruct (zlt (sizeof_stmt (Ssequence s1 s2)) Int.max_unsigned); try monadInv H.
  eapply no_switch_label_goto_stmt; eauto.
- destruct (zlt (sizeof_stmt (Sifthenelse e s1 s2)) Int.max_unsigned); try monadInv H.
  eapply no_switch_label_goto_stmt; eauto.
- destruct (zlt (sizeof_stmt (Sloop s1 s2)) Int.max_unsigned); try monadInv H.
  eapply no_switch_label_goto_stmt; eauto.
- destruct (zlt (sizeof_stmt (Sswitch e l)) Int.max_unsigned); monadInv H.
  monadInv EQ.
- destruct (zlt (sizeof_stmt (Slabel l s)) Int.max_unsigned); monadInv H.
  monadInv EQ.
- destruct (zlt (sizeof_stmt (Sgoto l)) Int.max_unsigned); monadInv H.
  monadInv EQ.
Qed.

If the function can be obfuscated, then there is no Sswitch nor Slabel nor Sgoto
Theorem no_switch_label_goto_function:
  forall f f',
    transf_function phi f = OK f' ->
    no_switch_label_goto_in_stmt (fn_body f).
Proof.
unfold transf_function; intros.
monadInv H.
eapply no_switch_label_goto_body; eauto.
Qed.

no_switch_label_goto_in_cont k indicates that there is no Sswitch nor Slabel nor Sgoto in the continuation k
Inductive no_switch_label_goto_in_cont: cont -> Prop :=
| no_switch_label_goto_in_stop: no_switch_label_goto_in_cont Kstop
| no_switch_label_goto_in_seq: forall s k, no_switch_label_goto_in_stmt s -> no_switch_label_goto_in_cont k -> no_switch_label_goto_in_cont (Kseq s k)
| no_switch_label_goto_in_loop1: forall s1 s2 k, no_switch_label_goto_in_stmt s1 -> no_switch_label_goto_in_stmt s2 -> no_switch_label_goto_in_cont k -> no_switch_label_goto_in_cont (Kloop1 s1 s2 k)
| no_switch_label_goto_in_loop2: forall s1 s2 k, no_switch_label_goto_in_stmt s1 -> no_switch_label_goto_in_stmt s2 -> no_switch_label_goto_in_cont k -> no_switch_label_goto_in_cont (Kloop2 s1 s2 k)
| no_switch_label_goto_in_Kcall: forall optid f e le k, no_switch_label_goto_in_stmt (fn_body f) -> no_switch_label_goto_in_cont k -> no_switch_label_goto_in_cont (Kcall optid f e le k).

End Utils.

Section PRESERVATION.

phi is the numerotation function
Variable phi: Z -> Int.int.

We assume that phi is an injective function of 0, 2^32 - 1 -> 0, 2^32 - 1
Variable phi_injective:
  forall x y,
    0 <= x <= Int.max_unsigned ->
    0 <= y <= Int.max_unsigned ->
    phi x = phi y ->
    x = y.

Variable prog: Clight.program.
Variable tprog: Clight.program.
Hypothesis TRANSF: transf_program phi prog = OK tprog.
Let ge := Clight.globalenv prog.
Let tge := Clight.globalenv tprog.

Lemma comp_env_preserved:
  Clight.genv_cenv tge = Clight.genv_cenv ge.
Proof.
  monadInv TRANSF. unfold tge; rewrite <- H0; auto.
Qed.

Lemma transf_programs:
  AST.transform_partial_program (transf_fundef phi) (program_of_program prog) = OK (program_of_program tprog).
Proof.
  monadInv TRANSF. rewrite EQ. destruct x; reflexivity.
Qed.

Lemma symbols_preserved:
  forall (s: ident), Genv.find_symbol tge s = Genv.find_symbol ge s.
Proof.
  exact (Genv.find_symbol_transf_partial _ _ transf_programs).
Qed.

Lemma varinfo_preserved:
  forall b, Genv.find_var_info tge b = Genv.find_var_info ge b.
Proof.
  exact (Genv.find_var_info_transf_partial _ _ transf_programs).
Qed.

Lemma functions_translated:
  forall (v: val) (f: Clight.fundef),
    Genv.find_funct ge v = Some f ->
    exists tf, Genv.find_funct tge v = Some tf /\ transf_fundef phi f = OK tf.
Proof.
  exact (Genv.find_funct_transf_partial _ _ transf_programs).
Qed.

Lemma function_ptr_translated:
  forall (b: block) (f: Clight.fundef),
    Genv.find_funct_ptr ge b = Some f ->
    exists tf, Genv.find_funct_ptr tge b = Some tf /\ transf_fundef phi f = OK tf.
Proof.
  exact (Genv.find_funct_ptr_transf_partial _ _ transf_programs).
Qed.

Lemma type_of_fundef_preserved:
  forall fd tfd,
    transf_fundef phi fd = OK tfd -> type_of_fundef tfd = type_of_fundef fd.
Proof.
  intros. destruct fd; monadInv H; auto.
  monadInv EQ. simpl; unfold type_of_function; simpl. auto.
Qed.

Section EXPR_PRESERVATION.

Evaluation of expressions is preserved

id is assumed to be the identifier of the pseudo ``program counter''
Variable (id: ident).
Variable (e: env).
Variables (le tle: temp_env).
Variable (m: mem).
The values of all variables different from id are preserved
Hypothesis LENV: forall id', id' <> id -> le!id' = tle!id'.

Evaluation of expressions is preserved
Theorem eval_expr_preserved:
  forall a v,
    eval_expr ge e le m a v ->
    not_in_expr id a ->
    eval_expr tge e tle m a v
Evaluation of l-values is preserved
with eval_lvalue_preserved:
       forall a loc ofs,
         eval_lvalue ge e le m a loc ofs ->
         not_in_expr id a ->
         eval_lvalue tge e tle m a loc ofs.
Proof.
{ destruct 1; intros; try (econstructor; fail).
  - econstructor.
    inv H0; rewrite <- LENV; auto.
  - econstructor.
    inv H0; eapply eval_lvalue_preserved; eauto.
  - econstructor.
    + inv H1; eapply eval_expr_preserved; eauto.
    + exact H0.
  - econstructor.
    + inv H2; eapply eval_expr_preserved; eauto.
    + inv H2; eapply eval_expr_preserved; eauto.
    + rewrite comp_env_preserved. exact H1.
  - econstructor.
    + inv H1; eapply eval_expr_preserved; eauto.
    + exact H0.
  - rewrite <- comp_env_preserved. eapply eval_Esizeof.
  - rewrite <- comp_env_preserved. eapply eval_Ealignof.
  - econstructor.
    + eapply eval_lvalue_preserved; eauto.
    + exact H0. }
{ destruct 1; intros; try (econstructor; eauto; fail).
  - eapply eval_Evar_global; eauto.
    rewrite symbols_preserved; auto.
  - econstructor.
    inv H0; eapply eval_expr_preserved; eauto.
  - rewrite <- comp_env_preserved in *.
    econstructor; eauto.
    inv H3; eapply eval_expr_preserved; eauto.
  - rewrite <- comp_env_preserved in *.
    econstructor; eauto.
    inv H2; eapply eval_expr_preserved; eauto. }
Qed.

Evaluation of expression lists is preserved
Theorem eval_exprlist_preserved:
  forall al tyl v,
    eval_exprlist ge e le m al tyl v ->
    (forall a, In a al -> not_in_expr id a) ->
    eval_exprlist tge e tle m al tyl v.
Proof.
induction 1; intros.
- constructor.
- econstructor; eauto.
  + eapply eval_expr_preserved; eauto.
    eapply H2; eauto.
    simpl; left; auto.
  + eapply IHeval_exprlist; eauto.
    intros; eapply H2; simpl; right; auto.
Qed.

End EXPR_PRESERVATION.

Context of a continuation, either Kloop1, Kloop2, Kcall (Kswitch unused)
Fixpoint context (k: cont): cont :=
  match k with
    | Kseq _ k' => context k'
    | _ => k
  end.

match_stmt_cont_in_loop1 s ls id_t starts current next_instr to_continues to_breaks k indicates that the statements s corresponds to the case associated with the number current in the labeled_statements ls, the next statement that can be found in the continuation k is associated with the case corresponding to next_instr. starts is a stack (list) of numbers corresponding to the start of each Sloop that were encountered, to_continues stores the numbers associated to the Scontinue of each already encountered Sloop, likewise for to_breaks
Inductive match_stmt_cont_in_loop1: statement -> labeled_statements -> (ident * type) -> list Z -> Z -> Z -> list Z -> list Z -> cont -> Prop :=
| match_skip_cont_seq_in_loop1: forall start id_t ls n next_instr to_continue to_break ls' s k,
                                  (exists s1 s2 k', context (Kseq s k) = Kloop1 s1 s2 k') ->
                                  0 < n <= Int.max_unsigned ->
                                  (select_switch_case (Int.unsigned (phi n)) ls =
                                   Some (LScons (Some (Int.unsigned (phi n))) (Ssequence Sskip (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') /\
                                   exists m, match_stmt_cont_in_loop1 s ls id_t start next_instr m to_continue to_break k) \/
                                  match_stmt_cont_in_loop1 s ls id_t start n next_instr to_continue to_break k ->
                                  match_stmt_cont_in_loop1 Sskip ls id_t start n next_instr to_continue to_break (Kseq s k)
| match_skip_cont_loop1_in_loop1: forall start id_t ls n next_instr to_continue to_break ls' s1 s2 k,
                                    0 < n <= Int.max_unsigned ->
                                    (select_switch_case (Int.unsigned (phi n)) ls =
                                     Some (LScons (Some (Int.unsigned (phi n))) (Ssequence Sskip (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') /\
                                     exists m, match_stmt_cont_in_loop2 s2 ls id_t start next_instr m to_continue to_break (Kloop2 s1 s2 k)) \/
                                    match_stmt_cont_in_loop2 s2 ls id_t start n next_instr to_continue to_break (Kloop2 s1 s2 k) ->
                                    match_stmt_cont_in_loop1 Sskip ls id_t start n next_instr to_continue to_break (Kloop1 s1 s2 k)
| match_assign_cont_in_loop1: forall start id_t ls n next_instr to_continue to_break ls' e1 e2 k,
                                (exists s1 s2 k', context k = Kloop1 s1 s2 k') ->
                                0 < n <= Int.max_unsigned ->
                                select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sassign e1 e2) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                                (exists m, match_stmt_cont_in_loop1 Sskip ls id_t start next_instr m to_continue to_break k) ->
                                match_stmt_cont_in_loop1 (Sassign e1 e2) ls id_t start n next_instr to_continue to_break k
| match_set_cont_in_loop1: forall start id_t ls n next_instr to_continue to_break ls' id e k,
                             (exists s1 s2 k', context k = Kloop1 s1 s2 k') ->
                             0 < n <= Int.max_unsigned ->
                             select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sset id e) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                             (exists m, match_stmt_cont_in_loop1 Sskip ls id_t start next_instr m to_continue to_break k) ->
                             match_stmt_cont_in_loop1 (Sset id e) ls id_t start n next_instr to_continue to_break k
| match_call_cont_in_loop1: forall start id_t ls n next_instr to_continue to_break ls' optid a al k,
                              (exists s1 s2 k', context k = Kloop1 s1 s2 k') ->
                              0 < n <= Int.max_unsigned ->
                              select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Scall optid a al) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                              (exists m, match_stmt_cont_in_loop1 Sskip ls id_t start next_instr m to_continue to_break k) ->
                              match_stmt_cont_in_loop1 (Scall optid a al) ls id_t start n next_instr to_continue to_break k
| match_builtin_cont_in_loop1: forall start id_t ls n next_instr to_continue to_break ls' optid ef tyargs al k,
                                 (exists s1 s2 k', context k = Kloop1 s1 s2 k') ->
                                 0 < n <= Int.max_unsigned ->
                                 select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sbuiltin optid ef tyargs al) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                                 (exists m, match_stmt_cont_in_loop1 Sskip ls id_t start next_instr m to_continue to_break k) ->
                                 match_stmt_cont_in_loop1 (Sbuiltin optid ef tyargs al) ls id_t start n next_instr to_continue to_break k
| match_sequence_cont_in_loop1: forall start id_t ls n next_instr to_continue to_break s1 s2 k,
                                  (exists s s' k', context k = Kloop1 s s' k') ->
                                  0 < n <= Int.max_unsigned ->
                                  match_stmt_cont_in_loop1 s1 ls id_t start (n) (n + sizeof_stmt s1) to_continue to_break (Kseq s2 k) ->
                                  match_stmt_cont_in_loop1 s2 ls id_t start (n + sizeof_stmt s1) next_instr to_continue to_break k ->
                                  match_stmt_cont_in_loop1 (Ssequence s1 s2) ls id_t start n next_instr to_continue to_break k
| match_ifthenelse_cont_in_loop1: forall start id_t ls ls' n next_instr to_continue to_break b s1 s2 k,
                                    (exists s s' k', context k = Kloop1 s s' k') ->
                                    0 < n <= Int.max_unsigned ->
                                    select_switch_case (Int.unsigned (phi n)) ls =
                                    Some (LScons (Some (Int.unsigned (phi n))) (Sifthenelse b (Ssequence (Sset (fst id_t) (Econst_int (phi (n + 1)) (snd id_t))) Sbreak) (Ssequence (Sset (fst id_t) (Econst_int (phi (n + 1 + sizeof_stmt s1)) (snd id_t))) Sbreak)) ls') ->
                                    match_stmt_cont_in_loop1 s1 ls id_t start (n + 1) next_instr to_continue to_break k ->
                                    match_stmt_cont_in_loop1 s2 ls id_t start (n + 1 + sizeof_stmt s1) next_instr to_continue to_break k ->
                                    match_stmt_cont_in_loop1 (Sifthenelse b s1 s2) ls id_t start n next_instr to_continue to_break k
| match_loop_cont_in_loop1: forall start id_t ls ls' n next_instr to_continue to_break s1 s2 k,
                              (exists s s' k', context k = Kloop1 s s' k') ->
                              0 < n <= Int.max_unsigned ->
                              select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sset (fst id_t) (Econst_int (phi (n + 1)) (snd id_t))) Sbreak) ls') ->
                              match_stmt_cont_in_loop1 s1 ls id_t (n::start) (n + 1) (n + 1 + sizeof_stmt s1) ((n + 1 + sizeof_stmt s1)::to_continue) (next_instr::to_break) (Kloop1 s1 s2 k) ->
                              match_stmt_cont_in_loop2 s2 ls id_t (n::start) (n + 1 + sizeof_stmt s1) n ((n + 1 + sizeof_stmt s1)::to_continue) (next_instr::to_break) (Kloop2 s1 s2 k) ->
                              match_stmt_cont_in_loop1 (Sloop s1 s2) ls id_t start n next_instr to_continue to_break k
| match_break_cont_seq_in_loop1: forall start id_t ls n next_instr to_continue to_break s k,
                                   (exists s1 s2 k', context (Kseq s k) = Kloop1 s1 s2 k') ->
                                   match_stmt_cont_in_loop1 Sbreak ls id_t start n next_instr to_continue to_break k ->
                                   match_stmt_cont_in_loop1 Sbreak ls id_t start n next_instr to_continue to_break (Kseq s k)
| match_break_cont_loop1_in_loop1: forall start id_t ls n next_instr to_continue to_break ls' s1 s2 k start' p q,
                                    0 < n <= Int.max_unsigned ->
                                    select_switch_case (Int.unsigned (phi n)) ls =
                                    Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sset (fst id_t) (Econst_int (phi to_break) (snd id_t))) Sbreak) ls') ->
                                    ((is_call_cont (context k) /\ exists m, match_stmt_cont Sskip ls id_t to_break m k /\ start' = nil /\ p = nil /\ q = nil) \/
                                    (exists s s' k', context k = Kloop1 s s' k' /\ exists m, match_stmt_cont_in_loop1 Sskip ls id_t start' to_break m p q k) \/
                                    (exists s s' k', context k = Kloop2 s s' k' /\ exists m, match_stmt_cont_in_loop2 Sskip ls id_t start' to_break m p q k)) ->
                                    match_stmt_cont_in_loop1 Sbreak ls id_t (start::start') n next_instr (to_continue::p) (to_break::q) (Kloop1 s1 s2 k)
| match_continue_cont_seq_in_loop1: forall start id_t ls n next_instr to_continue to_break s k,
                                      (exists s1 s2 k', context (Kseq s k) = Kloop1 s1 s2 k') ->
                                      match_stmt_cont_in_loop1 Scontinue ls id_t start n next_instr to_continue to_break k ->
                                      match_stmt_cont_in_loop1 Scontinue ls id_t start n next_instr to_continue to_break (Kseq s k)
| match_continue_cont_loop1_in_loop1: forall start id_t ls n next_instr to_continue to_continue' to_break ls' s1 s2 k,
                                        0 < n <= Int.max_unsigned ->
                                        select_switch_case (Int.unsigned (phi n)) ls =
                                        Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sset (fst id_t) (Econst_int (phi to_continue) (snd id_t))) Sbreak) ls') ->
                                        (exists m, match_stmt_cont_in_loop2 s2 ls id_t start to_continue m (to_continue::to_continue') to_break (Kloop2 s1 s2 k)) ->
                                        match_stmt_cont_in_loop1 Scontinue ls id_t start n next_instr (to_continue::to_continue') to_break (Kloop1 s1 s2 k)
| match_return_cont_in_loop1: forall start id_t ls n next_instr to_continue to_break ls' v k,
                                (exists s1 s2 k', context k = Kloop1 s1 s2 k') ->
                                0 < n <= Int.max_unsigned ->
                                select_switch_case (Int.unsigned (phi n)) ls =
                                Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sreturn v) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                                match_stmt_cont_in_loop1 (Sreturn v) ls id_t start n next_instr to_continue to_break k
similar to match_stmt_cont_in_loop1 with the exception that there Scontinues are not associated
with match_stmt_cont_in_loop2: statement -> labeled_statements -> ident * type -> list Z -> Z -> Z -> list Z -> list Z -> cont -> Prop :=
| match_skip_cont_seq_in_loop2: forall start id_t ls n next_instr to_continue to_break ls' s k,
                                  (exists s1 s2 k', context (Kseq s k) = Kloop2 s1 s2 k') ->
                                  0 < n <= Int.max_unsigned ->
                                  (select_switch_case (Int.unsigned (phi n)) ls =
                                   Some (LScons (Some (Int.unsigned (phi n))) (Ssequence Sskip (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') /\
                                   exists m, match_stmt_cont_in_loop2 s ls id_t start next_instr m to_continue to_break k) \/
                                  match_stmt_cont_in_loop2 s ls id_t start n next_instr to_continue to_break k ->
                                  match_stmt_cont_in_loop2 Sskip ls id_t start n next_instr to_continue to_break (Kseq s k)
| match_skip_cont_loop2_in_loop2: forall start start' id_t ls n next_instr to_continue to_break ls' s1 s2 k,
                                    0 < n <= Int.max_unsigned ->
                                    (select_switch_case (Int.unsigned (phi n)) ls =
                                     Some (LScons (Some (Int.unsigned (phi n))) (Ssequence Sskip (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') /\
                                     next_instr = start /\
                                     (exists ls'',
                                        select_switch_case (Int.unsigned (phi next_instr)) ls =
                                        Some (LScons (Some (Int.unsigned (phi next_instr))) (Ssequence (Sset (fst id_t) (Econst_int (phi (start + 1)) (snd id_t))) Sbreak) ls'')) \/
                                    (n = start /\
                                     select_switch_case (Int.unsigned (phi n)) ls =
                                     Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sset (fst id_t) (Econst_int (phi (start + 1)) (snd id_t))) Sbreak) ls'))) ->
                                    match_stmt_cont_in_loop2 Sskip ls id_t (start::start') n next_instr to_continue to_break (Kloop2 s1 s2 k)
| match_assign_cont_in_loop2: forall start id_t ls n next_instr to_continue to_break ls' e1 e2 k,
                                (exists s1 s2 k', context k = Kloop2 s1 s2 k') ->
                                0 < n <= Int.max_unsigned ->
                                select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sassign e1 e2) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                                (exists m, match_stmt_cont_in_loop2 Sskip ls id_t start next_instr m to_continue to_break k) ->
                                match_stmt_cont_in_loop2 (Sassign e1 e2) ls id_t start n next_instr to_continue to_break k
| match_set_cont_in_loop2: forall start id_t ls n next_instr to_continue to_break ls' id e k,
                             (exists s1 s2 k', context k = Kloop2 s1 s2 k') ->
                             0 < n <= Int.max_unsigned ->
                             select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sset id e) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                             (exists m, match_stmt_cont_in_loop2 Sskip ls id_t start next_instr m to_continue to_break k) ->
                             match_stmt_cont_in_loop2 (Sset id e) ls id_t start n next_instr to_continue to_break k
| match_call_cont_in_loop2: forall start id_t ls n next_instr to_continue to_break ls' optid a al k,
                              (exists s1 s2 k', context k = Kloop2 s1 s2 k') ->
                              0 < n <= Int.max_unsigned ->
                              select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Scall optid a al) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                              (exists m, match_stmt_cont_in_loop2 Sskip ls id_t start next_instr m to_continue to_break k) ->
                              match_stmt_cont_in_loop2 (Scall optid a al) ls id_t start n next_instr to_continue to_break k
| match_builtin_cont_in_loop2: forall start id_t ls n next_instr to_continue to_break ls' optid ef tyargs al k,
                                 (exists s1 s2 k', context k = Kloop2 s1 s2 k') ->
                                 0 < n <= Int.max_unsigned ->
                                 select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sbuiltin optid ef tyargs al) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                                 (exists m, match_stmt_cont_in_loop2 Sskip ls id_t start next_instr m to_continue to_break k) ->
                                 match_stmt_cont_in_loop2 (Sbuiltin optid ef tyargs al) ls id_t start n next_instr to_continue to_break k
| match_sequence_cont_in_loop2: forall start id_t ls n next_instr to_continue to_break s1 s2 k,
                             (exists s s' k', context k = Kloop2 s s' k') ->
                             0 < n <= Int.max_unsigned ->
                             match_stmt_cont_in_loop2 s1 ls id_t start (n) (n + sizeof_stmt s1) to_continue to_break (Kseq s2 k) ->
                             match_stmt_cont_in_loop2 s2 ls id_t start (n + sizeof_stmt s1) next_instr to_continue to_break k ->
                             match_stmt_cont_in_loop2 (Ssequence s1 s2) ls id_t start n next_instr to_continue to_break k
| match_ifthenelse_cont_in_loop2: forall start id_t ls ls' n next_instr to_continue to_break b s1 s2 k,
                                    (exists s s' k', context k = Kloop2 s s' k') ->
                                    0 < n <= Int.max_unsigned ->
                                    select_switch_case (Int.unsigned (phi n)) ls =
                                    Some (LScons (Some (Int.unsigned (phi n))) (Sifthenelse b (Ssequence (Sset (fst id_t) (Econst_int (phi (n + 1)) (snd id_t))) Sbreak) (Ssequence (Sset (fst id_t) (Econst_int (phi (n + 1 + sizeof_stmt s1)) (snd id_t))) Sbreak)) ls') ->
                                    match_stmt_cont_in_loop2 s1 ls id_t start (n + 1) next_instr to_continue to_break k ->
                                    match_stmt_cont_in_loop2 s2 ls id_t start (n + 1 + sizeof_stmt s1) next_instr to_continue to_break k ->
                                    match_stmt_cont_in_loop2 (Sifthenelse b s1 s2) ls id_t start n next_instr to_continue to_break k
| match_loop_cont_in_loop2: forall start id_t ls ls' n next_instr to_continue to_break s1 s2 k,
                              (exists s s' k', context k = Kloop2 s s' k') ->
                              0 < n <= Int.max_unsigned ->
                              select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sset (fst id_t) (Econst_int (phi (n + 1)) (snd id_t))) Sbreak) ls') ->
                              match_stmt_cont_in_loop1 s1 ls id_t (n::start) (n + 1) (n + 1 + sizeof_stmt s1) ((n + 1 + sizeof_stmt s1)::to_continue) (next_instr::to_break) (Kloop1 s1 s2 k) ->
                              match_stmt_cont_in_loop2 s2 ls id_t (n::start) (n + 1 + sizeof_stmt s1) n ((n + 1 + sizeof_stmt s1)::to_continue) (next_instr::to_break) (Kloop2 s1 s2 k) ->
                              match_stmt_cont_in_loop2 (Sloop s1 s2) ls id_t start n next_instr to_continue to_break k
| match_break_cont_seq_in_loop2: forall start id_t ls n next_instr to_continue to_break s k,
                                   (exists s1 s2 k', context (Kseq s k) = Kloop2 s1 s2 k') ->
                                   match_stmt_cont_in_loop2 Sbreak ls id_t start n next_instr to_continue to_break k ->
                                   match_stmt_cont_in_loop2 Sbreak ls id_t start n next_instr to_continue to_break (Kseq s k)
| match_break_cont_loop2_in_loop2: forall start start' id_t ls n next_instr to_continue to_break ls' s1 s2 k p q,
                                    0 < n <= Int.max_unsigned ->
                                    select_switch_case (Int.unsigned (phi n)) ls =
                                    Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sset (fst id_t) (Econst_int (phi to_break) (snd id_t))) Sbreak) ls') ->
                                    ((is_call_cont (context k) /\ exists m, match_stmt_cont Sskip ls id_t to_break m k /\ start' = nil /\ p = nil /\ q = nil) \/
                                    (exists s s' k', context k = Kloop1 s s' k' /\ exists m, match_stmt_cont_in_loop1 Sskip ls id_t start' to_break m p q k) \/
                                    (exists s s' k', context k = Kloop2 s s' k' /\ exists m, match_stmt_cont_in_loop2 Sskip ls id_t start' to_break m p q k)) ->
                                    match_stmt_cont_in_loop2 Sbreak ls id_t (start::start') n next_instr (to_continue::p) (to_break::q) (Kloop2 s1 s2 k)
| match_return_cont_in_loop2: forall start id_t ls n next_instr to_continue to_break ls' v k,
                                (exists s1 s2 k', context k = Kloop2 s1 s2 k') ->
                                0 < n <= Int.max_unsigned ->
                                select_switch_case (Int.unsigned (phi n)) ls =
                                Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sreturn v) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                                match_stmt_cont_in_loop2 (Sreturn v) ls id_t start n next_instr to_continue to_break k
similar to match_stmt_cont_in_loop1 with the exception that Scontinues and Sbreaks are not associated
with match_stmt_cont: statement -> labeled_statements -> ident * type -> Z -> Z -> cont -> Prop :=
| match_skip_cont_seq: forall id_t ls n next_instr ls' s k,
                                  is_call_cont (context (Kseq s k)) ->
                                  0 < n <= Int.max_unsigned ->
                                  (select_switch_case (Int.unsigned (phi n)) ls =
                                   Some (LScons (Some (Int.unsigned (phi n))) (Ssequence Sskip (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') /\
                                   exists m, match_stmt_cont s ls id_t next_instr m k) \/
                                  match_stmt_cont s ls id_t n next_instr k ->
                                  match_stmt_cont Sskip ls id_t n next_instr (Kseq s k)
| match_skip_cont_call_cont: forall id_t ls n next_instr ls' k,
                               is_call_cont k ->
                               ((select_switch_case (Int.unsigned (phi n)) ls =
                                Some (LScons (Some (Int.unsigned (phi n))) (Ssequence Sskip (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') /\
                                 0 < n <= Int.max_unsigned /\
                                 next_instr = 0 /\
                                 select_switch (Int.unsigned (phi next_instr)) ls = LSnil) \/
                                n = 0 /\
                                select_switch (Int.unsigned (phi n)) ls = LSnil) ->
                               match_stmt_cont Sskip ls id_t n next_instr k
| match_assign_cont: forall id_t ls n next_instr ls' e1 e2 k,
                       is_call_cont (context k) ->
                       0 < n <= Int.max_unsigned ->
                       select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sassign e1 e2) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                       (exists m, match_stmt_cont Sskip ls id_t next_instr m k) ->
                       match_stmt_cont (Sassign e1 e2) ls id_t n next_instr k
| match_set_cont: forall id_t ls n next_instr ls' id e k,
                    is_call_cont (context k) ->
                    0 < n <= Int.max_unsigned ->
                    select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sset id e) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                    (exists m, match_stmt_cont Sskip ls id_t next_instr m k) ->
                    match_stmt_cont (Sset id e) ls id_t n next_instr k
| match_scall_cont: forall id_t ls n next_instr ls' optid a al k,
                     is_call_cont (context k) ->
                     0 < n <= Int.max_unsigned ->
                     select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Scall optid a al) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                     (exists m, match_stmt_cont Sskip ls id_t next_instr m k) ->
                     match_stmt_cont (Scall optid a al) ls id_t n next_instr k
| match_builtin_cont: forall id_t ls n next_instr ls' optid ef tyargs al k,
                        is_call_cont (context k) ->
                        0 < n <= Int.max_unsigned ->
                        select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sbuiltin optid ef tyargs al) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                        (exists m, match_stmt_cont Sskip ls id_t next_instr m k) ->
                        match_stmt_cont (Sbuiltin optid ef tyargs al) ls id_t n next_instr k
| match_sequence_cont: forall id_t ls n next_instr s1 s2 k,
                         is_call_cont (context k) ->
                         0 < n <= Int.max_unsigned ->
                         match_stmt_cont s1 ls id_t (n) (n + sizeof_stmt s1) (Kseq s2 k) ->
                         match_stmt_cont s2 ls id_t (n + sizeof_stmt s1) next_instr k ->
                         match_stmt_cont (Ssequence s1 s2) ls id_t n next_instr k
| match_ifthenelse_cont: forall id_t ls ls' n next_instr b s1 s2 k,
                           is_call_cont (context k) ->
                           0 < n <= Int.max_unsigned ->
                           select_switch_case (Int.unsigned (phi n)) ls =
                           Some (LScons (Some (Int.unsigned (phi n))) (Sifthenelse b (Ssequence (Sset (fst id_t) (Econst_int (phi (n + 1)) (snd id_t))) Sbreak) (Ssequence (Sset (fst id_t) (Econst_int (phi (n + 1 + sizeof_stmt s1)) (snd id_t))) Sbreak)) ls') ->
                           match_stmt_cont s1 ls id_t (n + 1) next_instr k ->
                           match_stmt_cont s2 ls id_t (n + 1 + sizeof_stmt s1) next_instr k ->
                           match_stmt_cont (Sifthenelse b s1 s2) ls id_t n next_instr k
| match_loop_cont: forall id_t ls ls' n next_instr s1 s2 k,
                     is_call_cont (context k) ->
                     0 < n <= Int.max_unsigned ->
                     select_switch_case (Int.unsigned (phi n)) ls = Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sset (fst id_t) (Econst_int (phi (n + 1)) (snd id_t))) Sbreak) ls') ->
                     match_stmt_cont_in_loop1 s1 ls id_t (n::nil) (n + 1) (n + 1 + sizeof_stmt s1) ((n + 1 + sizeof_stmt s1)::nil) (next_instr::nil) (Kloop1 s1 s2 k) ->
                     match_stmt_cont_in_loop2 s2 ls id_t (n::nil) (n + 1 + sizeof_stmt s1) n ((n + 1 + sizeof_stmt s1)::nil) (next_instr::nil) (Kloop2 s1 s2 k) ->
                     match_stmt_cont (Sloop s1 s2) ls id_t n next_instr k
| match_return_cont: forall id_t ls n next_instr ls' v k,
                       is_call_cont (context k) ->
                       0 < n <= Int.max_unsigned ->
                       select_switch_case (Int.unsigned (phi n)) ls =
                       Some (LScons (Some (Int.unsigned (phi n))) (Ssequence (Sreturn v) (Ssequence (Sset (fst id_t) (Econst_int (phi next_instr) (snd id_t))) Sbreak)) ls') ->
                       match_stmt_cont (Sreturn v) ls id_t n next_instr k.

If the context of continuation k is either Kcall or Kstop then k is either Kcall or Kstop or Kseq
Lemma is_call_cont_context:
  forall k,
    is_call_cont (context k) ->
    is_call_cont k \/ exists s k', k = Kseq s k'.
Proof.
destruct k; intros; try (inv H; left; constructor; fail).
right; eauto.
Qed.

Helper lemma for selecting a case in appended labeled statements
Lemma select_switch_case_app_right:
  forall ls1 ls2 pc,
    select_switch_case pc ls1 = None ->
    select_switch_case pc (app_lstmt ls1 ls2) = select_switch_case pc ls2.
Proof.
induction ls1; simpl; intros; auto.
destruct o; try (destruct (zeq z pc); try inv H; eauto).
eauto.
Qed.

Helper lemma for selecting case
Lemma select_switch_nil_select_switch_case:
  forall pc ls,
    select_switch pc ls = LSnil ->
    select_switch_case pc ls = None.
Proof.
induction ls; simpl; intros; eauto.
unfold select_switch in H; simpl in H.
destruct o. destruct (zeq z pc); try inv H.
exploit IHls; eauto. exploit IHls; eauto.
unfold select_switch. destruct (select_switch_case pc ls); auto; inv H.
Qed.

Helper lemma for selecting a case in appended labeled statements
Lemma select_switch_default_app_right:
  forall ls1 ls2,
    select_switch_default ls1 = LSnil ->
    select_switch_default (app_lstmt ls1 ls2) = select_switch_default ls2.
Proof.
induction ls1; simpl; intros; auto.
destruct o; eauto; inv H.
Qed.

Helper lemma for selecting a case in appended labeled statements
Lemma select_switch_app_right:
  forall ls1 ls2 pc,
    select_switch pc ls1 = LSnil ->
    select_switch pc (app_lstmt ls1 ls2) = select_switch pc ls2.
Proof.
induction ls1; simpl; intros; auto.
exploit select_switch_nil_select_switch_case; eauto; intros.
unfold select_switch in *. rewrite H0 in H. simpl in *.
destruct o.
- destruct (zeq z pc); try inv H0; eauto.
  rewrite select_switch_case_app_right; eauto.
  rewrite select_switch_default_app_right; auto.
- inv H.
Qed.

app_lstmt is associative
Lemma app_lstmt_assoc:
  forall ls1 ls2 ls3,
    app_lstmt (app_lstmt ls1 ls2) ls3 = app_lstmt ls1 (app_lstmt ls2 ls3).
Proof.
induction ls1; simpl; intros; eauto.
rewrite IHls1; eauto.
Qed.

select_switch_case never returns Some LSnil
Lemma select_switch_case_not_nil:
  forall n ls,
    select_switch_case n ls <> Some LSnil.
Proof.
induction ls; simpl; try congruence.
destruct o; auto.
destruct (zeq z n); try congruence; auto.
Qed.

If the case cannot be selected in ls1 ++ ls2, it can't be found in neither ls1 nor ls2
Lemma select_switch_app_nil:
  forall n ls1 ls2,
    select_switch n (app_lstmt ls1 ls2) = LSnil ->
    select_switch n ls1 = LSnil /\ select_switch n ls2 = LSnil.
Proof.
induction ls1; simpl; intros.
- split; simpl; auto.
- split; simpl.
  + unfold select_switch; simpl.
    unfold select_switch in H; simpl in H.
    destruct o.
    * destruct (zeq z n); try inv H.
      exploit IHls1; eauto; intros.
      destruct H. unfold select_switch in H. rewrite H. rewrite H1. auto.
    * generalize (select_switch_case_not_nil n (app_lstmt ls1 ls2)); intros.
      destruct (select_switch_case n (app_lstmt ls1 ls2)); inv H.
      contradict H0; auto.
  + unfold select_switch in H; simpl in H.
    destruct o.
    * destruct (zeq z n); try inv H.
      exploit IHls1; eauto; intros.
      destruct H; auto. rewrite H1; auto.
    * generalize (select_switch_case_not_nil n (app_lstmt ls1 ls2)); intros.
      destruct (select_switch_case n (app_lstmt ls1 ls2)); inv H.
      contradict H0; auto.
Qed.

The composition of Int.unsigned and phi is still injective
Lemma phi_injection:
  forall n m,
    0 <= n <= Int.max_unsigned ->
    0 <= m <= Int.max_unsigned ->
    Int.unsigned (phi n) = Int.unsigned (phi m) ->
    n = m.
Proof.
intros; eapply phi_injective; eauto.
destruct (phi n); destruct (phi m); simpl in H1.
eapply Int.mkint_eq; eauto.
Qed.

If statement s has been successfully transformed into labeled_statements ls and if there are no case corresponding to Int.unsigned (phi pc) in ls then pc must be either too low (pc < n) or too high (n + sizeof_stmt s <= pc) and conversely
Lemma select_switch_in_loop1_flatten:
  forall s id_t n m k l ls pc,
    0 <= n ->
    (n + sizeof_stmt s) <= Int.max_unsigned ->
    0 <= pc <= Int.max_unsigned ->
    flatten_loop1 phi id_t s n m k l = OK ls ->
    (select_switch (Int.unsigned (phi pc)) ls = LSnil <-> pc < n \/ n + sizeof_stmt s <= pc)
with select_switch_in_loop2_flatten:
  forall s id_t n m k ls pc,
    0 <= n ->
    (n + sizeof_stmt s) <= Int.max_unsigned ->
    0 <= pc <= Int.max_unsigned ->
    flatten_loop2 phi id_t s n m k = OK ls ->
    (select_switch (Int.unsigned (phi pc)) ls = LSnil <-> pc < n \/ n + sizeof_stmt s <= pc).
Proof.
- destruct s; intros; split; try (monadInv H2; unfold select_switch; simpl; intros; destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); try inv H2; simpl; destruct (zeq pc n); try congruence; omega; fail); try (monadInv H2; unfold select_switch; simpl; intros; destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); destruct (zeq pc n); try omega; auto; simpl in H0; generalize (phi_injection n pc); intros; exploit H3; eauto; try omega; fail).
  + monadInv H2; intros. unfold sizeof_stmt in H0; fold sizeof_stmt in H0.
    generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
    exploit (select_switch_in_loop1_flatten s2 id_t (n + sizeof_stmt s1) m k l); eauto; try omega. intros [AA AB].
    exploit (select_switch_in_loop1_flatten s1 id_t (n)); eauto; try omega. intros [BA BB].
    unfold sizeof_stmt; fold sizeof_stmt; intros.
    unfold select_switch in H2; simpl in H2.
    exploit select_switch_app_nil; eauto; intros [A B].
    apply AA in B. apply BA in A.
    destruct A; destruct B; try omega.
  + monadInv H2. unfold sizeof_stmt in H0; fold sizeof_stmt in H0; unfold sizeof_stmt; fold sizeof_stmt; intros.
    generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
    exploit (select_switch_in_loop1_flatten s1 id_t (n)); eauto; try omega. intros [A B].
    exploit (select_switch_in_loop1_flatten s2 id_t (n + sizeof_stmt s1) m k l); eauto; try omega. intros [C D]. clear A C.
    destruct H2; try omega.
    * replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
                 | Some sl' => sl'
                 | None => select_switch_default (app_lstmt x x0)
               end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
      rewrite select_switch_app_right. eapply D. left; omega.
      eapply B. left; omega.
    * replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
                 | Some sl' => sl'
                 | None => select_switch_default (app_lstmt x x0)
               end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
      rewrite select_switch_app_right. eapply D. right; omega.
      eapply B. right; omega.
  + monadInv H2. unfold sizeof_stmt in H0; fold sizeof_stmt in H0; unfold sizeof_stmt; fold sizeof_stmt; generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
    exploit (select_switch_in_loop1_flatten s1 id_t (n + 1)); eauto; try omega; intros [A B].
    exploit (select_switch_in_loop1_flatten s2 id_t (n + 1 + sizeof_stmt s1)); eauto; try omega; intros [C D].
    unfold select_switch in H4; simpl in H4. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); try inv H4.
    exploit select_switch_app_nil; eauto; intros [AA BB].
    eapply A in AA; eapply C in BB.
    destruct AA; destruct BB; try omega.
    destruct (zeq n pc); try congruence; omega.
  + monadInv H2. unfold sizeof_stmt in H0; fold sizeof_stmt in H0; unfold sizeof_stmt; fold sizeof_stmt; intros.
    generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
    exploit (select_switch_in_loop1_flatten s1 id_t (n + 1)); eauto; try omega. intros [A B].
    exploit (select_switch_in_loop1_flatten s2 id_t (n + 1 + sizeof_stmt s1) m k l); eauto; try omega. intros [C D].
    unfold select_switch; simpl.
    destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); destruct H2; try omega.
    * exploit (phi_injection n pc); eauto; omega.
    * exploit (phi_injection n pc); eauto; omega.
    * replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
                 | Some sl' => sl'
                 | None => select_switch_default (app_lstmt x x0)
               end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
      rewrite select_switch_app_right. eapply D. left; omega.
      eapply B. left; omega.
    * replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
                 | Some sl' => sl'
                 | None => select_switch_default (app_lstmt x x0)
               end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
      rewrite select_switch_app_right. eapply D. right; omega.
      eapply B. right; omega.
  + monadInv H2. unfold sizeof_stmt in H0; fold sizeof_stmt in H0; unfold sizeof_stmt; fold sizeof_stmt; generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
    exploit (select_switch_in_loop1_flatten s1 id_t (n + 1)); eauto; try omega; intros [A B].
    exploit (select_switch_in_loop2_flatten s2 id_t (n + 1 + sizeof_stmt s1)); eauto; try omega; intros [C D].
    unfold select_switch in H4; simpl in H4. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); try inv H4.
    exploit select_switch_app_nil; eauto; intros [AA BB].
    eapply A in AA; eapply C in BB.
    destruct AA; destruct BB; try omega.
    destruct (zeq n pc); try congruence; omega.
  + monadInv H2. unfold sizeof_stmt in H0; fold sizeof_stmt in H0; unfold sizeof_stmt; fold sizeof_stmt; intros.
    generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
    exploit (select_switch_in_loop1_flatten s1 id_t (n + 1)); eauto; try omega. intros [A B].
    exploit (select_switch_in_loop2_flatten s2 id_t (n + 1 + sizeof_stmt s1) n m); eauto; try omega. intros [C D].
    unfold select_switch; simpl.
    destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); destruct H2; try omega.
    * exploit (phi_injection n pc); eauto; omega.
    * exploit (phi_injection n pc); eauto; omega.
    * replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
                 | Some sl' => sl'
                 | None => select_switch_default (app_lstmt x x0)
               end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
      rewrite select_switch_app_right. eapply D. left; omega.
      eapply B. left; omega.
    * replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
                 | Some sl' => sl'
                 | None => select_switch_default (app_lstmt x x0)
               end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
      rewrite select_switch_app_right. eapply D. right; omega.
      eapply B. right; omega.
- destruct s; intros; split; try (monadInv H2; unfold select_switch; simpl; intros; destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); try inv H2; simpl; destruct (zeq pc n); try congruence; omega; fail); try (monadInv H2; unfold select_switch; simpl; intros; destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); destruct (zeq pc n); try omega; auto; simpl in H0; generalize (phi_injection n pc); intros; exploit H3; eauto; try omega; fail).
  + monadInv H2; intros. unfold sizeof_stmt in H0; fold sizeof_stmt in H0.
    generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
    exploit (select_switch_in_loop2_flatten s2 id_t (n + sizeof_stmt s1) m k); eauto; try omega. intros [AA AB].
    exploit (select_switch_in_loop2_flatten s1 id_t (n)); eauto; try omega. intros [BA BB].
    unfold sizeof_stmt; fold sizeof_stmt; intros.
    unfold select_switch in H2; simpl in H2.
    exploit select_switch_app_nil; eauto; intros [A B].
    apply AA in B. apply BA in A.
    destruct A; destruct B; try omega.
  + monadInv H2. unfold sizeof_stmt in H0; fold sizeof_stmt in H0; unfold sizeof_stmt; fold sizeof_stmt; intros.
    generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
    exploit (select_switch_in_loop2_flatten s1 id_t (n)); eauto; try omega. intros [A B].
    exploit (select_switch_in_loop2_flatten s2 id_t (n + sizeof_stmt s1) m k); eauto; try omega. intros [C D].
    unfold select_switch; simpl.
    destruct H2; try omega.
    * replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
                 | Some sl' => sl'
                 | None => select_switch_default (app_lstmt x x0)
               end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
      rewrite select_switch_app_right. eapply D. left; omega.
      eapply B. left; omega.
    * replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
                 | Some sl' => sl'
                 | None => select_switch_default (app_lstmt x x0)
               end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
      rewrite select_switch_app_right. eapply D. right; omega.
      eapply B. right; omega.
  + monadInv H2. unfold sizeof_stmt in H0; fold sizeof_stmt in H0; unfold sizeof_stmt; fold sizeof_stmt; generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
    exploit (select_switch_in_loop2_flatten s1 id_t (n + 1)); eauto; try omega; intros [A B].
    exploit (select_switch_in_loop2_flatten s2 id_t (n + 1 + sizeof_stmt s1)); eauto; try omega; intros [C D].
    unfold select_switch in H4; simpl in H4. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); try inv H4.
    exploit select_switch_app_nil; eauto; intros [AA BB].
    eapply A in AA; eapply C in BB.
    destruct AA; destruct BB; try omega.
    destruct (zeq n pc); try congruence; omega.
  + monadInv H2. unfold sizeof_stmt in H0; fold sizeof_stmt in H0; unfold sizeof_stmt; fold sizeof_stmt; intros.
    generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
    exploit (select_switch_in_loop2_flatten s1 id_t (n + 1)); eauto; try omega. intros [A B].
    exploit (select_switch_in_loop2_flatten s2 id_t (n + 1 + sizeof_stmt s1) m k); eauto; try omega. intros [C D].
    unfold select_switch; simpl.
    destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); destruct H2; try omega.
    * exploit (phi_injection n pc); eauto; omega.
    * exploit (phi_injection n pc); eauto; omega.
    * replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
                 | Some sl' => sl'
                 | None => select_switch_default (app_lstmt x x0)
               end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
      rewrite select_switch_app_right. eapply D. left; omega.
      eapply B. left; omega.
    * replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
                 | Some sl' => sl'
                 | None => select_switch_default (app_lstmt x x0)
               end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
      rewrite select_switch_app_right. eapply D. right; omega.
      eapply B. right; omega.
  + monadInv H2. unfold sizeof_stmt in H0; fold sizeof_stmt in H0; unfold sizeof_stmt; fold sizeof_stmt; generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
    exploit (select_switch_in_loop1_flatten s1 id_t (n + 1)); eauto; try omega; intros [A B].
    exploit (select_switch_in_loop2_flatten s2 id_t (n + 1 + sizeof_stmt s1)); eauto; try omega; intros [C D].
    unfold select_switch in H4; simpl in H4. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); try inv H4.
    exploit select_switch_app_nil; eauto; intros [AA BB].
    eapply A in AA; eapply C in BB.
    destruct AA; destruct BB; try omega.
    destruct (zeq n pc); try congruence; omega.
  + monadInv H2. unfold sizeof_stmt in H0; fold sizeof_stmt in H0; unfold sizeof_stmt; fold sizeof_stmt; intros.
    generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
    exploit (select_switch_in_loop1_flatten s1 id_t (n + 1)); eauto; try omega. intros [A B].
    exploit (select_switch_in_loop2_flatten s2 id_t (n + 1 + sizeof_stmt s1) n m); eauto; try omega. intros [C D].
    unfold select_switch; simpl.
    destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); destruct H2; try omega.
    * exploit (phi_injection n pc); eauto; omega.
    * exploit (phi_injection n pc); eauto; omega.
    * replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
                 | Some sl' => sl'
                 | None => select_switch_default (app_lstmt x x0)
               end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
      rewrite select_switch_app_right. eapply D. left; omega.
      eapply B. left; omega.
    * replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
                 | Some sl' => sl'
                 | None => select_switch_default (app_lstmt x x0)
               end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
      rewrite select_switch_app_right. eapply D. right; omega.
      eapply B. right; omega.
Qed.

If statement s has been successfully transformed into labeled_statements ls and if there are no case corresponding to Int.unsigned (phi pc) in ls then pc must be either too low (pc < n) or too high (n + sizeof_stmt s <= pc) and conversely
Lemma select_switch_flatten:
  forall s id_t n m ls pc,
    0 <= n ->
    (n + sizeof_stmt s) <= Int.max_unsigned ->
    0 <= pc <= Int.max_unsigned ->
    flatten phi id_t s n m = OK ls ->
    (select_switch (Int.unsigned (phi pc)) ls = LSnil <-> pc < n \/ n + sizeof_stmt s <= pc).
Proof.
induction s; intros; split; try (monadInv H2; unfold select_switch; simpl; intros; destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); try inv H2; simpl; destruct (zeq pc n); try congruence; omega; fail); try (monadInv H2; unfold select_switch; simpl; intros; destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); destruct (zeq pc n); try omega; auto; simpl in H0; generalize (phi_injection n pc); intros; exploit H3; eauto; try omega; fail).
- unfold sizeof_stmt in H0; fold sizeof_stmt in H0; generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
  monadInv H2. unfold select_switch in H5; simpl in H5.
  exploit select_switch_app_nil; eauto; intros [A B].
  unfold sizeof_stmt; fold sizeof_stmt.
  exploit (IHs1 id_t (n)); eauto; try omega. intros [AA AB].
  exploit (IHs2 id_t (n + sizeof_stmt s1)); eauto; try omega. intros [BA BB].
  apply AA in A; apply BA in B.
  destruct A; destruct B; try omega.
- monadInv H2; intros. unfold sizeof_stmt in H2; fold sizeof_stmt in H2.
  generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
  unfold select_switch; simpl.
  unfold sizeof_stmt in H0; fold sizeof_stmt in H0; generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
  destruct H2; try omega.
  + exploit (IHs1 id_t (n)); eauto; try omega. intros [A B].
    exploit (IHs2 id_t (n + sizeof_stmt s1)); eauto; try omega. intros [C D].
    replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
   | Some sl' => sl'
   | None => select_switch_default (app_lstmt x x0)
   end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
    rewrite select_switch_app_right.
    * eapply D. left; omega.
    * eapply B. left; omega.
  + exploit (IHs1 id_t (n)); eauto; try omega. intros [A B].
    exploit (IHs2 id_t (n + sizeof_stmt s1)); eauto; try omega. intros [C D].
    replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
   | Some sl' => sl'
   | None => select_switch_default (app_lstmt x x0)
   end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
    rewrite select_switch_app_right.
    * eapply D. right; omega.
    * eapply B. right; omega.
- unfold sizeof_stmt in H0; fold sizeof_stmt in H0; generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
  monadInv H2. unfold select_switch in H5; simpl in H5.
  destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); try (inv H5; fail).
  exploit select_switch_app_nil; eauto; intros [A B].
  unfold sizeof_stmt; fold sizeof_stmt.
  exploit (IHs1 id_t (n + 1)); eauto; try omega. intros [AA AB].
  exploit (IHs2 id_t (n + 1 + sizeof_stmt s1)); eauto; try omega. intros [BA BB].
  apply AA in A; apply BA in B.
  destruct A; destruct B; try omega.
  destruct (zeq pc n); try congruence; try omega.
- monadInv H2; intros. unfold sizeof_stmt in H2; fold sizeof_stmt in H2.
  generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
  unfold select_switch; simpl.
  unfold sizeof_stmt in H0; fold sizeof_stmt in H0; generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
  destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); destruct H2; try omega.
  + exploit (phi_injection n pc); eauto; try omega.
  + exploit (phi_injection n pc); eauto; try omega.
  + exploit (IHs1 id_t (n + 1)); eauto; try omega. intros [A B].
    exploit (IHs2 id_t (n + 1 + sizeof_stmt s1)); eauto; try omega. intros [C D].
    replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
   | Some sl' => sl'
   | None => select_switch_default (app_lstmt x x0)
   end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
    rewrite select_switch_app_right.
    * eapply D. left; omega.
    * eapply B. left; omega.
  + exploit (IHs1 id_t (n + 1)); eauto; try omega. intros [A B].
    exploit (IHs2 id_t (n + 1 + sizeof_stmt s1)); eauto; try omega. intros [C D].
    replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
   | Some sl' => sl'
   | None => select_switch_default (app_lstmt x x0)
   end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
    rewrite select_switch_app_right.
    * eapply D. right; omega.
    * eapply B. right; omega.
- unfold sizeof_stmt in H0; fold sizeof_stmt in H0; generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
  monadInv H2. unfold select_switch in H5; simpl in H5.
  destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); try (inv H5; fail).
  exploit select_switch_app_nil; eauto; intros [A B].
  unfold sizeof_stmt; fold sizeof_stmt.
  exploit (select_switch_in_loop1_flatten s1 id_t (n + 1)); eauto; try omega. intros [AA AB].
  exploit (select_switch_in_loop2_flatten s2 id_t (n + 1 + sizeof_stmt s1)); eauto; try omega. intros [BA BB].
  apply AA in A; apply BA in B.
  destruct A; destruct B; try omega.
  destruct (zeq pc n); try congruence; try omega.
- monadInv H2; intros. unfold sizeof_stmt in H2; fold sizeof_stmt in H2.
  generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
  unfold select_switch; simpl.
  unfold sizeof_stmt in H0; fold sizeof_stmt in H0; generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
  destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi pc))); destruct H2; try omega.
  + exploit (phi_injection n pc); eauto; try omega.
  + exploit (phi_injection n pc); eauto; try omega.
  + exploit (select_switch_in_loop1_flatten s1 id_t (n + 1)); eauto; try omega. intros [A B].
    exploit (select_switch_in_loop2_flatten s2 id_t (n + 1 + sizeof_stmt s1)); eauto; try omega. intros [C D].
    replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
   | Some sl' => sl'
   | None => select_switch_default (app_lstmt x x0)
   end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
    rewrite select_switch_app_right.
    * eapply D. left; omega.
    * eapply B. left; omega.
  + exploit (select_switch_in_loop1_flatten s1 id_t (n + 1)); eauto; try omega. intros [A B].
    exploit (select_switch_in_loop2_flatten s2 id_t (n + 1 + sizeof_stmt s1)); eauto; try omega. intros [C D].
    replace (match select_switch_case (Int.unsigned (phi pc)) (app_lstmt x x0) with
   | Some sl' => sl'
   | None => select_switch_default (app_lstmt x x0)
   end) with (select_switch (Int.unsigned (phi pc)) (app_lstmt x x0)); auto.
    rewrite select_switch_app_right.
    * eapply D. right; omega.
    * eapply B. right; omega.
Qed.

Helper lemma relating cons and append over labeled_statements
Lemma lscons_app_lstmt:
  forall o s ls,
    LScons o s ls = app_lstmt (LScons o s LSnil) ls.
Proof.
simpl; auto. Qed.

Helper lemma relating cons and append over labeled_statements
Lemma app_lstmt_lscons:
  forall o s ls1 ls2,
    LScons o s (app_lstmt ls1 ls2) = app_lstmt (LScons o s ls1) ls2.
Proof.
simpl; auto. Qed.

LSnil is the identity element for appending labeled_statements
Lemma app_lstmt_lsnil:
  forall ls,
    app_lstmt ls LSnil = ls.
Proof.
induction ls; simpl; eauto. rewrite IHls; auto. Qed.

If the context of continuation k is Kloop1 then k must either be Kloop1 or Kseq
Lemma context_loop1:
  forall k s1 s2 k',
    context k = Kloop1 s1 s2 k' ->
    k = Kloop1 s1 s2 k' \/ exists s'' k'', k = Kseq s'' k''.
Proof.
induction k; intros; try (inv H). right; eauto. left; eauto. Qed.

If the context of continuation k is Kloop2 then k must either be Kloop2 or Kseq
Lemma context_loop2:
  forall k s1 s2 k',
    context k = Kloop2 s1 s2 k' ->
    k = Kloop2 s1 s2 k' \/ exists s'' k'', k = Kseq s'' k''.
Proof.
induction k; intros; try (inv H). right; eauto. left; eauto. Qed.

Fast-forward to the context
Lemma break_continue_seq_match_stmt_cont_in_loop1:
  forall k s s1 s2 k' start pc next_instr to_continue to_break ls id_t,
    context k = Kloop1 s1 s2 k' ->
    s = Sbreak \/ s = Scontinue ->
    (match_stmt_cont_in_loop1 s ls id_t start pc next_instr to_continue to_break (Kloop1 s1 s2 k') <->
    match_stmt_cont_in_loop1 s ls id_t start pc next_instr to_continue to_break k).
Proof.
intros; split.
- induction k; intros; try (simpl in H; inv H; fail).
  + destruct H0; subst s; econstructor; eauto.
  + simpl in H; inv H; eauto.
- induction k; intros; try (simpl in H; inv H; fail).
  + destruct H0; subst s; eapply IHk; inv H1; eauto.
  + simpl in H; inv H; eauto.
Qed.

Fast-forward to the context
Lemma break_seq_match_stmt_cont_in_loop2:
  forall k s1 s2 k' start pc next_instr to_continue to_break ls id_t,
    context k = Kloop2 s1 s2 k' ->
    (match_stmt_cont_in_loop2 Sbreak ls id_t start pc next_instr to_continue to_break (Kloop2 s1 s2 k') <->
    match_stmt_cont_in_loop2 Sbreak ls id_t start pc next_instr to_continue to_break k).
Proof.
intros; split.
- induction k; intros; try (simpl in H; inv H; fail).
  + econstructor; eauto.
  + simpl in H; inv H; eauto.
- induction k; intros; try (simpl in H; inv H; fail).
  + eapply IHk; inv H0; eauto.
  + simpl in H; inv H; eauto.
Qed.

Sbreak has the same semantics within a Kloop1 or a Kloop2 context
Lemma break_loop1_loop2:
  forall s1 s2 k ls id_t start pc next_instr to_continue to_break,
    match_stmt_cont_in_loop1 Sbreak ls id_t start pc next_instr to_continue to_break (Kloop1 s1 s2 k) <-> match_stmt_cont_in_loop2 Sbreak ls id_t start pc next_instr to_continue to_break (Kloop2 s1 s2 k).
Proof.
intros; split; intros; inv H; econstructor; eauto. Qed.

If statement s can be matched with a case in labeled_statements ls with number pc then pc must be 0 < pc <= Int.max_unsigned
Lemma match_stmt_cont_in_loop1_pos:
  forall s ls id_t start pc next_instr to_continue to_break k,
    match_stmt_cont_in_loop1 s ls id_t start pc next_instr to_continue to_break k ->
    0 < pc <= Int.max_unsigned
with match_stmt_cont_in_loop2_pos:
       forall s ls id_t start pc next_instr to_continue to_break k,
         match_stmt_cont_in_loop2 s ls id_t start pc next_instr to_continue to_break k ->
         0 < pc <= Int.max_unsigned.
Proof.
- destruct s; intros; inv H; auto.
  + destruct H0 as [s1 [s2 [k' H0]]].
    generalize (break_continue_seq_match_stmt_cont_in_loop1 k0 Sbreak s1 s2 k' start pc next_instr to_continue to_break ls id_t H0 (or_introl (eq_refl Sbreak))).
    intros. apply H in H1. inv H1; eauto.
  + destruct H0 as [s1 [s2 [k' H0]]].
    generalize (break_continue_seq_match_stmt_cont_in_loop1 k0 Scontinue s1 s2 k' start pc next_instr to_continue to_break ls id_t H0 (or_intror (eq_refl Scontinue))).
    intros. apply H in H1. inv H1; eauto.
- destruct s; intros; inv H; auto.
  destruct H0 as [s1 [s2 [k' H0]]].
  generalize (break_seq_match_stmt_cont_in_loop2 k0 s1 s2 k' start pc next_instr to_continue to_break ls id_t H0). intros. apply H in H1. inv H1; eauto.
Qed.

Obfuscating statement s through flatten returns a labeled_statements ls that can be matched with s
Fixpoint match_stmt_cont_flatten s { struct s } :
  forall k ls ls1 ls2 pc next_instr id_t,
    is_call_cont (context k) ->
    flatten phi id_t s pc next_instr = OK ls ->
    (forall s' k', k = Kseq s' k' ->
                   exists next_instr',
                     0 < next_instr <= Int.max_unsigned /\
                     match_stmt_cont s' (app_lstmt ls1 (app_lstmt ls ls2)) id_t next_instr next_instr' k') ->
    (is_call_cont k -> next_instr = 0 /\ select_switch (Int.unsigned (phi next_instr)) (app_lstmt ls1 (app_lstmt ls ls2)) = LSnil) ->
    (next_instr < pc \/ next_instr >= pc + sizeof_stmt s) ->
    (forall n, pc <= n <= Int.max_unsigned -> select_switch (Int.unsigned (phi n)) ls1 = LSnil) ->
    0 < pc ->
    pc + sizeof_stmt s <= Int.max_unsigned ->
    match_stmt_cont s (app_lstmt ls1 (app_lstmt ls ls2)) id_t pc next_instr k
with match_stmt_cont_in_loop1_flatten_loop1 s { struct s } :
  forall k ls ls1 ls2 start start' pc next_instr to_continue to_continue' to_break to_break' id_t,
    (exists s1 s2 k', context k = Kloop1 s1 s2 k' /\
    (forall counter ls' next,
       0 < counter <= Int.max_unsigned ->
       select_switch_case (Int.unsigned (phi counter)) (app_lstmt ls1 (app_lstmt ls ls2)) =
       Some (LScons (Some (Int.unsigned (phi counter))) (Ssequence (Sset (fst id_t) (Econst_int (phi to_break) (snd id_t))) Sbreak) ls') -> match_stmt_cont_in_loop1 Sbreak (app_lstmt ls1 (app_lstmt ls ls2)) id_t (start::start') counter next (to_continue::to_continue') (to_break::to_break') (Kloop1 s1 s2 k')) /\
    (forall counter ls' next,
      0 < counter <= Int.max_unsigned ->
      select_switch_case (Int.unsigned (phi counter)) (app_lstmt ls1 (app_lstmt ls ls2)) =
      Some (LScons (Some (Int.unsigned (phi counter))) (Ssequence (Sset (fst id_t) (Econst_int (phi to_continue) (snd id_t))) Sbreak) ls') -> match_stmt_cont_in_loop1 Scontinue (app_lstmt ls1 (app_lstmt ls ls2)) id_t (start::start') counter next (to_continue::to_continue') (to_break::to_break') (Kloop1 s1 s2 k'))) ->
    flatten_loop1 phi id_t s pc next_instr to_continue to_break = OK ls ->
    (forall s' k', k = Kseq s' k' ->
                   ((exists next_instr',
                     match_stmt_cont_in_loop1 s' (app_lstmt ls1 (app_lstmt ls ls2)) id_t (start::start') next_instr next_instr' (to_continue::to_continue') (to_break::to_break') k'))) ->
    (forall s1' s2' k', k = Kloop1 s1' s2' k' ->
                        (next_instr = to_continue) /\
                        (exists ls',
                           (next_instr = start + 1 + sizeof_stmt s1') /\
                           (0 < start /\ start + 1 + sizeof_stmt s1' + sizeof_stmt s2' <= Int.max_unsigned) /\
                           match_stmt_cont_in_loop2 s2' (app_lstmt ls1 (app_lstmt ls ls2)) id_t (start::start') next_instr start (to_continue::to_continue') (to_break::to_break') (Kloop2 s1' s2' k') /\
                           select_switch_case (Int.unsigned (phi start)) (app_lstmt ls1 (app_lstmt ls ls2)) = Some (LScons (Some (Int.unsigned (phi start))) (Ssequence (Sset (fst id_t) (Econst_int (phi (start + 1)) (snd id_t))) Sbreak) ls')) /\
                        ((is_call_cont (context k') /\ start' = nil /\ to_continue' = nil /\ to_break' = nil /\ exists next_instr', match_stmt_cont Sskip (app_lstmt ls1 (app_lstmt ls ls2)) id_t to_break next_instr' k') \/
                         (exists s1'' s2'' k'', context k' = Kloop1 s1'' s2'' k'' /\ exists next_instr', match_stmt_cont_in_loop1 Sskip (app_lstmt ls1 (app_lstmt ls ls2)) id_t start' to_break next_instr' to_continue' to_break' k') \/
                         (exists s1'' s2'' k'', context k' = Kloop2 s1'' s2'' k'' /\ exists next_instr', match_stmt_cont_in_loop2 Sskip (app_lstmt ls1 (app_lstmt ls ls2)) id_t start' to_break next_instr' to_continue' to_break' k'))) ->
    (next_instr < pc \/ next_instr >= pc + sizeof_stmt s) ->
    (forall n, pc <= n <= Int.max_unsigned -> select_switch (Int.unsigned (phi n)) ls1 = LSnil) ->
    0 < pc ->
    pc + sizeof_stmt s <= Int.max_unsigned ->
    match_stmt_cont_in_loop1 s (app_lstmt ls1 (app_lstmt ls ls2)) id_t (start::start') pc next_instr (to_continue::to_continue') (to_break::to_break') k
with match_stmt_cont_in_loop2_flatten_loop2 s { struct s } :
       forall k ls ls1 ls2 start start' pc next_instr to_continue to_continue' to_break to_break' id_t,
         (exists s1 s2 k', context k = Kloop2 s1 s2 k' /\
         (forall counter ls' next,
            0 < counter <= Int.max_unsigned ->
            select_switch_case (Int.unsigned (phi counter)) (app_lstmt ls1 (app_lstmt ls ls2)) =
            Some (LScons (Some (Int.unsigned (phi counter))) (Ssequence (Sset (fst id_t) (Econst_int (phi to_break) (snd id_t))) Sbreak) ls') -> match_stmt_cont_in_loop2 Sbreak (app_lstmt ls1 (app_lstmt ls ls2)) id_t (start::start') counter next (to_continue::to_continue') (to_break::to_break') (Kloop2 s1 s2 k'))) ->
         flatten_loop2 phi id_t s pc next_instr to_break = OK ls ->
         (forall s' k', k = Kseq s' k' ->
                        ((exists next_instr',
                          match_stmt_cont_in_loop2 s' (app_lstmt ls1 (app_lstmt ls ls2)) id_t (start::start') next_instr next_instr' (to_continue::to_continue') (to_break::to_break') k'))) ->
         (forall s1' s2' k', k = Kloop2 s1' s2' k' ->
                             (exists ls',
                                next_instr = start /\
                                (0 < start /\ start + 1 + sizeof_stmt s1' + sizeof_stmt s2' <= Int.max_unsigned) /\
                                select_switch_case (Int.unsigned (phi next_instr)) (app_lstmt ls1 (app_lstmt ls ls2)) = Some (LScons (Some (Int.unsigned (phi next_instr))) (Ssequence (Sset (fst id_t) (Econst_int (phi (start + 1)) (snd id_t))) Sbreak) ls')) /\
                             ((is_call_cont (context k') /\ start' = nil /\ to_continue' = nil /\ to_break' = nil /\ exists next_instr', match_stmt_cont Sskip (app_lstmt ls1 (app_lstmt ls ls2)) id_t to_break next_instr' k') \/
                             (exists s1'' s2'' k'', context k' = Kloop1 s1'' s2'' k'' /\ exists next_instr', match_stmt_cont_in_loop1 Sskip (app_lstmt ls1 (app_lstmt ls ls2)) id_t start' to_break next_instr' to_continue' to_break' k') \/
                             (exists s1'' s2'' k'', context k' = Kloop2 s1'' s2'' k'' /\ exists next_instr', match_stmt_cont_in_loop2 Sskip (app_lstmt ls1 (app_lstmt ls ls2)) id_t start' to_break next_instr' to_continue' to_break' k'))) ->
         (next_instr < pc \/ next_instr >= pc + sizeof_stmt s) ->
         (forall n, pc <= n <= Int.max_unsigned -> select_switch (Int.unsigned (phi n)) ls1 = LSnil) ->
         0 < pc ->
         pc + sizeof_stmt s <= Int.max_unsigned ->
         match_stmt_cont_in_loop2 s (app_lstmt ls1 (app_lstmt ls ls2)) id_t (start::start') pc next_instr (to_continue::to_continue') (to_break::to_break') k.
Proof.
{ destruct s; intros.
  - monadInv H0; destruct (is_call_cont_context k H).
    + econstructor; eauto.
      left; split.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { simpl in H6; eapply select_switch_nil_select_switch_case; eapply H4; try omega. }
      * exploit H2; eauto; intros [A B]; repeat split; eauto.
        simpl in H6; omega.
    + destruct H0 as [s' [k' H0]]. subst k. econstructor; eauto.
      * simpl in H6; omega.
      * left; split.
        { rewrite select_switch_case_app_right.
          - simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
          - simpl in H6; eapply select_switch_nil_select_switch_case; eapply H4; omega. }
        { exploit H1; eauto; intros [next_instr' [A B]]; eauto. }
  - monadInv H0; destruct (is_call_cont_context k H).
    + econstructor; eauto.
      * simpl in H6; omega.
      * simpl; rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { simpl in H6; eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * eexists. econstructor; eauto.
    + destruct H0 as [s' [k' H0]]. subst k. econstructor; eauto.
      * simpl in H6; omega.
      * simpl; rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { simpl in H6; eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * exploit H1; eauto; intros [next_instr' [A B]]. eexists. econstructor; eauto.
  - monadInv H0; destruct (is_call_cont_context k H).
    + econstructor; eauto.
      * simpl in H6; omega.
      * simpl; rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { simpl in H6; eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * eexists. econstructor; eauto.
    + destruct H0 as [s' [k' H0]]. subst k. econstructor; eauto.
      * simpl in H6; omega.
      * simpl; rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { simpl in H6; eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * exploit H1; eauto; intros [next_instr' [A B]]. eexists. econstructor; eauto.
  - monadInv H0; destruct (is_call_cont_context k H).
    + econstructor; eauto.
      * simpl in H6; omega.
      * simpl; rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { simpl in H6; eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * eexists. econstructor; eauto.
    + destruct H0 as [s' [k' H0]]. subst k. econstructor; eauto.
      * simpl in H6; omega.
      * simpl; rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { simpl in H6; eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * exploit H1; eauto; intros [next_instr' [A B]]. eexists. econstructor; eauto.
  - monadInv H0; destruct (is_call_cont_context k H).
    + econstructor; eauto.
      * simpl in H6; omega.
      * simpl; rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { simpl in H6; eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * eexists. econstructor; eauto.
    + destruct H0 as [s' [k' H0]]. subst k. econstructor; eauto.
      * simpl in H6; omega.
      * simpl; rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { simpl in H6; eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * exploit H1; eauto; intros [next_instr' [A B]]. eexists. econstructor; eauto.
  - monadInv H0; generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros; destruct (is_call_cont_context k H).
    + econstructor; eauto.
      * unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega.
rewrite select_switch_case_app_right. { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. } { unfold sizeof_stmt in H6; fold sizeof_stmt in H6; eapply select_switch_nil_select_switch_case; eapply H4; try omega. }
      * assert (app_lstmt ls1 (app_lstmt (app_lstmt x x0) ls2) = app_lstmt ls1 (app_lstmt x (app_lstmt x0 ls2))). repeat rewrite app_lstmt_assoc; eauto.
        rewrite H9. eapply match_stmt_cont_flatten; eauto.
        { intros. inversion H10. subst s'. subst k'. clear H10. eexists; split; eauto.
          - unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega.
          - assert (app_lstmt ls1 (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt (app_lstmt ls1 x) (app_lstmt x0 ls2)).
            repeat (rewrite app_lstmt_assoc); eauto.
            rewrite H10. eapply match_stmt_cont_flatten; eauto.
            + rewrite <- H10; rewrite <- H9; exact H1.
            + rewrite <- H10; rewrite <- H9; exact H2.
            + unfold sizeof_stmt in H3; fold sizeof_stmt in H3; omega.
            + intros. rewrite select_switch_app_right.
              * eapply (select_switch_flatten s1 id_t (pc)); eauto; try omega.
              * eapply H4; omega.
            + omega.
            + unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega. }
        { intros. inv H10. }
        { omega. }
        { unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega. }
      * assert (app_lstmt ls1 (app_lstmt (app_lstmt x x0) ls2) = app_lstmt (app_lstmt ls1 x) (app_lstmt x0 ls2)). repeat (rewrite app_lstmt_assoc); simpl; eauto.
        rewrite H9. eapply match_stmt_cont_flatten; eauto.
        { rewrite <- H9; exact H1. }
        { rewrite <- H9; exact H2. }
        { unfold sizeof_stmt in H3; fold sizeof_stmt in H3; omega. }
        { intros. rewrite select_switch_app_right.
          - eapply (select_switch_flatten s1 id_t (pc)); eauto; try omega.
          - eapply H4; omega. }
        { omega. }
        { unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega. }
    + destruct H8 as [s' [k' H8]]. subst k. unfold sizeof_stmt in H6; fold sizeof_stmt in H6; unfold sizeof_stmt in H3; fold sizeof_stmt in H3; econstructor; eauto.
      * omega.
      * assert (app_lstmt ls1 (app_lstmt (app_lstmt x x0) ls2) = app_lstmt ls1 (app_lstmt x (app_lstmt x0 ls2))). repeat (rewrite app_lstmt_assoc); eauto.
        rewrite H8. eapply match_stmt_cont_flatten; eauto.
        { intros. inversion H9; subst s'0; subst k'0; clear H9. eexists; split; eauto.
          - omega.
          - assert (app_lstmt ls1 (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt (app_lstmt ls1 x) (app_lstmt x0 ls2)). repeat (rewrite app_lstmt_assoc); eauto.
          rewrite H9. eapply match_stmt_cont_flatten; eauto.
            + rewrite <- H9; rewrite <- H8; exact H1.
            + rewrite <- H9; rewrite <- H8; exact H2.
            + omega.
            + intros. rewrite select_switch_app_right.
              * eapply select_switch_flatten; eauto; omega.
              * eapply H4; omega.
            + omega.
            + omega. }
        { intros. inv H9. }
        { omega. }
        { omega. }
      * assert (app_lstmt ls1 (app_lstmt (app_lstmt x x0) ls2) = app_lstmt (app_lstmt ls1 x) (app_lstmt x0 ls2)). repeat (rewrite app_lstmt_assoc); simpl; eauto.
        rewrite H8. eapply match_stmt_cont_flatten; eauto.
        { rewrite <- H8; exact H1. }
        { rewrite <- H8; exact H2. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - eapply select_switch_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
  - monadInv H0; generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros; unfold sizeof_stmt in H3; unfold sizeof_stmt in H6; fold sizeof_stmt in H3; fold sizeof_stmt in H6.
    econstructor; eauto.
    + omega.
    + rewrite lscons_app_lstmt. repeat (rewrite app_lstmt_assoc).
      simpl. rewrite select_switch_case_app_right.
      * simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
      * eapply select_switch_nil_select_switch_case; eapply H4; omega.
    + assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) LSnil)) (app_lstmt x (app_lstmt x0 ls2))). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
      rewrite H8. eapply match_stmt_cont_flatten; eauto.
      * rewrite <- H8; exact H1.
      * rewrite <- H8; exact H2.
      * omega.
      * intros. rewrite select_switch_app_right.
        { unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
          exploit (phi_injection pc n); try omega. }
        { eapply H4; omega. }
      * omega.
      * omega.
    + assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) x)) (app_lstmt x0 ls2)).
      rewrite lscons_app_lstmt. repeat (rewrite app_lstmt_assoc); simpl; eauto.
      rewrite H8. eapply match_stmt_cont_flatten; eauto.
      * rewrite <- H8; exact H1.
      * rewrite <- H8; exact H2.
      * omega.
      * intros. rewrite select_switch_app_right.
        { unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega.
          - exploit (phi_injection pc n); omega.
          - eapply select_switch_flatten; eauto; omega. }
        { eapply H4; omega. }
      * omega.
      * omega.
  - monadInv H0; generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros; unfold sizeof_stmt in H3; unfold sizeof_stmt in H6; fold sizeof_stmt in H3; fold sizeof_stmt in H6; destruct (is_call_cont_context k H).
    + econstructor; eauto.
      * omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2))). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
        rewrite H9. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. repeat split; eauto.
          - intros. econstructor; eauto.
            left. split; auto. eexists. repeat split; auto. econstructor; eauto.
            right. rewrite <- H9. eapply H2; eauto.
          - intros. econstructor; eauto. assert (app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
            rewrite H12.
            eexists. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
            + eexists. eexists. eexists. repeat split; eauto.
              intros. econstructor; eauto.
              left. split; auto. eexists. repeat split; auto. econstructor; eauto.
              right. rewrite <- H12. rewrite <- H9. eapply H2; eauto.
            + intros. inv H13.
            + intros. inv H13. repeat split; eauto.
              * eexists. repeat split; eauto.
                { omega. }
                { repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
                  - simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
                  - eapply select_switch_nil_select_switch_case; eapply H4; omega. }
              * left. repeat split; eauto. eexists. econstructor; eauto.
                right. rewrite <- H12; rewrite <- H9; eapply H2; eauto.
            + omega.
            + intros; rewrite select_switch_app_right.
              * unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
                { exploit (phi_injection pc n); try omega. }
                { eapply select_switch_in_loop1_flatten; eauto; try omega. }
              * eapply H4; omega.
            + omega.
            + omega. }
        { intros. inv H10. }
        { intros. inversion H10. subst s1'; subst s2'; subst k'; clear H10. repeat split; eauto.
          - eexists. repeat split; eauto.
            + omega.
            + assert (app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
              rewrite H10. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
              * eexists. eexists. eexists. repeat split; eauto.
                intros. econstructor; eauto.
                left. split; auto. eexists. repeat split; auto. econstructor; eauto.
                right. rewrite <- H10. rewrite <- H9. eapply H2; eauto.
              * intros. inv H11.
              * intros. inv H11. repeat split; eauto.
                { eexists. repeat split; eauto.
                  - omega.
                  - repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
                    + simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
                    + eapply select_switch_nil_select_switch_case; eapply H4; omega. }
                { left. repeat split; eauto. eexists. econstructor; eauto.
                  right. rewrite <- H10; rewrite <- H9; eapply H2; eauto. }
              * omega.
              * intros; rewrite select_switch_app_right.
                { unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
                  - exploit (phi_injection pc n); omega.
                  - eapply select_switch_in_loop1_flatten; eauto; try omega. }
                { eapply H4; omega. }
              * omega.
              * omega.
            + repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right. * simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
              * eapply select_switch_nil_select_switch_case; eapply H4; omega.
          - left. repeat split; eauto. eexists. econstructor; eauto.
            right. rewrite <- H9; eapply H2; eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            exploit (phi_injection pc n); omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) (app_lstmt x x0)) ls2) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt. repeat (rewrite app_lstmt_assoc); simpl; eauto.
        rewrite H9. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { eexists. eexists. eexists. repeat split; eauto.
          - intros. econstructor; eauto.
            left. split; eauto. eexists. repeat split; eauto. econstructor; eauto.
            right. rewrite <- H9; eapply H2; eauto. }
        { intros. inv H10. }
        { intros. inv H10. split.
          - eexists. repeat split; eauto.
            + omega.
            + repeat rewrite app_lstmt_assoc. rewrite select_switch_case_app_right.
              * simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
              * eapply select_switch_nil_select_switch_case; eapply H4; omega.
          - left. repeat split; eauto.
            eexists. econstructor; eauto. right. rewrite <- H9; eapply H2; eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            + exploit (phi_injection pc n); try omega.
            + eapply select_switch_in_loop1_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
    + destruct H8 as [s' [k' H8]]. subst k. econstructor; eauto.
      * omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2))). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
        rewrite H8. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. repeat split; eauto.
          - intros. econstructor; eauto.
            left. split; auto. exploit H1; eauto. intros [next_instr' [A B]].
            eexists. repeat split; eauto. econstructor; eauto.
            right. rewrite <- H8; exact B.
          - intros. econstructor; eauto. assert (app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
            rewrite H11.
            eexists. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
            + eexists. eexists. eexists. repeat split; eauto.
              intros. econstructor; eauto.
              left. split; auto. exploit H1; eauto. intros [next_instr' [A B]].
              eexists. repeat split; auto. econstructor; eauto.
              right. rewrite <- H11. rewrite <- H8; exact B.
            + intros. inv H12.
            + intros. inversion H12. subst s1'; subst s2'; subst k'0; clear H12. repeat split; eauto.
              * eexists. repeat split; eauto.
                { omega. }
                { repeat rewrite app_lstmt_assoc. rewrite select_switch_case_app_right.
                  - simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
                  - eapply select_switch_nil_select_switch_case; eapply H4; omega. }
              * left. repeat split; eauto. exploit H1; eauto; intros [next_instr' [A B]]. eexists. econstructor; eauto.
                right. rewrite <- H11. rewrite <- H8; eauto.
            + omega.
            + intros. rewrite select_switch_app_right.
              * unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
                { exploit (phi_injection pc n); omega. }
                { eapply select_switch_in_loop1_flatten; eauto; try omega. }
              * eapply H4; omega.
            + omega.
            + omega. }
        { intros. inv H9. }
        { intros. inversion H9. subst s1'; subst s2'; subst k'0; clear H9. repeat split; eauto.
          - eexists. repeat split; eauto.
            + omega.
            + assert (app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
              rewrite H9. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
              * eexists. eexists. eexists. repeat split; eauto.
                intros. econstructor; eauto.
                left. split; auto. exploit H1; eauto. intros [next_instr' [A B]].
                eexists. repeat split; auto. econstructor; eauto.
                right. rewrite <- H9. rewrite <- H8; exact B.
              * intros. inv H10.
              * intros. inversion H10. subst s1'; subst s2'; subst k'0; clear H10. repeat split; eauto.
                { eexists. repeat split; eauto.
                  - omega.
                  - repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
                    + simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
                    + eapply select_switch_nil_select_switch_case; eapply H4; omega. }
                { left. repeat split; eauto. exploit H1; eauto; intros [next_instr' [A B]]. eexists. econstructor; eauto.
                  right. rewrite <- H9. rewrite <- H8; eauto. }
              * omega.
              * intros. rewrite select_switch_app_right.
                { unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
                  - exploit (phi_injection pc n); try omega.
                  - eapply select_switch_in_loop1_flatten; eauto; try omega. }
                { eapply H4; omega. }
              * omega.
              * omega.
            + repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
              * simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
              * eapply select_switch_nil_select_switch_case; eapply H4; omega.
          - left. repeat split; eauto. exploit H1; eauto. intros [next_instr' [A B]]. eexists. econstructor; eauto.
            right. rewrite <- H8; eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            exploit (phi_injection pc n); omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) (app_lstmt x x0)) ls2) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt. repeat (rewrite app_lstmt_assoc); simpl; eauto.
        rewrite H8. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { eexists. eexists. eexists. repeat split; eauto.
          intros. econstructor; eauto.
          left. split; eauto. exploit H1; eauto; intros [next_instr' [A B]]. eexists. repeat split; auto. econstructor; eauto.
          right. rewrite <- H8; eauto. }
        { intros. inv H9. }
        { intros. inv H9. split.
          - eexists. repeat split; eauto.
            + omega.
            + repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
              * simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
              * eapply select_switch_nil_select_switch_case; eapply H4; omega.
          - left. repeat split; eauto. exploit H1; eauto; intros [next_instr' [A B]].
            eexists. econstructor; eauto. right. rewrite <- H8; eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            + exploit (phi_injection pc n); omega.
            + eapply select_switch_in_loop1_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
  - monadInv H0.
  - monadInv H0.
  - monadInv H0; destruct (is_call_cont_context k H).
    + econstructor; eauto.
      * simpl in H6; omega.
      * simpl; rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case; eauto; try omega. simpl in H6; eapply H4; try omega. }
    + destruct H0 as [s' [k' H0]]. subst k. econstructor; eauto.
      * simpl in H6; omega.
      * simpl; rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { simpl in H6; eapply select_switch_nil_select_switch_case; eapply H4; omega. }
  - monadInv H0.
  - monadInv H0.
  - monadInv H0. }
{ destruct s; intros.
  - destruct H as [s1 [s2 [k' [H [Hbreak Hcontinue]]]]]. monadInv H0. destruct (context_loop1 k s1 s2 k' H).
    + subst k. econstructor; eauto.
      * simpl in H6; omega.
      * left; split.
        { rewrite select_switch_case_app_right.
          - simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
          - eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
        { exploit H2; eauto. intros [C [A B]].
          destruct A as [ls' [A0 [A1 [A2 A3]]]].
          eauto. }
    + destruct H0 as [s'' [k'' H0]]. subst k. econstructor; eauto.
      * simpl in H6; omega.
      * left; split.
        { rewrite select_switch_case_app_right.
          - simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
          - eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
        { exploit H1; eauto. }
  - destruct H as [s1 [s2 [k' [H [Hbreak Hcontinue]]]]]. monadInv H0. destruct (context_loop1 k s1 s2 k' H).
    + subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H2; eauto. intros [C [A B]].
        destruct A as [ls' [A0 [A1 [A2 A3]]]].
        eexists. econstructor; eauto.
        generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros. omega.
    + destruct H0 as [s'' [k'' H0]]. subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H1; eauto. intros [next_instr' A].
        eexists. econstructor; eauto. eapply match_stmt_cont_in_loop1_pos; eauto.
  - destruct H as [s1 [s2 [k' [H [Hbreak Hcontinue]]]]]. monadInv H0. destruct (context_loop1 k s1 s2 k' H).
    + subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H2; eauto. intros [C [A B]].
        destruct A as [ls' [A0 [A1 [A2 A3]]]].
        eexists. econstructor; eauto.
        generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros. omega.
    + destruct H0 as [s'' [k'' H0]]. subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H1; eauto. intros [next_instr' A].
        eexists. econstructor; eauto. eapply match_stmt_cont_in_loop1_pos; eauto.
  - destruct H as [s1 [s2 [k' [H [Hbreak Hcontinue]]]]]. monadInv H0. destruct (context_loop1 k s1 s2 k' H).
    + subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H2; eauto. intros [C [A B]].
        destruct A as [ls' [A0 [A1 [A2 A3]]]].
        eexists. econstructor; eauto.
        generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros. omega.
    + destruct H0 as [s'' [k'' H0]]. subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H1; eauto. intros [next_instr' A].
        eexists. econstructor; eauto. eapply match_stmt_cont_in_loop1_pos; eauto.
  - destruct H as [s1 [s2 [k' [H [Hbreak Hcontinue]]]]]. monadInv H0. destruct (context_loop1 k s1 s2 k' H).
    + subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H2; eauto. intros [C [A B]].
        destruct A as [ls' [A0 [A1 [A2 A3]]]].
        eexists. econstructor; eauto.
        generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros. omega.
    + destruct H0 as [s'' [k'' H0]]. subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H1; eauto. intros [next_instr' A].
        eexists. econstructor; eauto. eapply match_stmt_cont_in_loop1_pos; eauto.
  - destruct H as [s1' [s2' [k' [H [Hbreak Hcontinue]]]]]. monadInv H0. generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros. unfold sizeof_stmt in H3; unfold sizeof_stmt in H6; fold sizeof_stmt in H3; fold sizeof_stmt in H6. destruct (context_loop1 k s1' s2' k' H).
    + subst k. econstructor; eauto.
      * omega.
      * assert (app_lstmt ls1 (app_lstmt (app_lstmt x x0) ls2) = app_lstmt ls1 (app_lstmt x (app_lstmt x0 ls2))). repeat (rewrite app_lstmt_assoc); auto.
        rewrite H8. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. rewrite <- H8; repeat split; eauto. }
        { intros. inversion H9; subst s'; subst k'0; clear H9. eexists.
          assert (app_lstmt ls1 (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt (app_lstmt ls1 x) (app_lstmt x0 ls2)). repeat (rewrite app_lstmt_assoc); eauto.
          rewrite H9. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
          - eexists. eexists. eexists. rewrite <- H9; rewrite <- H8; repeat split; eauto.
          - intros. inv H10.
          - rewrite <- H9; rewrite <- H8. exact H2.
          - unfold sizeof_stmt in H3; fold sizeof_stmt in H3; omega.
          - intros. rewrite select_switch_app_right.
            + eapply select_switch_in_loop1_flatten; eauto; omega.
            + eapply H4; omega.
          - omega.
          - omega. }
        { intros. inv H9. }
        { omega. }
        { omega. }
      * assert (app_lstmt ls1 (app_lstmt (app_lstmt x x0) ls2) = app_lstmt (app_lstmt ls1 x) (app_lstmt x0 ls2)). repeat (rewrite app_lstmt_assoc); simpl; eauto.
        rewrite H8. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. rewrite <- H8; repeat split; eauto. }
        { intros. inv H9. }
        { rewrite <- H8; exact H2. }
        { unfold sizeof_stmt in H3; fold sizeof_stmt in H3; omega. }
        { intros. rewrite select_switch_app_right.
          - eapply select_switch_in_loop1_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega. }
    + destruct H8 as [s'' [k'' H8]]. subst k. econstructor; eauto.
      * omega.
      * assert (app_lstmt ls1 (app_lstmt (app_lstmt x x0) ls2) = app_lstmt ls1 (app_lstmt x (app_lstmt x0 ls2))). repeat (rewrite app_lstmt_assoc); auto. rewrite H8.
        eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. rewrite <- H8; repeat split; eauto. }
        { intros. inversion H9; subst s'; subst k'0; clear H9. eexists.
          assert (app_lstmt ls1 (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt (app_lstmt ls1 x) (app_lstmt x0 ls2)). repeat (rewrite app_lstmt_assoc); eauto.
          rewrite H9. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
          - eexists. eexists. eexists. rewrite <- H9; rewrite <- H8; repeat split; eauto.
          - rewrite <- H9; rewrite <- H8. exact H1.
          - intros; inv H10.
          - unfold sizeof_stmt in H3; fold sizeof_stmt in H3; omega.
          - intros. rewrite select_switch_app_right.
            + eapply select_switch_in_loop1_flatten; eauto; omega.
            + eapply H4; omega.
          - omega.
          - unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega. }
        { intros. inv H9. }
        { omega. }
        { omega. }
      * assert (app_lstmt ls1 (app_lstmt (app_lstmt x x0) ls2) = app_lstmt (app_lstmt ls1 x) (app_lstmt x0 ls2)). repeat (rewrite app_lstmt_assoc); simpl; eauto.
        rewrite H8. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. rewrite <- H8; repeat split; eauto. }
        { rewrite <- H8; exact H1. }
        { intros; inv H9. }
        { unfold sizeof_stmt in H3; fold sizeof_stmt in H3; omega. }
        { intros. rewrite select_switch_app_right.
          - eapply select_switch_in_loop1_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega. }
  - destruct H as [s1' [s2' [k' [H [Hbreak Hcontinue]]]]]. monadInv H0. generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros. unfold sizeof_stmt in H6; fold sizeof_stmt in H6; destruct (context_loop1 k s1' s2' k' H).
    + subst k. econstructor; eauto.
      * unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. eapply H4; omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) LSnil)) (app_lstmt x (app_lstmt x0 ls2))). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
        rewrite H8. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. rewrite <- H8; repeat split; eauto. }
        { intros. inv H9. }
        { rewrite <- H8. exact H2. }
        { unfold sizeof_stmt in H3; fold sizeof_stmt in H3; omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            exploit (phi_injection pc n); omega.
          - eapply H4; omega. }
        { omega. }
        { unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) x)) (app_lstmt x0 ls2)).
        rewrite app_lstmt_lscons; repeat (rewrite app_lstmt_assoc); eauto.
        rewrite H8. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. rewrite <- H8; repeat split; eauto. }
        { intros. inv H9. }
        { rewrite <- H8. exact H2. }
        { unfold sizeof_stmt in H3; fold sizeof_stmt in H3; omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            + exploit (phi_injection pc n); omega.
            + eapply select_switch_in_loop1_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega. }
    + destruct H8 as [s'' [k'' H8]]. subst k. econstructor; eauto.
      * unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. eapply H4; omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) LSnil)) (app_lstmt x (app_lstmt x0 ls2))). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
        rewrite H8. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. rewrite <- H8; repeat split; eauto. }
        { rewrite <- H8. exact H1. }
        { intros. inv H9. }
        { unfold sizeof_stmt in H3; fold sizeof_stmt in H3; omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            exploit (phi_injection pc n); omega.
          - eapply H4; omega. }
        { omega. }
        { unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) x)) (app_lstmt x0 ls2)).
        rewrite app_lstmt_lscons; repeat (rewrite app_lstmt_assoc); eauto.
        rewrite H8. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. rewrite <- H8; repeat split; eauto. }
        { rewrite <- H8. exact H1. }
        { intros. inv H9. }
        { unfold sizeof_stmt in H3; fold sizeof_stmt in H3; omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            + exploit (phi_injection pc n); omega.
            + eapply select_switch_in_loop1_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega. }
  - destruct H as [s1' [s2' [k' [H [Hbreak Hcontinue]]]]]. monadInv H0. generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros. unfold sizeof_stmt in H3; unfold sizeof_stmt in H6; fold sizeof_stmt in H3; fold sizeof_stmt in H6; destruct (context_loop1 k s1' s2' k' H).
    + subst k. econstructor; eauto.
      * omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2))). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); auto.
        rewrite H8. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. repeat split; eauto.
          - exploit H2; eauto. intros [C [A B]].
            destruct A as [ls' [A0 [A1 [A2 A3]]]].
            intros. econstructor; eauto.
            right. left. eexists. eexists. eexists.
            split; eauto. eexists.
            econstructor; eauto.
            + generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega.
            + right; rewrite <- H8; eauto.
          - exploit H2; eauto. intros [C [A B]].
            destruct A as [ls' [A0 [A1 [A2 A3]]]].
            intros. econstructor; eauto.
            eexists. assert (app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
            rewrite H11. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
            + eexists. eexists. eexists. repeat split; eauto.
              intros. econstructor; eauto.
              right. left. eexists. eexists. eexists.
              split; eauto. eexists.
              econstructor; eauto.
              * generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega.
              * right; rewrite <- H11; rewrite <- H8; eauto.
            + intros. inv H12.
            + intros. inversion H12; subst s1'0; subst s2'0; subst k'0; clear H12. repeat split; eauto.
              * eexists. repeat split; eauto.
                { omega. }
                { repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
                  - simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
                  - eapply select_switch_nil_select_switch_case; eapply H4; omega. }
              * right. left. eexists. eexists. eexists. repeat split; eauto.
                eexists. econstructor; eauto.
                { generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega. }
                { right. rewrite <- H11. rewrite <- H8; eauto. }
            + omega.
            + intros. rewrite select_switch_app_right.
              * unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
                { exploit (phi_injection pc n); omega. }
                { eapply select_switch_in_loop1_flatten; eauto; try omega. }
              * eapply H4; omega.
            + omega.
            + omega. }
        { intros. inv H9. }
        { intros. inversion H9; subst s1'0; subst s2'0; subst k'0; clear H9. repeat split; eauto.
          - eexists. repeat split; eauto.
            + omega.
            + assert (app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
              rewrite H9. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
              * eexists. eexists. eexists. repeat split; eauto.
                exploit H2; eauto. intros [C [A B]].
                destruct A as [ls' [A0 [A1 [A2 A3]]]].
                intros. econstructor; eauto.
                right. left. eexists. eexists. eexists.
                split; eauto. eexists.
                econstructor; eauto.
                { generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega. }
                { right; rewrite <- H9; rewrite <- H8; eauto. }
              * intros. inv H10.
              * intros. inversion H10; subst s1'0; subst s2'0; subst k'0; clear H10. repeat split; eauto.
                { eexists. repeat split; eauto.
                  - omega.
                  - repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
                    + simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
                    + eapply select_switch_nil_select_switch_case; eapply H4; omega. }
                { right. left. eexists. eexists. eexists. repeat split; eauto.
                  exploit H2; eauto. intros [C [A B]].
                  destruct A as [ls' [A0 [A1 [A2 A3]]]].
                  eexists. econstructor; eauto.
                  - generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega.
                  - right; rewrite <- H9; rewrite <- H8; eauto. }
              * omega.
              * intros. rewrite select_switch_app_right.
                { unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
                  - exploit (phi_injection pc n); omega.
                  - eapply select_switch_in_loop1_flatten; eauto; try omega. }
                { eapply H4; omega. }
              * omega.
              * omega.
            + repeat rewrite app_lstmt_assoc. rewrite select_switch_case_app_right.
              * simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
              * eapply select_switch_nil_select_switch_case; eapply H4; omega.
          - exploit H2; eauto. intros [C [A B]]. destruct A as [ls' [A0 [A1 [A2 A3]]]].
            right. left. eexists. eexists. eexists.
            split; eauto. eexists. econstructor; eauto.
            + generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega.
            + right. rewrite <- H8. eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            exploit (phi_injection pc n); omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) (app_lstmt x x0)) ls2) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt. repeat (rewrite app_lstmt_assoc); simpl; eauto.
        rewrite H8. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { eexists. eexists. eexists. repeat split; eauto.
          intros. econstructor; eauto.
          exploit H2; eauto. intros [C [A B]]. destruct A as [ls'' [A0 [A1 [A2 A3]]]].
          right. left. eexists. eexists. eexists. split; eauto.
          eexists. econstructor; eauto.
          - generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); intros; omega.
          - rewrite <- H8. eauto. }
        { intros. inv H9. }
        { intros. inversion H9; subst s1'0; subst s2'0; subst k'0; clear H9.
          exploit H2; eauto. intros [C [A B]]. destruct A as [ls'' [A0 [A1 [A2 A3]]]]. split.
          - eexists. repeat split; eauto.
            + omega.
            + repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
              * simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
              * eapply select_switch_nil_select_switch_case; eapply H4; omega.
          - right. left. eexists. eexists. eexists. split; eauto.
            eexists. econstructor; eauto.
            + generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega.
            + right. rewrite <- H8; eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            + exploit (phi_injection pc n); omega.
            + eapply select_switch_in_loop1_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
    + destruct H8 as [s'' [k'' H8]]; subst k. econstructor; eauto.
      * omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * exploit H1; eauto. intros [next_instr' A].
        assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2))). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); auto. rewrite H8.
        eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. repeat split; eauto.
          - intros. econstructor; eauto.
            right. left. eexists. eexists. eexists. split; eauto.
            eexists. econstructor; eauto.
            eapply match_stmt_cont_in_loop1_pos; eauto. right; rewrite <- H8; eauto.
          - intros. econstructor; eauto.
            assert (app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
            rewrite H11. eexists. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
            + eexists. eexists. eexists. repeat split; eauto.
              intros. econstructor; eauto.
              right. left. eexists. eexists. eexists. repeat split; eauto.
              eexists. econstructor; eauto.
              eapply match_stmt_cont_in_loop1_pos; eauto. right; rewrite <- H11; rewrite <- H8; eauto.
            + intros. inv H12.
            + intros. inversion H12; subst s1'0; subst s2'0; subst k'0; clear H12. repeat split; eauto.
              * eexists. repeat split; eauto.
                { omega. }
                { repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
                  - simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
                  - eapply select_switch_nil_select_switch_case; eapply H4; omega. }
              * right. left. eexists. eexists. eexists. repeat split; eauto.
                eexists. econstructor; eauto.
                eapply match_stmt_cont_in_loop1_pos; eauto. right; rewrite <- H11; rewrite <- H8; eauto.
            + omega.
            + intros. rewrite select_switch_app_right.
              * unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
                { exploit (phi_injection pc n); omega. }
                { eapply select_switch_in_loop1_flatten; eauto; try omega. }
              * eapply H4; omega.
            + omega.
            + omega. }
        { intros. inv H9. }
        { intros. inversion H9; subst s1'0; subst s2'0; subst k'0; clear H9. repeat split; eauto.
          - eexists. repeat split; eauto.
            + omega.
            + assert (app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
              rewrite H9. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
              * eexists. eexists. eexists. repeat split; eauto.
                intros. econstructor; eauto.
                right. left. eexists. eexists. eexists. repeat split; eauto.
                eexists. econstructor; eauto.
                eapply match_stmt_cont_in_loop1_pos; eauto. right; rewrite <- H9; rewrite <- H8; eauto.
              * intros. inv H10.
              * intros. inversion H10; subst s1'0; subst s2'0; subst k'0; clear H10. repeat split; eauto.
                { eexists. repeat split; eauto.
                  - omega.
                  - repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
                    + simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
                    + eapply select_switch_nil_select_switch_case; eapply H4; omega. }
                { right. left. eexists. eexists. eexists. repeat split; eauto.
                  eexists. econstructor; eauto.
                  eapply match_stmt_cont_in_loop1_pos; eauto. right; rewrite <- H9; rewrite <- H8; eauto. }
              * omega.
              * intros. rewrite select_switch_app_right.
                { unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
                  - exploit (phi_injection pc n); omega.
                  - eapply select_switch_in_loop1_flatten; eauto; try omega. }
                { eapply H4; omega. }
              * omega.
              * omega.
            + repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
              * simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
              * eapply select_switch_nil_select_switch_case; eapply H4; omega.
          - right. left. eexists. eexists. eexists. split; eauto.
            eexists. econstructor; eauto.
            + eapply match_stmt_cont_in_loop1_pos; eauto.
            + right; rewrite <- H8; eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            exploit (phi_injection pc n); omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
      * exploit H1; eauto. intros [next_instr' A].
        assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) (app_lstmt x x0)) ls2) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt. repeat (rewrite app_lstmt_assoc); simpl; eauto. rewrite H8.
        eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { rewrite <- H8. eexists. eexists. eexists. repeat split; eauto.
          intros. econstructor; eauto.
          right. left. eexists. eexists. eexists. split; eauto.
          eexists. econstructor; eauto.
          eapply match_stmt_cont_in_loop1_pos; eauto. }
        { intros. inv H9. }
        { intros. inversion H9; subst s1'0; subst s2'0; subst k'0; clear H9. split.
          - eexists. repeat split; eauto.
            + omega.
            + repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
              * simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
              * eapply select_switch_nil_select_switch_case; eapply H4; omega.
          - right. left. eexists. eexists. eexists. split; eauto.
            eexists. rewrite <- H8. econstructor; eauto.
            eapply match_stmt_cont_in_loop1_pos; eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            + exploit (phi_injection pc n); omega.
            + eapply select_switch_in_loop1_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
  - destruct H as [s1' [s2' [k' [H [Hbreak Hcontinue]]]]]. monadInv H0.
    eapply break_continue_seq_match_stmt_cont_in_loop1; eauto.
    eapply Hbreak; eauto. simpl in H6; omega.
    rewrite select_switch_case_app_right.
    simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
    eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega.
  - destruct H as [s1' [s2' [k' [H [Hbreak Hcontinue]]]]]. monadInv H0.
    eapply break_continue_seq_match_stmt_cont_in_loop1; eauto.
    eapply Hcontinue; eauto. simpl in H6; omega.
    rewrite select_switch_case_app_right.
    simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
    eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega.
  - destruct H as [s1 [s2 [k' [H [Hbreak Hcontinue]]]]]. monadInv H0. destruct (context_loop1 k s1 s2 k' H).
    + subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
    + destruct H0 as [s'' [k'' H0]]. subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
  - monadInv H0.
  - monadInv H0.
  - monadInv H0. }
{ destruct s; intros.
  - destruct H as [s1 [s2 [k' [H Hcontinue]]]]. monadInv H0. destruct (context_loop2 k s1 s2 k' H).
    + subst k. econstructor; eauto.
      * simpl in H6; omega.
      * left; split.
        { rewrite select_switch_case_app_right.
          - simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
          - eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
        { exploit H2; eauto. intros [A B].
          destruct A as [ls' [A1 [A2 A3]]]. eauto. }
    + destruct H0 as [s'' [k'' H0]]. subst k. econstructor; eauto.
      * simpl in H6; omega.
      * exploit H1; eauto; intros.
        left; split.
        { rewrite select_switch_case_app_right.
          - simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
          - eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
        { exact H0. }
  - destruct H as [s1 [s2 [k' [H Hcontinue]]]]. monadInv H0. destruct (context_loop2 k s1 s2 k' H).
    + subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H2; eauto. intros [A B]. destruct A as [ls' [A1 [A2 A3]]].
        eexists. econstructor; eauto.
        rewrite A1. generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); omega.
    + destruct H0 as [s'' [k'' H0]]. subst k.
      econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H1; eauto. intros [next_instr' A].
        eexists. econstructor; eauto.
        eapply match_stmt_cont_in_loop2_pos; eauto.
  - destruct H as [s1 [s2 [k' [H Hcontinue]]]]. monadInv H0. destruct (context_loop2 k s1 s2 k' H).
    + subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H2; eauto. intros [A B]. destruct A as [ls' [A1 [A2 A3]]].
        eexists. econstructor; eauto.
        rewrite A1. generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); omega.
    + destruct H0 as [s'' [k'' H0]]. subst k.
      econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H1; eauto. intros [next_instr' A].
        eexists. econstructor; eauto.
        eapply match_stmt_cont_in_loop2_pos; eauto.
  - destruct H as [s1 [s2 [k' [H Hcontinue]]]]. monadInv H0. destruct (context_loop2 k s1 s2 k' H).
    + subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H2; eauto. intros [A B]. destruct A as [ls' [A1 [A2 A3]]].
        eexists. econstructor; eauto.
        rewrite A1. generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); omega.
    + destruct H0 as [s'' [k'' H0]]. subst k.
      econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H1; eauto. intros [next_instr' A].
        eexists. econstructor; eauto.
        eapply match_stmt_cont_in_loop2_pos; eauto.
  - destruct H as [s1 [s2 [k' [H Hcontinue]]]]. monadInv H0. destruct (context_loop2 k s1 s2 k' H).
    + subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H2; eauto. intros [A B]. destruct A as [ls' [A1 [A2 A3]]].
        eexists. econstructor; eauto.
        rewrite A1. generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); omega.
    + destruct H0 as [s'' [k'' H0]]. subst k.
      econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
      * exploit H1; eauto. intros [next_instr' A].
        eexists. econstructor; eauto.
        eapply match_stmt_cont_in_loop2_pos; eauto.
  - destruct H as [s1' [s2' [k' [H Hcontinue]]]]. monadInv H0. unfold sizeof_stmt in H3; fold sizeof_stmt in H3; unfold sizeof_stmt in H6; fold sizeof_stmt in H6. generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros Hs1_pos Hs2_pos.
    destruct (context_loop2 k s1' s2' k' H).
    + subst k. econstructor; eauto.
      * omega.
      * assert (app_lstmt ls1 (app_lstmt (app_lstmt x x0) ls2) = app_lstmt ls1 (app_lstmt x (app_lstmt x0 ls2))). repeat (rewrite app_lstmt_assoc); auto.
        rewrite H0. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { eexists. eexists. eexists. split; eauto.
          rewrite <- H0; exact Hcontinue. }
        { intros. inversion H7; subst s'; subst k'0; clear H7.
          eexists. assert (app_lstmt ls1 (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt (app_lstmt ls1 x) (app_lstmt x0 ls2)). repeat (rewrite app_lstmt_assoc); eauto.
          rewrite H7. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
          - eexists. eexists. eexists. split; eauto.
            rewrite <- H7; rewrite <- H0; exact Hcontinue.
          - intros. inv H8.
          - exploit H2; eauto. intros. inv H8. rewrite <- H7. rewrite <- H0; eauto.
          - unfold sizeof_stmt in H3; fold sizeof_stmt in H3. generalize (sizeof_stmt_pos s2); generalize (sizeof_stmt_pos s1); omega.
          - generalize (sizeof_stmt_pos s1); intros.
            rewrite select_switch_app_right.
            + eapply select_switch_in_loop2_flatten; eauto; omega.
            + eapply H4; omega.
          - generalize (sizeof_stmt_pos s1); omega.
          - unfold sizeof_stmt in H6; fold sizeof_stmt in H6; omega. }
        { intros. inv H7. }
        { omega. }
        { omega. }
      * assert (app_lstmt ls1 (app_lstmt (app_lstmt x x0) ls2) = app_lstmt (app_lstmt ls1 x) (app_lstmt x0 ls2)). repeat (rewrite app_lstmt_assoc); simpl; eauto.
        rewrite H0. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { eexists. eexists. eexists. split; eauto.
          rewrite <- H0; exact Hcontinue. }
        { intros. inv H7. }
        { exploit H2; eauto. intros. inv H7. rewrite <- H0; eauto. }
        { omega. }
        { intros; rewrite select_switch_app_right.
          - eapply select_switch_in_loop2_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
    + generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros.
      destruct H0 as [s'' [k'' H0]]; subst k. econstructor; eauto.
      * omega.
      * assert (app_lstmt ls1 (app_lstmt (app_lstmt x x0) ls2) = app_lstmt ls1 (app_lstmt x (app_lstmt x0 ls2))). repeat (rewrite app_lstmt_assoc); auto.
        rewrite H0. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { rewrite <- H0. eexists. eexists. eexists. split; eauto. }
        { intros. inversion H9; subst s'; subst k'0; clear H9. exploit H1; eauto; intros [next_instr' A].
          eexists. assert (app_lstmt ls1 (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt (app_lstmt ls1 x) (app_lstmt x0 ls2)). repeat (rewrite app_lstmt_assoc); eauto.
          rewrite H9. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
          - eexists. eexists. eexists. rewrite <- H9; rewrite <- H0; split; eauto.
          - intros. inv H10. rewrite <- H9; rewrite <- H0; eauto.
          - intros. inv H10.
          - omega.
          - intros. rewrite select_switch_app_right.
            + eapply select_switch_in_loop2_flatten; eauto; omega.
            + eapply H4; omega.
          - omega.
          - omega. }
        { intros. inv H9. }
        { omega. }
        { omega. }
      * assert (app_lstmt ls1 (app_lstmt (app_lstmt x x0) ls2) = app_lstmt (app_lstmt ls1 x) (app_lstmt x0 ls2)). repeat (rewrite app_lstmt_assoc); simpl; eauto.
        rewrite H0. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { eexists. eexists. eexists. rewrite <- H0; split; eauto. }
        { intros. inv H9. rewrite <- H0. eapply H1; eauto. }
        { intros. inv H9. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - eapply select_switch_in_loop2_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
  - destruct H as [s1' [s2' [k' [H Hbreak]]]]. monadInv H0. generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros. unfold sizeof_stmt in H3; fold sizeof_stmt in H3; unfold sizeof_stmt in H6; fold sizeof_stmt in H6. destruct (context_loop2 k s1' s2' k' H).
    + subst k. econstructor; eauto.
      * omega.
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x x0)) ls2) = app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x (app_lstmt x0 ls2)))).
        repeat (rewrite app_lstmt_lscons). repeat (rewrite app_lstmt_assoc); eauto.
        rewrite H8. rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. eapply H4; omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) LSnil)) (app_lstmt x (app_lstmt x0 ls2))).
        rewrite lscons_app_lstmt. repeat (rewrite app_lstmt_assoc); eauto.
        rewrite H8. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { rewrite <- H8. eexists. eexists. eexists. split; eauto. }
        { intros. inv H9. }
        { intros. inv H9. rewrite <- H8. eapply H2. eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl. destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            exploit (phi_injection pc n); omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt. repeat (rewrite app_lstmt_assoc); eauto.
        rewrite H8. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { rewrite <- H8. eexists. eexists. eexists. split; eauto. }
        { intros. inv H9. }
        { intros. inv H9. rewrite <- H8. eapply H2. eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl. destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            + exploit (phi_injection pc n); omega.
            + eapply select_switch_in_loop2_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
    + destruct H8 as [s'' [k'' H8]]. subst k. econstructor; eauto.
      * omega.
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x x0)) ls2) = app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x (app_lstmt x0 ls2)))).
        repeat (rewrite app_lstmt_lscons). repeat (rewrite app_lstmt_assoc); eauto.
        rewrite H8. rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. eapply H4; omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) LSnil)) (app_lstmt x (app_lstmt x0 ls2))).
        rewrite lscons_app_lstmt. repeat (rewrite app_lstmt_assoc); eauto.
        rewrite H8. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { rewrite <- H8. eexists. eexists. eexists. split; eauto. }
        { intros. inv H9. rewrite <- H8. eapply H1. eauto. }
        { intros. inv H9. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl. destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            exploit (phi_injection pc n); omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Sifthenelse e
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1)) (snd id_t))) Sbreak)
                 (Ssequence
                    (Sset (fst id_t)
                       (Econst_int (phi (pc + 1 + sizeof_stmt s1))
                          (snd id_t))) Sbreak)) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt. repeat (rewrite app_lstmt_assoc); eauto.
        rewrite H8. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { rewrite <- H8. eexists. eexists. eexists. split; eauto. }
        { intros. inv H9. rewrite <- H8. eapply H1. eauto. }
        { intros. inv H9. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl. destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            + exploit (phi_injection pc n); omega.
            + eapply select_switch_in_loop2_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
  - destruct H as [s1' [s2' [k' [H Hbreak]]]]. monadInv H0. generalize (sizeof_stmt_pos s1); generalize (sizeof_stmt_pos s2); intros. unfold sizeof_stmt in H3; fold sizeof_stmt in H3; unfold sizeof_stmt in H6; fold sizeof_stmt in H6. destruct (context_loop2 k s1' s2' k' H).
    + subst k. econstructor; eauto.
      * omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2))). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); auto.
        rewrite H8. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. repeat split; eauto.
          - intros. exploit H2; eauto. intros [A B]. destruct A as [ls'' [A1 [A2 A3]]].
            econstructor; eauto. right. right.
            eexists. eexists. eexists. split; eauto.
            rewrite <- H8. eexists. econstructor; eauto.
            generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega.
          - intros. econstructor; eauto.
            eexists. assert (app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
            rewrite H11. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
            + exploit H2; eauto. intros [A B]. destruct A as [ls'' [A1 [A2 A3]]].
              eexists. eexists. eexists. repeat split; eauto.
              intros. econstructor; eauto.
              right. right. eexists. eexists. eexists. eexists. repeat split; eauto.
              eexists. econstructor; eauto.
              * generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega.
              * right; rewrite <- H11; rewrite <- H8; eauto.
            + intros. inv H12.
            + intros. inversion H12; subst s1'0; subst s2'0; subst k'0; clear H12. repeat split; eauto.
              * eexists. repeat split; eauto.
                { omega. }
                { repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
                  - simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
                  - eapply select_switch_nil_select_switch_case; eapply H4; omega. }
              * exploit H2; eauto. intros [A B]. destruct A as [ls'' [A1 [A2 A3]]].
                right. right. eexists. eexists. eexists. repeat split; eauto.
                eexists. econstructor; eauto.
                { generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega. }
                { right; rewrite <- H11; rewrite <- H8; eauto. }
            + omega.
            + intros. rewrite select_switch_app_right.
              * unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
                { exploit (phi_injection pc n); omega. }
                { eapply select_switch_in_loop1_flatten; eauto; try omega. }
              * eapply H4; omega.
            + omega.
            + omega. }
        { intros. inv H9. }
        { intros. inversion H9; subst s1'0; subst s2'0; subst k'0. repeat split; eauto.
          - eexists. repeat split; eauto.
            + omega.
            + assert (app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
              rewrite H10; eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
              * eexists. eexists. eexists. repeat split; eauto.
                intros. econstructor; eauto.
                exploit H2; eauto; intros [A B]. destruct A as [ls'' [A1 [A2 A3]]].
                right. right. eexists. eexists. eexists. repeat split; eauto.
                eexists. econstructor; eauto.
                { generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega. }
                { right. rewrite <- H10; rewrite <- H8; eauto. }
              * intros. inv H11.
              * intros. inversion H11; subst s1'0; subst s2'0; subst k'0; clear H11. repeat split; eauto.
                { eexists. repeat split; eauto.
                  - omega.
                  - repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
                    + simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
                    + eapply select_switch_nil_select_switch_case; eapply H4; omega. }
                { exploit H2; eauto; intros [A B]. destruct A as [ls'' [A1 [A2 A3]]].
                  right. right. eexists. eexists. eexists. repeat split; eauto.
                  eexists. econstructor; eauto.
                  - generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega.
                  - right. rewrite <- H10; rewrite <- H8; eauto. }
              * omega.
              * intros. rewrite select_switch_app_right.
                { unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
                  - exploit (phi_injection pc n); omega.
                  - eapply select_switch_in_loop1_flatten; eauto; try omega. }
                { eapply H4; omega. }
              * omega.
              * omega.
            + repeat (rewrite app_lstmt_assoc); rewrite select_switch_case_app_right.
              * simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
              * eapply select_switch_nil_select_switch_case; eapply H4; omega.
          - right. right. eexists. eexists. eexists.
            split; eauto. exploit H2; eauto; intros [A B]. destruct A as [ls'' [A1 [A2 A3]]].
            eexists. econstructor; eauto.
            + generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega.
            + right; rewrite <- H8; eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            exploit (phi_injection pc n); omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) (app_lstmt x x0)) ls2) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt. repeat (rewrite app_lstmt_assoc); simpl; eauto.
        rewrite H8. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { eexists. eexists. eexists. repeat split; eauto.
          - intros. exploit H2; eauto. intros [A B]. destruct A as [ls'' [A1 [A2 A3]]].
            econstructor; eauto. right. right.
            eexists. eexists. eexists. split; eauto.
            rewrite <- H8. eexists. econstructor; eauto.
            generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega. }
        { intros. inv H9. }
        { intros. inversion H9; subst s1'0; subst s2'0; subst k'0; clear H9. repeat split; eauto.
          - eexists. repeat split; eauto.
            + omega.
            + repeat (rewrite app_lstmt_assoc); rewrite select_switch_case_app_right.
              * simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
              * eapply select_switch_nil_select_switch_case; eapply H4; omega.
          - right. right. eexists. eexists. eexists. split; eauto.
            exploit H2; eauto; intros [A B]. destruct A as [ls'' [A1 [A2 A3]]].
            eexists. econstructor; eauto.
            + generalize (sizeof_stmt_pos s1'); generalize (sizeof_stmt_pos s2'); omega.
            + right; rewrite <- H8; eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            + exploit (phi_injection pc n); omega.
            + eapply select_switch_in_loop1_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
    + destruct H8 as [s'' [k'' H8]]. subst k. econstructor; eauto.
      * omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case; eapply H4; omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) (app_lstmt x x0)) ls2) = app_lstmt (app_lstmt ls1 (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2))). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); auto.
        rewrite H8. eapply match_stmt_cont_in_loop1_flatten_loop1; eauto.
        { eexists. eexists. eexists. repeat split; eauto.
          - intros. exploit H1; eauto. intros [next_instr' A].
            econstructor; eauto. right. right.
            eexists. eexists. eexists. repeat split; eauto.
            rewrite <- H8. eexists. econstructor; eauto.
            eapply match_stmt_cont_in_loop2_pos; eauto.
          - intros. econstructor; eauto.
            eexists. assert (app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
            rewrite H11. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
            + eexists. eexists. eexists. repeat split; eauto.
              rewrite <- H11; rewrite <- H8; intros; econstructor; eauto.
              exploit H1; eauto. intros [next_instr' A].
              right. right. eexists. eexists. eexists. repeat split; eauto.
              eexists. econstructor; eauto.
              eapply match_stmt_cont_in_loop2_pos; eauto.
            + intros. inv H12.
            + intros. inversion H12; subst s1'0; subst s2'0; subst k'0; clear H12. repeat split; eauto.
              * eexists. repeat split; eauto.
                { omega. }
                { repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
                  - simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
                  - eapply select_switch_nil_select_switch_case. eapply H4; omega. }
              * right. right. eexists. eexists. eexists. repeat split; eauto.
                exploit H1; eauto. intros [next_instr' A].
                eexists. econstructor; eauto.
                { eapply match_stmt_cont_in_loop2_pos; eauto. }
                { right. rewrite <- H11. rewrite <- H8; eauto. }
            + omega.
            + intros. rewrite select_switch_app_right.
              * unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
                { exploit (phi_injection pc n); omega. }
                { eapply select_switch_in_loop1_flatten; eauto; omega. }
              * eapply H4; omega.
            + omega.
            + omega. }
        { intros. inv H9. }
        { intros. inversion H9; subst s1'0; subst s2'0; subst k'0; clear H9. split; eauto.
          - eexists. repeat split; eauto.
            + eexists. repeat split; eauto.
              * omega.
              * assert (app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) LSnil)) (app_lstmt x (app_lstmt x0 ls2)) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt; repeat (rewrite app_lstmt_assoc); eauto.
                rewrite H9. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
                { exploit H1; eauto; intros [next_instr' A]. eexists. eexists. eexists. repeat split; eauto.
                  rewrite <- H9; rewrite <- H8; intros; econstructor; eauto.
                  right. right. eexists. eexists. eexists. repeat split; eauto.
                  eexists. econstructor; eauto.
                  eapply match_stmt_cont_in_loop2_pos; eauto. }
                { intros. inv H10. }
                { intros. inversion H10; subst s1'0; subst s2'0; subst k'0; clear H10. repeat split; eauto.
                  - eexists. repeat split; eauto.
                    + omega.
                    + repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
                      * simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
                      * eapply select_switch_nil_select_switch_case. eapply H4; omega.
                  - exploit H1; eauto; intros [next_instr' A]. right. right. eexists. eexists. eexists. repeat split; eauto.
                    eexists. rewrite <- H9; rewrite <- H8; econstructor; eauto.
                    eapply match_stmt_cont_in_loop2_pos; eauto. }
                { omega. }
                { intros. rewrite select_switch_app_right.
                  - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
                    + exploit (phi_injection pc n); omega.
                    + eapply select_switch_in_loop1_flatten; eauto; try omega.
                  - eapply H4; omega. }
                { omega. }
                { omega. }
              * repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
                { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
                { eapply select_switch_nil_select_switch_case. eapply H4; omega. }
            + right. right. eexists. eexists. eexists.
              split; eauto. exploit H1; eauto; intros [next_instr' A].
              rewrite <- H8. eexists. econstructor; eauto.
              eapply match_stmt_cont_in_loop2_pos; eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            exploit (phi_injection pc n); omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
      * assert (app_lstmt ls1
        (app_lstmt
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) (app_lstmt x x0)) ls2) = app_lstmt
        (app_lstmt ls1
           (LScons (Some (Int.unsigned (phi pc)))
              (Ssequence
                 (Sset (fst id_t) (Econst_int (phi (pc + 1)) (snd id_t)))
                 Sbreak) x)) (app_lstmt x0 ls2)). rewrite lscons_app_lstmt. repeat (rewrite app_lstmt_assoc); simpl; eauto.
        rewrite H8. eapply match_stmt_cont_in_loop2_flatten_loop2; eauto.
        { eexists. eexists. eexists. repeat split; eauto.
          intros. exploit H1; eauto. intros [next_instr' A].
          econstructor; eauto. right. right.
          eexists. eexists. eexists. split; eauto.
          rewrite <- H8. eexists. econstructor; eauto.
          eapply match_stmt_cont_in_loop2_pos; eauto. }
        { intros. inv H9. }
        { intros. inversion H9; subst s1'0; subst s2'0; subst k'0; clear H9. repeat split; eauto.
          - eexists. repeat split; eauto.
            + omega.
            + repeat (rewrite app_lstmt_assoc). rewrite select_switch_case_app_right.
              * simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
              * eapply select_switch_nil_select_switch_case; eapply H4; omega.
          - right. right. eexists. eexists. eexists. split; eauto.
            exploit H1; eauto; intros [next_instr' A].
            rewrite <- H8. eexists. econstructor; eauto.
            eapply match_stmt_cont_in_loop2_pos; eauto. }
        { omega. }
        { intros. rewrite select_switch_app_right.
          - unfold select_switch; simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi n))); try omega; eauto.
            + exploit (phi_injection pc n); omega.
            + eapply select_switch_in_loop1_flatten; eauto; omega.
          - eapply H4; omega. }
        { omega. }
        { omega. }
  - destruct H as [s1' [s2' [k' [H Hbreak]]]].
    eapply break_seq_match_stmt_cont_in_loop2; eauto.
    eapply Hbreak; eauto.
    + simpl in H6; omega.
    + monadInv H0.
      rewrite select_switch_case_app_right; simpl.
      * destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto.
      * eapply select_switch_nil_select_switch_case; simpl in H6; eapply H4; omega.
  - monadInv H0.
  - destruct H as [s1 [s2 [k' [H Hcontinue]]]]. monadInv H0. destruct (context_loop2 k s1 s2 k' H).
    + subst k. econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
    + destruct H0 as [s'' [k'' H0]]. subst k.
      econstructor; eauto.
      * simpl in H6; omega.
      * rewrite select_switch_case_app_right.
        { simpl; destruct (zeq (Int.unsigned (phi pc)) (Int.unsigned (phi pc))); try omega; eauto. }
        { eapply select_switch_nil_select_switch_case. simpl in H6; eapply H4; omega. }
  - monadInv H0.
  - monadInv H0.
  - monadInv H0. }
Grab Existential Variables. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply 0. eapply 0. eapply 0. eapply 0. eapply 0. eapply 0. eapply 0. eapply 0. eapply LSnil. eapply 0. eapply LSnil. eapply 0. eapply LSnil. eapply 0. eapply LSnil. eapply 0. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply LSnil. eapply 0. eapply LSnil. eapply 0. eapply LSnil. eapply 0. eapply LSnil. eapply 0. eapply LSnil. eapply 0. eapply LSnil. eapply 0. eapply LSnil. eapply 0. eapply LSnil. eapply 0. eapply LSnil. eapply LSnil. eapply 0. eapply LSnil. eapply LSnil. eapply 0. eapply LSnil. eapply LSnil. eapply 0. eapply LSnil. eapply LSnil. eapply 0.
Qed.

CompCert doesn't allow stuttering in their simulation diagram: infinitely many transitions in the source program must correspond to infinitely many transitions in the second program. Therefore, when one transition in the first program corresponds to zero in the second, there must be some measure that strictly decreases. These transitions that correspond to no transition in the transformed program are the following ones: - Sskip with a Kseq s k continuation - Scontinue with a Kseq s k continuation - Sbreak with a Kseq s k continuation - Sskip with a Kloop1 s1 s2 k continuation - Sskip with a Kloop2 s1 s2 k continuation Hence, the measure m must respect the following properties: m (s1, Kseq s2 k) < m (Ssequence s1 s2, k) m (s, k) < m (Sskip, Kseq s k) m (Scontinue, k) < m (Scontinue, Kseq s k) m (Sbreak, k) < m (Sbreak, Kseq s k) m (s2, Kloop2 s1 s2 k) < m (Sskip, Kloop1 s1 s2 k) m (Sloop s1 s2, k) < m (Sskip, Kloop2 s1 s2 k)

Fixpoint num_stmt (s: statement): nat :=
  match s with
    | Ssequence s1 s2 => S (S (num_stmt s1 + num_stmt s2))
    | _ => O
  end.

Fixpoint num_cont (k: cont): nat :=
  match k with
    | Kseq s k => S (num_cont k + num_stmt s)
    | Kstop | Kcall _ _ _ _ _ | Kswitch _ => O
    | Kloop1 _ s2 k => S (S (num_cont k) + num_stmt s2)
    | Kloop2 _ _ k => S (num_cont k)
  end.

The following measure can be used
Definition measure (st: Clight.state): nat :=
  match st with
    | State _ s k _ _ _ => (num_stmt s + num_cont k)%nat
    | _ => 0%nat
  end.

matching loops according to the context given by the continuation k
Inductive match_loop (ls: labeled_statements) (id_t: ident * type): list Z -> list Z -> list Z -> cont -> Prop :=
| match_loop_cont_loop1: forall start start' to_continue to_continue' to_break to_break' s1 s2 k,
                           0 < start <= Int.max_unsigned ->
                           start + 1 + sizeof_stmt s1 = to_continue ->
                           match_stmt_cont_in_loop1 s1 ls id_t (start::start') (start + 1) (start + 1 + sizeof_stmt s1) (to_continue::to_continue') (to_break::to_break') (Kloop1 s1 s2 k) ->
                           match_stmt_cont_in_loop2 s2 ls id_t (start::start') (start + 1 + sizeof_stmt s1) start (to_continue::to_continue') (to_break::to_break') (Kloop2 s1 s2 k) ->
                           match_loop ls id_t start' to_continue' to_break' k ->
                           match_loop ls id_t (start::start') (to_continue::to_continue') (to_break::to_break') (Kloop1 s1 s2 k)
| match_loop_cont_loop2: forall start start' to_continue to_continue' to_break to_break' s1 s2 k,
                           0 < start <= Int.max_unsigned ->
                           start + 1 + sizeof_stmt s1 = to_continue ->
                           match_stmt_cont_in_loop1 s1 ls id_t (start::start') (start + 1) (start + 1 + sizeof_stmt s1) (to_continue::to_continue') (to_break::to_break') (Kloop1 s1 s2 k) ->
                           match_stmt_cont_in_loop2 s2 ls id_t (start::start') (start + 1 + sizeof_stmt s1) start (to_continue::to_continue') (to_break::to_break') (Kloop2 s1 s2 k) ->
                           match_loop ls id_t start' to_continue' to_break' k ->
                           match_loop ls id_t (start::start') (to_continue::to_continue') (to_break::to_break') (Kloop2 s1 s2 k)
| match_loop_cont_call: forall optid f e le k,
                          match_loop ls id_t nil nil nil (Kcall optid f e le k)
| match_loop_cont_stop: match_loop ls id_t nil nil nil Kstop
| match_loop_cont_seq: forall start to_continue to_break s k,
                         match_loop ls id_t start to_continue to_break (context (Kseq s k)) ->
                         match_loop ls id_t start to_continue to_break (Kseq s k).

Matching loops depends only on the context of continuation k
Lemma match_loop_context:
  forall ls id_t start continue break k,
    match_loop ls id_t start continue break k <->
    match_loop ls id_t start continue break (context k).
Proof.
intros; destruct k; simpl; try tauto.
split; intros.
- inv H; simpl in H4; auto.
- constructor; simpl; auto.
Qed.

Matching loops in a call_cont context
Lemma match_loop_call_cont_context:
  forall ls id_t k,
    is_call_cont (context k) ->
    match_loop ls id_t nil nil nil (context k).
Proof.
induction k; intros; simpl; try econstructor; try (simpl in H; inv H; fail).
eapply IHk; simpl in H; auto.
Qed.

Matching loops in a Kloop1 context
Lemma match_loop_loop1_context:
  forall ls id_t start continue break k s1 s2 k',
    context k = Kloop1 s1 s2 k' ->
    match_loop ls id_t start continue break k ->
    exists to_start to_start' to_continue to_continue' to_break to_break',
      start = to_start::to_start' /\ continue = to_continue::to_continue' /\ break = to_break::to_break'.
Proof.
induction k; intros; try (simpl in H; inv H; fail).
- inv H0; simpl in H; eapply IHk; eauto.
  eapply match_loop_context; simpl in H5; auto.
- inv H0. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto.
Qed.

Matching loops in a Kloop2 context
Lemma match_loop_loop2_context:
  forall ls id_t start continue break k s1 s2 k',
    context k = Kloop2 s1 s2 k' ->
    match_loop ls id_t start continue break k ->
    exists to_start to_start' to_continue to_continue' to_break to_break',
      start = to_start::to_start' /\ continue = to_continue::to_continue' /\ break = to_break::to_break'.
Proof.
induction k; intros; try (simpl in H; inv H; fail).
- inv H0; simpl in H; eapply IHk; eauto.
  eapply match_loop_context; simpl in H5; auto.
- inv H0. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto.
Qed.

Characterisation of matching loops in a call_cont context
Lemma match_loop_call_cont_context_charact:
  forall ls id_t start to_continue to_break k,
    is_call_cont (context k) ->
    match_loop ls id_t start to_continue to_break k ->
    start = nil /\ to_continue = nil /\ to_break = nil.
Proof.
induction k; intros; try (simpl in H; inv H).
- inv H0; auto.
- simpl in H; eapply IHk; eauto.
  inv H0; simpl in H5; eapply match_loop_context in H5; auto.
- inv H0; auto.
Qed.

Characterisation of context
Lemma context_charact:
  forall k,
    is_call_cont (context k) \/
    (exists s1 s2 k', context k = Kloop1 s1 s2 k') \/
    (exists s1 s2 k', context k = Kloop2 s1 s2 k') \/
    (exists k', context k = Kswitch k').
Proof.
induction k; try (simpl; tauto).
- simpl; right; left; eauto.
- simpl; right; right; left; eauto.
- simpl; right; right; right; eauto.
Qed.

If k doesn't contain a Kswitch then its context cannot be a Kswitch
Lemma no_switch_context:
  forall k k',
    no_switch_label_goto_in_cont k ->
    context k <> Kswitch k'.
Proof.
induction k; intros; try (simpl; congruence).
- inv H; simpl; apply IHk; auto.
- inv H.
Qed.

call_cont k doesn't contain a Kswitch if k doesn't
Lemma no_switch_label_goto_in_cont_call_cont:
  forall k,
    no_switch_label_goto_in_cont k ->
    no_switch_label_goto_in_cont (call_cont k).
Proof.
induction 1; simpl; eauto.
- econstructor.
- econstructor; eauto.
Qed.

Matching Kstop and Kcall continuations
Inductive match_call_cont: cont -> cont -> Prop :=
| match_call_cont_stop: forall k tk,
                          call_cont k = Kstop ->
                          call_cont tk = Kstop ->
                          match_call_cont k tk
| match_call_cont_call: forall k tk optid f tf e le tle k' tk' ls,
                          call_cont k = Kcall optid f e le k' ->
                          call_cont tk = Kcall optid tf e tle tk' ->
                          transf_function phi f = OK tf ->
                          flatten phi (new_ident_for_function f, tint) (fn_body f) 1 0 = OK ls ->
                          (forall id, id <> new_ident_for_function f -> le!id = tle!id) ->
                          (exists next_instr ls' tk'',
                            tk' = Kseq
     (Ssequence
        (Sset (new_ident_for_function f)
           (Econst_int (phi next_instr) tint)) Sbreak)
     (Kseq (seq_of_labeled_statement ls')
        (Kswitch
           (Kloop1
              (Ssequence
                 (Sifthenelse
                    (Ebinop One (Etempvar (new_ident_for_function f) tint)
                       (Econst_int (phi 0) tint) tint) Sskip Sbreak)
                 (Sswitch (Etempvar (new_ident_for_function f) tint) ls))
              Sskip tk''))) /\
                            (is_call_cont tk'') /\
                            ((is_call_cont (context k') /\ exists next_instr', match_stmt_cont Sskip ls (new_ident_for_function f, tint) next_instr next_instr' k') \/
                             (exists s1 s2 k'', context k' = Kloop1 s1 s2 k'' /\
                                                exists start start' next_instr' to_continue to_continue' to_break to_break',
                               match_stmt_cont_in_loop1 Sskip ls (new_ident_for_function f, tint) (start::start') next_instr next_instr' (to_continue::to_continue') (to_break::to_break') k' /\
                               match_loop ls (new_ident_for_function f, tint) (start::start') (to_continue::to_continue') (to_break::to_break') k') \/
                             (exists s1 s2 k'', context k' = Kloop2 s1 s2 k'' /\
                                                exists start start' next_instr' to_continue to_continue' to_break to_break',
                               match_stmt_cont_in_loop2 Sskip ls (new_ident_for_function f, tint) (start::start') next_instr next_instr' (to_continue::to_continue') (to_break::to_break') k' /\
                               match_loop ls (new_ident_for_function f, tint) (start::start') (to_continue::to_continue') (to_break::to_break') k'))) ->
                          match_call_cont k' tk' ->
                          match_call_cont k tk.

match_call_cont k tk depends only on the context of k and tk
Lemma match_call_cont_seq:
  forall k tk, match_call_cont k tk ->
  forall s, match_call_cont (Kseq s k) tk.
Proof.
induction 1; intros.
- econstructor 1; eauto.
- econstructor 2; eauto.
Qed.

match_call_cont k tk depends only on the context of k and tk
Lemma match_call_cont_seq_bis:
  forall k tk,
    match_call_cont k tk ->
    forall s, match_call_cont k (Kseq s tk).
Proof.
induction 1; intros.
- econstructor 1; eauto.
- econstructor 2; eauto.
Qed.

match_call_cont k tk depends only on the context of k and tk
Lemma match_call_cont_loop1:
  forall k tk,
    match_call_cont k tk ->
    forall s1 s2, match_call_cont (Kloop1 s1 s2 k) tk.
Proof.
induction 1; intros.
- econstructor 1; eauto.
- econstructor 2; eauto.
Qed.

match_call_cont k tk depends only on the context of k and tk
Lemma match_call_cont_loop1_bis:
  forall k tk,
    match_call_cont k tk ->
    forall s1 s2, match_call_cont k (Kloop1 s1 s2 tk).
Proof.
induction 1; intros.
- econstructor 1; eauto.
- econstructor 2; eauto.
Qed.

match_call_cont k tk depends only on the context of k and tk
Lemma match_call_cont_loop2:
  forall k tk,
    match_call_cont k tk ->
    forall s1 s2, match_call_cont (Kloop2 s1 s2 k) tk.
Proof.
induction 1; intros.
- econstructor 1; eauto.
- econstructor 2; eauto.
Qed.

match_call_cont k tk depends only on the context of k and tk
Lemma match_call_cont_loop2_bis:
  forall k tk,
    match_call_cont k tk ->
    forall s1 s2, match_call_cont k (Kloop2 s1 s2 tk).
Proof.
induction 1; intros.
- econstructor 1; eauto.
- econstructor 2; eauto.
Qed.

match_call_cont k tk depends only on the context of k and tk
Lemma match_call_cont_switch_bis:
  forall k tk,
    match_call_cont k tk ->
    match_call_cont k (Kswitch tk).
Proof.
induction 1; intros.
- econstructor 1; eauto.
- econstructor 2; eauto.
Qed.

match_call_cont k tk depends only on the context of k and tk
Lemma match_call_cont_call_cont:
  forall k tk,
    match_call_cont k tk ->
    match_call_cont (call_cont k) (call_cont tk).
Proof.
induction 1.
- rewrite H; rewrite H0; econstructor 1; eauto.
- rewrite H; rewrite H0; econstructor 2; simpl; eauto.
Qed.

Relating execution states
Inductive match_states: Clight.state -> Clight.state -> Prop :=
| match_regular_states:
    forall f s k e le m tf tk tle ls n
           (TRF: transf_function phi f = OK tf)
           (TENV: forall id, id <> new_ident_for_function f ->
                             le!id = tle!id)
           (NSTMT: not_in_stmt (new_ident_for_function f) s)
           (NCONT: not_in_cont (new_ident_for_function f) k)
           (NSLG: no_switch_label_goto_in_stmt s)
           (NSLGK: no_switch_label_goto_in_cont k)
           (LS: flatten phi (new_ident_for_function f, tint) (fn_body f) 1 0 = OK ls)
           (PC: tle!(new_ident_for_function f) = Some (Vint (phi n)))
           (MSTMT: (is_call_cont (context k) /\ exists next_instr, match_stmt_cont s ls (new_ident_for_function f, tint) n next_instr k) \/
           (exists s1 s2 k', context k = Kloop1 s1 s2 k' /\
                             exists start start' next_instr to_continue to_continue' to_break to_break',
                               match_stmt_cont_in_loop1 s ls (new_ident_for_function f, tint) (start::start') n next_instr (to_continue::to_continue') (to_break::to_break') k /\
                               match_loop ls (new_ident_for_function f, tint) (start::start') (to_continue::to_continue') (to_break::to_break') k) \/
           (exists s1 s2 k', context k = Kloop2 s1 s2 k' /\
                             exists start start' next_instr to_continue to_continue' to_break to_break',
                               match_stmt_cont_in_loop2 s ls (new_ident_for_function f, tint) (start::start') n next_instr (to_continue::to_continue') (to_break::to_break') k /\
                               match_loop ls (new_ident_for_function f, tint) (start::start') (to_continue::to_continue') (to_break::to_break') k))
           (MCONT: match_call_cont k tk)
           (CCONT: is_call_cont tk),
      match_states
        (State f s k e le m)
        (State tf
               (Sloop (Ssequence
                         (Sifthenelse
                            (Ebinop One
                                    (Etempvar (new_ident_for_function f) tint)
                                    (Econst_int (phi 0) tint) tint)
                            Sskip
                            Sbreak)
                         (Sswitch (Etempvar (new_ident_for_function f) tint) ls)) Sskip)
               tk e tle m)
| match_call_states:
    forall fd tfd args k tk m
           (TRFD: transf_fundef phi fd = OK tfd)
           (MCONT: match_call_cont k tk)
           (NCONT: forall id, not_in_cont id k)
           (NSLGK: no_switch_label_goto_in_cont k)
           (CCONT: is_call_cont k)
           (TCONT: is_call_cont tk),
      match_states (Callstate fd args k m) (Callstate tfd args tk m)
| match_return_states:
    forall v k tk m
           (MCONT: match_call_cont k tk)
           (NCONT: forall id, not_in_cont id k)
           (NSLGK: no_switch_label_goto_in_cont k)
           (CCONT: is_call_cont k)
           (TCONT: is_call_cont tk),
      match_states (Returnstate v k m) (Returnstate v tk m).

Lemma is_call_cont_call_cont:
  forall k,
    is_call_cont (call_cont k).
Proof.
induction k; simpl; eauto.
Qed.

Lemma alloc_variables_preserved:
  forall e m l e' m',
    alloc_variables ge e m l e' m' ->
    alloc_variables tge e m l e' m'.
Proof.
intros; induction H; econstructor; try (rewrite comp_env_preserved); eauto.
Qed.

Lemma bind_parameters_preserved:
  forall e m params args m',
    bind_parameters ge e m params args m' ->
    bind_parameters tge e m params args m'.
Proof.
intros; induction H; econstructor; try (rewrite comp_env_preserved); eauto.
Qed.

Simulation diagram
Theorem simulation:
  forall S1 t S2, step1 ge S1 t S2 ->
                  forall S1' (MS: match_states S1 S1'),
                  exists S2',
                    (plus step1 tge S1' t S2' \/
                     (star step1 tge S1' t S2' /\ measure S2 < measure S1)%nat)
                    /\ match_states S2 S2'.
Proof.
induction 1; intros; inv MS.
- destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext MSTMT]; destruct MSTMT as [next_instr MSTMT]. inv MSTMT.
    eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H7; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eapply eval_lvalue_preserved; eauto. inv NSTMT; auto. eapply eval_expr_preserved; eauto. inv NSTMT; auto. eauto. rewrite comp_env_preserved. eauto.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { intros. rewrite PTree.gso; auto. }
      { constructor. }
      { constructor. }
      { rewrite PTree.gss; auto. }
  + destruct MSTMT as [s1 [s2 [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' MSTMT]]]]]]]. destruct MSTMT as [MSTMT MSTMT']. inv MSTMT. eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H7; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eapply eval_lvalue_preserved; eauto. inv NSTMT; auto. eapply eval_expr_preserved; eauto. inv NSTMT; auto. eauto. rewrite comp_env_preserved. eauto.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { intros. rewrite PTree.gso; auto. }
      { constructor. }
      { constructor. }
      { rewrite PTree.gss; auto. }
      { right. left. eexists. eexists. eexists. split; eauto.
        destruct H16. eexists. eexists. eexists. eexists. eexists. eexists. eexists. eauto. }
  + destruct MSTMT as [s1 [s2 [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' MSTMT]]]]]]]. destruct MSTMT as [MSTMT MSTMT']. inv MSTMT. eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto.
      unfold select_switch; rewrite H7; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eapply eval_lvalue_preserved; eauto. inv NSTMT; auto. eapply eval_expr_preserved; eauto. inv NSTMT; auto. eauto. rewrite comp_env_preserved. eauto.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { intros. rewrite PTree.gso; auto. }
      { constructor. }
      { constructor. }
      { rewrite PTree.gss; auto. }
      { right. right. eexists. eexists. eexists. split; eauto.
        destruct H16. eexists. eexists. eexists. eexists. eexists. eexists. eexists. eauto. }
- destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext MSTMT]; destruct MSTMT as [next_instr MSTMT]. inv MSTMT.
    eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H4; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eapply eval_expr_preserved; eauto. inv NSTMT; auto.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { intros; destruct (ident_eq id id0).
        - subst id0; rewrite PTree.gss.
          rewrite PTree.gso; auto. rewrite PTree.gss; auto.
        - repeat (rewrite PTree.gso); auto. }
      { constructor. }
      { constructor. }
      { rewrite PTree.gss; auto. }
  + destruct MSTMT as [s1 [s2 [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]. inv MSTMT. eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H4; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eapply eval_expr_preserved; eauto. inv NSTMT; auto.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { intros; destruct (ident_eq id id0).
        - subst id0; rewrite PTree.gss.
          rewrite PTree.gso; auto. rewrite PTree.gss; auto.
        - repeat (rewrite PTree.gso); auto. }
      { constructor. }
      { constructor. }
      { rewrite PTree.gss; auto. }
      { right. left. eexists. eexists. eexists. destruct H13; repeat split; eauto.
        eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. }
  + destruct MSTMT as [s1 [s2 [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]. inv MSTMT. eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H4; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eapply eval_expr_preserved; eauto. inv NSTMT; auto.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { intros; destruct (ident_eq id id0).
        - subst id0; rewrite PTree.gss.
          rewrite PTree.gso; auto. rewrite PTree.gss; auto.
        - repeat (rewrite PTree.gso); auto. }
      { constructor. }
      { constructor. }
      { rewrite PTree.gss; auto. }
      { right. right. eexists. eexists. eexists. destruct H13; split; eauto.
        eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. }
- generalize (functions_translated _ _ H2); intros [tf' [A B]].
  destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext MSTMT]; destruct MSTMT as [next_instr MSTMT]. inv MSTMT.
    eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H14; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eauto. eapply eval_expr_preserved; eauto. inv NSTMT; eauto. eapply eval_exprlist_preserved; eauto. inv NSTMT; auto. eauto. rewrite (type_of_fundef_preserved fd). exact H3. exact B.
      econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { econstructor 2; simpl; eauto.
        eexists. eexists. eexists. split; eauto.
        eapply match_call_cont_seq_bis. eapply match_call_cont_seq_bis. eapply match_call_cont_switch_bis. eapply match_call_cont_loop1_bis. eauto. }
      { intros. inv NSTMT; econstructor; eauto. }
      { inv NSLG; econstructor; eauto.
        eapply no_switch_label_goto_function; eauto. }
      { econstructor. }
      { econstructor. }
  + destruct MSTMT as [s1 [s2 [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]. inv MSTMT. eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H17; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eauto. eapply eval_expr_preserved; eauto. inv NSTMT; eauto. eapply eval_exprlist_preserved; eauto. inv NSTMT; auto. eauto. rewrite (type_of_fundef_preserved fd). exact H3. exact B.
      econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { econstructor 2; simpl; eauto.
        eexists. eexists. eexists. repeat split; eauto.
        - right. left. destruct H18 as [next_instr' H18].
          eexists. eexists. eexists. split; eauto.
          eexists. eexists. eexists. eexists. eexists. eexists. eexists. split; eauto.
        - eapply match_call_cont_seq_bis. eapply match_call_cont_seq_bis. eapply match_call_cont_switch_bis. eapply match_call_cont_loop1_bis. eauto. }
      { intros. inv NSTMT; econstructor; eauto. }
      { inv NSLG; econstructor; eauto.
        eapply no_switch_label_goto_function; eauto. }
      { econstructor. }
      { econstructor. }
  + destruct MSTMT as [s1 [s2 [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]. inv MSTMT. eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H17; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eauto. eapply eval_expr_preserved; eauto. inv NSTMT; eauto. eapply eval_exprlist_preserved; eauto. inv NSTMT; auto. eauto. rewrite (type_of_fundef_preserved fd). exact H3. exact B.
      econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { econstructor 2; simpl; eauto.
        eexists. eexists. eexists. repeat split; eauto.
        - right. right. destruct H18 as [next_instr' H18].
          eexists. eexists. eexists. split; eauto.
          eexists. eexists. eexists. eexists. eexists. eexists. eexists. split; eauto.
        - eapply match_call_cont_seq_bis. eapply match_call_cont_seq_bis. eapply match_call_cont_switch_bis. eapply match_call_cont_loop1_bis. eauto. }
      { intros. inv NSTMT; econstructor; eauto. }
      { inv NSLG; econstructor; eauto.
        eapply no_switch_label_goto_function; eauto. }
      { econstructor. }
      { econstructor. }
- destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext MSTMT]; destruct MSTMT as [next_instr MSTMT]. inv MSTMT.
    eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H12; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eapply eval_exprlist_preserved; eauto. inv NSTMT; auto. eapply external_call_symbols_preserved; eauto. exact symbols_preserved. exact (Genv.public_symbol_transf_partial _ _ transf_programs). exact varinfo_preserved.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. repeat (rewrite E0_left); repeat (rewrite E0_right); eauto.
    * econstructor; eauto.
      { intros; rewrite PTree.gso; auto.
        unfold set_opttemp. destruct optid.
        - destruct (ident_eq i id).
          + subst i. repeat (rewrite PTree.gss); auto.
          + repeat (rewrite PTree.gso); auto.
        - eauto. }
      { constructor. }
      { constructor. }
      { rewrite PTree.gss; auto. }
  + destruct MSTMT as [s1 [s2 [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]. inv MSTMT. eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H15; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eapply eval_exprlist_preserved; eauto. inv NSTMT; auto. eapply external_call_symbols_preserved; eauto. exact symbols_preserved. exact (Genv.public_symbol_transf_partial _ _ transf_programs). exact varinfo_preserved.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. repeat (rewrite E0_left); repeat (rewrite E0_right); eauto.
    * econstructor; eauto.
      { intros; rewrite PTree.gso; auto.
        unfold set_opttemp. destruct optid.
        - destruct (ident_eq i id).
          + subst i. repeat (rewrite PTree.gss); auto.
          + repeat (rewrite PTree.gso); auto.
        - eauto. }
      { constructor. }
      { constructor. }
      { rewrite PTree.gss; auto. }
      { right. left. eexists. eexists. eexists. destruct H16; split; eauto.
        eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. }
  + destruct MSTMT as [s1 [s2 [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]. inv MSTMT. eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H15; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eapply eval_exprlist_preserved; eauto. inv NSTMT; auto. eapply external_call_symbols_preserved; eauto. exact symbols_preserved. exact (Genv.public_symbol_transf_partial _ _ transf_programs). exact varinfo_preserved.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. repeat (rewrite E0_left); repeat (rewrite E0_right); eauto.
    * econstructor; eauto.
      { intros; rewrite PTree.gso; auto.
        unfold set_opttemp. destruct optid.
        - destruct (ident_eq i id).
          + subst i. repeat (rewrite PTree.gss); auto.
          + repeat (rewrite PTree.gso); auto.
        - eauto. }
      { constructor. }
      { constructor. }
      { rewrite PTree.gss; auto. }
      { right. right. eexists. eexists. eexists. destruct H16; split; eauto.
        eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. }
- destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext MSTMT]; destruct MSTMT as [next_instr MSTMT]. inv MSTMT.
    eexists. split.
    * right. split. econstructor. simpl. omega.
    * econstructor; eauto.
      { inv NSTMT; auto. }
      { inv NSTMT; econstructor; auto. }
      { inv NSLG; auto. }
      { inv NSLG; econstructor; auto. }
      { eapply match_call_cont_seq; eauto. }
  + destruct MSTMT as [s [s' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]. inv MSTMT. eexists. split.
    * right. split. econstructor. simpl. omega.
    * econstructor; eauto.
      { inv NSTMT; auto. }
      { inv NSTMT; econstructor; auto. }
      { inv NSLG; auto. }
      { inv NSLG; econstructor; auto. }
      { right. left. eexists. eexists. eexists. split; eauto.
        eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. eapply match_loop_context in MSTMT'. constructor; simpl; auto. }
      { eapply match_call_cont_seq; eauto. }
  + destruct MSTMT as [s [s' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]. inv MSTMT. eexists. split.
    * right. split. econstructor. simpl. omega.
    * econstructor; eauto.
      { inv NSTMT; auto. }
      { inv NSTMT; econstructor; auto. }
      { inv NSLG; auto. }
      { inv NSLG; econstructor; auto. }
      { right. right. eexists. eexists. eexists. split; eauto.
        eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. eapply match_loop_context in MSTMT'. econstructor. eauto. }
      { eapply match_call_cont_seq; eauto. }
- destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext MSTMT]; destruct MSTMT as [next_instr MSTMT]. inv MSTMT; try (inv H; fail).
    destruct H7 as [[H7 [next_instr' H8]] | H7].
    * eexists; split.
      { left. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
        eapply star_step. econstructor.
        eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H7; simpl.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. right; auto.
        eapply star_step. econstructor. left; auto.
        eapply star_step. econstructor. econstructor.
        eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. }
      { econstructor; eauto.
        - intros. rewrite PTree.gso; eauto.
        - inv NCONT; auto.
        - inv NCONT; auto.
        - inv NSLGK; auto.
        - inv NSLGK; auto.
        - rewrite PTree.gss; auto.
        - inv MCONT; simpl in H.
          + econstructor 1; eauto.
          + econstructor 2; eauto. }
    * eexists; split.
      { right; split.
        - econstructor.
        - simpl; omega. }
      { econstructor; eauto.
        - inv NCONT; auto.
        - inv NCONT; auto.
        - inv NSLGK; auto.
        - inv NSLGK; auto.
        - inv MCONT; simpl in H.
          + econstructor 1; eauto.
          + econstructor 2; eauto. }
  + destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]. inv MSTMT; try (inv H; fail).
    destruct H10 as [[H10 [next_instr' H11]] | H10].
    * eexists; split.
      { left. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
        eapply star_step. econstructor.
        eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H10; simpl.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. right; auto.
        eapply star_step. econstructor. left; auto.
        eapply star_step. econstructor. econstructor.
        eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. }
      { econstructor; eauto.
        - intros. rewrite PTree.gso; eauto.
        - inv NCONT; auto.
        - inv NCONT; auto.
        - inv NSLGK; auto.
        - inv NSLGK; auto.
        - rewrite PTree.gss; auto.
        - right. left. eexists. eexists. eexists. split; eauto.
          eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. eapply match_loop_context in MSTMT'; eapply match_loop_context; simpl in MSTMT'; auto.
        - inv MCONT; simpl in H.
          + econstructor 1; eauto.
          + econstructor 2; eauto. }
    * eexists; split.
      { right; split.
        - econstructor.
        - simpl; omega. }
      { econstructor; eauto.
        - inv NCONT; auto.
        - inv NCONT; auto.
        - inv NSLGK; auto.
        - inv NSLGK; auto.
        - right. left. eexists. eexists. eexists. split; eauto.
          eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. eapply match_loop_context in MSTMT'; eapply match_loop_context; simpl in MSTMT'; auto.
        - inv MCONT; simpl in H.
          + econstructor 1; eauto.
          + econstructor 2; eauto. }
  + destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]. inv MSTMT; try (inv H; fail).
    destruct H10 as [[H10 [next_instr' H11]] | H0].
    * eexists; split.
      { left. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
        eapply star_step. econstructor.
        eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H10; simpl.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. right; auto.
        eapply star_step. econstructor. left; auto.
        eapply star_step. econstructor. econstructor.
        eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. }
      { econstructor; eauto.
        - intros. rewrite PTree.gso; eauto.
        - inv NCONT; auto.
        - inv NCONT; auto.
        - inv NSLGK; auto.
        - inv NSLGK; auto.
        - rewrite PTree.gss; auto.
        - right. right. eexists. eexists. eexists. split; eauto.
          eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. eapply match_loop_context in MSTMT'; eapply match_loop_context; simpl in MSTMT'; auto.
        - inv MCONT; simpl in H.
          + econstructor 1; eauto.
          + econstructor 2; eauto. }
    * eexists; split.
      { right; split.
        - econstructor.
        - simpl; omega. }
      { econstructor; eauto.
        - inv NCONT; auto.
        - inv NCONT; auto.
        - inv NSLGK; auto.
        - inv NSLGK; auto.
        - right. right. eexists. eexists. eexists. split; eauto.
          eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. eapply match_loop_context in MSTMT'; eapply match_loop_context; simpl in MSTMT'; auto.
        - inv MCONT; simpl in H.
          + econstructor 1; eauto.
          + econstructor 2; eauto. }
- eexists; split.
  + right; split.
    * econstructor.
    * simpl; omega.
  + destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
    * destruct MSTMT as [Hcontext MSTMT]; destruct MSTMT as [next_instr MSTMT]. inv MSTMT.
    * destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT.
      econstructor; eauto.
      { inv NCONT; auto. }
      { inv NSLGK; auto. }
      { right. left. eexists. eexists. eexists. split; eauto.
        eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. eapply match_loop_context in MSTMT'; eapply match_loop_context; simpl in MSTMT'; auto. }
      { inv MCONT; simpl in H.
        - econstructor 1; eauto.
        - econstructor 2; eauto. }
    * destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT.
- eexists; split.
  + right; split.
    * econstructor.
    * simpl; omega.
  + destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
    * destruct MSTMT as [Hcontext MSTMT]; destruct MSTMT as [next_instr MSTMT]. inv MSTMT.
    * destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT.
      econstructor; eauto.
      { inv NCONT; auto. }
      { inv NSLGK; auto. }
      { right. left. eexists. eexists. eexists. split; eauto.
        eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. eapply match_loop_context in MSTMT'; eapply match_loop_context; simpl in MSTMT'; auto. }
      { inv MCONT; simpl in H.
        - econstructor 1; eauto.
        - econstructor 2; eauto. }
    * destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT.
      econstructor; eauto.
      { inv NCONT; auto. }
      { inv NSLGK; auto. }
      { right. right. eexists. eexists. eexists. split; eauto.
        eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. eapply match_loop_context in MSTMT'; eapply match_loop_context; simpl in MSTMT'; auto. }
      { inv MCONT; simpl in H.
        - econstructor 1; eauto.
        - econstructor 2; eauto. }
- destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext MSTMT]; destruct MSTMT as [next_instr MSTMT]. inv MSTMT. destruct b.
    * eexists; split.
      { left. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
        eapply star_step. econstructor.
        eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H6; simpl.
        eapply star_step. econstructor.
        eapply star_step. econstructor. eapply eval_expr_preserved; eauto. inv NSTMT; auto. eauto.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. right; auto.
        eapply star_step. econstructor. left; auto.
        eapply star_step. econstructor. econstructor.
        eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. }
      { econstructor; eauto.
        - intros; rewrite PTree.gso; auto.
        - inv NSTMT; auto.
        - inv NSLG; auto.
        - rewrite PTree.gss; auto. }
    * eexists; split.
      { left. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
        eapply star_step. econstructor.
        eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H6; simpl.
        eapply star_step. econstructor.
        eapply star_step. econstructor. eapply eval_expr_preserved; eauto. inv NSTMT; auto. eauto.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. right; auto.
        eapply star_step. econstructor. left; auto.
        eapply star_step. econstructor. econstructor.
        eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. }
      { econstructor; eauto.
        - intros; rewrite PTree.gso; auto.
        - inv NSTMT; auto.
        - inv NSLG; auto.
        - rewrite PTree.gss; auto. }
  + destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT. destruct b.
    * eexists; split.
      { left. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
        eapply star_step. econstructor.
        eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H6; simpl.
        eapply star_step. econstructor.
        eapply star_step. econstructor. eapply eval_expr_preserved; eauto. inv NSTMT; auto. eauto.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. right; auto.
        eapply star_step. econstructor. left; auto.
        eapply star_step. econstructor. econstructor.
        eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. }
      { econstructor; eauto.
        - intros; rewrite PTree.gso; auto.
        - inv NSTMT; auto.
        - inv NSLG; auto.
        - rewrite PTree.gss; auto.
        - right. left. eexists. eexists. eexists. split; eauto.
          eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. }
    * eexists; split.
      { left. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
        eapply star_step. econstructor.
        eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H6; simpl.
        eapply star_step. econstructor.
        eapply star_step. econstructor. eapply eval_expr_preserved; eauto. inv NSTMT; auto. eauto.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. right; auto.
        eapply star_step. econstructor. left; auto.
        eapply star_step. econstructor. econstructor.
        eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. }
      { econstructor; eauto.
        - intros; rewrite PTree.gso; auto.
        - inv NSTMT; auto.
        - inv NSLG; auto.
        - rewrite PTree.gss; auto.
        - right. left. eexists. eexists. eexists. split; eauto.
          eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. }
  + destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT. destruct b.
    * eexists; split.
      { left. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
        eapply star_step. econstructor.
        eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H6; simpl.
        eapply star_step. econstructor.
        eapply star_step. econstructor. eapply eval_expr_preserved; eauto. inv NSTMT; auto. eauto.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. right; auto.
        eapply star_step. econstructor. left; auto.
        eapply star_step. econstructor. econstructor.
        eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. }
      { econstructor; eauto.
        - intros; rewrite PTree.gso; auto.
        - inv NSTMT; auto.
        - inv NSLG; auto.
        - rewrite PTree.gss; auto.
        - right. right. eexists. eexists. eexists. split; eauto.
          eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. }
    * eexists; split.
      { left. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
        eapply star_step. econstructor.
        eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H6; simpl.
        eapply star_step. econstructor.
        eapply star_step. econstructor. eapply eval_expr_preserved; eauto. inv NSTMT; auto. eauto.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. right; auto.
        eapply star_step. econstructor. left; auto.
        eapply star_step. econstructor. econstructor.
        eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. }
      { econstructor; eauto.
        - intros; rewrite PTree.gso; auto.
        - inv NSTMT; auto.
        - inv NSLG; auto.
        - rewrite PTree.gss; auto.
        - right. right. eexists. eexists. eexists. split; eauto.
          eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. }
- destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext MSTMT]; destruct MSTMT as [next_instr MSTMT]. inv MSTMT.
    eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H3; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { intros. rewrite PTree.gso; eauto. }
      { inv NSTMT; auto. }
      { inv NSTMT; econstructor; auto. }
      { inv NSLG; auto. }
      { inv NSLG; econstructor; auto. }
      { rewrite PTree.gss; auto. }
      { right. left. eexists. eexists. eexists. split; simpl; eauto.
        eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. econstructor; eauto. eapply match_loop_context. eapply match_loop_call_cont_context; eauto. }
      { inv MCONT; simpl in H.
        - econstructor 1; eauto.
        - econstructor 2; eauto. }
  + destruct MSTMT as [s [s' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]. inv MSTMT. eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H3; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { intros. rewrite PTree.gso; eauto. }
      { inv NSTMT; auto. }
      { inv NSTMT; econstructor; auto. }
      { inv NSLG; auto. }
      { inv NSLG; econstructor; auto. }
      { rewrite PTree.gss; auto. }
      { right. left. eexists. eexists. eexists. split; eauto.
        eexists. eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. econstructor; eauto. }
      { inv MCONT; simpl in H.
        - econstructor 1; eauto.
        - econstructor 2; eauto. }
  + destruct MSTMT as [s [s' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]. inv MSTMT. eexists. split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H3; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { intros. rewrite PTree.gso; eauto. }
      { inv NSTMT; auto. }
      { inv NSTMT; econstructor; auto. }
      { inv NSLG; auto. }
      { inv NSLG; econstructor; auto. }
      { rewrite PTree.gss; auto. }
      { right. left. eexists. eexists. eexists. split; eauto.
        eexists. eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. econstructor; eauto. }
      { inv MCONT; simpl in H.
        - econstructor 1; eauto.
        - econstructor 2; eauto. }
- destruct H; subst x.
  + destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
    * destruct MSTMT as [Hcontext MSTMT]; destruct MSTMT as [next_instr MSTMT]. inv MSTMT. inv H.
    * destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT.
      destruct H10 as [[H10 [next_instr' H11]] | H10].
      { eexists; split.
        - left. econstructor. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
          eapply star_step. econstructor.
          eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H10; simpl.
          eapply star_step. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor. right; auto.
          eapply star_step. econstructor. left; auto.
          eapply star_step. econstructor. econstructor.
          eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
        - econstructor; eauto.
          + intros. rewrite PTree.gso; eauto.
          + inv NCONT; auto.
          + inv NCONT; econstructor; eauto.
          + inv NSLGK; auto.
          + inv NSLGK; econstructor; eauto.
          + rewrite PTree.gss; auto.
          + right. right. eexists. eexists. eexists. repeat split; eauto.
            simpl in Hcontext. inv Hcontext.
            eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. inv MSTMT'; econstructor; eauto.
          + inv MCONT; simpl in H.
            * econstructor 1; eauto.
            * econstructor 2; eauto. }
      { eexists; split.
        - right; split.
          + econstructor.
          + simpl; omega.
        - econstructor; eauto.
          + inv NCONT; auto.
          + inv NCONT; econstructor; eauto.
          + inv NSLGK; auto.
          + inv NSLGK; econstructor; eauto.
          + right. right. eexists. eexists. eexists. repeat split; eauto.
            simpl in Hcontext. inv Hcontext.
            eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. inv MSTMT'; econstructor; eauto.
          + inv MCONT; simpl in H.
            * econstructor 1; eauto.
            * econstructor 2; eauto. }
    * destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. simpl in Hcontext; inv Hcontext.
  + destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
    * destruct MSTMT as [Hcontext MSTMT]; destruct MSTMT as [next_instr MSTMT]. inv MSTMT.
    * destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT.
      eexists; split.
      { left. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
        eapply star_step. econstructor.
        eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H11; simpl.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. right; auto.
        eapply star_step. econstructor. left; auto.
        eapply star_step. econstructor. econstructor.
        eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. }
      { econstructor; eauto.
        - intros. rewrite PTree.gso; eauto.
        - inv NCONT; auto.
        - inv NCONT; econstructor; eauto.
        - inv NSLGK; auto.
        - inv NSLGK; econstructor; eauto.
        - rewrite PTree.gss; auto.
        - right. right. eexists. eexists. eexists. repeat split; eauto.
          simpl in Hcontext. inv Hcontext.
          destruct H12 as [next_instr' H12].
          eexists. eexists. eexists. eexists. eexists. eexists. eexists. repeat split; eauto. inv MSTMT'; econstructor; eauto.
        - inv MCONT; simpl in H.
          + econstructor 1; eauto.
          + econstructor 2; eauto. }
    * destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. simpl in Hcontext; inv Hcontext.
- destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext MSTMT]. simpl in Hcontext; inv Hcontext.
  + destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT.
    eexists; split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H13; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { intros. rewrite PTree.gso; eauto. }
      { econstructor. }
      { inv NCONT; eauto. }
      { econstructor. }
      { inv NSLGK; auto. }
      { rewrite PTree.gss; auto. }
      { destruct H14 as [H | [H | H]].
        - left; destruct H. destruct H0. destruct H0. split; eauto.
        - right. left. destruct H as [s [s' [k'' [H [next_instr' H0]]]]].
          eexists. eexists. eexists. repeat split; eauto.
          inv MSTMT'. generalize (match_loop_loop1_context _ _ _ _ _ _ _ _ _ H H16).
          intros [to_start [to_start' [continue [continue' [break [break' [Hstart [Hcontinue Hbreak]]]]]]]]. subst start'. subst to_continue'. subst to_break'. eexists. eexists. eexists. eexists. eexists. eexists. eexists. split; eauto.
        - right. right. destruct H as [s [s' [k'' [H [next_instr' H0]]]]].
          eexists. eexists. eexists. repeat split; eauto.
          inv MSTMT'. generalize (match_loop_loop2_context _ _ _ _ _ _ _ _ _ H H16).
          intros [to_start [to_start' [continue [continue' [break [break' [Hstart [Hcontinue Hbreak]]]]]]]]. subst start'. subst to_continue'. subst to_break'. eexists. eexists. eexists. eexists. eexists. eexists. eexists. split; eauto. }
      { inv MCONT; simpl in H.
        - econstructor 1; eauto.
        - econstructor 2; eauto. }
  + destruct MSTMT as [s1' [s2' [k' [Hcontext MSTMT]]]]. simpl in Hcontext; inv Hcontext.
- destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext MSTMT]. simpl in Hcontext; inv Hcontext.
  + destruct MSTMT as [s [s' [k' [Hcontext MSTMT]]]]. simpl in Hcontext; inv Hcontext.
  + destruct MSTMT as [s [s' [k' [Hcontext MSTMT]]]]. simpl in Hcontext; inv Hcontext. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT. destruct H11.
    * destruct H as [H [H0 H1]]. subst next_instr.
      eexists; split.
      { left. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
        eapply star_step. econstructor.
        eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H; simpl.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. right; auto.
        eapply star_step. econstructor. left; auto.
        eapply star_step. econstructor. econstructor.
        eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. }
      { econstructor; eauto.
        - intros; rewrite PTree.gso; eauto.
        - inv NCONT. econstructor; eauto.
        - inv NCONT; eauto.
        - inv NSLGK; econstructor; eauto.
        - inv NSLGK; eauto.
        - rewrite PTree.gss; eauto.
        - generalize (context_charact k'); intros.
          destruct H0 as [H0 | [H0 | [H0 | H0]]].
          + left. split; eauto.
            destruct H1 as [ls'' H1].
            eexists. inv MSTMT'; econstructor; eauto.
            * generalize (match_loop_call_cont_context_charact _ _ _ _ _ _ H0 H16).
              intros [A [B C]]. subst start'; subst to_continue'; subst to_break'; eauto.
            * generalize (match_loop_call_cont_context_charact _ _ _ _ _ _ H0 H16).
              intros [A [B C]]. subst start'; subst to_continue'; subst to_break'; eauto.
          + right. left. destruct H0 as [s1 [s2 [k'' H0]]].
            eexists. eexists. eexists. split; eauto.
            destruct H1 as [ls'' H1].
            inv MSTMT'. generalize (match_loop_loop1_context _ _ _ _ _ _ _ _ _ H0 H16). intros [to_start [to_start' [continue [continue' [break [break' [A [B C]]]]]]]].
            subst start'; subst to_continue'; subst to_break'.
            eexists. eexists. eexists. eexists. eexists. eexists. eexists. split; eauto.
            econstructor; eauto.
          + right. right. destruct H0 as [s1 [s2 [k'' H0]]].
            eexists. eexists. eexists. split; eauto.
            destruct H1 as [ls'' H1].
            inv MSTMT'. generalize (match_loop_loop2_context _ _ _ _ _ _ _ _ _ H0 H16). intros [to_start [to_start' [continue [continue' [break [break' [A [B C]]]]]]]].
            subst start'; subst to_continue'; subst to_break'.
            eexists. eexists. eexists. eexists. eexists. eexists. eexists. split; eauto.
            econstructor; eauto.
          + destruct H0 as [kk H0]. inv NSLGK.
            generalize (no_switch_context k' kk H7); intros. contradiction.
        - inv MCONT; simpl in H.
          + econstructor 1; eauto.
          + econstructor 2; eauto. }
    * destruct H as [H0 H]; subst n.
      eexists; split.
      { right. split.
        - econstructor.
        - simpl; omega. }
      { econstructor; eauto.
        - inv NCONT. econstructor; eauto.
        - inv NCONT; eauto.
        - inv NSLGK; econstructor; eauto.
        - inv NSLGK; eauto.
        - generalize (context_charact k'); intros.
          destruct H0 as [H0 | [H0 | [H0 | H0]]].
          + left. split; eauto.
            eexists. inv MSTMT'; econstructor; eauto.
            * generalize (match_loop_call_cont_context_charact _ _ _ _ _ _ H0 H15).
              intros [A [B C]]. subst start'; subst to_continue'; subst to_break'; eauto.
            * generalize (match_loop_call_cont_context_charact _ _ _ _ _ _ H0 H15).
              intros [A [B C]]. subst start'; subst to_continue'; subst to_break'; eauto.
          + right. left. destruct H0 as [s1 [s2 [k'' H0]]].
            eexists. eexists. eexists. split; eauto.
            inv MSTMT'. generalize (match_loop_loop1_context _ _ _ _ _ _ _ _ _ H0 H15). intros [to_start [to_start' [continue [continue' [break [break' [A [B C]]]]]]]].
            subst start'; subst to_continue'; subst to_break'.
            eexists. eexists. eexists. eexists. eexists. eexists. eexists. split; eauto.
            econstructor; eauto.
          + right. right. destruct H0 as [s1 [s2 [k'' H0]]].
            eexists. eexists. eexists. split; eauto.
            inv MSTMT'. generalize (match_loop_loop2_context _ _ _ _ _ _ _ _ _ H0 H15). intros [to_start [to_start' [continue [continue' [break [break' [A [B C]]]]]]]].
            subst start'; subst to_continue'; subst to_break'.
            eexists. eexists. eexists. eexists. eexists. eexists. eexists. split; eauto.
            econstructor; eauto.
          + destruct H0 as [kk H0]. inv NSLGK.
            generalize (no_switch_context k' kk H6); intros. contradiction.
        - inv MCONT; simpl in H.
          + econstructor 1; eauto.
          + econstructor 2; eauto. }
- destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext MSTMT]. simpl in Hcontext; inv Hcontext.
  + destruct MSTMT as [s [s' [k' [Hcontext MSTMT]]]]. simpl in Hcontext; inv Hcontext.
  + destruct MSTMT as [s [s' [k' [Hcontext MSTMT]]]]. simpl in Hcontext; inv Hcontext. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT.
    eexists; split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H13; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. right; auto.
      eapply star_step. econstructor. left; auto.
      eapply star_step. econstructor. econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { intros; rewrite PTree.gso; eauto. }
      { econstructor. }
      { inv NCONT; eauto. }
      { econstructor. }
      { inv NSLGK; eauto. }
      { rewrite PTree.gss; eauto. }
      { destruct H14 as [H14 | [H14 | H14]].
        - left. destruct H14. split; eauto.
          destruct H0 as [next_instr' [H0 A]]. eexists. eauto.
        - right; left. destruct H14 as [s1' [s2' [k'' [H14 [next_instr' H15]]]]].
          eexists. eexists. eexists. split; eauto.
          inv MSTMT'. generalize (match_loop_loop1_context _ _ _ _ _ _ _ _ _ H14 H16). intros [to_start [to_start' [continue [continue' [break [break' [A [B C]]]]]]]].
          subst start'; subst to_continue'; subst to_break'.
          eexists. eexists. eexists. eexists. eexists. eexists. eexists. split; eauto.
        - right; right. destruct H14 as [s1' [s2' [k'' [H14 [next_instr' H15]]]]].
          eexists. eexists. eexists. split; eauto.
          inv MSTMT'. generalize (match_loop_loop2_context _ _ _ _ _ _ _ _ _ H14 H16). intros [to_start [to_start' [continue [continue' [break [break' [A [B C]]]]]]]].
          subst start'; subst to_continue'; subst to_break'.
          eexists. eexists. eexists. eexists. eexists. eexists. eexists. split; eauto. }
      { inv MCONT; simpl in H.
        - econstructor 1; eauto.
        - econstructor 2; eauto. }
- destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext MSTMT]. destruct MSTMT as [next_instr MSTMT]. inv MSTMT.
    eexists; split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H3; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. unfold blocks_of_env, block_of_binding. rewrite comp_env_preserved. eauto.
      econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { simpl; eapply match_call_cont_call_cont; eauto. }
      { intros. eapply not_in_cont_call_cont; eauto. }
      { eapply no_switch_label_goto_in_cont_call_cont; eauto. }
      { eapply is_call_cont_call_cont. }
      { eapply is_call_cont_call_cont. }
  + destruct MSTMT as [s [s' [k' [Hcontext MSTMT]]]]. simpl in Hcontext; inv Hcontext. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT.
    eexists; split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H4; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. unfold blocks_of_env, block_of_binding. rewrite comp_env_preserved. eauto.
      econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { simpl; eapply match_call_cont_call_cont; eauto. }
      { intros. eapply not_in_cont_call_cont; eauto. }
      { eapply no_switch_label_goto_in_cont_call_cont; eauto. }
      { eapply is_call_cont_call_cont. }
      { eapply is_call_cont_call_cont. }
  + destruct MSTMT as [s [s' [k' [Hcontext MSTMT]]]]. simpl in Hcontext; inv Hcontext. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT.
    eexists; split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H4; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. unfold blocks_of_env, block_of_binding. rewrite comp_env_preserved. eauto.
      econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { simpl; eapply match_call_cont_call_cont; eauto. }
      { intros. eapply not_in_cont_call_cont; eauto. }
      { eapply no_switch_label_goto_in_cont_call_cont; eauto. }
      { eapply is_call_cont_call_cont. }
      { eapply is_call_cont_call_cont. }
- destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext MSTMT]. destruct MSTMT as [next_instr MSTMT]. inv MSTMT.
    eexists; split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H5; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eapply eval_expr_preserved; eauto. inv NSTMT; eauto. monadInv TRF. simpl; eauto. unfold blocks_of_env, block_of_binding. rewrite comp_env_preserved. eauto.
      econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { simpl; eapply match_call_cont_call_cont; eauto. }
      { intros. eapply not_in_cont_call_cont; eauto. }
      { eapply no_switch_label_goto_in_cont_call_cont; eauto. }
      { eapply is_call_cont_call_cont. }
      { eapply is_call_cont_call_cont. }
  + destruct MSTMT as [s [s' [k' [Hcontext MSTMT]]]]. simpl in Hcontext; inv Hcontext. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT.
    eexists; split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H6; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eapply eval_expr_preserved; eauto. inv NSTMT; eauto. monadInv TRF. simpl; eauto. unfold blocks_of_env, block_of_binding. rewrite comp_env_preserved. eauto.
      econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { simpl; eapply match_call_cont_call_cont; eauto. }
      { intros. eapply not_in_cont_call_cont; eauto. }
      { eapply no_switch_label_goto_in_cont_call_cont; eauto. }
      { eapply is_call_cont_call_cont. }
      { eapply is_call_cont_call_cont. }
  + destruct MSTMT as [s [s' [k' [Hcontext MSTMT]]]]. simpl in Hcontext; inv Hcontext. destruct MSTMT as [start [start' [next_instr [to_continue [to_continue' [to_break [to_break' [MSTMT MSTMT']]]]]]]]; inv MSTMT.
    eexists; split.
    * left. econstructor. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
      eapply star_step. econstructor.
      eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H6; simpl.
      eapply star_step. econstructor.
      eapply star_step. econstructor.
      eapply star_step. econstructor. eapply eval_expr_preserved; eauto. inv NSTMT; eauto. monadInv TRF. simpl; eauto. unfold blocks_of_env, block_of_binding. rewrite comp_env_preserved. eauto.
      econstructor.
      eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
    * econstructor; eauto.
      { simpl; eapply match_call_cont_call_cont; eauto. }
      { intros. eapply not_in_cont_call_cont; eauto. }
      { eapply no_switch_label_goto_in_cont_call_cont; eauto. }
      { eapply is_call_cont_call_cont. }
      { eapply is_call_cont_call_cont. }
- destruct MSTMT as [MSTMT | [MSTMT | MSTMT]].
  + destruct MSTMT as [Hcontext [next_instr MSTMT]]. inv MSTMT.
    * inv H.
    * destruct H2.
      { destruct H2 as [H2 [H3 [H4 H5]]].
        eexists. split.
        - left. econstructor. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try (exploit (phi_injection n 0); omega; fail). simpl; eauto. rewrite Int.unsigned_zero. rewrite Int.unsigned_one. destruct (zeq 1 0); try omega; simpl.
          eapply star_step. econstructor.
          eapply star_step. eapply step_switch. econstructor. eauto. unfold sem_switch_arg; simpl; eauto. unfold select_switch; rewrite H2; simpl.
          eapply star_step. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor. right; eauto.
          eapply star_step. econstructor. left; eauto.
          eapply star_step. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor. rewrite H4. econstructor. econstructor. eauto. rewrite PTree.gss; eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi next_instr)) (Int.unsigned (phi next_instr))); try congruence. simpl. rewrite Int.unsigned_zero. destruct (zeq 0 0); try omega; simpl; eauto.
          simpl; eapply star_step. econstructor.
          eapply star_step. eapply step_break_loop1.
          eapply star_step. eapply step_skip_call. eauto. unfold blocks_of_env, block_of_binding. rewrite comp_env_preserved. eauto.
          econstructor. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto.
        - econstructor; eauto.
          intros. destruct k; try (inv H1; fail).
          + econstructor.
          + inv NCONT; econstructor; eauto. }
      { destruct H2. eexists. split.
        - left. econstructor. econstructor.
          eapply star_step. econstructor.
          eapply star_step. econstructor. econstructor. econstructor. eauto. econstructor. simpl; unfold sem_cmp; simpl; unfold sem_binarith; simpl; eauto. unfold bool_val; simpl. unfold Int.eq. destruct (zeq (Int.unsigned (phi n)) (Int.unsigned (phi 0))); try congruence. simpl; eauto. rewrite Int.unsigned_zero. destruct (zeq 0 0); try omega; simpl.
          eapply star_step. econstructor.
          eapply star_step. eapply step_break_loop1.
          eapply star_step. eapply step_skip_call. eauto. unfold blocks_of_env, block_of_binding. rewrite comp_env_preserved. eauto.
          econstructor. eauto. eauto. eauto. eauto. eauto. eauto.
        - econstructor; eauto.
          intros. destruct k; try (inv H1; fail).
          + econstructor.
          + inv NCONT; econstructor; eauto. }
  + destruct MSTMT as [s1 [s2 [k' [Hcontext MSTMT]]]].
    destruct k; try (inv H; simpl in Hcontext; inv Hcontext; fail).
  + destruct MSTMT as [s1 [s2 [k' [Hcontext MSTMT]]]].
    destruct k; try (inv H; simpl in Hcontext; inv Hcontext; fail).
- inv NSLG.
- inv NSLGK.
- inv NSLGK.
- inv NSLG.
- inv NSLG.
- monadInv TRFD. monadInv EQ. unfold obf_body in EQ0. destruct (zlt (sizeof_stmt (fn_body f)) Int.max_unsigned); monadInv EQ0. simpl.
  eexists; split.
  + left. econstructor. econstructor. inv H; econstructor; simpl; eauto. eapply alloc_variables_preserved; eauto. eapply bind_parameters_preserved; eauto.
    simpl. eapply star_step. econstructor.
    eapply star_step. econstructor. econstructor.
    eapply star_step. econstructor. econstructor. eauto. eauto. eauto. eauto.
  + econstructor; eauto.
    * unfold transf_function. unfold obf_body. rewrite EQ. destruct (zlt (sizeof_stmt (fn_body f)) Int.max_unsigned); try omega. simpl. auto.
    * inv H. intros. rewrite PTree.gso; auto. rewrite PTree.gso; auto.
    * apply new_ident_not_in_body.
    * eapply no_switch_label_goto_function; eauto.
      unfold transf_function. unfold obf_body. instantiate (2 := phi).
      rewrite EQ. destruct (zlt (sizeof_stmt (fn_body f)) Int.max_unsigned); try omega. simpl. eauto.
    * rewrite PTree.gss; auto.
    * left. split.
      { destruct k; try (inv CCONT; simpl; econstructor). }
      { exists 0. replace x with (app_lstmt LSnil (app_lstmt x LSnil)).
        - eapply match_stmt_cont_flatten; eauto.
          + destruct k; try (inv CCONT; simpl; econstructor).
          + intros. subst k; inv CCONT.
          + intros; simpl.
            rewrite select_switch_app_right; simpl; auto.
            eapply select_switch_flatten; eauto; try omega.
            generalize (Int.unsigned_range_2 (Int.zero)). rewrite Int.unsigned_zero; auto.
          + omega.
          + omega.
          + omega.
        - simpl. apply app_lstmt_lsnil. }
- monadInv TRFD.
  eexists; split.
  + left; econstructor. econstructor. eapply external_call_symbols_preserved; eauto.
    exact symbols_preserved. exact (Genv.public_symbol_transf_partial _ _ transf_programs). exact varinfo_preserved.
    econstructor. rewrite E0_right. auto.
  + econstructor; eauto.
- destruct tk; try (inv TCONT; fail).
  + inv MCONT.
    * simpl in H; inv H.
    * simpl in H0; inv H0.
  + inv MCONT.
    * simpl in H; inv H.
    * destruct H4 as [next_instr [ls' [tk'' H4]]].
      destruct H4 as [H4 [A B]].
      eexists. split.
      { simpl in H0. inv H0. left. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor.
        eapply star_step. econstructor. right; eauto.
        eapply star_step. econstructor. left; eauto.
        eapply star_step. econstructor. econstructor.
        eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. eauto. }
      { simpl in H; inv H. simpl in H0; inv H0.
        econstructor; eauto.
        - intros. rewrite PTree.gso.
          + unfold set_opttemp. destruct optid0; eauto.
            destruct (ident_eq i id).
            * subst i; repeat rewrite PTree.gss; eauto.
            * repeat rewrite PTree.gso; eauto.
          + eauto.
        - econstructor.
        - generalize (NCONT (new_ident_for_function f1)); intros.
          inv H. eauto. exact H4.
        - econstructor.
        - inv NSLGK; eauto.
        - rewrite PTree.gss; eauto.
        - inv H5.
          + econstructor 1; simpl in H0; eauto.
          + econstructor 2; simpl in H0; eauto. }
Qed.

Lemma initial_states_simulation:
  forall S, Clight.initial_state prog S ->
            exists R, Clight.initial_state tprog R /\ match_states S R.
Proof.
intros. inv H.
  exploit function_ptr_translated; eauto. intros [tf [A B]].
  econstructor; split.
  econstructor.
  eapply Genv.init_mem_transf_partial. eexact transf_programs. eauto.
  change (Clight.prog_main tprog) with (AST.prog_main tprog).
  rewrite (transform_partial_program_main _ _ transf_programs).
  instantiate (1 := b). rewrite <- H1. apply symbols_preserved.
  eauto.
  rewrite <- H3; apply type_of_fundef_preserved; auto.
  econstructor; eauto.
  econstructor; simpl; eauto.
  econstructor. econstructor. econstructor. econstructor.
Qed.

Lemma final_states_simulation:
  forall S R r,
  match_states S R -> Clight.final_state S r -> Clight.final_state R r.
Proof.
intros; inv H0; inv H.
destruct tk; try inv TCONT.
- econstructor.
- inv MCONT. simpl in H0; inv H0. simpl in H; inv H.
Qed.

Final theorem of semantics preservation
Theorem transf_program_correct:
  forward_simulation (Clight.semantics1 prog) (Clight.semantics1 tprog).
Proof.
  eapply forward_simulation_star_wf with (order := ltof _ measure).
  - exact (Genv.public_symbol_transf_partial _ _ transf_programs).
  - eapply initial_states_simulation.
  - eapply final_states_simulation.
  - eapply well_founded_ltof.
  - eapply simulation.
Qed.

End PRESERVATION.

Section PRESERVATION_IDENT.

Parametrisation with the identity function over 0, 2^32 - 1

Definition phi_ident := Int.repr.

Variable prog: Clight.program.
Variable tprog: Clight.program.
Hypothesis TRANSF: transf_program phi_ident prog = OK tprog.
Let ge := Genv.globalenv prog.
Let tge := Genv.globalenv tprog.

Theorem phi_ident_injective:
  forall x y,
    0 <= x <= Int.max_unsigned ->
    0 <= y <= Int.max_unsigned ->
    phi_ident x = phi_ident y ->
    x = y.
Proof.
unfold phi_ident; intros.
replace x with (Int.unsigned (Int.repr x)); try (rewrite Int.unsigned_repr; auto; fail).
rewrite H1; rewrite Int.unsigned_repr; auto.
Qed.

Theorem transf_program_correct_ident:
  forward_simulation (Clight.semantics1 prog) (Clight.semantics1 tprog).
Proof.
  eapply (transf_program_correct phi_ident phi_ident_injective); eauto.
Qed.

End PRESERVATION_IDENT.

Section PRESERVATION_INV.

Parametrisation with the \ x -> 2^32 - 1 - x function
Definition phi_inv x := Int.repr (Int.max_unsigned - x).

Variable prog: Clight.program.
Variable tprog: Clight.program.
Hypothesis TRANSF: transf_program phi_inv prog = OK tprog.
Let ge := Genv.globalenv prog.
Let tge := Genv.globalenv tprog.

Theorem phi_inv_injective:
  forall x y,
    0 <= x <= Int.max_unsigned ->
    0 <= y <= Int.max_unsigned ->
    phi_inv x = phi_inv y ->
    x = y.
Proof.
intros; assert (Int.unsigned (phi_inv x) = Int.unsigned (phi_inv y)); try congruence.
unfold phi_inv in H2. rewrite Int.unsigned_repr in H2; try omega. rewrite Int.unsigned_repr in H2; try omega.
Qed.

Theorem transf_program_correct_inv:
  forward_simulation (Clight.semantics1 prog) (Clight.semantics1 tprog).
Proof.
  eapply (transf_program_correct phi_inv phi_inv_injective); eauto.
Qed.

End PRESERVATION_INV.